summaryrefslogtreecommitdiff
path: root/hw/pci
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2013-07-08 08:00:23 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2013-07-08 08:00:23 -0500
commitdc11549ec213f85f6a024c7df68d349464cd1688 (patch)
tree92cd5c58d10412e722dd26b27c55a23065590605 /hw/pci
parent945dad6d9d795f03fd839c6e36cc883b3839f5e5 (diff)
parent7588e2b0559ae72d3c2952c7807fc05c03099970 (diff)
downloadqemu-dc11549ec213f85f6a024c7df68d349464cd1688.tar.gz
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.objs2
-rw-r--r--hw/pci/pci-hotplug-old.c (renamed from hw/pci/pci-hotplug.c)75
-rw-r--r--hw/pci/pci.c137
-rw-r--r--hw/pci/pci_host.c1
-rw-r--r--hw/pci/pcie_aer.c9
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);