Skip bus_master_enable region creation on PCI devices init in order to be sure the IOMMU device (if present) would be created in advance. Add this memory region at machine_done time.
Signed-off-by: Marcel Apfelbaum <mar...@redhat.com> --- hw/i386/pc.c | 17 +++++++++++++++++ hw/pci/pci.c | 22 ++++++++++++---------- include/hw/pci/pci.h | 2 ++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 99437e0..f9ac543 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -32,6 +32,7 @@ #include "hw/ide.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" +#include "hw/pci/pci_bridge.h" #include "hw/nvram/fw_cfg.h" #include "hw/timer/hpet.h" #include "hw/smbios/smbios.h" @@ -1156,12 +1157,26 @@ typedef struct PcRomPciInfo { uint64_t w64_max; } PcRomPciInfo; +static void pci_bus_enable_bus_master(PCIBus *bus, PCIDevice *dev, void *opaque) +{ + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + + pci_init_bus_master(dev); + + if (pc->is_bridge) { + PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev)); + pci_for_each_device(sec_bus, pci_bus_num(sec_bus), + pci_bus_enable_bus_master, opaque); + } +} + static void pc_machine_done(Notifier *notifier, void *data) { PCMachineState *pcms = container_of(notifier, PCMachineState, machine_done); PCIBus *bus = pcms->bus; + pci_for_each_device(bus, pci_bus_num(bus), pci_bus_enable_bus_master, NULL); if (bus) { int extra_hosts = 0; @@ -1169,6 +1184,8 @@ void pc_machine_done(Notifier *notifier, void *data) QLIST_FOREACH(bus, &bus->child, sibling) { /* look for expander root buses */ if (pci_bus_is_root(bus)) { + pci_for_each_device(bus, pci_bus_num(bus), + pci_bus_enable_bus_master, NULL); extra_hosts++; } } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index bb605ef..e22b1c8 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -828,6 +828,18 @@ static void pci_config_free(PCIDevice *pci_dev) g_free(pci_dev->used); } +void pci_init_bus_master(PCIDevice *pci_dev) +{ + AddressSpace *dma_as = pci_device_iommu_address_space(pci_dev); + + memory_region_init_alias(&pci_dev->bus_master_enable_region, + OBJECT(pci_dev), "bus master", + dma_as->root, 0, memory_region_size(dma_as->root)); + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); + address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region, + pci_dev->name); +} + static void do_pci_unregister_device(PCIDevice *pci_dev) { pci_dev->bus->devices[pci_dev->devfn] = NULL; @@ -845,7 +857,6 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, PCIConfigReadFunc *config_read = pc->config_read; PCIConfigWriteFunc *config_write = pc->config_write; Error *local_err = NULL; - AddressSpace *dma_as; DeviceState *dev = DEVICE(pci_dev); pci_dev->bus = bus; @@ -885,15 +896,6 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, } pci_dev->devfn = devfn; - dma_as = pci_device_iommu_address_space(pci_dev); - - memory_region_init_alias(&pci_dev->bus_master_enable_region, - OBJECT(pci_dev), "bus master", - dma_as->root, 0, memory_region_size(dma_as->root)); - memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); - address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region, - name); - pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); pci_dev->irq_state = 0; pci_config_alloc(pci_dev); diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index ef6ba51..95a930f 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -343,6 +343,8 @@ int pci_device_load(PCIDevice *s, QEMUFile *f); MemoryRegion *pci_address_space(PCIDevice *dev); MemoryRegion *pci_address_space_io(PCIDevice *dev); +void pci_init_bus_master(PCIDevice *dev); + /* * Should not normally be used by devices. For use by sPAPR target * where QEMU emulates firmware. -- 2.4.3