KVM: VMX: Move posted interrupt delivery code to common header
authorIsaku Yamahata <isaku.yamahata@intel.com>
Sat, 22 Feb 2025 01:47:44 +0000 (09:47 +0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 14 Mar 2025 18:20:55 +0000 (14:20 -0400)
Move posted interrupt delivery code to common header so that TDX can
leverage it.

No functional change intended.

Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
[binbin: split into new patch]
Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Chao Gao <chao.gao@intel.com>
Message-ID: <20250222014757.897978-4-binbin.wu@linux.intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/common.h
arch/x86/kvm/vmx/vmx.c

index a298ac7..8f30de0 100644 (file)
@@ -109,4 +109,71 @@ static inline int __vmx_handle_ept_violation(struct kvm_vcpu *vcpu, gpa_t gpa,
        return kvm_mmu_page_fault(vcpu, gpa, error_code, NULL, 0);
 }
 
+static inline void kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu,
+                                                    int pi_vec)
+{
+#ifdef CONFIG_SMP
+       if (vcpu->mode == IN_GUEST_MODE) {
+               /*
+                * The vector of the virtual has already been set in the PIR.
+                * Send a notification event to deliver the virtual interrupt
+                * unless the vCPU is the currently running vCPU, i.e. the
+                * event is being sent from a fastpath VM-Exit handler, in
+                * which case the PIR will be synced to the vIRR before
+                * re-entering the guest.
+                *
+                * When the target is not the running vCPU, the following
+                * possibilities emerge:
+                *
+                * Case 1: vCPU stays in non-root mode. Sending a notification
+                * event posts the interrupt to the vCPU.
+                *
+                * Case 2: vCPU exits to root mode and is still runnable. The
+                * PIR will be synced to the vIRR before re-entering the guest.
+                * Sending a notification event is ok as the host IRQ handler
+                * will ignore the spurious event.
+                *
+                * Case 3: vCPU exits to root mode and is blocked. vcpu_block()
+                * has already synced PIR to vIRR and never blocks the vCPU if
+                * the vIRR is not empty. Therefore, a blocked vCPU here does
+                * not wait for any requested interrupts in PIR, and sending a
+                * notification event also results in a benign, spurious event.
+                */
+
+               if (vcpu != kvm_get_running_vcpu())
+                       __apic_send_IPI_mask(get_cpu_mask(vcpu->cpu), pi_vec);
+               return;
+       }
+#endif
+       /*
+        * The vCPU isn't in the guest; wake the vCPU in case it is blocking,
+        * otherwise do nothing as KVM will grab the highest priority pending
+        * IRQ via ->sync_pir_to_irr() in vcpu_enter_guest().
+        */
+       kvm_vcpu_wake_up(vcpu);
+}
+
+/*
+ * Post an interrupt to a vCPU's PIR and trigger the vCPU to process the
+ * interrupt if necessary.
+ */
+static inline void __vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu,
+                                                 struct pi_desc *pi_desc, int vector)
+{
+       if (pi_test_and_set_pir(vector, pi_desc))
+               return;
+
+       /* If a previous notification has sent the IPI, nothing to do.  */
+       if (pi_test_and_set_on(pi_desc))
+               return;
+
+       /*
+        * The implied barrier in pi_test_and_set_on() pairs with the smp_mb_*()
+        * after setting vcpu->mode in vcpu_enter_guest(), thus the vCPU is
+        * guaranteed to see PID.ON=1 and sync the PIR to IRR if triggering a
+        * posted interrupt "fails" because vcpu->mode != IN_GUEST_MODE.
+        */
+       kvm_vcpu_trigger_posted_interrupt(vcpu, POSTED_INTR_VECTOR);
+}
+
 #endif /* __KVM_X86_VMX_COMMON_H */
index e7e4512..9ad53ab 100644 (file)
@@ -4182,50 +4182,6 @@ void vmx_msr_filter_changed(struct kvm_vcpu *vcpu)
                pt_update_intercept_for_msr(vcpu);
 }
 
-static inline void kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu,
-                                                    int pi_vec)
-{
-#ifdef CONFIG_SMP
-       if (vcpu->mode == IN_GUEST_MODE) {
-               /*
-                * The vector of the virtual has already been set in the PIR.
-                * Send a notification event to deliver the virtual interrupt
-                * unless the vCPU is the currently running vCPU, i.e. the
-                * event is being sent from a fastpath VM-Exit handler, in
-                * which case the PIR will be synced to the vIRR before
-                * re-entering the guest.
-                *
-                * When the target is not the running vCPU, the following
-                * possibilities emerge:
-                *
-                * Case 1: vCPU stays in non-root mode. Sending a notification
-                * event posts the interrupt to the vCPU.
-                *
-                * Case 2: vCPU exits to root mode and is still runnable. The
-                * PIR will be synced to the vIRR before re-entering the guest.
-                * Sending a notification event is ok as the host IRQ handler
-                * will ignore the spurious event.
-                *
-                * Case 3: vCPU exits to root mode and is blocked. vcpu_block()
-                * has already synced PIR to vIRR and never blocks the vCPU if
-                * the vIRR is not empty. Therefore, a blocked vCPU here does
-                * not wait for any requested interrupts in PIR, and sending a
-                * notification event also results in a benign, spurious event.
-                */
-
-               if (vcpu != kvm_get_running_vcpu())
-                       __apic_send_IPI_mask(get_cpu_mask(vcpu->cpu), pi_vec);
-               return;
-       }
-#endif
-       /*
-        * The vCPU isn't in the guest; wake the vCPU in case it is blocking,
-        * otherwise do nothing as KVM will grab the highest priority pending
-        * IRQ via ->sync_pir_to_irr() in vcpu_enter_guest().
-        */
-       kvm_vcpu_wake_up(vcpu);
-}
-
 static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
                                                int vector)
 {
@@ -4285,20 +4241,7 @@ static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
        if (!vcpu->arch.apic->apicv_active)
                return -1;
 
-       if (pi_test_and_set_pir(vector, &vt->pi_desc))
-               return 0;
-
-       /* If a previous notification has sent the IPI, nothing to do.  */
-       if (pi_test_and_set_on(&vt->pi_desc))
-               return 0;
-
-       /*
-        * The implied barrier in pi_test_and_set_on() pairs with the smp_mb_*()
-        * after setting vcpu->mode in vcpu_enter_guest(), thus the vCPU is
-        * guaranteed to see PID.ON=1 and sync the PIR to IRR if triggering a
-        * posted interrupt "fails" because vcpu->mode != IN_GUEST_MODE.
-        */
-       kvm_vcpu_trigger_posted_interrupt(vcpu, POSTED_INTR_VECTOR);
+       __vmx_deliver_posted_interrupt(vcpu, &vt->pi_desc, vector);
        return 0;
 }