diff options
author | Alexey Kardashevskiy <aik@ozlabs.ru> | 2013-08-10 01:09:08 +1000 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2013-08-27 08:30:48 +0300 |
commit | 9eda7d373e9c691c070eddcbe3467b991f67f6bd (patch) | |
tree | 79b9f450dd31dc5ab348b4620ea2852d993181ab /hw | |
parent | 1ae2757c6c4525c9b42f408c86818f843bad7418 (diff) |
pci: Introduce helper to retrieve a PCI device's DMA address space
A PCI device's DMA address space (possibly an IOMMU) is returned by a
method on the PCIBus. At the moment that only has one caller, so the
method is simply open coded. We'll need another caller for VFIO, so
this patch introduces a helper/wrapper function.
If IOMMU is not set, the pci_device_iommu_address_space() function
returns the parent's IOMMU skipping the "bus master" address space as
otherwise proper emulation would require more effort for no benefit.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
[aik: added inheritance from parent if iommu is not set for the current bus]
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/pci/pci.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 4c004f5daa..8c33352c9a 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -812,12 +812,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, } pci_dev->bus = bus; - if (bus->iommu_fn) { - dma_as = bus->iommu_fn(bus, bus->iommu_opaque, devfn); - } else { - /* FIXME: inherit memory region from bus creator */ - dma_as = &address_space_memory; - } + dma_as = pci_device_iommu_address_space(pci_dev); memory_region_init_alias(&pci_dev->bus_master_enable_region, OBJECT(pci_dev), "bus master", @@ -2239,6 +2234,23 @@ static void pci_device_class_init(ObjectClass *klass, void *data) k->props = pci_props; } +AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) +{ + PCIBus *bus = PCI_BUS(dev->bus); + + if (bus->iommu_fn) { + return bus->iommu_fn(bus, bus->iommu_opaque, dev->devfn); + } + + if (bus->parent_dev) { + /** We are ignoring the bus master DMA bit of the bridge + * as it would complicate things such as VFIO for no good reason */ + return pci_device_iommu_address_space(bus->parent_dev); + } + + return &address_space_memory; +} + void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque) { bus->iommu_fn = fn; |