diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 149994b815..728c6d4b3b 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2596,6 +2596,21 @@ PCIDevice *pci_get_function_0(PCIDevice *pci_dev) } } +MSIMessage pci_get_msi_message(PCIDevice *dev, int vector) +{ + MSIMessage msg; + if (msix_enabled(dev)) { + msg = msix_get_message(dev, vector); + } else if (msi_enabled(dev)) { + msg = msi_get_message(dev, vector); + } else { + /* Should never happen */ + error_report("%s: unknown interrupt type", __func__); + abort(); + } + return msg; +} + static const TypeInfo pci_device_type_info = { .name = TYPE_PCI_DEVICE, .parent = TYPE_DEVICE, diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 9ed1624f09..74d797d1cf 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -805,4 +805,6 @@ extern const VMStateDescription vmstate_pci_device; .offset = vmstate_offset_pointer(_state, _field, PCIDevice), \ } +MSIMessage pci_get_msi_message(PCIDevice *dev, int vector); + #endif diff --git a/kvm-all.c b/kvm-all.c index 69ff658f4d..ca30a58a11 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1246,15 +1246,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) MSIMessage msg = {0, 0}; if (dev) { - if (msix_enabled(dev)) { - msg = msix_get_message(dev, vector); - } else if (msi_enabled(dev)) { - msg = msi_get_message(dev, vector); - } else { - /* Should never happen */ - error_report("%s: unknown interrupt type", __func__); - abort(); - } + msg = pci_get_msi_message(dev, vector); } if (kvm_gsi_direct_mapping()) { diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 8875034500..61f57f9f20 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -36,6 +36,7 @@ #include "hw/i386/apic_internal.h" #include "hw/i386/apic-msidef.h" #include "hw/i386/intel_iommu.h" +#include "hw/i386/x86-iommu.h" #include "exec/ioport.h" #include "standard-headers/asm-x86/hyperv.h" @@ -3413,9 +3414,26 @@ struct MSIRouteEntry { static QLIST_HEAD(, MSIRouteEntry) msi_route_list = \ QLIST_HEAD_INITIALIZER(msi_route_list); +static void kvm_update_msi_routes_all(void *private, bool global, + uint32_t index, uint32_t mask) +{ + int cnt = 0; + MSIRouteEntry *entry; + MSIMessage msg; + /* TODO: explicit route update */ + QLIST_FOREACH(entry, &msi_route_list, list) { + cnt++; + msg = pci_get_msi_message(entry->dev, entry->vector); + kvm_irqchip_update_msi_route(kvm_state, entry->virq, + msg, entry->dev); + } + trace_kvm_x86_update_msi_routes(cnt); +} + int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, int vector, PCIDevice *dev) { + static bool notify_list_inited = false; MSIRouteEntry *entry; if (!dev) { @@ -3432,6 +3450,18 @@ int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, QLIST_INSERT_HEAD(&msi_route_list, entry, list); trace_kvm_x86_add_msi_route(route->gsi); + + if (!notify_list_inited) { + /* For the first time we do add route, add ourselves into + * IOMMU's IEC notify list if needed. */ + X86IOMMUState *iommu = x86_iommu_get_default(); + if (iommu) { + x86_iommu_iec_register_notifier(iommu, + kvm_update_msi_routes_all, + NULL); + } + notify_list_inited = true; + } return 0; } diff --git a/target-i386/trace-events b/target-i386/trace-events index 818058c4ac..ccc49e31e8 100644 --- a/target-i386/trace-events +++ b/target-i386/trace-events @@ -4,3 +4,4 @@ kvm_x86_fixup_msi_error(uint32_t gsi) "VT-d failed to remap interrupt for GSI %" PRIu32 kvm_x86_add_msi_route(int virq) "Adding route entry for virq %d" kvm_x86_remove_msi_route(int virq) "Removing route entry for virq %d" +kvm_x86_update_msi_routes(int num) "Updated %d MSI routes"