aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cpu/x86/Makefile.inc2
-rw-r--r--src/cpu/x86/mp_init.c3
-rw-r--r--src/cpu/x86/topology.c104
-rw-r--r--src/device/cpu_device.c10
-rw-r--r--src/include/cpu/x86/topology.h14
-rw-r--r--src/include/device/device.h9
6 files changed, 123 insertions, 19 deletions
diff --git a/src/cpu/x86/Makefile.inc b/src/cpu/x86/Makefile.inc
index 2381b6fa20..cb76343463 100644
--- a/src/cpu/x86/Makefile.inc
+++ b/src/cpu/x86/Makefile.inc
@@ -65,3 +65,5 @@ $(SIPI_BIN): $(SIPI_RMOD)
$(call src-to-obj,$(TARGET_STAGE),$(SIPI_BIN).manual): $(SIPI_BIN)
@printf " OBJCOPY $(subst $(obj)/,,$(@))\n"
cd $(dir $<); $(OBJCOPY_rmodules_$(ARCH-$(TARGET_STAGE)-y)) -I binary $(notdir $<) $(target-objcopy) $(abspath $@)
+
+ramstage-y += topology.c
diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c
index a5d2ae6caa..4e92b75954 100644
--- a/src/cpu/x86/mp_init.c
+++ b/src/cpu/x86/mp_init.c
@@ -13,6 +13,7 @@
#include <cpu/x86/msr.h>
#include <cpu/x86/mtrr.h>
#include <cpu/x86/smm.h>
+#include <cpu/x86/topology.h>
#include <cpu/x86/mp.h>
#include <delay.h>
#include <device/device.h>
@@ -203,6 +204,8 @@ static asmlinkage void ap_init(unsigned int index)
dev->path.apic.initial_lapicid = initial_lapicid();
dev->enabled = 1;
+ set_cpu_topology_from_leaf_b(dev);
+
if (cpu_is_intel())
printk(BIOS_INFO, "AP: slot %u apic_id %x, MCU rev: 0x%08x\n", index,
dev->path.apic.apic_id, get_current_microcode_rev());
diff --git a/src/cpu/x86/topology.c b/src/cpu/x86/topology.c
new file mode 100644
index 0000000000..6c8d7fd420
--- /dev/null
+++ b/src/cpu/x86/topology.c
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <cpu/cpu.h>
+#include <device/device.h>
+#include <cpu/x86/topology.h>
+
+#define CPUID_EXTENDED_CPU_TOPOLOGY 0x0b
+#define LEVEL_TYPE_CORE 2
+#define LEVEL_TYPE_SMT 1
+
+#define CPUID_CPU_TOPOLOGY(x, val) \
+ (((val) >> CPUID_CPU_TOPOLOGY_##x##_SHIFT) & CPUID_CPU_TOPOLOGY_##x##_MASK)
+
+#define CPUID_CPU_TOPOLOGY_LEVEL_TYPE_SHIFT 0x8
+#define CPUID_CPU_TOPOLOGY_LEVEL_TYPE_MASK 0xff
+#define CPUID_CPU_TOPOLOGY_LEVEL(res) CPUID_CPU_TOPOLOGY(LEVEL_TYPE, (res).ecx)
+
+#define CPUID_CPU_TOPOLOGY_LEVEL_BITS_SHIFT 0x0
+#define CPUID_CPU_TOPOLOGY_LEVEL_BITS_MASK 0x1f
+#define CPUID_CPU_TOPOLOGY_THREAD_BITS(res) CPUID_CPU_TOPOLOGY(LEVEL_BITS, (res).eax)
+#define CPUID_CPU_TOPOLOGY_CORE_BITS(res, threadbits) \
+ ((CPUID_CPU_TOPOLOGY(LEVEL_BITS, (res).eax)) - threadbits)
+
+/* 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)
+{
+ 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_TOPOLOGY)
+ return CB_ERR;
+
+ cpu_id_op = CPUID_EXTENDED_CPU_TOPOLOGY;
+
+ *core_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;
+
+ *thread_bits = CPUID_CPU_TOPOLOGY_THREAD_BITS(cpuid_regs);
+ do {
+ level_num++;
+ cpuid_regs = cpuid_ext(cpu_id_op, level_num);
+ if (CPUID_CPU_TOPOLOGY_LEVEL(cpuid_regs) == LEVEL_TYPE_CORE) {
+ *core_bits = CPUID_CPU_TOPOLOGY_CORE_BITS(cpuid_regs, *thread_bits);
+ break;
+ }
+ /* Stop when level type is invalid i.e 0 */
+ } while (CPUID_CPU_TOPOLOGY_LEVEL(cpuid_regs));
+
+ return CB_SUCCESS;
+}
+
+static void set_cpu_topology(struct device *cpu, unsigned int node,
+ unsigned int package, unsigned int core,
+ unsigned int thread)
+{
+ cpu->path.apic.node_id = node;
+ cpu->path.apic.package_id = package;
+ cpu->path.apic.core_id = core;
+ cpu->path.apic.thread_id = thread;
+}
+
+void set_cpu_topology_from_leaf_b(struct device *cpu)
+{
+ static uint32_t core_bits, thread_bits;
+ static enum cb_err core_thread_bits_ret;
+ static bool done = false;
+ if (!done) {
+ core_thread_bits_ret = get_cpu_core_thread_bits(&core_bits, &thread_bits);
+ done = true;
+ }
+
+ const uint32_t apicid = cpu->path.apic.initial_lapicid;
+ uint32_t package_id, core_id, thread_id;
+ /*
+ * If leaf_b does not exist set the following best-guess defaults:
+ * - 1 package
+ * - no SMP
+ * - core_id = apicid
+ * CPU specific code can always update these later on.
+ */
+ if (core_thread_bits_ret != CB_SUCCESS) {
+ package_id = 0;
+ core_id = apicid;
+ thread_id = 0;
+ } else {
+ package_id = apicid >> (thread_bits + core_bits);
+ core_id = (apicid >> thread_bits) & ((1 << core_bits) - 1);
+ thread_id = apicid & ((1 << thread_bits) - 1);
+ }
+
+ set_cpu_topology(cpu, 0, package_id, core_id, thread_id);
+}
diff --git a/src/device/cpu_device.c b/src/device/cpu_device.c
index 9185cc67f2..be28ff64dc 100644
--- a/src/device/cpu_device.c
+++ b/src/device/cpu_device.c
@@ -29,13 +29,3 @@ struct device *add_cpu_device(struct bus *cpu_bus, unsigned int apic_id,
return cpu;
}
-
-void set_cpu_topology(struct device *cpu, unsigned int node,
- unsigned int package, unsigned int core,
- unsigned int thread)
-{
- cpu->path.apic.node_id = node;
- cpu->path.apic.package_id = package;
- cpu->path.apic.core_id = core;
- cpu->path.apic.thread_id = thread;
-}
diff --git a/src/include/cpu/x86/topology.h b/src/include/cpu/x86/topology.h
new file mode 100644
index 0000000000..db29d09f5b
--- /dev/null
+++ b/src/include/cpu/x86/topology.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef CPU_X86_TOPOLOGY_H
+#define CPU_X86_TOPOLOGY_H
+
+#include <device/device.h>
+
+/* Fill in the topology in struct path APIC based CPUID EAX=0xb.
+ * If leaf 0xb is not supported or is not implemented then no topology
+ * will be filled in.
+ */
+void set_cpu_topology_from_leaf_b(struct device *cpu);
+
+#endif
diff --git a/src/include/device/device.h b/src/include/device/device.h
index 8a663f095c..831141f851 100644
--- a/src/include/device/device.h
+++ b/src/include/device/device.h
@@ -240,15 +240,6 @@ struct device *dev_find_lapic(unsigned int apic_id);
int dev_count_cpu(void);
struct device *add_cpu_device(struct bus *cpu_bus, unsigned int apic_id,
int enabled);
-void set_cpu_topology(struct device *cpu, unsigned int node,
- unsigned int package, unsigned int core, unsigned int thread);
-
-#define amd_cpu_topology(cpu, node, core) \
- set_cpu_topology(cpu, node, 0, core, 0)
-
-#define intel_cpu_topology(cpu, package, core, thread) \
- set_cpu_topology(cpu, 0, package, core, thread)
-
void mp_init_cpus(DEVTREE_CONST struct bus *cpu_bus);
static inline void mp_cpu_bus_init(struct device *dev)
{