mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
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: Paolo Bonzini <pbonzini@redhat.com> Link: https://lore.kernel.org/r/20250611224604.313496-28-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
parent
0a64c447f6
commit
f5369619f7
|
|
@ -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, \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user