Skip to content

Commit a4beb5f

Browse files
gkurzdgibson
authored andcommitted
spapr_pci: Robustify support of PCI bridges
Some recent error handling cleanups unveiled issues with our support of PCI bridges: 1) QEMU aborts when using non-standard PCI bridge types, unveiled by commit 7ef1553 "spapr_pci: Drop some dead error handling" $ qemu-system-ppc64 -M pseries -device pcie-pci-bridge Unexpected error in object_property_find() at qom/object.c:1240: qemu-system-ppc64: -device pcie-pci-bridge: Property '.chassis_nr' not found Aborted (core dumped) This happens because we assume all PCI bridge types to have a "chassis_nr" property. This property only exists with the standard PCI bridge type "pci-bridge" actually. We could possibly revert 7ef1553 but it seems much simpler to check the presence of "chassis_nr" earlier. 2) QEMU abort if same "chassis_nr" value is used several times, unveiled by commit d262312 "qom: Drop parameter @errp of object_property_add() & friends" $ qemu-system-ppc64 -M pseries -device pci-bridge,chassis_nr=1 \ -device pci-bridge,chassis_nr=1 Unexpected error in object_property_try_add() at qom/object.c:1167: qemu-system-ppc64: -device pci-bridge,chassis_nr=1: attempt to add duplicate property '40000100' to object (type 'container') Aborted (core dumped) This happens because we assume that "chassis_nr" values are unique, but nobody enforces that and we end up generating duplicate DRC ids. The PCI code doesn't really care for duplicate "chassis_nr" properties since it is only used to initialize the "Chassis Number Register" of the bridge, with no functional impact on QEMU. So, even if passing the same value several times might look weird, it never broke anything before, so I guess we don't necessarily want to enforce strict checking in the PCI code now. Workaround both issues in the PAPR code: check that the bridge has a unique and non null "chassis_nr" when plugging it into its parent bus. Fixes: 05929a6 ("spapr: Don't use bus number for building DRC ids") Fixes: 7ef1553 ("spapr_pci: Drop some dead error handling") Fixes: d262312 ("qom: Drop parameter @errp of object_property_add() & friends") Reported-by: Thomas Huth <[email protected]> Signed-off-by: Greg Kurz <[email protected]> Message-Id: <[email protected]> [dwg: Move check slightly to a better place] Signed-off-by: David Gibson <[email protected]>
1 parent 14de3d4 commit a4beb5f

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

hw/ppc/spapr_pci.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,57 @@ static void spapr_pci_bridge_plug(SpaprPhbState *phb,
14801480
add_drcs(phb, bus);
14811481
}
14821482

1483+
/* Returns non-zero if the value of "chassis_nr" is already in use */
1484+
static int check_chassis_nr(Object *obj, void *opaque)
1485+
{
1486+
int new_chassis_nr =
1487+
object_property_get_uint(opaque, "chassis_nr", &error_abort);
1488+
int chassis_nr =
1489+
object_property_get_uint(obj, "chassis_nr", NULL);
1490+
1491+
if (!object_dynamic_cast(obj, TYPE_PCI_BRIDGE)) {
1492+
return 0;
1493+
}
1494+
1495+
/* Skip unsupported bridge types */
1496+
if (!chassis_nr) {
1497+
return 0;
1498+
}
1499+
1500+
/* Skip self */
1501+
if (obj == opaque) {
1502+
return 0;
1503+
}
1504+
1505+
return chassis_nr == new_chassis_nr;
1506+
}
1507+
1508+
static bool bridge_has_valid_chassis_nr(Object *bridge, Error **errp)
1509+
{
1510+
int chassis_nr =
1511+
object_property_get_uint(bridge, "chassis_nr", NULL);
1512+
1513+
/*
1514+
* slotid_cap_init() already ensures that "chassis_nr" isn't null for
1515+
* standard PCI bridges, so this really tells if "chassis_nr" is present
1516+
* or not.
1517+
*/
1518+
if (!chassis_nr) {
1519+
error_setg(errp, "PCI Bridge lacks a \"chassis_nr\" property");
1520+
error_append_hint(errp, "Try -device pci-bridge instead.\n");
1521+
return false;
1522+
}
1523+
1524+
/* We want unique values for "chassis_nr" */
1525+
if (object_child_foreach_recursive(object_get_root(), check_chassis_nr,
1526+
bridge)) {
1527+
error_setg(errp, "Bridge chassis %d already in use", chassis_nr);
1528+
return false;
1529+
}
1530+
1531+
return true;
1532+
}
1533+
14831534
static void spapr_pci_plug(HotplugHandler *plug_handler,
14841535
DeviceState *plugged_dev, Error **errp)
14851536
{
@@ -1508,6 +1559,9 @@ static void spapr_pci_plug(HotplugHandler *plug_handler,
15081559
g_assert(drc);
15091560

15101561
if (pc->is_bridge) {
1562+
if (!bridge_has_valid_chassis_nr(OBJECT(plugged_dev), errp)) {
1563+
return;
1564+
}
15111565
spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev));
15121566
}
15131567

0 commit comments

Comments
 (0)