device/pci_device.c: Add way to limit max bus numbers

By default this limits PCI buses to CONFIG_MMCONF_BUS_NUMBER.
Some platforms have multiple PCI root busses (e.g. xeon_sp), where bus
numbers are limited. This provides a basic check. On some platforms it
looks like programming 0xff to the subordinate bus number confuses and
hangs the hardware.

Change-Id: I0582b156df1a5f76119a3687886c4d58f2d3ad6f
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/59395
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Jonathan Zhang <jonzhang@fb.com>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
diff --git a/src/device/pci_device.c b/src/device/pci_device.c
index 9de2946..e600f34 100644
--- a/src/device/pci_device.c
+++ b/src/device/pci_device.c
@@ -1532,6 +1532,18 @@
 	if (state == PCI_ROUTE_SCAN) {
 		link->secondary = parent->subordinate + 1;
 		link->subordinate = link->secondary + dev->hotplug_buses;
+		link->max_subordinate = parent->max_subordinate
+						? parent->max_subordinate
+						: (CONFIG_ECAM_MMCONF_BUS_NUMBER - 1);
+	}
+
+	if (link->secondary > link->max_subordinate)
+		die("%s: No more busses available!\n", __func__);
+
+	/* This ought to only happen with hotplug buses.  */
+	if (link->subordinate > link->max_subordinate) {
+		printk(BIOS_WARNING, "%s: Limiting subordinate busses\n", __func__);
+		link->subordinate = link->max_subordinate;
 	}
 
 	if (state == PCI_ROUTE_CLOSE) {
@@ -1541,7 +1553,7 @@
 	} else if (state == PCI_ROUTE_SCAN) {
 		primary = parent->secondary;
 		secondary = link->secondary;
-		subordinate = 0xff; /* MAX PCI_BUS number here */
+		subordinate = link->max_subordinate;
 	} else if (state == PCI_ROUTE_FINAL) {
 		primary = parent->secondary;
 		secondary = link->secondary;
diff --git a/src/include/device/device.h b/src/include/device/device.h
index 8b1dde1..b4b2d20 100644
--- a/src/include/device/device.h
+++ b/src/include/device/device.h
@@ -85,7 +85,8 @@
 	uint16_t	bridge_cmd;		/* Bridge command register */
 	unsigned char	link_num;	/* The index of this link */
 	uint16_t	secondary;	/* secondary bus number */
-	uint16_t	subordinate;	/* max subordinate bus number */
+	uint16_t	subordinate;	/* subordinate bus number */
+	uint16_t	max_subordinate;	/* max subordinate bus number */
 	unsigned char   cap;		/* PCi capability offset */
 	uint32_t	hcdn_reg;		/* For HyperTransport link  */