diff options
| -rw-r--r-- | hw/pci/pci.c | 31 | ||||
| -rw-r--r-- | include/hw/pci/pci.h | 2 | ||||
| -rw-r--r-- | include/hw/pci/pci_bus.h | 1 |
3 files changed, 34 insertions, 0 deletions
diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 297196b242..c3df9d6656 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2912,6 +2912,19 @@ static void pci_device_get_iommu_bus_devfn(PCIDevice *dev, } } + /* + * When multiple PCI Express Root Buses are defined using pxb-pcie, + * the IOMMU configuration may be specific to each root bus. However, + * pxb-pcie acts as a special root complex whose parent is effectively + * the default root complex(pcie.0). Ensure that we retrieve the + * correct IOMMU ops(if any) in such cases. + */ + if (pci_bus_is_express(iommu_bus) && pci_bus_is_root(iommu_bus)) { + if (parent_bus->iommu_per_bus) { + break; + } + } + iommu_bus = parent_bus; } @@ -3172,6 +3185,24 @@ void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque) bus->iommu_opaque = opaque; } +/* + * Similar to pci_setup_iommu(), but sets iommu_per_bus to true, + * indicating that the IOMMU is specific to this bus. This is used by + * IOMMU implementations that are tied to a specific PCIe root complex. + * + * In QEMU, pxb-pcie behaves as a special root complex whose parent is + * effectively the default root complex (pcie.0). The iommu_per_bus + * is checked in pci_device_get_iommu_bus_devfn() to ensure the correct + * IOMMU ops are returned, avoiding the use of the parent’s IOMMU when + * it's not appropriate. + */ +void pci_setup_iommu_per_bus(PCIBus *bus, const PCIIOMMUOps *ops, + void *opaque) +{ + pci_setup_iommu(bus, ops, opaque); + bus->iommu_per_bus = true; +} + static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque) { Range *range = opaque; diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 6b7d3ac8a3..6bccb25ac2 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -773,6 +773,8 @@ int pci_iommu_unregister_iotlb_notifier(PCIDevice *dev, uint32_t pasid, */ void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque); +void pci_setup_iommu_per_bus(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque); + pcibus_t pci_bar_address(PCIDevice *d, int reg, uint8_t type, pcibus_t size); diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h index 2261312546..c738446788 100644 --- a/include/hw/pci/pci_bus.h +++ b/include/hw/pci/pci_bus.h @@ -35,6 +35,7 @@ struct PCIBus { enum PCIBusFlags flags; const PCIIOMMUOps *iommu_ops; void *iommu_opaque; + bool iommu_per_bus; uint8_t devfn_min; uint32_t slot_reserved_mask; pci_set_irq_fn set_irq; |