diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-07-08 08:00:23 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-07-08 08:00:23 -0500 |
commit | dc11549ec213f85f6a024c7df68d349464cd1688 (patch) | |
tree | 92cd5c58d10412e722dd26b27c55a23065590605 /hw/pci | |
parent | 945dad6d9d795f03fd839c6e36cc883b3839f5e5 (diff) | |
parent | 7588e2b0559ae72d3c2952c7807fc05c03099970 (diff) |
Merge remote-tracking branch 'mst/tags/for_anthony' into staging
pci,misc enhancements
This includes some pci enhancements:
Better support for systems with multiple PCI root buses
FW cfg interface for more robust pci programming in BIOS
Minor fixes/cleanups for fw cfg and cross-version migration -
because of dependencies with other patches
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
# gpg: Signature made Sun 07 Jul 2013 03:11:18 PM CDT using RSA key ID D28D5469
# gpg: Can't check signature: public key not found
# By David Gibson (10) and others
# Via Michael S. Tsirkin
* mst/tags/for_anthony:
pci: Fold host_buses list into PCIHostState functionality
pci: Remove domain from PCIHostBus
pci: Simpler implementation of primary PCI bus
pci: Add root bus parameter to pci_nic_init()
pci: Add root bus argument to pci_get_bus_devfn()
pci: Replace pci_find_domain() with more general pci_root_bus_path()
pci: Use helper to find device's root bus in pci_find_domain()
pci: Abolish pci_find_root_bus()
pci: Move pci_read_devaddr to pci-hotplug-old.c
pci: Cleanup configuration for pci-hotplug.c
pvpanic: fix fwcfg for big endian hosts
pvpanic: initialization cleanup
MAINTAINERS: s/Marcelo/Paolo/
e1000: cleanup process_tx_desc
pc_piix: cleanup init compat handling
pc: pass PCI hole ranges to Guests
pci: store PCI hole ranges in guestinfo structure
range: add Range structure
Message-id: 1373228271-31223-1-git-send-email-mst@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/pci')
-rw-r--r-- | hw/pci/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/pci/pci-hotplug-old.c (renamed from hw/pci/pci-hotplug.c) | 75 | ||||
-rw-r--r-- | hw/pci/pci.c | 137 | ||||
-rw-r--r-- | hw/pci/pci_host.c | 1 | ||||
-rw-r--r-- | hw/pci/pcie_aer.c | 9 |
5 files changed, 137 insertions, 87 deletions
diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs index a7fb9d0c11..720f438ac9 100644 --- a/hw/pci/Makefile.objs +++ b/hw/pci/Makefile.objs @@ -8,4 +8,4 @@ common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o common-obj-$(CONFIG_NO_PCI) += pci-stub.o common-obj-$(CONFIG_ALL) += pci-stub.o -obj-$(CONFIG_PCI_HOTPLUG) += pci-hotplug.o +common-obj-$(CONFIG_PCI_HOTPLUG_OLD) += pci-hotplug-old.o diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug-old.c index 12287d1efc..8077289756 100644 --- a/hw/pci/pci-hotplug.c +++ b/hw/pci/pci-hotplug-old.c @@ -1,5 +1,7 @@ /* - * QEMU PCI hotplug support + * Deprecated PCI hotplug interface support + * This covers the old pci_add / pci_del command, whereas the more general + * device_add / device_del commands are now preferred. * * Copyright (c) 2004 Fabrice Bellard * @@ -34,17 +36,43 @@ #include "sysemu/blockdev.h" #include "qapi/error.h" -#if defined(TARGET_I386) +static int pci_read_devaddr(Monitor *mon, const char *addr, + int *busp, unsigned *slotp) +{ + int dom; + + /* strip legacy tag */ + if (!strncmp(addr, "pci_addr=", 9)) { + addr += 9; + } + if (pci_parse_devaddr(addr, &dom, busp, slotp, NULL)) { + monitor_printf(mon, "Invalid pci address\n"); + return -1; + } + if (dom != 0) { + monitor_printf(mon, "Multiple PCI domains not supported, use device_add\n"); + return -1; + } + return 0; +} + static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, const char *devaddr, const char *opts_str) { Error *local_err = NULL; QemuOpts *opts; + PCIBus *root = pci_find_primary_bus(); PCIBus *bus; int ret, devfn; - bus = pci_get_bus_devfn(&devfn, devaddr); + if (!root) { + monitor_printf(mon, "no primary PCI bus (if there are multiple" + " PCI roots, you must use device_add instead)"); + return NULL; + } + + bus = pci_get_bus_devfn(&devfn, root, devaddr); if (!bus) { monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); return NULL; @@ -71,7 +99,7 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, monitor_printf(mon, "Parameter addr not supported\n"); return NULL; } - return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); + return pci_nic_init(&nd_table[ret], root, "rtl8139", devaddr); } static int scsi_hot_add(Monitor *mon, DeviceState *adapter, @@ -113,18 +141,23 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter, int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo) { - int dom, pci_bus; + int pci_bus; unsigned slot; + PCIBus *root = pci_find_primary_bus(); PCIDevice *dev; const char *pci_addr = qdict_get_str(qdict, "pci_addr"); switch (dinfo->type) { case IF_SCSI: - if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { + if (!root) { + monitor_printf(mon, "no primary PCI bus (if there are multiple" + " PCI roots, you must use device_add instead)"); + goto err; + } + if (pci_read_devaddr(mon, pci_addr, &pci_bus, &slot)) { goto err; } - dev = pci_find_device(pci_find_root_bus(dom), pci_bus, - PCI_DEVFN(slot, 0)); + dev = pci_find_device(root, pci_bus, PCI_DEVFN(slot, 0)); if (!dev) { monitor_printf(mon, "no pci device with address %s\n", pci_addr); goto err; @@ -151,6 +184,7 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, DriveInfo *dinfo = NULL; int type = -1; char buf[128]; + PCIBus *root = pci_find_primary_bus(); PCIBus *bus; int devfn; @@ -180,7 +214,12 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, dinfo = NULL; } - bus = pci_get_bus_devfn(&devfn, devaddr); + if (!root) { + monitor_printf(mon, "no primary PCI bus (if there are multiple" + " PCI roots, you must use device_add instead)"); + return NULL; + } + bus = pci_get_bus_devfn(&devfn, root, devaddr); if (!bus) { monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); return NULL; @@ -250,27 +289,33 @@ 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->bus), + 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 monitor_printf(mon, "failed to add %s\n", opts); } -#endif static int pci_device_hot_remove(Monitor *mon, const char *pci_addr) { + PCIBus *root = pci_find_primary_bus(); PCIDevice *d; - int dom, bus; + int bus; unsigned slot; Error *local_err = NULL; - if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { + if (!root) { + monitor_printf(mon, "no primary PCI bus (if there are multiple" + " PCI roots, you must use device_del instead)"); + return -1; + } + + if (pci_read_devaddr(mon, pci_addr, &bus, &slot)) { return -1; } - d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0)); + d = pci_find_device(root, bus, PCI_DEVFN(slot, 0)); if (!d) { monitor_printf(mon, "slot %d empty\n", slot); return -1; diff --git a/hw/pci/pci.c b/hw/pci/pci.c index ceb6a5d9cc..dcc85ef0af 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -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" @@ -89,12 +90,7 @@ static void pci_del_option_rom(PCIDevice *pdev); static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; -struct PCIHostBus { - int domain; - struct PCIBus *bus; - QLIST_ENTRY(PCIHostBus) next; -}; -static QLIST_HEAD(, PCIHostBus) host_buses; +static QLIST_HEAD(, PCIHostState) pci_host_bridges; static const VMStateDescription vmstate_pcibus = { .name = "PCIBUS", @@ -237,46 +233,54 @@ static int pcibus_reset(BusState *qbus) return 1; } -static void pci_host_bus_register(int domain, PCIBus *bus) +static void pci_host_bus_register(PCIBus *bus, DeviceState *parent) { - struct PCIHostBus *host; - host = g_malloc0(sizeof(*host)); - host->domain = domain; - host->bus = bus; - QLIST_INSERT_HEAD(&host_buses, host, next); + PCIHostState *host_bridge = PCI_HOST_BRIDGE(parent); + + QLIST_INSERT_HEAD(&pci_host_bridges, host_bridge, next); } -PCIBus *pci_find_root_bus(int domain) +PCIBus *pci_find_primary_bus(void) { - struct PCIHostBus *host; + PCIBus *primary_bus = NULL; + PCIHostState *host; - QLIST_FOREACH(host, &host_buses, next) { - if (host->domain == domain) { - return host->bus; + QLIST_FOREACH(host, &pci_host_bridges, next) { + if (primary_bus) { + /* We have multiple root buses, refuse to select a primary */ + return NULL; } + primary_bus = host->bus; } - return NULL; + return primary_bus; } -int pci_find_domain(const PCIBus *bus) +PCIBus *pci_device_root_bus(const PCIDevice *d) { - PCIDevice *d; - struct PCIHostBus *host; + PCIBus *bus = d->bus; - /* obtain root bus */ while ((d = bus->parent_dev) != NULL) { bus = d->bus; } - QLIST_FOREACH(host, &host_buses, next) { - if (host->bus == bus) { - return host->domain; - } + return bus; +} + +const char *pci_root_bus_path(PCIDevice *dev) +{ + 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); + + 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, @@ -292,7 +296,8 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent, /* host bridge */ QLIST_INIT(&bus->child); - pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */ + + pci_host_bus_register(bus, parent); vmstate_register(NULL, -1, &vmstate_pcibus, bus); } @@ -522,7 +527,7 @@ static void pci_set_default_subsystem_id(PCIDevice *pci_dev) * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL * [[<domain>:]<bus>:]<slot>.<func>, return -1 on error */ -static int pci_parse_devaddr(const char *addr, int *domp, int *busp, +int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned int *slotp, unsigned int *funcp) { const char *p; @@ -581,36 +586,34 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, return 0; } -int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, - unsigned *slotp) -{ - /* strip legacy tag */ - if (!strncmp(addr, "pci_addr=", 9)) { - addr += 9; - } - if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) { - monitor_printf(mon, "Invalid pci address\n"); - return -1; - } - return 0; -} - -PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) +PCIBus *pci_get_bus_devfn(int *devfnp, PCIBus *root, const char *devaddr) { int dom, bus; unsigned slot; + assert(!root->parent_dev); + + if (!root) { + fprintf(stderr, "No primary PCI bus\n"); + return NULL; + } + if (!devaddr) { *devfnp = -1; - return pci_find_bus_nr(pci_find_root_bus(0), 0); + return pci_find_bus_nr(root, 0); } if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) { return NULL; } + if (dom != 0) { + fprintf(stderr, "No support for non-zero PCI domains\n"); + return NULL; + } + *devfnp = PCI_DEVFN(slot, 0); - return pci_find_bus_nr(pci_find_root_bus(dom), bus); + return pci_find_bus_nr(root, bus); } static void pci_init_cmask(PCIDevice *dev) @@ -1526,11 +1529,11 @@ static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num) PciInfoList *qmp_query_pci(Error **errp) { PciInfoList *info, *head = NULL, *cur_item = NULL; - struct PCIHostBus *host; + PCIHostState *host_bridge; - QLIST_FOREACH(host, &host_buses, next) { + QLIST_FOREACH(host_bridge, &pci_host_bridges, next) { info = g_malloc0(sizeof(*info)); - info->value = qmp_query_pci_bus(host->bus, 0); + info->value = qmp_query_pci_bus(host_bridge->bus, 0); /* XXX: waiting for the qapi to support GSList */ if (!cur_item) { @@ -1570,7 +1573,8 @@ static const char * const pci_nic_names[] = { /* Initialize a PCI NIC. */ /* FIXME callers should check for failure, but don't */ -PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, +PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus, + const char *default_model, const char *default_devaddr) { const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr; @@ -1584,7 +1588,7 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, if (i < 0) return NULL; - bus = pci_get_bus_devfn(&devfn, devaddr); + bus = pci_get_bus_devfn(&devfn, rootbus, devaddr); if (!bus) { error_report("Invalid PCI device address %s for device %s", devaddr, pci_nic_names[i]); @@ -1599,7 +1603,8 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, return pci_dev; } -PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, +PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, + const char *default_model, const char *default_devaddr) { PCIDevice *res; @@ -1607,7 +1612,7 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, if (qemu_show_nic_models(nd->model, pci_nic_models)) exit(0); - res = pci_nic_init(nd, default_model, default_devaddr); + res = pci_nic_init(nd, rootbus, default_model, default_devaddr); if (!res) exit(1); return res; @@ -1998,10 +2003,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->bus), 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; @@ -2135,30 +2140,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->bus)); - 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. */ @@ -2192,11 +2197,11 @@ static int pci_qdev_find_recursive(PCIBus *bus, int pci_qdev_find_device(const char *id, PCIDevice **pdev) { - struct PCIHostBus *host; + PCIHostState *host_bridge; int rc = -ENODEV; - QLIST_FOREACH(host, &host_buses, next) { - int tmp = pci_qdev_find_recursive(host->bus, id, pdev); + QLIST_FOREACH(host_bridge, &pci_host_bridges, next) { + int tmp = pci_qdev_find_recursive(host_bridge->bus, id, pdev); if (!tmp) { rc = 0; break; diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index 12254b18a9..7dd9b25609 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -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), }; diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index 1ce72ce944..ca762ab09a 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -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,10 +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->bus), + id, pci_root_bus_path(dev), pci_bus_num(dev->bus), dev->devfn, ret); assert(*ret_data); |