On Mon, 23 Jun 2025 10:42:25 +0100 Shameer Kolothum <shameerali.kolothum.th...@huawei.com> wrote:
> Currently, pci_setup_iommu() registers IOMMU ops for a given PCIBus. > However, when retrieving IOMMU ops for a device using > pci_device_get_iommu_bus_devfn(), the function checks the parent_dev > and fetches IOMMU ops from the parent device, even if the current > bus does not have any associated IOMMU ops. > > This behavior works for now because QEMU's IOMMU implementations are > globally scoped, and host bridges rely on the bypass_iommu property > to skip IOMMU translation when needed. > > However, this model will break with the soon to be introduced > arm-smmuv3 device, which allows users to associate the IOMMU > with a specific PCIe root complex (e.g., the default pcie.0 > or a pxb-pcie root complex). > > For example, consider the following setup with multiple root > complexes: > > -device arm-smmuv3,primary-bus=pcie.0,id=smmuv3.0 \ > ... > -device pxb-pcie,id=pcie.1,bus_nr=8,bus=pcie.0 \ > -device pcie-root-port,id=pcie.port1,bus=pcie.1 \ > -device virtio-net-pci,bus=pcie.port1 > > In Qemu, pxb-pcie acts as a special root complex whose parent is > effectively the default root complex(pcie.0). Hence, though pcie.1 > has no associated SMMUv3 as per above, pci_device_get_iommu_bus_devfn() > will incorrectly return the IOMMU ops from pcie.0 due to the fallback > via parent_dev. > > To fix this, introduce a new helper pci_setup_iommu_per_bus() that > explicitly sets the new iommu_per_bus field in the PCIBus structure. Maybe call out where this will later be called from? Otherwise seems like a reasonable solution to me. One trivial comment inline. Reviewed-by: Jonathan Cameron <jonathan.came...@huawei.com> > Update pci_device_get_iommu_bus_devfn() to use this when determining > the correct IOMMU ops, ensuring accurate behavior for per-bus IOMMUs. > > Signed-off-by: Shameer Kolothum <shameerali.kolothum.th...@huawei.com> > --- > Please refer cover letter for more details on the issue that > this is trying to fix. > --- > hw/pci/pci.c | 25 +++++++++++++++++++++++++ > include/hw/pci/pci.h | 2 ++ > include/hw/pci/pci_bus.h | 1 + > 3 files changed, 28 insertions(+) > > diff --git a/hw/pci/pci.c b/hw/pci/pci.c > index c70b5ceeba..e1940c05d9 100644 > --- a/hw/pci/pci.c > +++ b/hw/pci/pci.c > @@ -3169,6 +3182,18 @@ void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps > *ops, void *opaque) > bus->iommu_opaque = opaque; > } > > +/* > + * This is same as pci_setup_iommu() except it sets the iommu_per_bus > + * to true indicating the iommu is specific to this bus and Trivial: Odd line wrap. At least not can go up a line. > + * not applicable to any parent or child. > + */ > +void pci_setup_iommu_per_bus(PCIBus *bus, const PCIIOMMUOps *ops, > + void *opaque) > +{ > + pci_setup_iommu(bus, ops, opaque); > + bus->iommu_per_bus = true;