On Fri, 31 Oct 2025 10:49:41 +0000 Shameer Kolothum <[email protected]> wrote:
> Introduce an optional supports_address_space() callback in PCIIOMMUOps to > allow a vIOMMU implementation to reject devices that should not be attached > to it. > > Currently, get_address_space() is the first and mandatory callback into the > vIOMMU layer, which always returns an address space. For certain setups, such > as hardware accelerated vIOMMUs (e.g. ARM SMMUv3 with accel=on), attaching > emulated endpoint devices is undesirable as it may impact the behavior or > performance of VFIO passthrough devices, for example, by triggering > unnecessary invalidations on the host IOMMU. > > The new callback allows a vIOMMU to check and reject unsupported devices > early during PCI device registration. LGTM Reviewed-by: Jonathan Cameron <[email protected]> > > Cc: Michael S. Tsirkin <[email protected]> > Signed-off-by: Shameer Kolothum <[email protected]> > --- > hw/pci/pci.c | 20 ++++++++++++++++++++ > include/hw/pci/pci.h | 17 +++++++++++++++++ > 2 files changed, 37 insertions(+) > > diff --git a/hw/pci/pci.c b/hw/pci/pci.c > index 9693d7f10c..fa9cf5dab2 100644 > --- a/hw/pci/pci.c > +++ b/hw/pci/pci.c > @@ -135,6 +135,21 @@ static void pci_set_master(PCIDevice *d, bool enable) > d->is_master = enable; /* cache the status */ > } > > +static bool > +pci_device_supports_iommu_address_space(PCIDevice *dev, Error **errp) > +{ > + PCIBus *bus; > + PCIBus *iommu_bus; > + int devfn; > + > + pci_device_get_iommu_bus_devfn(dev, &iommu_bus, &bus, &devfn); > + if (iommu_bus && iommu_bus->iommu_ops->supports_address_space) { > + return iommu_bus->iommu_ops->supports_address_space(bus, > + iommu_bus->iommu_opaque, devfn, errp); > + } > + return true; > +} > + > static void pci_init_bus_master(PCIDevice *pci_dev) > { > AddressSpace *dma_as = pci_device_iommu_address_space(pci_dev); > @@ -1413,6 +1428,11 @@ static PCIDevice *do_pci_register_device(PCIDevice > *pci_dev, > pci_dev->config_write = config_write; > bus->devices[devfn] = pci_dev; > pci_dev->version_id = 2; /* Current pci device vmstate version */ > + if (!pci_device_supports_iommu_address_space(pci_dev, errp)) { > + do_pci_unregister_device(pci_dev); > + bus->devices[devfn] = NULL; > + return NULL; > + } > if (phase_check(PHASE_MACHINE_READY)) { > pci_init_bus_master(pci_dev); > } > diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h > index cf99b5bb68..dfeba8c9bd 100644 > --- a/include/hw/pci/pci.h > +++ b/include/hw/pci/pci.h > @@ -417,6 +417,23 @@ typedef struct IOMMUPRINotifier { > * framework for a set of devices on a PCI bus. > */ > typedef struct PCIIOMMUOps { > + /** > + * @supports_address_space: Optional pre-check to determine if a PCI > + * device can have an IOMMU address space. > + * > + * @bus: the #PCIBus being accessed. > + * > + * @opaque: the data passed to pci_setup_iommu(). > + * > + * @devfn: device and function number. > + * > + * @errp: pass an Error out only when return false > + * > + * Returns: true if the device can be associated with an IOMMU address > + * space, false otherwise with errp set. > + */ > + bool (*supports_address_space)(PCIBus *bus, void *opaque, int devfn, > + Error **errp); > /** > * @get_address_space: get the address space for a set of devices > * on a PCI bus.
