diff options
Diffstat (limited to 'hw/pci/pci.c')
| -rw-r--r-- | hw/pci/pci.c | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 377084f1a8..23d2ae2ab2 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -416,6 +416,22 @@ const char *pci_root_bus_path(PCIDevice *dev) return rootbus->qbus.name; } +bool pci_bus_bypass_iommu(PCIBus *bus) +{ + PCIBus *rootbus = bus; + PCIHostState *host_bridge; + + if (!pci_bus_is_root(bus)) { + rootbus = pci_device_root_bus(bus->parent_dev); + } + + host_bridge = PCI_HOST_BRIDGE(rootbus->qbus.parent); + + assert(host_bridge->bus == rootbus); + + return host_bridge->bypass_iommu; +} + static void pci_root_bus_init(PCIBus *bus, DeviceState *parent, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, @@ -521,6 +537,22 @@ int pci_bus_num(PCIBus *s) return PCI_BUS_GET_CLASS(s)->bus_num(s); } +/* Returns the min and max bus numbers of a PCI bus hierarchy */ +void pci_bus_range(PCIBus *bus, int *min_bus, int *max_bus) +{ + int i; + *min_bus = *max_bus = pci_bus_num(bus); + + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { + PCIDevice *dev = bus->devices[i]; + + if (dev && PCI_DEVICE_GET_CLASS(dev)->is_bridge) { + *min_bus = MIN(*min_bus, dev->config[PCI_SECONDARY_BUS]); + *max_bus = MAX(*max_bus, dev->config[PCI_SUBORDINATE_BUS]); + } + } +} + int pci_bus_numa_node(PCIBus *bus) { return PCI_BUS_GET_CLASS(bus)->numa_node(bus); @@ -2718,7 +2750,7 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) iommu_bus = parent_bus; } - if (iommu_bus && iommu_bus->iommu_fn) { + if (!pci_bus_bypass_iommu(bus) && iommu_bus && iommu_bus->iommu_fn) { return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, devfn); } return &address_space_memory; |