diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-06-04 18:32:44 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-06-04 18:33:24 +0100 |
commit | d6688ba17b934f20f5e8953dbaafc9408d8799c5 (patch) | |
tree | 88f5ea991ec6a037e578ef43fe2c40e0509f39f6 /hw/pci | |
parent | 3b730f570c5872ceea2137848f1d4554d4847441 (diff) | |
parent | 309750fad51f17d1ec6195c5d8ad7d741596ddb6 (diff) |
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc, acpi, virtio, tpm
This includes pxb support by Marcel, as well as multiple enhancements all over
the place.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
# gpg: Signature made Thu Jun 4 11:51:02 2015 BST using RSA key ID D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg: aka "Michael S. Tsirkin <mst@redhat.com>"
* remotes/mst/tags/for_upstream: (28 commits)
vhost: logs sharing
hw/acpi: piix4_pm_init(): take fw_cfg object no more
hw/acpi: move "etc/system-states" fw_cfg file from PIIX4 to core
hw/acpi: acpi_pm1_cnt_init(): take "disable_s3" and "disable_s4"
pc-dimm: don't assert if pc-dimm alignment != hotpluggable mem range size
docs: Add PXB documentation
apci: fix PXB behaviour if used with unsupported BIOS
hw/pxb: add numa_node parameter
hw/pci: add support for NUMA nodes
hw/pxb: add map_irq func
hw/pci: inform bios if the system has extra pci root buses
hw/pci: introduce PCI Expander Bridge (PXB)
hw/pci: removed 'rootbus nr is 0' assumption from qmp_pci_query
hw/acpi: remove from root bus 0 the crs resources used by other buses.
hw/acpi: add _CRS method for extra root busses
hw/apci: add _PRT method for extra PCI root busses
hw/acpi: add support for i440fx 'snooping' root busses
hw/pci: extend PCI config access to support devices behind PXB
hw/i386: query only for q35/pc when looking for pci host bridge
hw/pci: made pci_bus_num a PCIBusClass method
...
Conflicts:
hw/i386/pc_piix.c
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/pci')
-rw-r--r-- | hw/pci/pci.c | 78 |
1 files changed, 66 insertions, 12 deletions
diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 3423c3a1eb..750f3dacea 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -88,9 +88,28 @@ static void pci_bus_unrealize(BusState *qbus, Error **errp) vmstate_unregister(NULL, &vmstate_pcibus, bus); } +static bool pcibus_is_root(PCIBus *bus) +{ + return !bus->parent_dev; +} + +static int pcibus_num(PCIBus *bus) +{ + if (pcibus_is_root(bus)) { + return 0; /* pci host bridge */ + } + return bus->parent_dev->config[PCI_SECONDARY_BUS]; +} + +static uint16_t pcibus_numa_node(PCIBus *bus) +{ + return NUMA_NODE_UNASSIGNED; +} + static void pci_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); + PCIBusClass *pbc = PCI_BUS_CLASS(klass); k->print_dev = pcibus_dev_print; k->get_dev_path = pcibus_get_dev_path; @@ -98,12 +117,17 @@ static void pci_bus_class_init(ObjectClass *klass, void *data) k->realize = pci_bus_realize; k->unrealize = pci_bus_unrealize; k->reset = pcibus_reset; + + pbc->is_root = pcibus_is_root; + pbc->bus_num = pcibus_num; + pbc->numa_node = pcibus_numa_node; } static const TypeInfo pci_bus_info = { .name = TYPE_PCI_BUS, .parent = TYPE_BUS, .instance_size = sizeof(PCIBus), + .class_size = sizeof(PCIBusClass), .class_init = pci_bus_class_init, }; @@ -278,7 +302,10 @@ PCIBus *pci_device_root_bus(const PCIDevice *d) { PCIBus *bus = d->bus; - while ((d = bus->parent_dev) != NULL) { + while (!pci_bus_is_root(bus)) { + d = bus->parent_dev; + assert(d != NULL); + bus = d->bus; } @@ -291,7 +318,6 @@ const char *pci_root_bus_path(PCIDevice *dev) PCIHostState *host_bridge = PCI_HOST_BRIDGE(rootbus->qbus.parent); PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_GET_CLASS(host_bridge); - assert(!rootbus->parent_dev); assert(host_bridge->bus == rootbus); if (hc->root_bus_path) { @@ -325,7 +351,7 @@ bool pci_bus_is_express(PCIBus *bus) bool pci_bus_is_root(PCIBus *bus) { - return !bus->parent_dev; + return PCI_BUS_GET_CLASS(bus)->is_root(bus); } void pci_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent, @@ -379,9 +405,12 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, int pci_bus_num(PCIBus *s) { - if (pci_bus_is_root(s)) - return 0; /* pci host bridge */ - return s->parent_dev->config[PCI_SECONDARY_BUS]; + return PCI_BUS_GET_CLASS(s)->bus_num(s); +} + +int pci_bus_numa_node(PCIBus *bus) +{ + return PCI_BUS_GET_CLASS(bus)->numa_node(bus); } static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) @@ -1576,7 +1605,8 @@ PciInfoList *qmp_query_pci(Error **errp) QLIST_FOREACH(host_bridge, &pci_host_bridges, next) { info = g_malloc0(sizeof(*info)); - info->value = qmp_query_pci_bus(host_bridge->bus, 0); + info->value = qmp_query_pci_bus(host_bridge->bus, + pci_bus_num(host_bridge->bus)); /* XXX: waiting for the qapi to support GSList */ if (!cur_item) { @@ -1681,10 +1711,28 @@ static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) { return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) & PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ && - dev->config[PCI_SECONDARY_BUS] < bus_num && + dev->config[PCI_SECONDARY_BUS] <= bus_num && bus_num <= dev->config[PCI_SUBORDINATE_BUS]; } +/* Whether a given bus number is in a range of a root bus */ +static bool pci_root_bus_in_range(PCIBus *bus, int bus_num) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { + PCIDevice *dev = bus->devices[i]; + + if (dev && PCI_DEVICE_GET_CLASS(dev)->is_bridge) { + if (pci_secondary_bus_in_range(dev, bus_num)) { + return true; + } + } + } + + return false; +} + static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) { PCIBus *sec; @@ -1706,12 +1754,18 @@ static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) /* try child bus */ for (; bus; bus = sec) { QLIST_FOREACH(sec, &bus->child, sibling) { - assert(!pci_bus_is_root(sec)); - if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { + if (pci_bus_num(sec) == bus_num) { return sec; } - if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) { - break; + /* PXB buses assumed to be children of bus 0 */ + if (pci_bus_is_root(sec)) { + if (pci_root_bus_in_range(sec, bus_num)) { + break; + } + } else { + if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) { + break; + } } } } |