We do not want a potential broadcast to all VCPUs to run in a host IRQ handler. Implement an API that sends an MSI interrupt but only if it's safe from interrupt context, that is if it is a unicast. Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx> --- include/linux/kvm_host.h | 2 ++ virt/kvm/irq_comm.c | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index c446435..ddb476a 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -618,6 +618,8 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic, int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level); int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm, int irq_source_id, int level); +int kvm_set_msi_inatomic(struct kvm_kernel_irq_routing_entry *irq_entry, + struct kvm *kvm); void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin); void kvm_register_irq_ack_notifier(struct kvm *kvm, struct kvm_irq_ack_notifier *kian); diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 5afb431..3395e03 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -114,13 +114,20 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, return r; } -int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, int level) +static bool kvm_msi_is_multicast(unsigned dest, int dest_mode) { - struct kvm_lapic_irq irq; + if (dest_mode == 0) + /* Physical mode. */ + return dest == 0xff; + else + /* Logical mode. */ + return dest & (dest - 1); +} - if (!level) - return -1; +static int __kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm, bool noblock) +{ + struct kvm_lapic_irq irq; trace_kvm_msi_set_irq(e->msi.address_lo, e->msi.data); @@ -134,10 +141,30 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, irq.level = 1; irq.shorthand = 0; + /* Multicast MSI doesn't really block but might take a long time. */ + if (unlikely(noblock && kvm_msi_is_multicast(irq.dest_id, + irq.delivery_mode))) + return -EWOULDBLOCK; + /* TODO Deal with RH bit of MSI message address */ return kvm_irq_delivery_to_apic(kvm, NULL, &irq); } +int kvm_set_msi_inatomic(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm) +{ + return __kvm_set_msi(e, kvm, true); +} + +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm, int irq_source_id, int level) +{ + if (unlikely(!level)) + return -1; + + return __kvm_set_msi(e, kvm, false); +} + int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) { struct kvm_kernel_irq_routing_entry route; -- MST -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html