Commit f5369619 authored by Sean Christopherson's avatar Sean Christopherson
Browse files

KVM: x86: Move IRQ routing/delivery APIs from x86.c => irq.c



Move a bunch of IRQ routing and delivery APIs from x86.c to irq.c.  x86.c
has grown quite fat, and irq.c is the perfect landing spot.

Opportunistically rewrite kvm_arch_irq_bypass_del_producer()'s comment, as
the existing comment has several typos and is rather confusing.

Suggested-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20250611224604.313496-28-seanjc@google.com


Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
parent 0a64c447
Loading
Loading
Loading
Loading
+88 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@

#include <linux/export.h>
#include <linux/kvm_host.h>
#include <linux/kvm_irqfd.h>

#include "hyperv.h"
#include "ioapic.h"
@@ -332,6 +333,18 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
	return -EWOULDBLOCK;
}

int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event,
			bool line_status)
{
	if (!irqchip_in_kernel(kvm))
		return -ENXIO;

	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
					irq_event->irq, irq_event->level,
					line_status);
	return 0;
}

bool kvm_arch_can_set_irq_routing(struct kvm *kvm)
{
	return irqchip_in_kernel(kvm);
@@ -495,6 +508,81 @@ void kvm_arch_irq_routing_update(struct kvm *kvm)
		kvm_make_scan_ioapic_request(kvm);
}

int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons,
				      struct irq_bypass_producer *prod)
{
	struct kvm_kernel_irqfd *irqfd =
		container_of(cons, struct kvm_kernel_irqfd, consumer);
	struct kvm *kvm = irqfd->kvm;
	int ret = 0;

	kvm_arch_start_assignment(irqfd->kvm);

	spin_lock_irq(&kvm->irqfds.lock);
	irqfd->producer = prod;

	if (irqfd->irq_entry.type == KVM_IRQ_ROUTING_MSI) {
		ret = kvm_x86_call(pi_update_irte)(irqfd, irqfd->kvm, prod->irq,
						   irqfd->gsi, &irqfd->irq_entry);
		if (ret)
			kvm_arch_end_assignment(irqfd->kvm);
	}
	spin_unlock_irq(&kvm->irqfds.lock);

	return ret;
}

void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
				      struct irq_bypass_producer *prod)
{
	struct kvm_kernel_irqfd *irqfd =
		container_of(cons, struct kvm_kernel_irqfd, consumer);
	struct kvm *kvm = irqfd->kvm;
	int ret;

	WARN_ON(irqfd->producer != prod);

	/*
	 * If the producer of an IRQ that is currently being posted to a vCPU
	 * is unregistered, change the associated IRTE back to remapped mode as
	 * the IRQ has been released (or repurposed) by the device driver, i.e.
	 * KVM must relinquish control of the IRTE.
	 */
	spin_lock_irq(&kvm->irqfds.lock);
	irqfd->producer = NULL;

	if (irqfd->irq_entry.type == KVM_IRQ_ROUTING_MSI) {
		ret = kvm_x86_call(pi_update_irte)(irqfd, irqfd->kvm, prod->irq,
						   irqfd->gsi, NULL);
		if (ret)
			pr_info("irq bypass consumer (eventfd %p) unregistration fails: %d\n",
				irqfd->consumer.eventfd, ret);
	}

	spin_unlock_irq(&kvm->irqfds.lock);


	kvm_arch_end_assignment(irqfd->kvm);
}

int kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
				  struct kvm_kernel_irq_routing_entry *old,
				  struct kvm_kernel_irq_routing_entry *new)
{
	return kvm_x86_call(pi_update_irte)(irqfd, irqfd->kvm, irqfd->producer->irq,
					    irqfd->gsi, new);
}

bool kvm_arch_irqfd_route_changed(struct kvm_kernel_irq_routing_entry *old,
				  struct kvm_kernel_irq_routing_entry *new)
{
	if (old->type != KVM_IRQ_ROUTING_MSI ||
	    new->type != KVM_IRQ_ROUTING_MSI)
		return true;

