KVM: PPC: Book3S HV nestedv2: Register the VPA with the L0
authorJordan Niethe <jniethe5@gmail.com>
Fri, 1 Dec 2023 13:26:15 +0000 (18:56 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 7 Dec 2023 12:33:08 +0000 (23:33 +1100)
In the nestedv2 case, the L1 may register the L2's VPA with the L0. This
allows the L0 to manage the L2's dispatch count, as well as enable
possible performance optimisations by seeing if certain resources are
not being used by the L2 (such as the PMCs).

Use the H_GUEST_SET_STATE call to inform the L0 of the L2's VPA
address. This can not be done in the H_GUEST_VCPU_RUN input buffer.

Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20231201132618.555031-11-vaibhav@linux.ibm.com
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_nestedv2.c

index 2477021bff540b21030866a9ecb3e8c7e9c1dde8..d8729ec81ca083cdc4ac219f954b323f59afe279 100644 (file)
@@ -682,6 +682,7 @@ void kvmhv_nestedv2_vcpu_free(struct kvm_vcpu *vcpu, struct kvmhv_nestedv2_io *i
 int kvmhv_nestedv2_flush_vcpu(struct kvm_vcpu *vcpu, u64 time_limit);
 int kvmhv_nestedv2_set_ptbl_entry(unsigned long lpid, u64 dw0, u64 dw1);
 int kvmhv_nestedv2_parse_output(struct kvm_vcpu *vcpu);
+int kvmhv_nestedv2_set_vpa(struct kvm_vcpu *vcpu, unsigned long vpa);
 
 #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
 
index 47fe470375dfbe91b7cfb08a21a76a8db4ebe7bf..2ee3f24785708ebe7d8d925b12e27b31e028f450 100644 (file)
@@ -650,7 +650,8 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,
        return err;
 }
 
-static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap)
+static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap,
+                              struct kvmppc_vpa *old_vpap)
 {
        struct kvm *kvm = vcpu->kvm;
        void *va;
@@ -690,9 +691,8 @@ static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap)
                kvmppc_unpin_guest_page(kvm, va, gpa, false);
                va = NULL;
        }
-       if (vpap->pinned_addr)
-               kvmppc_unpin_guest_page(kvm, vpap->pinned_addr, vpap->gpa,
-                                       vpap->dirty);
+       *old_vpap = *vpap;
+
        vpap->gpa = gpa;
        vpap->pinned_addr = va;
        vpap->dirty = false;
@@ -702,6 +702,9 @@ static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap)
 
 static void kvmppc_update_vpas(struct kvm_vcpu *vcpu)
 {
+       struct kvm *kvm = vcpu->kvm;
+       struct kvmppc_vpa old_vpa = { 0 };
+
        if (!(vcpu->arch.vpa.update_pending ||
              vcpu->arch.slb_shadow.update_pending ||
              vcpu->arch.dtl.update_pending))
@@ -709,17 +712,34 @@ static void kvmppc_update_vpas(struct kvm_vcpu *vcpu)
 
        spin_lock(&vcpu->arch.vpa_update_lock);
        if (vcpu->arch.vpa.update_pending) {
-               kvmppc_update_vpa(vcpu, &vcpu->arch.vpa);
-               if (vcpu->arch.vpa.pinned_addr)
+               kvmppc_update_vpa(vcpu, &vcpu->arch.vpa, &old_vpa);
+               if (old_vpa.pinned_addr) {
+                       if (kvmhv_is_nestedv2())
+                               kvmhv_nestedv2_set_vpa(vcpu, ~0ull);
+                       kvmppc_unpin_guest_page(kvm, old_vpa.pinned_addr, old_vpa.gpa,
+                                               old_vpa.dirty);
+               }
+               if (vcpu->arch.vpa.pinned_addr) {
                        init_vpa(vcpu, vcpu->arch.vpa.pinned_addr);
+                       if (kvmhv_is_nestedv2())
+                               kvmhv_nestedv2_set_vpa(vcpu, __pa(vcpu->arch.vpa.pinned_addr));
+               }
        }
        if (vcpu->arch.dtl.update_pending) {
-               kvmppc_update_vpa(vcpu, &vcpu->arch.dtl);
+               kvmppc_update_vpa(vcpu, &vcpu->arch.dtl, &old_vpa);
+               if (old_vpa.pinned_addr)
+                       kvmppc_unpin_guest_page(kvm, old_vpa.pinned_addr, old_vpa.gpa,
+                                               old_vpa.dirty);
                vcpu->arch.dtl_ptr = vcpu->arch.dtl.pinned_addr;
                vcpu->arch.dtl_index = 0;
        }
-       if (vcpu->arch.slb_shadow.update_pending)
-               kvmppc_update_vpa(vcpu, &vcpu->arch.slb_shadow);
+       if (vcpu->arch.slb_shadow.update_pending) {
+               kvmppc_update_vpa(vcpu, &vcpu->arch.slb_shadow, &old_vpa);
+               if (old_vpa.pinned_addr)
+                       kvmppc_unpin_guest_page(kvm, old_vpa.pinned_addr, old_vpa.gpa,
+                                               old_vpa.dirty);
+       }
+
        spin_unlock(&vcpu->arch.vpa_update_lock);
 }
 
index fd3c4f2d94805601f677cc1e9b3c0e2385a7a3b5..5378eb40b162f2690879f43fbaeb3f0b003536a7 100644 (file)
@@ -855,6 +855,35 @@ free_gsb:
 }
 EXPORT_SYMBOL_GPL(kvmhv_nestedv2_set_ptbl_entry);
 
+/**
+ * kvmhv_nestedv2_set_vpa() - register L2 VPA with L0
+ * @vcpu: vcpu
+ * @vpa: L1 logical real address
+ */
+int kvmhv_nestedv2_set_vpa(struct kvm_vcpu *vcpu, unsigned long vpa)
+{
+       struct kvmhv_nestedv2_io *io;
+       struct kvmppc_gs_buff *gsb;
+       int rc = 0;
+
+       io = &vcpu->arch.nestedv2_io;
+       gsb = io->vcpu_run_input;
+
+       kvmppc_gsb_reset(gsb);
+       rc = kvmppc_gse_put_u64(gsb, KVMPPC_GSID_VPA, vpa);
+       if (rc < 0)
+               goto out;
+
+       rc = kvmppc_gsb_send(gsb, 0);
+       if (rc < 0)
+               pr_err("KVM-NESTEDv2: couldn't register the L2 VPA (rc=%d)\n", rc);
+
+out:
+       kvmppc_gsb_reset(gsb);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(kvmhv_nestedv2_set_vpa);
+
 /**
  * kvmhv_nestedv2_parse_output() - receive values from H_GUEST_RUN_VCPU output
  * @vcpu: vcpu