aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2019-04-10 11:49:28 +1000
committerDavid Gibson <david@gibson.dropbear.id.au>2019-06-12 10:41:49 +1000
commit05929a6c5dfe1028ef66250b7bbf11939f8e77cd (patch)
treef33ce2839b43b42289bf63e0501a95d1a5c50762 /hw
parenta1ec25b287dd64bdb782061168f8e34552102d48 (diff)
downloadqemu-05929a6c5dfe1028ef66250b7bbf11939f8e77cd.zip
qemu-05929a6c5dfe1028ef66250b7bbf11939f8e77cd.tar.gz
qemu-05929a6c5dfe1028ef66250b7bbf11939f8e77cd.tar.bz2
spapr: Don't use bus number for building DRC ids
DRC ids are more or less arbitrary, as long as they're consistent. For PCI, we notionally build them from the phb's index along with PCI bus number, slot and function number. Using bus number is broken, however, because it can change if the guest re-enumerates the PCI topology for whatever reason (e.g. due to hotplug of a bridge, which we don't support yet but want to). Fortunately, there's an alternative. Bridges are required to have a unique non-zero "chassis number" that we can use instead. Adjust the code to use that instead. This looks like it would introduce a guest visible breaking change, but in fact it does not because we don't yet ever use non-zero bus numbers. Both chassis and bus number are always 0 for the root bus, so there's no change for the existing cases. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Acked-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/ppc/spapr_pci.c54
1 files changed, 40 insertions, 14 deletions
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 7352028..9d99bc0 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1221,23 +1221,40 @@ static const char *dt_name_from_class(uint8_t class, uint8_t subclass,
*/
static uint32_t drc_id_from_devfn(SpaprPhbState *phb,
- uint32_t busnr,
- int32_t devfn)
+ uint8_t chassis, int32_t devfn)
{
- return (phb->index << 16) | (busnr << 8) | devfn;
+ return (phb->index << 16) | (chassis << 8) | devfn;
}
static SpaprDrc *drc_from_devfn(SpaprPhbState *phb,
- uint32_t busnr, int32_t devfn)
+ uint8_t chassis, int32_t devfn)
{
return spapr_drc_by_id(TYPE_SPAPR_DRC_PCI,
- drc_id_from_devfn(phb, busnr, devfn));
+ drc_id_from_devfn(phb, chassis, devfn));
+}
+
+static uint8_t chassis_from_bus(PCIBus *bus, Error **errp)
+{
+ if (pci_bus_is_root(bus)) {
+ return 0;
+ } else {
+ PCIDevice *bridge = pci_bridge_get_device(bus);
+
+ return object_property_get_uint(OBJECT(bridge), "chassis_nr", errp);
+ }
}
static SpaprDrc *drc_from_dev(SpaprPhbState *phb, PCIDevice *dev)
{
- uint32_t busnr = pci_bus_num(PCI_BUS(qdev_get_parent_bus(DEVICE(dev))));
- return drc_from_devfn(phb, busnr, dev->devfn);
+ Error *local_err = NULL;
+ uint8_t chassis = chassis_from_bus(pci_get_bus(dev), &local_err);
+
+ if (local_err) {
+ error_report_err(local_err);
+ return NULL;
+ }
+
+ return drc_from_devfn(phb, chassis, dev->devfn);
}
static void add_drcs(SpaprPhbState *phb)
@@ -1516,14 +1533,19 @@ static void spapr_pci_plug(HotplugHandler *plug_handler,
spapr_drc_reset(drc);
} else if (PCI_FUNC(pdev->devfn) == 0) {
int i;
+ uint8_t chassis = chassis_from_bus(pci_get_bus(pdev), &local_err);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
for (i = 0; i < 8; i++) {
SpaprDrc *func_drc;
SpaprDrcClass *func_drck;
SpaprDREntitySense state;
- func_drc = drc_from_devfn(phb, pci_bus_num(bus),
- PCI_DEVFN(slotnr, i));
+ func_drc = drc_from_devfn(phb, chassis, PCI_DEVFN(slotnr, i));
func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
state = func_drck->dr_entity_sense(func_drc);
@@ -1571,18 +1593,23 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
g_assert(drc->dev == plugged_dev);
if (!spapr_drc_unplug_requested(drc)) {
- PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
uint32_t slotnr = PCI_SLOT(pdev->devfn);
SpaprDrc *func_drc;
SpaprDrcClass *func_drck;
SpaprDREntitySense state;
int i;
+ Error *local_err = NULL;
+ uint8_t chassis = chassis_from_bus(pci_get_bus(pdev), &local_err);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
/* ensure any other present functions are pending unplug */
if (PCI_FUNC(pdev->devfn) == 0) {
for (i = 1; i < 8; i++) {
- func_drc = drc_from_devfn(phb, pci_bus_num(bus),
- PCI_DEVFN(slotnr, i));
+ func_drc = drc_from_devfn(phb, chassis, PCI_DEVFN(slotnr, i));
func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
state = func_drck->dr_entity_sense(func_drc);
if (state == SPAPR_DR_ENTITY_SENSE_PRESENT
@@ -1603,8 +1630,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
*/
if (PCI_FUNC(pdev->devfn) == 0) {
for (i = 7; i >= 0; i--) {
- func_drc = drc_from_devfn(phb, pci_bus_num(bus),
- PCI_DEVFN(slotnr, i));
+ func_drc = drc_from_devfn(phb, chassis, PCI_DEVFN(slotnr, i));
func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
state = func_drck->dr_entity_sense(func_drc);
if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) {