@@ -1480,6 +1480,57 @@ static void spapr_pci_bridge_plug(SpaprPhbState *phb,
add_drcs(phb, bus);
}
+/* Returns non-zero if the value of "chassis_nr" is already in use */
+static int check_chassis_nr(Object *obj, void *opaque)
+{
+ int new_chassis_nr =
+ object_property_get_uint(opaque, "chassis_nr", &error_abort);
+ int chassis_nr =
+ object_property_get_uint(obj, "chassis_nr", NULL);
+
+ if (!object_dynamic_cast(obj, TYPE_PCI_BRIDGE)) {
+ return 0;
+ }
+
+ /* Skip unsupported bridge types */
+ if (!chassis_nr) {
+ return 0;
+ }
+
+ /* Skip self */
+ if (obj == opaque) {
+ return 0;
+ }
+
+ return chassis_nr == new_chassis_nr;
+}
+
+static bool bridge_has_valid_chassis_nr(Object *bridge, Error **errp)
+{
+ int chassis_nr =
+ object_property_get_uint(bridge, "chassis_nr", NULL);
+
+ /*
+ * slotid_cap_init() already ensures that "chassis_nr" isn't null for
+ * standard PCI bridges, so this really tells if "chassis_nr" is present
+ * or not.
+ */
+ if (!chassis_nr) {
+ error_setg(errp, "PCI Bridge lacks a \"chassis_nr\" property");
+ error_append_hint(errp, "Try -device pci-bridge instead.\n");
+ return false;
+ }
+
+ /* We want unique values for "chassis_nr" */
+ if (object_child_foreach_recursive(object_get_root(), check_chassis_nr,
+ bridge)) {
+ error_setg(errp, "Bridge chassis %d already in use", chassis_nr);
+ return false;
+ }
+
+ return true;
+}
+
static void spapr_pci_plug(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp)
{
@@ -1508,6 +1559,9 @@ static void spapr_pci_plug(HotplugHandler *plug_handler,
g_assert(drc);
if (pc->is_bridge) {
+ if (!bridge_has_valid_chassis_nr(OBJECT(plugged_dev), errp)) {
+ return;
+ }
spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev));
}