aboutsummaryrefslogtreecommitdiff
path: root/hw/pci
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-06-04 18:32:44 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-06-04 18:33:24 +0100
commitd6688ba17b934f20f5e8953dbaafc9408d8799c5 (patch)
tree88f5ea991ec6a037e578ef43fe2c40e0509f39f6 /hw/pci
parent3b730f570c5872ceea2137848f1d4554d4847441 (diff)
parent309750fad51f17d1ec6195c5d8ad7d741596ddb6 (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.c78
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;
+ }
}
}
}