mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 02:53:36 +02:00
KVM: SVM: Stop walking list of routing table entries when updating IRTE
Now that KVM explicitly passes the new/current GSI routing to pi_update_irte(), simply use the provided routing entry and stop walking the routing table to find that entry. KVM, via setup_routing_entry() and sanity checked by kvm_get_msi_route(), disallows having a GSI configured to trigger multiple MSIs. I.e. this is subtly a glorified nop, as KVM allows at most one MSI per GSI, the for-loop can only ever process one entry, and that entry is the new/current entry (see the WARN_ON_ONCE() added by "KVM: x86: Pass new routing entries and irqfd when updating IRTEs" to ensure @new matches the entry found in the routing table). Tested-by: Sairaj Kodilkar <sarunkod@amd.com> Link: https://lore.kernel.org/r/20250611224604.313496-25-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
parent
95d50ebe6d
commit
1e663ed239
|
|
@ -844,11 +844,10 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
|
|||
unsigned int host_irq, uint32_t guest_irq,
|
||||
struct kvm_kernel_irq_routing_entry *new)
|
||||
{
|
||||
struct kvm_kernel_irq_routing_entry *e;
|
||||
struct kvm_irq_routing_table *irq_rt;
|
||||
bool enable_remapped_mode = true;
|
||||
bool set = !!new;
|
||||
int idx, ret = 0;
|
||||
struct vcpu_data vcpu_info;
|
||||
struct vcpu_svm *svm = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!kvm_arch_has_assigned_device(kvm) || !kvm_arch_has_irq_bypass())
|
||||
return 0;
|
||||
|
|
@ -860,72 +859,53 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
|
|||
svm_ir_list_del(irqfd);
|
||||
|
||||
pr_debug("SVM: %s: host_irq=%#x, guest_irq=%#x, set=%#x\n",
|
||||
__func__, host_irq, guest_irq, set);
|
||||
__func__, host_irq, guest_irq, !!new);
|
||||
|
||||
idx = srcu_read_lock(&kvm->irq_srcu);
|
||||
irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
|
||||
/**
|
||||
* Here, we setup with legacy mode in the following cases:
|
||||
* 1. When cannot target interrupt to a specific vcpu.
|
||||
* 2. Unsetting posted interrupt.
|
||||
* 3. APIC virtualization is disabled for the vcpu.
|
||||
* 4. IRQ has incompatible delivery mode (SMI, INIT, etc)
|
||||
*/
|
||||
if (new && new->type == KVM_IRQ_ROUTING_MSI &&
|
||||
!get_pi_vcpu_info(kvm, new, &vcpu_info, &svm) &&
|
||||
kvm_vcpu_apicv_active(&svm->vcpu)) {
|
||||
struct amd_iommu_pi_data pi;
|
||||
|
||||
if (guest_irq >= irq_rt->nr_rt_entries ||
|
||||
hlist_empty(&irq_rt->map[guest_irq])) {
|
||||
pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n",
|
||||
guest_irq, irq_rt->nr_rt_entries);
|
||||
goto out;
|
||||
}
|
||||
enable_remapped_mode = false;
|
||||
|
||||
hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) {
|
||||
struct vcpu_data vcpu_info;
|
||||
struct vcpu_svm *svm = NULL;
|
||||
|
||||
if (e->type != KVM_IRQ_ROUTING_MSI)
|
||||
continue;
|
||||
|
||||
WARN_ON_ONCE(new && memcmp(e, new, sizeof(*new)));
|
||||
/*
|
||||
* Try to enable guest_mode in IRTE. Note, the address
|
||||
* of the vCPU's AVIC backing page is passed to the
|
||||
* IOMMU via vcpu_info->pi_desc_addr.
|
||||
*/
|
||||
pi.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
|
||||
svm->vcpu.vcpu_id);
|
||||
pi.is_guest_mode = true;
|
||||
pi.vcpu_data = &vcpu_info;
|
||||
ret = irq_set_vcpu_affinity(host_irq, &pi);
|
||||
|
||||
/**
|
||||
* Here, we setup with legacy mode in the following cases:
|
||||
* 1. When cannot target interrupt to a specific vcpu.
|
||||
* 2. Unsetting posted interrupt.
|
||||
* 3. APIC virtualization is disabled for the vcpu.
|
||||
* 4. IRQ has incompatible delivery mode (SMI, INIT, etc)
|
||||
* Here, we successfully setting up vcpu affinity in
|
||||
* IOMMU guest mode. Now, we need to store the posted
|
||||
* interrupt information in a per-vcpu ir_list so that
|
||||
* we can reference to them directly when we update vcpu
|
||||
* scheduling information in IOMMU irte.
|
||||
*/
|
||||
if (!get_pi_vcpu_info(kvm, e, &vcpu_info, &svm) && set &&
|
||||
kvm_vcpu_apicv_active(&svm->vcpu)) {
|
||||
struct amd_iommu_pi_data pi;
|
||||
if (!ret)
|
||||
ret = svm_ir_list_add(svm, irqfd, &pi);
|
||||
}
|
||||
|
||||
enable_remapped_mode = false;
|
||||
if (!ret && svm) {
|
||||
trace_kvm_pi_irte_update(host_irq, svm->vcpu.vcpu_id,
|
||||
guest_irq, vcpu_info.vector,
|
||||
vcpu_info.pi_desc_addr, !!new);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to enable guest_mode in IRTE. Note, the address
|
||||
* of the vCPU's AVIC backing page is passed to the
|
||||
* IOMMU via vcpu_info->pi_desc_addr.
|
||||
*/
|
||||
pi.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
|
||||
svm->vcpu.vcpu_id);
|
||||
pi.is_guest_mode = true;
|
||||
pi.vcpu_data = &vcpu_info;
|
||||
ret = irq_set_vcpu_affinity(host_irq, &pi);
|
||||
|
||||
/**
|
||||
* Here, we successfully setting up vcpu affinity in
|
||||
* IOMMU guest mode. Now, we need to store the posted
|
||||
* interrupt information in a per-vcpu ir_list so that
|
||||
* we can reference to them directly when we update vcpu
|
||||
* scheduling information in IOMMU irte.
|
||||
*/
|
||||
if (!ret && pi.is_guest_mode)
|
||||
svm_ir_list_add(svm, irqfd, &pi);
|
||||
}
|
||||
|
||||
if (!ret && svm) {
|
||||
trace_kvm_pi_irte_update(host_irq, svm->vcpu.vcpu_id,
|
||||
e->gsi, vcpu_info.vector,
|
||||
vcpu_info.pi_desc_addr, set);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed to update PI IRTE\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed to update PI IRTE\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (enable_remapped_mode)
|
||||
|
|
@ -933,7 +913,6 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
|
|||
else
|
||||
ret = 0;
|
||||
out:
|
||||
srcu_read_unlock(&kvm->irq_srcu, idx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user