| From 53b7ca1a359389276c76fbc9e1009d8626a17e40 Mon Sep 17 00:00:00 2001 |
| From: Paolo Bonzini <pbonzini@redhat.com> |
| Date: Mon, 22 Nov 2021 19:43:11 -0500 |
| Subject: KVM: x86: Use a stable condition around all VT-d PI paths |
| |
| From: Paolo Bonzini <pbonzini@redhat.com> |
| |
| commit 53b7ca1a359389276c76fbc9e1009d8626a17e40 upstream. |
| |
| Currently, checks for whether VT-d PI can be used refer to the current |
| status of the feature in the current vCPU; or they more or less pick |
| vCPU 0 in case a specific vCPU is not available. |
| |
| However, these checks do not attempt to synchronize with changes to |
| the IRTE. In particular, there is no path that updates the IRTE when |
| APICv is re-activated on vCPU 0; and there is no path to wakeup a CPU |
| that has APICv disabled, if the wakeup occurs because of an IRTE |
| that points to a posted interrupt. |
| |
| To fix this, always go through the VT-d PI path as long as there are |
| assigned devices and APICv is available on both the host and the VM side. |
| Since the relevant condition was copied over three times, take the hint |
| and factor it into a separate function. |
| |
| Suggested-by: Sean Christopherson <seanjc@google.com> |
| Cc: stable@vger.kernel.org |
| Reviewed-by: Sean Christopherson <seanjc@google.com> |
| Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> |
| Reviewed-by: David Matlack <dmatlack@google.com> |
| Message-Id: <20211123004311.2954158-5-pbonzini@redhat.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/kvm/vmx/posted_intr.c | 20 +++++++++++--------- |
| 1 file changed, 11 insertions(+), 9 deletions(-) |
| |
| --- a/arch/x86/kvm/vmx/posted_intr.c |
| +++ b/arch/x86/kvm/vmx/posted_intr.c |
| @@ -5,6 +5,7 @@ |
| #include <asm/cpu.h> |
| |
| #include "lapic.h" |
| +#include "irq.h" |
| #include "posted_intr.h" |
| #include "trace.h" |
| #include "vmx.h" |
| @@ -77,13 +78,18 @@ after_clear_sn: |
| pi_set_on(pi_desc); |
| } |
| |
| +static bool vmx_can_use_vtd_pi(struct kvm *kvm) |
| +{ |
| + return irqchip_in_kernel(kvm) && enable_apicv && |
| + kvm_arch_has_assigned_device(kvm) && |
| + irq_remapping_cap(IRQ_POSTING_CAP); |
| +} |
| + |
| void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu) |
| { |
| struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); |
| |
| - if (!kvm_arch_has_assigned_device(vcpu->kvm) || |
| - !irq_remapping_cap(IRQ_POSTING_CAP) || |
| - !kvm_vcpu_apicv_active(vcpu)) |
| + if (!vmx_can_use_vtd_pi(vcpu->kvm)) |
| return; |
| |
| /* Set SN when the vCPU is preempted */ |
| @@ -141,9 +147,7 @@ int pi_pre_block(struct kvm_vcpu *vcpu) |
| struct pi_desc old, new; |
| struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); |
| |
| - if (!kvm_arch_has_assigned_device(vcpu->kvm) || |
| - !irq_remapping_cap(IRQ_POSTING_CAP) || |
| - !kvm_vcpu_apicv_active(vcpu)) |
| + if (!vmx_can_use_vtd_pi(vcpu->kvm)) |
| return 0; |
| |
| WARN_ON(irqs_disabled()); |
| @@ -256,9 +260,7 @@ int pi_update_irte(struct kvm *kvm, unsi |
| struct vcpu_data vcpu_info; |
| int idx, ret = 0; |
| |
| - if (!kvm_arch_has_assigned_device(kvm) || |
| - !irq_remapping_cap(IRQ_POSTING_CAP) || |
| - !kvm_vcpu_apicv_active(kvm->vcpus[0])) |
| + if (!vmx_can_use_vtd_pi(kvm)) |
| return 0; |
| |
| idx = srcu_read_lock(&kvm->irq_srcu); |