summaryrefslogtreecommitdiff
path: root/src/soc/intel/xeon_sp
diff options
context:
space:
mode:
authorShuo Liu <shuo.liu@intel.com>2024-03-27 04:52:37 +0800
committerLean Sheng Tan <sheng.tan@9elements.com>2024-05-28 09:47:35 +0000
commit70de5bf9fdfeb33dfc717512e400b56ab02b165d (patch)
treee68fbbe6bf7c2547dc1623948564f004abdc55de /src/soc/intel/xeon_sp
parentbd33b6ab9fde904dd8a532ce20e8a6331ba8dafb (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/intel/xeon_sp')
-rw-r--r--src/soc/intel/xeon_sp/include/soc/numa.h15
-rw-r--r--src/soc/intel/xeon_sp/numa.c72
-rw-r--r--src/soc/intel/xeon_sp/spr/chip.c2
-rw-r--r--src/soc/intel/xeon_sp/spr/soc_util.c2
-rw-r--r--src/soc/intel/xeon_sp/uncore.c2
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;