]> git.proxmox.com Git - qemu.git/commitdiff
pci: Replace pci_find_domain() with more general pci_root_bus_path()
authorDavid Gibson <david@gibson.dropbear.id.au>
Thu, 6 Jun 2013 08:48:49 +0000 (18:48 +1000)
committerMichael S. Tsirkin <mst@redhat.com>
Sun, 7 Jul 2013 20:10:57 +0000 (23:10 +0300)
pci_find_domain() is used in a number of places where we want an id for a
whole PCI domain (i.e. the subtree under a PCI root bus).  The trouble is
that many platforms may support multiple independent host bridges with no
hardware supplied notion of domain number.

This patch, therefore, replaces calls to pci_find_domain() with calls to
a new pci_root_bus_path() returning a string.  The new call is implemented
in terms of a new callback in the host bridge class, so it can be defined
in some way that's well defined for the platform.  When no callback is
available we fall back on the qbus name.

Most current uses of pci_find_domain() are for error or informational
messages, so the change in identifiers should be harmless.  The exception
is pci_get_dev_path(), whose results form part of migration streams.  To
maintain compatibility with old migration streams, the PIIX PCI host is
altered to always supply "0000" for this path, which matches the old domain
number (since the code didn't actually support domains other than 0).

For the pseries (spapr) PCI bridge we use a different platform-unique
identifier (pseries machines can routinely have dozens of PCI host
bridges).  Theoretically that breaks migration streams, but given that we
don't yet have migration support for pseries, it doesn't matter.

Any other machines that have working migration support including PCI
devices will need to be updated to maintain migration stream compatibility.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
hw/pci-host/piix.c
hw/pci-host/q35.c
hw/pci/pci-hotplug-old.c
hw/pci/pci.c
hw/pci/pci_host.c
hw/pci/pcie_aer.c
hw/ppc/spapr_pci.c
include/hw/pci/pci.h
include/hw/pci/pci_host.h

index f9e68c30999c9cea119be103fbcd5872bc2348ef..c36e725ba1c1f044b321a7799cff79eee40efe9b 100644 (file)
@@ -629,11 +629,20 @@ static const TypeInfo i440fx_info = {
     .class_init    = i440fx_class_init,
 };
 
+static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
+                                                PCIBus *rootbus)
+{
+    /* For backwards compat with old device paths */
+    return "0000";
+}
+
 static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
 
+    hc->root_bus_path = i440fx_pcihost_root_bus_path;
     k->init = i440fx_pcihost_initfn;
     dc->fw_name = "pci";
     dc->no_user = 1;
index 3a5cff989e475c60801d9553753e9d6f11ed183d..13148ed533513bcb4b3a2787bcae23c124ab74f3 100644 (file)
@@ -63,6 +63,13 @@ static int q35_host_init(SysBusDevice *dev)
     return 0;
 }
 
+static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
+                                          PCIBus *rootbus)
+{
+    /* For backwards compat with old device paths */
+    return "0000";
+}
+
 static Property mch_props[] = {
     DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
                         MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
@@ -73,7 +80,9 @@ static void q35_host_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
 
+    hc->root_bus_path = q35_host_root_bus_path;
     k->init = q35_host_init;
     dc->props = mch_props;
     dc->fw_name = "pci";
index 37e0720513431ce7905fba0f6825d95d9643300f..e2518108f40ea2c8c5a3e0521728d3ddccac2651 100644 (file)
@@ -275,8 +275,8 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict)
     }
 
     if (dev) {
-        monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
-                       pci_find_domain(dev),
+        monitor_printf(mon, "OK root bus %s, bus %d, slot %d, function %d\n",
+                       pci_root_bus_path(dev),
                        pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
                        PCI_FUNC(dev->devfn));
     } else
index 69a699574e978124f8146e09cf17b4ff5bdf7334..350b87229487ea2a0a635820390390cd4334190c 100644 (file)
@@ -25,6 +25,7 @@
 #include "hw/pci/pci.h"
 #include "hw/pci/pci_bridge.h"
 #include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_host.h"
 #include "monitor/monitor.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
