soc/amd/common/data_fabric: handle multiple PCI root domains

In the case of SoCs hat have more than one PCI root, we need to check to
which PCI root the PCI bus number, IO and MMIO regions configured in the
data fabric registers get routed to and only tell the resource allocator
about the resources that get routed to the current PCI root domain. For
this the numbers of the domains need to match the PCI root's destination
data fabric ID.

Signed-off-by: Felix Held <felix-coreboot@felixheld.de>
Change-Id: Ib6a6412f733d321044678d2b064c33418a53861c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/77113
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin L Roth <gaumless@gmail.com>
diff --git a/src/soc/amd/common/block/data_fabric/Kconfig b/src/soc/amd/common/block/data_fabric/Kconfig
index ba771c6..699c888 100644
--- a/src/soc/amd/common/block/data_fabric/Kconfig
+++ b/src/soc/amd/common/block/data_fabric/Kconfig
@@ -14,6 +14,22 @@
 	  fabric registers so that it knows in which regions it can properly
 	  allocate the non-fixed MMIO devices.
 
+config SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN_MULTI_PCI_ROOT
+	bool
+	depends on SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN
+	help
+	  On AMD SoCs with more than one PCI root, make sure to only report the
+	  PCI bus number, IO, and MMIO resources that get decoded to a specific
+	  PCI root in the corresponding coreboot domain. This will make sure
+	  that the allocation the resoucre allocator calculates will be decoded
+	  correctly to the PCI roots. In order for coreboot to know the correct
+	  mapping, the coreboot domain numbers must be set to the corresponding
+	  data fabric destination ID. On AMD systems with only one PCI root,
+	  this isn't needed and even though selecting this option works when
+	  the coreboot domain numbers are set up correctly, some link-time
+	  optimizations won't be possible, so it's preferable to only select
+	  this option on SoCs with multiple PCI roots.
+
 config SOC_AMD_COMMON_BLOCK_DATA_FABRIC_MULTI_PCI_SEGMENT
 	bool
 	depends on SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN
diff --git a/src/soc/amd/common/block/data_fabric/domain.c b/src/soc/amd/common/block/data_fabric/domain.c
index d693879..3924351 100644
--- a/src/soc/amd/common/block/data_fabric/domain.c
+++ b/src/soc/amd/common/block/data_fabric/domain.c
@@ -113,8 +113,10 @@
 		if (ctrl.np)
 			continue;
 
-		/* TODO: Systems with more than one PCI root need to check to which PCI root
-		   the MMIO range gets decoded to. */
+		/* Only look at MMIO regions that are decoded to the right PCI root */
+		if (CONFIG(SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN_MULTI_PCI_ROOT) &&
+		    ctrl.dst_fabric_id != domain->path.domain.domain)
+			continue;
 
 		data_fabric_get_mmio_base_size(i, &mmio_base, &mmio_limit);
 
@@ -168,8 +170,10 @@
 
 		limit_reg.raw = data_fabric_broadcast_read32(DF_IO_LIMIT(i));
 
-		/* TODO: Systems with more than one PCI root need to check to which PCI root
-		   the IO range gets decoded to. */
+		/* Only look at IO regions that are decoded to the right PCI root */
+		if (CONFIG(SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN_MULTI_PCI_ROOT) &&
+		    limit_reg.dst_fabric_id != domain->path.domain.domain)
+			continue;
 
 		io_base = base_reg.io_base << DF_IO_ADDR_SHIFT;
 		io_limit = ((limit_reg.io_limit + 1) << DF_IO_ADDR_SHIFT) - 1;
diff --git a/src/soc/amd/common/block/data_fabric/pci_segment_multi.c b/src/soc/amd/common/block/data_fabric/pci_segment_multi.c
index 6782221..a474ed9 100644
--- a/src/soc/amd/common/block/data_fabric/pci_segment_multi.c
+++ b/src/soc/amd/common/block/data_fabric/pci_segment_multi.c
@@ -15,8 +15,10 @@
 		pci_bus_base.raw = data_fabric_broadcast_read32(DF_PCI_CFG_BASE(i));
 		pci_bus_limit.raw = data_fabric_broadcast_read32(DF_PCI_CFG_LIMIT(i));
 
-		/* TODO: Systems with more than one PCI root need to check to which PCI root
-		   the PCI bus number range gets decoded to. */
+		if (CONFIG(SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN_MULTI_PCI_ROOT) &&
+		    pci_bus_limit.dst_fabric_id != domain->path.domain.domain)
+			continue;
+
 		if (pci_bus_base.we && pci_bus_base.re) {
 			/* TODO: Implement support for multiple PCI segments in coreboot */
 			if (pci_bus_base.segment_num) {
@@ -31,5 +33,7 @@
 		}
 	}
 
+	printk(BIOS_ERR, "No valid DF PCI CFG register pair found for domain %x.\n",
+	       domain->path.domain.domain);
 	return CB_ERR;
 }
diff --git a/src/soc/amd/common/block/data_fabric/pci_segment_single.c b/src/soc/amd/common/block/data_fabric/pci_segment_single.c
index 5f2152b..d4e1580 100644
--- a/src/soc/amd/common/block/data_fabric/pci_segment_single.c
+++ b/src/soc/amd/common/block/data_fabric/pci_segment_single.c
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <amdblocks/data_fabric.h>
+#include <console/console.h>
 #include <device/device.h>
 #include <types.h>
 
@@ -12,8 +13,10 @@
 	for (unsigned int i = 0; i < DF_PCI_CFG_MAP_COUNT; i++) {
 		pci_bus_map.raw = data_fabric_broadcast_read32(DF_PCI_CFG_MAP(i));
 
-		/* TODO: Systems with more than one PCI root need to check to which PCI root
-		   the PCI bus number range gets decoded to. */
+		if (CONFIG(SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN_MULTI_PCI_ROOT) &&
+		    pci_bus_map.dst_fabric_id != domain->path.domain.domain)
+			continue;
+
 		if (pci_bus_map.we && pci_bus_map.re) {
 			*first_bus = pci_bus_map.bus_num_base;
 			*last_bus = pci_bus_map.bus_num_limit;
@@ -21,5 +24,7 @@
 		}
 	}
 
+	printk(BIOS_ERR, "No valid DF PCI CFG register found for domain %x.\n",
+	       domain->path.domain.domain);
 	return CB_ERR;
 }