From ea8313934548b4f41c8b27078cabb2b017074af7 Mon Sep 17 00:00:00 2001 From: Felix Held Date: Tue, 8 Aug 2023 02:55:09 +0200 Subject: soc/amd/common/data_fabric: read PCI bus decoding from DF registers The data fabric also controls which PCI bus numbers get decoded to the PCI root. In order for the resource allocator to know how the hardware is configured, read the corresponding data fabric registers to get the information that then gets passed to the allocator. Picasso, Cezanne, Mendocino and Rembrandt only support one PCI segment with 256 buses while the Phoenix and Glinda data fabric hardware has support for more PCI segments. Due to this change, the register layout is different and incompatible between those two, so introduce the SOC_AMD_COMMON_BLOCK_DATA_FABRIC_MULTI_PCI_SEGMENT Kconfig option for a SoC to specify which implementation is needed. At the moment, coreboot doesn't have support for multiple PCI segments and the code doesn't support PCI segments other than segment 0. On Picasso the PCI bus number limit read back from the data fabric register is 255 even though CONFIG_ECAM_MMCONF_BUS_NUMBER is set to 64, so also make sure that the bus and limit returned by data_fabric_get_pci_bus_numbers is within the expected limits. TEST=PCI bus allocation still works on Mandolin (Picasso) and Birman (Phoenix). Picasso has 64 PCI buses. coreboot puts this info into the resource producer in _SB\PCI0\_CRS which the Linux kernel reads: * coreboot: PCI0 _CRS: adding busses [0-3f] * Linux: pci_bus 0000:00: root bus resource [bus 00-3f] This matches the information in the ACPI MCFG table. Signed-off-by: Felix Held Change-Id: Ide5fa9b3e95cfd59232048910cc8feacb6dbdb94 Reviewed-on: https://review.coreboot.org/c/coreboot/+/77080 Reviewed-by: Martin L Roth Reviewed-by: Eric Lai Tested-by: build bot (Jenkins) --- src/soc/amd/common/block/data_fabric/Kconfig | 11 +++++++ src/soc/amd/common/block/data_fabric/Makefile.inc | 6 ++++ src/soc/amd/common/block/data_fabric/domain.c | 13 +++++--- .../common/block/data_fabric/pci_segment_multi.c | 35 ++++++++++++++++++++++ .../common/block/data_fabric/pci_segment_single.c | 25 ++++++++++++++++ .../common/block/include/amdblocks/data_fabric.h | 3 ++ src/soc/amd/glinda/Kconfig | 1 + src/soc/amd/phoenix/Kconfig | 1 + 8 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 src/soc/amd/common/block/data_fabric/pci_segment_multi.c create mode 100644 src/soc/amd/common/block/data_fabric/pci_segment_single.c diff --git a/src/soc/amd/common/block/data_fabric/Kconfig b/src/soc/amd/common/block/data_fabric/Kconfig index 4c4f7b34e1..ba771c6dce 100644 --- a/src/soc/amd/common/block/data_fabric/Kconfig +++ b/src/soc/amd/common/block/data_fabric/Kconfig @@ -13,3 +13,14 @@ config SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN resource allocator about the MMIO regions configured in the data 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_MULTI_PCI_SEGMENT + bool + depends on SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN + help + Some AMD SoCs support more than one PCI segment with 256 buses. Those + SoCs however have a different data fabric register layout for the PCI + bus number decoding. SoCs that use a data fabric register pair for + the PCI bus number which includes the segment number must select this + option; SoCs that use one data fabric register for the PCI bus number + which doesn't include a segment number field mustn't select this. diff --git a/src/soc/amd/common/block/data_fabric/Makefile.inc b/src/soc/amd/common/block/data_fabric/Makefile.inc index 868df82e1c..f01c70dfb0 100644 --- a/src/soc/amd/common/block/data_fabric/Makefile.inc +++ b/src/soc/amd/common/block/data_fabric/Makefile.inc @@ -2,3 +2,9 @@ ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_DATA_FABRIC) += data_fabric_helper.c ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN) += domain.c + +ifeq ($(CONFIG_SOC_AMD_COMMON_BLOCK_DATA_FABRIC_MULTI_PCI_SEGMENT),y) +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN) += pci_segment_multi.c +else +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN) += pci_segment_single.c +endif # !CONFIG_SOC_AMD_COMMON_BLOCK_APOB_NV_DISABLE diff --git a/src/soc/amd/common/block/data_fabric/domain.c b/src/soc/amd/common/block/data_fabric/domain.c index 88b116063b..d693879ce6 100644 --- a/src/soc/amd/common/block/data_fabric/domain.c +++ b/src/soc/amd/common/block/data_fabric/domain.c @@ -16,10 +16,15 @@ void amd_pci_domain_scan_bus(struct device *domain) { uint8_t bus, limit; - /* TODO: Systems with more than one PCI root need to read the data fabric registers to - see which PCI bus numbers get decoded to which PCI root. */ - bus = 0; - limit = CONFIG_ECAM_MMCONF_BUS_NUMBER - 1; + if (data_fabric_get_pci_bus_numbers(domain, &bus, &limit) != CB_SUCCESS) { + printk(BIOS_ERR, "No PCI bus numbers decoded to PCI root.\n"); + return; + } + + /* TODO: Check if bus >= CONFIG_ECAM_MMCONF_BUS_NUMBER and return in that case */ + + /* Make sure to not report more than CONFIG_ECAM_MMCONF_BUS_NUMBER PCI buses */ + limit = MIN(limit, CONFIG_ECAM_MMCONF_BUS_NUMBER - 1); /* Set bus first number of PCI root */ domain->link_list->secondary = bus; 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 new file mode 100644 index 0000000000..67822216cd --- /dev/null +++ b/src/soc/amd/common/block/data_fabric/pci_segment_multi.c @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include + +enum cb_err data_fabric_get_pci_bus_numbers(struct device *domain, uint8_t *first_bus, + uint8_t *last_bus) +{ + union df_pci_cfg_base pci_bus_base; + union df_pci_cfg_limit pci_bus_limit; + + for (unsigned int i = 0; i < DF_PCI_CFG_MAP_COUNT; i++) { + 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 (pci_bus_base.we && pci_bus_base.re) { + /* TODO: Implement support for multiple PCI segments in coreboot */ + if (pci_bus_base.segment_num) { + printk(BIOS_ERR, "DF PCI CFG register pair %d uses bus " + "segment != 0.\n", i); + return CB_ERR; + } + + *first_bus = pci_bus_base.bus_num_base; + *last_bus = pci_bus_limit.bus_num_limit; + return CB_SUCCESS; + } + } + + 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 new file mode 100644 index 0000000000..5f2152b668 --- /dev/null +++ b/src/soc/amd/common/block/data_fabric/pci_segment_single.c @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + +enum cb_err data_fabric_get_pci_bus_numbers(struct device *domain, uint8_t *first_bus, + uint8_t *last_bus) +{ + union df_pci_cfg_map pci_bus_map; + + 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 (pci_bus_map.we && pci_bus_map.re) { + *first_bus = pci_bus_map.bus_num_base; + *last_bus = pci_bus_map.bus_num_limit; + return CB_SUCCESS; + } + } + + return CB_ERR; +} diff --git a/src/soc/amd/common/block/include/amdblocks/data_fabric.h b/src/soc/amd/common/block/include/amdblocks/data_fabric.h index f1a7c297ff..341bad6415 100644 --- a/src/soc/amd/common/block/include/amdblocks/data_fabric.h +++ b/src/soc/amd/common/block/include/amdblocks/data_fabric.h @@ -48,6 +48,9 @@ void data_fabric_disable_mmio_reg(unsigned int reg); int data_fabric_find_unused_mmio_reg(void); void data_fabric_set_mmio_np(void); +enum cb_err data_fabric_get_pci_bus_numbers(struct device *domain, uint8_t *first_bus, + uint8_t *last_bus); + /* Inform the resource allocator about the usable IO and MMIO regions and PCI bus numbers */ void amd_pci_domain_read_resources(struct device *domain); void amd_pci_domain_scan_bus(struct device *domain); diff --git a/src/soc/amd/glinda/Kconfig b/src/soc/amd/glinda/Kconfig index a241ad10fa..b51cff39e0 100644 --- a/src/soc/amd/glinda/Kconfig +++ b/src/soc/amd/glinda/Kconfig @@ -43,6 +43,7 @@ config SOC_AMD_GLINDA select SOC_AMD_COMMON_BLOCK_CPUFREQ_FAM1AH select SOC_AMD_COMMON_BLOCK_DATA_FABRIC select SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN + select SOC_AMD_COMMON_BLOCK_DATA_FABRIC_MULTI_PCI_SEGMENT select SOC_AMD_COMMON_BLOCK_ESPI_EXTENDED_DECODE_RANGES # TODO: Check if this is still correct select SOC_AMD_COMMON_BLOCK_GRAPHICS # TODO: Check if this is still correct select SOC_AMD_COMMON_BLOCK_HAS_ESPI # TODO: Check if this is still correct diff --git a/src/soc/amd/phoenix/Kconfig b/src/soc/amd/phoenix/Kconfig index b506464928..6bed749731 100644 --- a/src/soc/amd/phoenix/Kconfig +++ b/src/soc/amd/phoenix/Kconfig @@ -44,6 +44,7 @@ config SOC_AMD_PHOENIX select SOC_AMD_COMMON_BLOCK_CPUFREQ_FAM17H_19H select SOC_AMD_COMMON_BLOCK_DATA_FABRIC select SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN + select SOC_AMD_COMMON_BLOCK_DATA_FABRIC_MULTI_PCI_SEGMENT select SOC_AMD_COMMON_BLOCK_ESPI_EXTENDED_DECODE_RANGES select SOC_AMD_COMMON_BLOCK_GRAPHICS # TODO: Check if this is still correct select SOC_AMD_COMMON_BLOCK_HAS_ESPI -- cgit v1.2.3