Commit 1e663ed2 authored by Sean Christopherson's avatar Sean Christopherson
Browse files

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: default avatarSairaj Kodilkar <sarunkod@amd.com>
Link: https://lore.kernel.org/r/20250611224604.313496-25-seanjc@google.com


Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
parent 95d50ebe
Loading
Loading
Loading
Loading
+43 −64
Original line number Diff line number Diff line
@@ -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,26 +859,7 @@ 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;

		if (e->type != KVM_IRQ_ROUTING_MSI)
			continue;

		WARN_ON_ONCE(new && memcmp(e, new, sizeof(*new)));
		 __func__, host_irq, guest_irq, !!new);

	/**
	 * Here, we setup with legacy mode in the following cases:
@@ -888,7 +868,8 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
	 * 3. APIC virtualization is disabled for the vcpu.
	 * 4. IRQ has incompatible delivery mode (SMI, INIT, etc)
	 */
		if (!get_pi_vcpu_info(kvm, e, &vcpu_info, &svm) && set &&
	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;

@@ -912,28 +893,26 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
		 * 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);
					 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 (enable_remapped_mode)
		ret = irq_set_vcpu_affinity(host_irq, NULL);
	else
		ret = 0;
out:
	srcu_read_unlock(&kvm->irq_srcu, idx);
	return ret;
}