Currently, kvm_arch_fixup_msi_route() unconditionally uses the default system IOMMU for interrupt remapping when IOMMU is present. This approach fails when an IOMMU is attached to a non-system bus and serves only a subset of devices, because the kernel does not program IRT (Interrupt Remapping Table) entries for devices outside the IOMMU's scope.
This patch changes the behavior to perform per-device IOMMU lookup: - For PCI devices: Use pci_device_get_x86_iommu() to find the specific IOMMU serving that device, if any - For non-PCI devices (IOAPIC): Fall back to the default IOMMU only if interrupt remapping is enabled (ioapic_as != address_space_memory) This ensures MSI route translation occurs only for devices actually managed by an IOMMU, enabling proper interrupt remapping in configurations where IOMMUs are attached to arbitrary buses. NOTE: This patch assumes that only non-PCI device calling is IOAPIC and checks ioapic_as to determine interrupt remapping. Signed-off-by: Sairaj Kodilkar <[email protected]> --- hw/intc/ioapic.c | 3 ++- target/i386/kvm/kvm.c | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 1b3f1e824ac4..f1b881ee6118 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -438,8 +438,9 @@ static void ioapic_machine_done_notify(Notifier *notifier, void *data) #ifdef ACCEL_GSI_IRQFD_POSSIBLE IOAPICCommonState *s = container_of(notifier, IOAPICCommonState, machine_done); + X86MachineState *x86ms = X86_MACHINE(qdev_get_machine()); - if (accel_irqchip_is_split()) { + if (accel_irqchip_is_split() && x86ms->ioapic_as != &address_space_memory) { X86IOMMUState *iommu = x86_iommu_get_default(); if (iommu) { /* Register this IOAPIC with IOMMU IEC notifier, so that diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 644c45fb0a02..ffe977ceb418 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -6746,7 +6746,15 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address) int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, uint64_t address, uint32_t data, PCIDevice *dev) { - X86IOMMUState *iommu = x86_iommu_get_default(); + X86IOMMUState *iommu = NULL; + MachineState *ms = MACHINE(qdev_get_machine()); + X86MachineState *x86ms = X86_MACHINE(ms); + + if (dev) { + iommu = x86_iommu_device_get(dev); + } else if (x86ms->ioapic_as != &address_space_memory) { + iommu = x86_iommu_get_default(); + } if (iommu) { X86IOMMUClass *class = X86_IOMMU_DEVICE_GET_CLASS(iommu); @@ -6848,6 +6856,7 @@ int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, { static bool notify_list_inited = false; MSIRouteEntry *entry; + X86IOMMUState *iommu = NULL; if (!dev) { /* These are (possibly) IOAPIC routes only used for split @@ -6867,13 +6876,13 @@ int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, 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(); + iommu = x86_iommu_device_get(dev); if (iommu) { x86_iommu_iec_register_notifier(iommu, kvm_update_msi_routes_all, NULL); + notify_list_inited = true; } - notify_list_inited = true; } return 0; } -- 2.34.1
