device: Add a helper function to add a downstream bus

Adding downstream busses at runtime is a common pattern so add a helper
function.

Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Change-Id: Ic898189b92997b93304fcbf47c73e2bb5ec09023
Reviewed-on: https://review.coreboot.org/c/coreboot/+/80210
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
diff --git a/src/device/device.c b/src/device/device.c
index 811b709..d877e14 100644
--- a/src/device/device.c
+++ b/src/device/device.c
@@ -125,6 +125,41 @@
 	return dev;
 }
 
+DECLARE_SPIN_LOCK(bus_lock)
+
+/**
+ * Allocate a new bus structure
+ *
+ * Allocate a new downstream bus structure below a device and attach it
+ * to the device tree if the device doesn't already have a downstream bus.
+ *
+ * @param parent Parent device the to be created bus should be attached to.
+ * @return Pointer to the newly created bus structure or the existing bus.
+ *
+ */
+static struct bus *__alloc_bus(struct device *parent)
+{
+	if (parent->link_list)
+		return parent->link_list;
+
+	struct bus *bus = calloc(1, sizeof(struct bus));
+	if (!bus)
+		die("Couldn't allocate downstream bus!\n");
+	parent->link_list = bus;
+	bus->dev = parent;
+
+	return bus;
+}
+
+struct bus *alloc_bus(struct device *parent)
+{
+	struct bus *bus;
+	spin_lock(&bus_lock);
+	bus = __alloc_bus(parent);
+	spin_unlock(&bus_lock);
+	return bus;
+}
+
 /**
  * See if a device structure already exists and if not allocate it.
  *
diff --git a/src/include/device/device.h b/src/include/device/device.h
index 83588d4..13bc8dc 100644
--- a/src/include/device/device.h
+++ b/src/include/device/device.h
@@ -171,6 +171,7 @@
 
 /* Generic device interface functions */
 struct device *alloc_dev(struct bus *parent, struct device_path *path);
+struct bus *alloc_bus(struct device *parent);
 void dev_initialize_chips(void);
 void dev_enumerate(void);
 void dev_configure(void);
@@ -229,10 +230,9 @@
 static inline void mp_cpu_bus_init(struct device *dev)
 {
 	/* Make sure the cpu cluster has a downstream bus for LAPICs to be allocated. */
-	if (!dev->link_list)
-		add_more_links(dev, 1);
+	struct bus *bus = alloc_bus(dev);
 
-	mp_init_cpus(dev->link_list);
+	mp_init_cpus(bus);
 }
 
 /* Debug functions */
diff --git a/src/soc/intel/xeon_sp/chip_common.c b/src/soc/intel/xeon_sp/chip_common.c
index bf2a015..845e968 100644
--- a/src/soc/intel/xeon_sp/chip_common.c
+++ b/src/soc/intel/xeon_sp/chip_common.c
@@ -72,14 +72,7 @@
 	if (!sr)
 		return;
 
-	if (!dev->link_list) {
-		dev->link_list = calloc(1, sizeof(struct bus));
-		if (!dev->link_list)
-			die("%s: out of memory.\n", __func__);
-	}
-
-	struct bus *bus = dev->link_list;
-	bus->dev = dev;
+	struct bus *bus = alloc_bus(dev);
 	bus->secondary = sr->BusBase;
 	bus->subordinate = sr->BusBase;
 	bus->max_subordinate = sr->BusLimit;
diff --git a/src/soc/intel/xeon_sp/spr/ioat.c b/src/soc/intel/xeon_sp/spr/ioat.c
index 02f35cf..60936a8 100644
--- a/src/soc/intel/xeon_sp/spr/ioat.c
+++ b/src/soc/intel/xeon_sp/spr/ioat.c
@@ -45,12 +45,7 @@
 
 	domain->ops = &ioat_domain_ops;
 
-	domain->link_list = calloc(1, sizeof(struct bus));
-	if (!domain->link_list)
-		die("%s: out of memory.\n", __func__);
-
-	struct bus *const bus = domain->link_list;
-	bus->dev = domain;
+	struct bus *const bus = alloc_bus(domain);
 	bus->secondary = bus_base;
 	bus->subordinate = bus->secondary;
 	bus->max_subordinate = bus_limit;