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);
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);
}
* framework for a set of devices on a PCI bus.
*/
typedef struct PCIIOMMUOps {
+ /**
+ * @supports_address_space: Optional pre-check to determine whether a PCI
+ * device can be associated with an IOMMU. If this callback returns true,
+ * the IOMMU accepts the device association and get_address_space() can be
+ * called to obtain the address_space to be used.
+ *
+ * @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, 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.