[RFC PATCH v3.1 09/13] x86/cpu/topology: Initialize sbm topology after topology parsing
From: K Prateek Nayak
Date: Tue Oct 06 2026 - 23:52:54 EST
From: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
Once the topology is parsed, the APICIDs of all present CPUs and topology
shifts are available for use.
Use the max APICID encountered during traversal and TOPO_TILE_DOMAIN /
TOPO_MODULE_DOMAIN shift to determine the maximum number of CPUs that
can be associated with a single LLC instance and the maximum number of
LLC instances that can exist on a the processor to initialize
sparsebitmap (sbm) topology.
On AMD heterogeneous processors, the Cache Identifier leaf CPUID
0x8000001d field "NumSharingCache" give true value of threads sharing
the cache instance and not the number of bits reserved for a cache
instance in APICID.
To avoid incorrect calculations, shifts from extended topology leaf
0x80000026 on AMD and Hygon systems are used to derive the domain
shifts.
[ tim.c.chen: TOPO_TILE_DOMAIN / TOPO_MODULE_DOMAIN based
initialization. ]
[ kprateek: Commit message. Adapting to new sbm helper. ]
(Not-yet-)Signed-off-by: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
(Not-yet-)Signed-off-by: Tim Chen <tim.c.chen@xxxxxxxxxxxxxxx>
Signed-off-by: K Prateek Nayak <kprateek.nayak@xxxxxxx>
---
Changelog rfc v3 .. rfc v3.1:
o Fix incorrect shifts derivation by using
"dom_shifts[TOPO_TILE_DOMAIN - 1]" instead of
"dom_shifts[TOPO_TILE_DOMAIN] - 1" (Chenyu, Sashiko).
---
arch/x86/kernel/cpu/topology.c | 40 +++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kernel/cpu/topology.c b/arch/x86/kernel/cpu/topology.c
index 4913b64ec592..7467fa90b879 100644
--- a/arch/x86/kernel/cpu/topology.c
+++ b/arch/x86/kernel/cpu/topology.c
@@ -23,6 +23,7 @@
*/
#define pr_fmt(fmt) "CPU topo: " fmt
#include <linux/cpu.h>
+#include <linux/sbm.h>
#include <xen/xen.h>
@@ -449,13 +450,45 @@ static __init bool restrict_to_up(void)
return apic_is_disabled;
}
+int arch_sbm_cpu_instance_id(int cpu)
+{
+ u32 sbm_shift = x86_topo_system.dom_shifts[TOPO_DIE_DOMAIN - 1];
+ u32 apicid = cpuid_to_apicid[cpu];
+
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
+ boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
+ sbm_shift = x86_topo_system.dom_shifts[TOPO_TILE_DOMAIN - 1];
+
+ return (apicid >> sbm_shift);
+}
+
+static __init void init_sbm_topology(u32 max_apicid)
+{
+ u32 sbm_shift = x86_topo_system.dom_shifts[TOPO_DIE_DOMAIN - 1];
+ int num_sbm_instances, max_threads_per_instance;
+
+ /*
+ * On Intel systems, memory controllers are present at TOPO_DIE_DOMAIN.
+ * On newer AMD and Hygon systems, LLC is at TOPO_TILE_DOMAIN so use
+ * that instead.
+ */
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
+ boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
+ sbm_shift = x86_topo_system.dom_shifts[TOPO_TILE_DOMAIN - 1];
+
+ num_sbm_instances = 1 + (max_apicid >> sbm_shift);
+ max_threads_per_instance = (1 << sbm_shift);
+
+ sbm_set_topology(num_sbm_instances, max_threads_per_instance);
+}
+
void __init topology_init_possible_cpus(void)
{
unsigned int assigned = topo_info.nr_assigned_cpus;
unsigned int disabled = topo_info.nr_disabled_cpus;
unsigned int cnta, cntb, cpu, allowed = 1;
unsigned int total = assigned + disabled;
- u32 apicid, firstid;
+ u32 apicid, firstid, maxid;
/*
* If there was no APIC registered, then fake one so that the
@@ -536,10 +569,13 @@ void __init topology_init_possible_cpus(void)
cpuid_to_apicid[topo_info.nr_assigned_cpus++] = apicid;
}
+ maxid = topo_info.boot_cpu_apic_id;
+
for (cpu = 0; cpu < allowed; cpu++) {
apicid = cpuid_to_apicid[cpu];
set_cpu_possible(cpu, true);
+ maxid = max(maxid, apicid);
if (apicid == BAD_APICID)
continue;
@@ -547,6 +583,8 @@ void __init topology_init_possible_cpus(void)
cpu_mark_primary_thread(cpu, apicid);
set_cpu_present(cpu, test_bit(apicid, phys_cpu_present_map));
}
+
+ init_sbm_topology(maxid);
}
/*
--
2.34.1