@@ -270,19 +271,20 @@ PCIBus *pci_device_root_bus(const PCIDevice *d)
     return bus;
 }
 
-int pci_find_domain(const PCIDevice *dev)
+const char *pci_root_bus_path(PCIDevice *dev)
 {
-    const PCIBus *rootbus = pci_device_root_bus(dev);
-    struct PCIHostBus *host;
+    PCIBus *rootbus = pci_device_root_bus(dev);
+    PCIHostState *host_bridge = PCI_HOST_BRIDGE(rootbus->qbus.parent);
+    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_GET_CLASS(host_bridge);
 
-    QLIST_FOREACH(host, &host_buses, next) {
-        if (host->bus == rootbus) {
-            return host->domain;
-        }
+    assert(!rootbus->parent_dev);
+    assert(host_bridge->bus == rootbus);
+
+    if (hc->root_bus_path) {
+        return (*hc->root_bus_path)(host_bridge, rootbus);
     }
 
-    abort();    /* should not be reached */
-    return -1;
+    return rootbus->qbus.name;
 }
 
 static void pci_bus_init(PCIBus *bus, DeviceState *parent,
@@ -2000,10 +2002,10 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
         for (i = offset; i < offset + size; i++) {
             overlapping_cap = pci_find_capability_at_offset(pdev, i);
             if (overlapping_cap) {
-                fprintf(stderr, "ERROR: %04x:%02x:%02x.%x "
+                fprintf(stderr, "ERROR: %s:%02x:%02x.%x "
                         "Attempt to add PCI capability %x at offset "
                         "%x overlaps existing capability %x at offset %x\n",
-                        pci_find_domain(pdev), pci_bus_num(pdev->bus),
+                        pci_root_bus_path(pdev), pci_bus_num(pdev->bus),
                         PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
                         cap_id, offset, overlapping_cap, i);
                 return -EINVAL;
@@ -2137,30 +2139,30 @@ static char *pcibus_get_dev_path(DeviceState *dev)
      * domain:Bus:Slot.Func for systems without nested PCI bridges.
      * Slot.Function list specifies the slot and function numbers for all
      * devices on the path from root to the specific device. */
-    char domain[] = "DDDD:00";
+    const char *root_bus_path;
+    int root_bus_len;
     char slot[] = ":SS.F";
-    int domain_len = sizeof domain - 1 /* For '\0' */;
     int slot_len = sizeof slot - 1 /* For '\0' */;
     int path_len;
     char *path, *p;
     int s;
 
+    root_bus_path = pci_root_bus_path(d);
+    root_bus_len = strlen(root_bus_path);
+
     /* Calculate # of slots on path between device and root. */;
     slot_depth = 0;
     for (t = d; t; t = t->bus->parent_dev) {
         ++slot_depth;
     }
 
-    path_len = domain_len + slot_len * slot_depth;
+    path_len = root_bus_len + slot_len * slot_depth;
 
     /* Allocate memory, fill in the terminating null byte. */
     path = g_malloc(path_len + 1 /* For '\0' */);
     path[path_len] = '\0';
 
-    /* First field is the domain. */
-    s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d));
-    assert(s == domain_len);
-    memcpy(path, domain, domain_len);
+    memcpy(path, root_bus_path, root_bus_len);
 
     /* Fill in slot numbers. We walk up from device to root, so need to print
      * them in the reverse order, last to first. */
index 12254b18a925d68a9c169d9bb7c4c66bab17c8d9..7dd9b25609d7778bc4def15ea34904bb9eabc88b 100644 (file)
@@ -169,6 +169,7 @@ static const TypeInfo pci_host_type_info = {
     .name = TYPE_PCI_HOST_BRIDGE,
     .parent = TYPE_SYS_BUS_DEVICE,
     .abstract = true,
+    .class_size = sizeof(PCIHostBridgeClass),
     .instance_size = sizeof(PCIHostState),
 };
 
index 06f77acc21bee8b4e88af81dff5098ab93ad5d73..ca762ab09a211a0c1a24667ba2efc665031f8326 100644 (file)
@@ -817,9 +817,9 @@ void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
     qdict = qobject_to_qdict(data);
 
     devfn = (int)qdict_get_int(qdict, "devfn");
-    monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n",
+    monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n",
                    qdict_get_str(qdict, "id"),
-                   (int) qdict_get_int(qdict, "domain"),
+                   qdict_get_str(qdict, "root_bus"),
                    (int) qdict_get_int(qdict, "bus"),
                    PCI_SLOT(devfn), PCI_FUNC(devfn));
 }
@@ -1020,9 +1020,9 @@ int do_pcie_aer_inject_error(Monitor *mon,
 
     ret = pcie_aer_inject_error(dev, &err);
     *ret_data = qobject_from_jsonf("{'id': %s, "
-                                   "'domain': %d, 'bus': %d, 'devfn': %d, "
+                                   "'root_bus': %s, 'bus': %d, 'devfn': %d, "
                                    "'ret': %d}",
-                                   id, pci_find_domain(dev),
+                                   id, pci_root_bus_path(dev),
                                    pci_bus_num(dev->bus), dev->devfn,
                                    ret);
     assert(*ret_data);
index c8c12c8241b2a7cd24d3ac99d3f16b31efa14954..f7be24c755f16fde4a49f8c9d8895c073df8a772 100644 (file)
@@ -696,11 +696,21 @@ static Property spapr_phb_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge,
+                                           PCIBus *rootbus)
+{
+    sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(host_bridge);
+
+    return sphb->dtbusname;
+}
+
 static void spapr_phb_class_init(ObjectClass *klass, void *data)
 {
+    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
     DeviceClass *dc = DEVICE_CLASS(klass);
 
+    hc->root_bus_path = spapr_phb_root_bus_path;
     sdc->init = spapr_phb_init;
     dc->props = spapr_phb_properties;
     dc->reset = spapr_phb_reset;
index f2bf1edbd9d0ba88651c4a51b7b965df2982d626..e0597b7e9e838de2a44850260e4b2f1545e3efbe 100644 (file)
@@ -391,7 +391,7 @@ void pci_for_each_device(PCIBus *bus, int bus_num,
                          void *opaque);
 PCIBus *pci_find_primary_bus(void);
 PCIBus *pci_device_root_bus(const PCIDevice *d);
-int pci_find_domain(const PCIDevice *dev);
+const char *pci_root_bus_path(PCIDevice *dev);
 PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
 int pci_qdev_find_device(const char *id, PCIDevice **pdev);
 PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
index 236cd0f75cb946e49fb845727c5137720b7b799b..44052f2b4d7eaabeead2dbfba2a83ad6f5e132bd 100644 (file)
 #define TYPE_PCI_HOST_BRIDGE "pci-host-bridge"
 #define PCI_HOST_BRIDGE(obj) \
     OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE)
+#define PCI_HOST_BRIDGE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PCIHostBridgeClass, (klass), TYPE_PCI_HOST_BRIDGE)
+#define PCI_HOST_BRIDGE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PCIHostBridgeClass, (obj), TYPE_PCI_HOST_BRIDGE)
 
 struct PCIHostState {
     SysBusDevice busdev;
@@ -44,6 +48,12 @@ struct PCIHostState {
     PCIBus *bus;
 };
 
+typedef struct PCIHostBridgeClass {
+    SysBusDeviceClass parent_class;
+
+    const char *(*root_bus_path)(PCIHostState *, PCIBus *);
+} PCIHostBridgeClass;
+
 /* common internal helpers for PCI/PCIe hosts, cut off overflows */
 void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
                                   uint32_t limit, uint32_t val, uint32_t len);