@@ -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++;
}
}
@@ -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);
@@ -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.
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 <marcel@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(-)