	return !!memcmp(&old->msi, &new->msi, sizeof(new->msi));
}

#ifdef CONFIG_KVM_IOAPIC
#define IOAPIC_ROUTING_ENTRY(irq) \
	{ .gsi = irq, .type = KVM_IRQ_ROUTING_IRQCHIP,	\
+0 −87
Original line number Diff line number Diff line
@@ -6420,18 +6420,6 @@ void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
		kvm_vcpu_kick(vcpu);
}

int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event,
			bool line_status)
{
	if (!irqchip_in_kernel(kvm))
		return -ENXIO;

	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
					irq_event->irq, irq_event->level,
					line_status);
	return 0;
}

int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
			    struct kvm_enable_cap *cap)
{
@@ -13504,81 +13492,6 @@ bool kvm_arch_has_noncoherent_dma(struct kvm *kvm)
}
EXPORT_SYMBOL_GPL(kvm_arch_has_noncoherent_dma);

int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons,
				      struct irq_bypass_producer *prod)
{
	struct kvm_kernel_irqfd *irqfd =
		container_of(cons, struct kvm_kernel_irqfd, consumer);
	struct kvm *kvm = irqfd->kvm;
	int ret = 0;

	kvm_arch_start_assignment(irqfd->kvm);

	spin_lock_irq(&kvm->irqfds.lock);
	irqfd->producer = prod;

	if (irqfd->irq_entry.type == KVM_IRQ_ROUTING_MSI) {
		ret = kvm_x86_call(pi_update_irte)(irqfd, irqfd->kvm, prod->irq,
						   irqfd->gsi, &irqfd->irq_entry);
		if (ret)
			kvm_arch_end_assignment(irqfd->kvm);
	}
	spin_unlock_irq(&kvm->irqfds.lock);

	return ret;
}

void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
				      struct irq_bypass_producer *prod)
{
	struct kvm_kernel_irqfd *irqfd =
		container_of(cons, struct kvm_kernel_irqfd, consumer);
	struct kvm *kvm = irqfd->kvm;
	int ret;

	WARN_ON(irqfd->producer != prod);

	/*
	 * When producer of consumer is unregistered, we change back to
	 * remapped mode, so we can re-use the current implementation
	 * when the irq is masked/disabled or the consumer side (KVM
	 * int this case doesn't want to receive the interrupts.
	*/
	spin_lock_irq(&kvm->irqfds.lock);
	irqfd->producer = NULL;

	if (irqfd->irq_entry.type == KVM_IRQ_ROUTING_MSI) {
		ret = kvm_x86_call(pi_update_irte)(irqfd, irqfd->kvm, prod->irq,
						   irqfd->gsi, NULL);
		if (ret)
			pr_info("irq bypass consumer (eventfd %p) unregistration fails: %d\n",
				irqfd->consumer.eventfd, ret);
	}

	spin_unlock_irq(&kvm->irqfds.lock);


	kvm_arch_end_assignment(irqfd->kvm);
}

int kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
				  struct kvm_kernel_irq_routing_entry *old,
				  struct kvm_kernel_irq_routing_entry *new)
{
	return kvm_x86_call(pi_update_irte)(irqfd, irqfd->kvm, irqfd->producer->irq,
					    irqfd->gsi, new);
}

bool kvm_arch_irqfd_route_changed(struct kvm_kernel_irq_routing_entry *old,
				  struct kvm_kernel_irq_routing_entry *new)
{
	if (old->type != KVM_IRQ_ROUTING_MSI ||
	    new->type != KVM_IRQ_ROUTING_MSI)
		return true;

	return !!memcmp(&old->msi, &new->msi, sizeof(new->msi));
}

bool kvm_vector_hashing_enabled(void)
{
	return vector_hashing;