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 #include #include +#include #include #include #include @@ -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 +#include +#include + +#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 + +/* 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) {