Skip to content

Commit 1e663ed

Browse files
committed
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>
1 parent 95d50eb commit 1e663ed

File tree

1 file changed

+43
-64
lines changed

1 file changed

+43
-64
lines changed

arch/x86/kvm/svm/avic.c

Lines changed: 43 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -844,11 +844,10 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
844844
unsigned int host_irq, uint32_t guest_irq,
845845
struct kvm_kernel_irq_routing_entry *new)
846846
{
847-
struct kvm_kernel_irq_routing_entry *e;
848-
struct kvm_irq_routing_table *irq_rt;
849847
bool enable_remapped_mode = true;
850-
bool set = !!new;
851-
int idx, ret = 0;
848+
struct vcpu_data vcpu_info;
849+
struct vcpu_svm *svm = NULL;
850+
int ret = 0;
852851

853852
if (!kvm_arch_has_assigned_device(kvm) || !kvm_arch_has_irq_bypass())
854853
return 0;
@@ -860,80 +859,60 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
860859
svm_ir_list_del(irqfd);
861860

862861
pr_debug("SVM: %s: host_irq=%#x, guest_irq=%#x, set=%#x\n",
863-
__func__, host_irq, guest_irq, set);
864-
865-
idx = srcu_read_lock(&kvm->irq_srcu);
866-
irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
867-
868-
if (guest_irq >= irq_rt->nr_rt_entries ||
869-
hlist_empty(&irq_rt->map[guest_irq])) {
870-
pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n",
871-
guest_irq, irq_rt->nr_rt_entries);
872-
goto out;
873-
}
874-
875-
hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) {
876-
struct vcpu_data vcpu_info;
877-
struct vcpu_svm *svm = NULL;
862+
__func__, host_irq, guest_irq, !!new);
863+
864+
/**
865+
* Here, we setup with legacy mode in the following cases:
866+
* 1. When cannot target interrupt to a specific vcpu.
867+
* 2. Unsetting posted interrupt.
868+
* 3. APIC virtualization is disabled for the vcpu.
869+
* 4. IRQ has incompatible delivery mode (SMI, INIT, etc)
870+
*/
871+
if (new && new->type == KVM_IRQ_ROUTING_MSI &&
872+
!get_pi_vcpu_info(kvm, new, &vcpu_info, &svm) &&
873+
kvm_vcpu_apicv_active(&svm->vcpu)) {
874+
struct amd_iommu_pi_data pi;
878875

879-
if (e->type != KVM_IRQ_ROUTING_MSI)
880-
continue;
876+
enable_remapped_mode = false;
881877

882-
WARN_ON_ONCE(new && memcmp(e, new, sizeof(*new)));
878+
/*
879+
* Try to enable guest_mode in IRTE. Note, the address
880+
* of the vCPU's AVIC backing page is passed to the
881+
* IOMMU via vcpu_info->pi_desc_addr.
882+
*/
883+
pi.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
884+
svm->vcpu.vcpu_id);
885+
pi.is_guest_mode = true;
886+
pi.vcpu_data = &vcpu_info;
887+
ret = irq_set_vcpu_affinity(host_irq, &pi);
883888

884889
/**
885-
* Here, we setup with legacy mode in the following cases:
886-
* 1. When cannot target interrupt to a specific vcpu.
887-
* 2. Unsetting posted interrupt.
888-
* 3. APIC virtualization is disabled for the vcpu.
889-
* 4. IRQ has incompatible delivery mode (SMI, INIT, etc)
890+
* Here, we successfully setting up vcpu affinity in
891+
* IOMMU guest mode. Now, we need to store the posted
892+
* interrupt information in a per-vcpu ir_list so that
893+
* we can reference to them directly when we update vcpu
894+
* scheduling information in IOMMU irte.
890895
*/
891-
if (!get_pi_vcpu_info(kvm, e, &vcpu_info, &svm) && set &&
892-
kvm_vcpu_apicv_active(&svm->vcpu)) {
893-
struct amd_iommu_pi_data pi;
894-
895-
enable_remapped_mode = false;
896-
897-
/*
898-
* Try to enable guest_mode in IRTE. Note, the address
899-
* of the vCPU's AVIC backing page is passed to the
900-
* IOMMU via vcpu_info->pi_desc_addr.
901-
*/
902-
pi.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
903-
svm->vcpu.vcpu_id);
904-
pi.is_guest_mode = true;
905-
pi.vcpu_data = &vcpu_info;
906-
ret = irq_set_vcpu_affinity(host_irq, &pi);
907-
908-
/**
909-
* Here, we successfully setting up vcpu affinity in
910-
* IOMMU guest mode. Now, we need to store the posted
911-
* interrupt information in a per-vcpu ir_list so that
912-
* we can reference to them directly when we update vcpu
913-
* scheduling information in IOMMU irte.
914-
*/
915-
if (!ret && pi.is_guest_mode)
916-
svm_ir_list_add(svm, irqfd, &pi);
917-
}
896+
if (!ret)
897+
ret = svm_ir_list_add(svm, irqfd, &pi);
898+
}
918899

919-
if (!ret && svm) {
920-
trace_kvm_pi_irte_update(host_irq, svm->vcpu.vcpu_id,
921-
e->gsi, vcpu_info.vector,
922-
vcpu_info.pi_desc_addr, set);
923-
}
900+
if (!ret && svm) {
901+
trace_kvm_pi_irte_update(host_irq, svm->vcpu.vcpu_id,
902+
guest_irq, vcpu_info.vector,
903+
vcpu_info.pi_desc_addr, !!new);
904+
}
924905

925-
if (ret < 0) {
926-
pr_err("%s: failed to update PI IRTE\n", __func__);
927-
goto out;
928-
}
906+
if (ret < 0) {
907+
pr_err("%s: failed to update PI IRTE\n", __func__);
908+
goto out;
929909
}
930910

931911
if (enable_remapped_mode)
932912
ret = irq_set_vcpu_affinity(host_irq, NULL);
933913
else
934914
ret = 0;
935915
out:
936-
srcu_read_unlock(&kvm->irq_srcu, idx);
937916
return ret;
938917
}
939918

0 commit comments

Comments
 (0)