Skip to content

Commit f1f758a

Browse files
committed
x86/topology: Add a mechanism to track topology via APIC IDs
Topology on X86 is determined by the registered APIC IDs and the segmentation information retrieved from CPUID. Depending on the granularity of the provided CPUID information the most fine grained scheme looks like this according to Intel terminology: [PKG][DIEGRP][DIE][TILE][MODULE][CORE][THREAD] Not enumerated domain levels consume 0 bits in the APIC ID. This allows to provide a consistent view at the topology and determine other information precisely like the number of cores in a package on hybrid systems, where the existing assumption that number or cores == number of threads / threads per core does not hold. Provide per domain level bitmaps which record the APIC ID split into the domain levels to make later evaluation of domain level specific information simple. This allows to calculate e.g. the logical IDs without any further extra logic. Contrary to the existing registration mechanism this records disabled CPUs, which are subject to later hotplug as well. That's useful for boot time sizing of package or die dependent allocations without using heuristics. Signed-off-by: Thomas Gleixner <[email protected]> Tested-by: Michael Kelley <[email protected]> Tested-by: Sohil Mehta <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 5c5682b commit f1f758a

File tree

1 file changed

+46
-2
lines changed

1 file changed

+46
-2
lines changed

arch/x86/kernel/cpu/topology.c

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
// SPDX-License-Identifier: GPL-2.0-only
2-
2+
/*
3+
* CPU/APIC topology
4+
*
5+
* The APIC IDs describe the system topology in multiple domain levels.
6+
* The CPUID topology parser provides the information which part of the
7+
* APIC ID is associated to the individual levels:
8+
*
9+
* [PACKAGE][DIEGRP][DIE][TILE][MODULE][CORE][THREAD]
10+
*
11+
* The root space contains the package (socket) IDs.
12+
*
13+
* Not enumerated levels consume 0 bits space, but conceptually they are
14+
* always represented. If e.g. only CORE and THREAD levels are enumerated
15+
* then the DIE, MODULE and TILE have the same physical ID as the PACKAGE.
16+
*
17+
* If SMT is not supported, then the THREAD domain is still used. It then
18+
* has the same physical ID as the CORE domain and is the only child of
19+
* the core domain.
20+
*
21+
* This allows a unified view on the system independent of the enumerated
22+
* domain levels without requiring any conditionals in the code.
23+
*/
24+
#define pr_fmt(fmt) "CPU topo: " fmt
325
#include <linux/cpu.h>
426

527
#include <xen/xen.h>
@@ -9,6 +31,8 @@
931
#include <asm/mpspec.h>
1032
#include <asm/smp.h>
1133

34+
#include "cpu.h"
35+
1236
/*
1337
* Map cpu index to physical APIC ID
1438
*/
@@ -23,6 +47,9 @@ DECLARE_BITMAP(phys_cpu_present_map, MAX_LOCAL_APIC) __read_mostly;
2347
/* Used for CPU number allocation and parallel CPU bringup */
2448
u32 cpuid_to_apicid[] __read_mostly = { [0 ... NR_CPUS - 1] = BAD_APICID, };
2549

50+
/* Bitmaps to mark registered APICs at each topology domain */
51+
static struct { DECLARE_BITMAP(map, MAX_LOCAL_APIC); } apic_maps[TOPO_MAX_DOMAIN] __ro_after_init;
52+
2653
/*
2754
* Keep track of assigned, disabled and rejected CPUs. Present assigned
2855
* with 1 as CPU #0 is reserved for the boot CPU.
@@ -39,6 +66,8 @@ static struct {
3966
.real_bsp_apic_id = BAD_APICID,
4067
};
4168

69+
#define domain_weight(_dom) bitmap_weight(apic_maps[_dom].map, MAX_LOCAL_APIC)
70+
4271
bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
4372
{
4473
return phys_id == (u64)cpuid_to_apicid[cpu];
@@ -81,6 +110,17 @@ early_initcall(smp_init_primary_thread_mask);
81110
static inline void cpu_mark_primary_thread(unsigned int cpu, unsigned int apicid) { }
82111
#endif
83112

113+
/*
114+
* Convert the APIC ID to a domain level ID by masking out the low bits
115+
* below the domain level @dom.
116+
*/
117+
static inline u32 topo_apicid(u32 apicid, enum x86_topology_domains dom)
118+
{
119+
if (dom == TOPO_SMT_DOMAIN)
120+
return apicid;
121+
return apicid & (UINT_MAX << x86_topo_system.dom_shifts[dom - 1]);
122+
}
123+
84124
static int topo_lookup_cpuid(u32 apic_id)
85125
{
86126
int i;
@@ -151,7 +191,7 @@ static __init bool check_for_real_bsp(u32 apic_id)
151191

152192
static __init void topo_register_apic(u32 apic_id, u32 acpi_id, bool present)
153193
{
154-
int cpu;
194+
int cpu, dom;
155195

156196
if (present) {
157197
set_bit(apic_id, phys_cpu_present_map);
@@ -170,6 +210,10 @@ static __init void topo_register_apic(u32 apic_id, u32 acpi_id, bool present)
170210
} else {
171211
topo_info.nr_disabled_cpus++;
172212
}
213+
214+
/* Register present and possible CPUs in the domain maps */
215+
for (dom = TOPO_SMT_DOMAIN; dom < TOPO_MAX_DOMAIN; dom++)
216+
set_bit(topo_apicid(apic_id, dom), apic_maps[dom].map);
173217
}
174218

175219
/**

0 commit comments

Comments
 (0)