On 10/31/25 11:49 AM, Shameer Kolothum 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.
>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Looks a reasonable solution to me
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
> ---
> 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.