]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: SVM: Stop walking list of routing table entries when updating IRTE
authorSean Christopherson <seanjc@google.com>
Wed, 11 Jun 2025 22:45:26 +0000 (15:45 -0700)
committerSean Christopherson <seanjc@google.com>
Mon, 23 Jun 2025 16:50:26 +0000 (09:50 -0700)
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>
arch/x86/kvm/svm/avic.c

index e09722f5b5fab97a91610d722a20028e9816a0b1..a1a5b86a37fef8bb9ee475e9d604c067eceb3d28 100644 (file)
@@ -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);
-
-       idx = srcu_read_lock(&kvm->irq_srcu);
-       irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
-
-       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;
-       }
-
-       hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) {
-               struct vcpu_data vcpu_info;
-               struct vcpu_svm *svm = NULL;
+                __func__, host_irq, guest_irq, !!new);
+
+       /**
+        * 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 (e->type != KVM_IRQ_ROUTING_MSI)
-                       continue;
+               enable_remapped_mode = false;
 
-               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;
-
-                       enable_remapped_mode = false;
-
-                       /*
-                        * 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)
+                       ret = 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 && svm) {
+               trace_kvm_pi_irte_update(host_irq, svm->vcpu.vcpu_id,
+                                        guest_irq, vcpu_info.vector,
+                                        vcpu_info.pi_desc_addr, !!new);
+       }
 
-               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;
 }