diff options
author | Shuo Liu <shuo.liu@intel.com> | 2024-03-27 04:52:37 +0800 |
---|---|---|
committer | Lean Sheng Tan <sheng.tan@9elements.com> | 2024-05-28 09:47:35 +0000 |
commit | 70de5bf9fdfeb33dfc717512e400b56ab02b165d (patch) | |
tree | e68fbbe6bf7c2547dc1623948564f004abdc55de /src/soc | |
parent | bd33b6ab9fde904dd8a532ce20e8a6331ba8dafb (diff) |
soc/intel/xeon_sp: Add PD_TYPE_CLUSTER
Add a new proximity type to represent the sub-NUMA cluster (SNC).
This patch adds necessary Xeon-SP common code level support for
SNC support. When SNC on, each SNC cluster will have a proximity
domain. DIMMs and CPU cores are attached to SNC proximity domains
instead of the processor proximity domains.
With SNC, there are 3 types of proximity domains,
PD_TYPE_PROCESSOR, PD_TYPE_GENERIC_INITIATOR and PD_TYPE_CLUSTER.
proximity domain type checks in Xeon-SP codes are updated to
correctly handle the adding of the new type.
This patch doesn't actually enable SNC. To fully enable SNC, SoC
codes need to override soc_get_cluster_count(), soc_set_cpu_node_
id() and memory_to_pd(), and call soc_set_cpu_node_id() in its
per-CPU init routine.
Change-Id: I32558983780f302ff4893901540a90baebf47add
Signed-off-by: Shuo Liu <shuo.liu@intel.com>
Co-authored-by: Ziang Wang <ziang.wang@intel.com>
Co-authored-by: Gang Chen <gang.c.chen@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/81443
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com>
Diffstat (limited to 'src/soc')
-rw-r--r-- | src/soc/intel/xeon_sp/include/soc/numa.h | 15 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/numa.c | 72 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/chip.c | 2 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/soc_util.c | 2 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/uncore.c | 2 |
5 files changed, 81 insertions, 12 deletions
diff --git a/src/soc/intel/xeon_sp/include/soc/numa.h b/src/soc/intel/xeon_sp/include/soc/numa.h index d12451774c..b64488190f 100644 --- a/src/soc/intel/xeon_sp/include/soc/numa.h +++ b/src/soc/intel/xeon_sp/include/soc/numa.h @@ -19,6 +19,17 @@ enum proximity_domain_type { * Generic Initiator domain is a CXL memory device. */ PD_TYPE_GENERIC_INITIATOR, + /* + * PD_TYPE_CLUSTER is for Sub-NUMA cluster (SNC). SNC is localization + * domain within a socket, composed of a set of CPU cores, last-level + * cache pieces and memory controllers, which are close to each other. + * SNC will be reported as NUMA nodes to OS so that the performance + * proximity could be fully exploited for task assignment and scheduling. + * + * For more, please refer to + * https://www.intel.com/content/www/us/en/developer/articles/technical/xeon-processor-scalable-family-technical-overview.html + */ + PD_TYPE_CLUSTER, PD_TYPE_MAX }; @@ -40,6 +51,7 @@ struct proximity_domain { * sockets, so we need a bitmap. */ uint8_t socket_bitmap; + uint8_t cluster_bitmap; /* Relative distances (memory latency) from all domains */ uint8_t *distances; /* @@ -68,4 +80,7 @@ uint32_t get_generic_initiator_mem_size(void); uint32_t memory_to_pd(const struct SystemMemoryMapElement *mem); uint32_t device_to_pd(const struct device *dev); +uint8_t soc_get_cluster_count(void); +void soc_set_cpu_node_id(struct device *cpu); + #endif /* NUMA_H */ diff --git a/src/soc/intel/xeon_sp/numa.c b/src/soc/intel/xeon_sp/numa.c index 1f0b9a3f60..8ce49818e9 100644 --- a/src/soc/intel/xeon_sp/numa.c +++ b/src/soc/intel/xeon_sp/numa.c @@ -25,6 +25,9 @@ static void dump_pds(void) printk(BIOS_DEBUG, "\t\tbase(64MB):0x%x\n", pds.pds[i].base); printk(BIOS_DEBUG, "\t\tsize(64MB):0x%x\n", pds.pds[i].size); } + if (pds.pds[i].pd_type == PD_TYPE_CLUSTER) { + printk(BIOS_DEBUG, "\t\tcluster_bitmap:0x%x\n", pds.pds[i].cluster_bitmap); + } } } @@ -32,20 +35,25 @@ static void fill_pds(void) { uint8_t num_sockets = soc_get_num_cpus(); uint8_t num_cxlnodes = get_cxl_node_count(); + uint8_t num_clusters = soc_get_cluster_count(); const IIO_UDS *hob = get_iio_uds(); /* * Rules/assumptions: - * 1. Each processor has a processor proximity domain regardless whether + * 1. Each socket has a processor proximity domain regardless whether * a processor has DIMM attached to it or not. - * 2. All system memory map elements are either from processor attached memory, + * 2. When sub-NUMA cluster (SNC) is on, soc_get_cluster_count() will return a + * non-zero value and each SNC cluster will have one proximity domain. + * For SNC case, DIMMs and CPU cores are attached to SNC proximity domains instead + * of the processor proximity domains. + * 3. All system memory map elements are either from processor attached memory, * or from CXL memory. Each CXL node info entry has a corresponding entry * in system memory map elements. - * 3. Each CXL device may have multiple HDMs (Host-managed Device Memory). Each + * 4. Each CXL device may have multiple HDMs (Host-managed Device Memory). Each * HDM has one and only one CXL node info entry. Each CXL node info entry * represents a generic initiator proximity domain. */ - pds.num_pds = num_cxlnodes + num_sockets; + pds.num_pds = num_cxlnodes + num_sockets + num_sockets * num_clusters; pds.pds = xmalloc(sizeof(struct proximity_domain) * pds.num_pds); if (!pds.pds) die("%s %d out of memory.", __FILE__, __LINE__); @@ -57,12 +65,23 @@ static void fill_pds(void) for (uint8_t socket = 0; socket < num_sockets; socket++) { if (!soc_cpu_is_enabled(socket)) continue; + const uint8_t socket_id = hob->PlatformData.IIO_resource[socket].SocketID; pds.pds[i].pd_type = PD_TYPE_PROCESSOR; - pds.pds[i].socket_bitmap = 1 << hob->PlatformData.IIO_resource[socket].SocketID; + pds.pds[i].socket_bitmap = 1 << socket_id; pds.pds[i].distances = malloc(sizeof(uint8_t) * pds.num_pds); if (!pds.pds[i].distances) die("%s %d out of memory.", __FILE__, __LINE__); i++; + /* Fill in cluster domains */ + for (uint8_t cluster = 0; cluster < num_clusters; cluster++) { + pds.pds[i].pd_type = PD_TYPE_CLUSTER; + pds.pds[i].socket_bitmap = 1 << socket_id; + pds.pds[i].cluster_bitmap = 1 << cluster; + pds.pds[i].distances = malloc(sizeof(uint8_t) * pds.num_pds); + if (!pds.pds[i].distances) + die("%s %d out of memory.", __FILE__, __LINE__); + i++; + } } /* If there are no CXL nodes, we are done */ @@ -100,7 +119,7 @@ uint32_t get_generic_initiator_mem_size(void) uint32_t size = 0; for (i = 0; i < pds.num_pds; i++) { - if (pds.pds[i].pd_type == PD_TYPE_PROCESSOR) + if (pds.pds[i].pd_type != PD_TYPE_GENERIC_INITIATOR) continue; size += pds.pds[i].size; } @@ -123,6 +142,22 @@ static uint32_t socket_to_pd(uint8_t socket) return XEONSP_INVALID_PD_INDEX; } +static uint32_t cluster_to_pd(uint8_t socket, uint8_t cluster) +{ + for (uint8_t i = 0; i < pds.num_pds; i++) { + if (pds.pds[i].pd_type != PD_TYPE_CLUSTER) + continue; + if (pds.pds[i].socket_bitmap == (1 << socket) && + pds.pds[i].cluster_bitmap == (1 << cluster)) + return i; + } + + printk(BIOS_ERR, "%s: could not find proximity domain for socket/cluster %d/%d.\n", + __func__, socket, cluster); + + return XEONSP_INVALID_PD_INDEX; +} + uint32_t device_to_pd(const struct device *dev) { /* first to see if the dev is bound to specific pd */ @@ -130,8 +165,12 @@ uint32_t device_to_pd(const struct device *dev) if (pds.pds[i].dev == dev) return i; - if (dev->path.type == DEVICE_PATH_APIC) - return socket_to_pd(dev->path.apic.package_id); + if (dev->path.type == DEVICE_PATH_APIC) { + if (soc_get_cluster_count()) + return cluster_to_pd(dev->path.apic.package_id, dev->path.apic.node_id); + else + return socket_to_pd(dev->path.apic.package_id); + } if ((dev->path.type == DEVICE_PATH_DOMAIN) || (dev->path.type == DEVICE_PATH_PCI)) @@ -143,8 +182,12 @@ uint32_t device_to_pd(const struct device *dev) return XEONSP_INVALID_PD_INDEX; } -uint32_t memory_to_pd(const struct SystemMemoryMapElement *mem) +__weak uint32_t memory_to_pd(const struct SystemMemoryMapElement *mem) { + /* + * TODO: For SNC case, link DRAM range to cluster id instead of socket id + * in SoC codes. + */ return socket_to_pd(mem->SocketId); } @@ -183,3 +226,14 @@ void setup_pds(void) fill_pd_distances(); dump_pds(); } + +__weak uint8_t soc_get_cluster_count(void) +{ + //TODO: Implement in SoC codes. + return 0; +} + +__weak void soc_set_cpu_node_id(struct device *cpu) +{ + //TODO: Implement in SoC codes. +}; diff --git a/src/soc/intel/xeon_sp/spr/chip.c b/src/soc/intel/xeon_sp/spr/chip.c index 1eab917284..e179df0e15 100644 --- a/src/soc/intel/xeon_sp/spr/chip.c +++ b/src/soc/intel/xeon_sp/spr/chip.c @@ -176,7 +176,7 @@ static void rcec_init(struct device *dev) uint32_t ep_bus; uint8_t i; for (i = 0; i < pds.num_pds; i++) { - if (pds.pds[i].pd_type == PD_TYPE_PROCESSOR) + if (pds.pds[i].pd_type != PD_TYPE_GENERIC_INITIATOR) continue; ep_bus = PCI_BDF(pds.pds[i].dev) >> 20; if (ep_bus == ecrc_bus + 1) diff --git a/src/soc/intel/xeon_sp/spr/soc_util.c b/src/soc/intel/xeon_sp/spr/soc_util.c index 17addfc75c..584532785e 100644 --- a/src/soc/intel/xeon_sp/spr/soc_util.c +++ b/src/soc/intel/xeon_sp/spr/soc_util.c @@ -94,7 +94,7 @@ bool is_iio_cxl_stack_res(const STACK_RES *res) assert(pds.num_pds); for (uint8_t i = 0; i < pds.num_pds; i++) { - if (pds.pds[i].pd_type == PD_TYPE_PROCESSOR) + if (pds.pds[i].pd_type != PD_TYPE_GENERIC_INITIATOR) continue; uint32_t bus = PCI_BDF(pds.pds[i].dev) >> 20; diff --git a/src/soc/intel/xeon_sp/uncore.c b/src/soc/intel/xeon_sp/uncore.c index a6ac7c8be7..d2d46220a2 100644 --- a/src/soc/intel/xeon_sp/uncore.c +++ b/src/soc/intel/xeon_sp/uncore.c @@ -284,7 +284,7 @@ static void mc_add_dram_resources(struct device *dev, int *res_count) /* CXL Memory */ uint8_t i; for (i = 0; i < pds.num_pds; i++) { - if (pds.pds[i].pd_type == PD_TYPE_PROCESSOR) + if (pds.pds[i].pd_type != PD_TYPE_GENERIC_INITIATOR) continue; unsigned long flags = IORESOURCE_CACHEABLE; |