summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cpu/x86/topology.c60
-rw-r--r--src/include/cpu/x86/topology.h5
-rw-r--r--src/soc/intel/xeon_sp/spr/cpu.c5
3 files changed, 70 insertions, 0 deletions
diff --git a/src/cpu/x86/topology.c b/src/cpu/x86/topology.c
index 6c8d7fd420..baa4a7a584 100644
--- a/src/cpu/x86/topology.c
+++ b/src/cpu/x86/topology.c
@@ -4,6 +4,8 @@
#include <device/device.h>
#include <cpu/x86/topology.h>
+#define CPUID_EXTENDED_CPU_TOPOLOGY2 0x1f
+
#define CPUID_EXTENDED_CPU_TOPOLOGY 0x0b
#define LEVEL_TYPE_CORE 2
#define LEVEL_TYPE_SMT 1
@@ -21,6 +23,64 @@
#define CPUID_CPU_TOPOLOGY_CORE_BITS(res, threadbits) \
((CPUID_CPU_TOPOLOGY(LEVEL_BITS, (res).eax)) - threadbits)
+/* Return the level shift for the highest supported level (the package) */
+static enum cb_err get_cpu_package_bits(uint32_t *package_bits)
+{
+ struct cpuid_result cpuid_regs;
+ int level_num, cpu_id_op = 0;
+ const uint32_t cpuid_max_func = cpuid_get_max_func();
+
+ /*
+ * Not all CPUs support this, those won't get topology filled in here.
+ * CPU specific code can do this however.
+ */
+ if (cpuid_max_func >= CPUID_EXTENDED_CPU_TOPOLOGY2)
+ cpu_id_op = CPUID_EXTENDED_CPU_TOPOLOGY2;
+ else if (cpuid_max_func >= CPUID_EXTENDED_CPU_TOPOLOGY)
+ cpu_id_op = CPUID_EXTENDED_CPU_TOPOLOGY;
+ else
+ return CB_ERR;
+
+ *package_bits = level_num = 0;
+ cpuid_regs = cpuid_ext(cpu_id_op, level_num);
+
+ /*
+ * Sub-leaf index 0 enumerates SMT level, some AMD CPUs leave this CPUID leaf
+ * reserved so bail out. Cpu specific code can fill in the topology later.
+ */
+ if (CPUID_CPU_TOPOLOGY_LEVEL(cpuid_regs) != LEVEL_TYPE_SMT)
+ return CB_ERR;
+
+ do {
+ *package_bits = (CPUID_CPU_TOPOLOGY(LEVEL_BITS, (cpuid_regs).eax));
+ level_num++;
+ cpuid_regs = cpuid_ext(cpu_id_op, level_num);
+ /* Stop when level type is invalid i.e 0. */
+ } while (CPUID_CPU_TOPOLOGY_LEVEL(cpuid_regs));
+
+ return CB_SUCCESS;
+}
+
+void set_cpu_node_id_leaf_1f_b(struct device *cpu)
+{
+ static uint32_t package_bits;
+ static enum cb_err package_bits_ret;
+ static bool done = false;
+
+ if (!done) {
+ package_bits_ret = get_cpu_package_bits(&package_bits);
+ done = true;
+ }
+
+ const uint32_t apicid = cpu->path.apic.initial_lapicid;
+
+ /*
+ * If leaf_1f or leaf_b does not exist don't update the node_id.
+ */
+ if (package_bits_ret == CB_SUCCESS)
+ cpu->path.apic.node_id = (apicid >> package_bits);
+}
+
/* Get number of bits for core ID and SMT ID */
static enum cb_err get_cpu_core_thread_bits(uint32_t *core_bits, uint32_t *thread_bits)
{
diff --git a/src/include/cpu/x86/topology.h b/src/include/cpu/x86/topology.h
index db29d09f5b..d66f2eb821 100644
--- a/src/include/cpu/x86/topology.h
+++ b/src/include/cpu/x86/topology.h
@@ -11,4 +11,9 @@
*/
void set_cpu_topology_from_leaf_b(struct device *cpu);
+/* Fill in the topology node ID in struct path APIC based CPUID EAX=0x1f
+ * or CPUID EAX=0xb. If those leaves aren't supported then the node ID
+ * won't be updated.
+ */
+void set_cpu_node_id_leaf_1f_b(struct device *cpu);
#endif
diff --git a/src/soc/intel/xeon_sp/spr/cpu.c b/src/soc/intel/xeon_sp/spr/cpu.c
index 2ed8e2290a..f9c8e26273 100644
--- a/src/soc/intel/xeon_sp/spr/cpu.c
+++ b/src/soc/intel/xeon_sp/spr/cpu.c
@@ -14,6 +14,7 @@
#include <cpu/x86/lapic.h>
#include <cpu/x86/mp.h>
#include <cpu/x86/mtrr.h>
+#include <cpu/x86/topology.h>
#include <device/pci_mmio_cfg.h>
#include <intelblocks/cpulib.h>
#include <intelblocks/mp_init.h>
@@ -82,6 +83,10 @@ static void each_cpu_init(struct device *cpu)
__func__, dev_path(cpu), cpu_index(), cpu->path.apic.apic_id,
cpu->path.apic.package_id);
+ /* Populate the node ID. It will be used as proximity ID. */
+ set_cpu_node_id_leaf_1f_b(cpu);
+ assert (cpu->path.apic.node_id < CONFIG_MAX_SOCKET);
+
/*
* Enable PWR_PERF_PLTFRM_OVR and PROCHOT_LOCK.
* The value set by FSP is 20_005f, we set it to 1a_00a4_005b.