2024-02-13 21:04:13

by Thomas Gleixner

[permalink] [raw]
Subject: [patch V6 00/19] x86/cpu: Rework topology evaluation

This is a follow up on V5 of this work:

https://lore.kernel.org/all/[email protected]

and contains only the not yet applied part which reworks the CPUID
parsing. This is also preparatory work for the general overhaul of APIC ID
enumeration and management.

Changes vs. V5:

- Fix the AMD leaf 0x8000008 parsing
- Update to generated CPUID leaf structures
- Address review comments (coding style, comments, changelogs, boot_cpu_has())

This applies on Linus tree and is available from git:

git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git topo-cpuid-v6

Delta patch to V5 appended.

Thanks,

tglx
---
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index a45346ad552b..de1648ee2b9e 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -705,12 +705,10 @@ static inline u32 per_cpu_l2c_id(unsigned int cpu)
}

#ifdef CONFIG_CPU_SUP_AMD
-extern u32 amd_get_nodes_per_socket(void);
extern u32 amd_get_highest_perf(void);
extern void amd_clear_divider(void);
extern void amd_check_microcode(void);
#else
-static inline u32 amd_get_nodes_per_socket(void) { return 0; }
static inline u32 amd_get_highest_perf(void) { return 0; }
static inline void amd_clear_divider(void) { }
static inline void amd_check_microcode(void) { }
diff --git a/arch/x86/kernel/cpu/topology.h b/arch/x86/kernel/cpu/topology.h
index 0d1ebb3a56e7..2a3c838b6044 100644
--- a/arch/x86/kernel/cpu/topology.h
+++ b/arch/x86/kernel/cpu/topology.h
@@ -7,10 +7,10 @@ struct topo_scan {
unsigned int dom_shifts[TOPO_MAX_DOMAIN];
unsigned int dom_ncpus[TOPO_MAX_DOMAIN];

- // Legacy CPUID[1]:EBX[23:16] number of logical processors
+ /* Legacy CPUID[1]:EBX[23:16] number of logical processors */
unsigned int ebx1_nproc_shift;

- // AMD specific node ID which cannot be mapped into APIC space.
+ /* AMD specific node ID which cannot be mapped into APIC space. */
u16 amd_nodes_per_pkg;
u16 amd_node_id;
};
diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c
index 9e149673ea82..1a8b3ad493af 100644
--- a/arch/x86/kernel/cpu/topology_amd.c
+++ b/arch/x86/kernel/cpu/topology_amd.c
@@ -10,11 +10,12 @@
static bool parse_8000_0008(struct topo_scan *tscan)
{
struct {
- u32 ncores : 8,
- __rsvd0 : 4,
- apicidsize : 4,
- perftscsize : 2,
- __rsvd1 : 14;
+ // ecx
+ u32 cpu_nthreads : 8, // Number of physical threads - 1
+ : 4, // Reserved
+ apicid_coreid_len : 4, // Number of thread core ID bits (shift) in APIC ID
+ perf_tsc_len : 2, // Performance time-stamp counter size
+ : 14; // Reserved
} ecx;
unsigned int sft;

@@ -23,12 +24,12 @@ static bool parse_8000_0008(struct topo_scan *tscan)

cpuid_leaf_reg(0x80000008, CPUID_ECX, &ecx);

- /* If the APIC ID size is 0, then get the shift value from ecx.ncores */
- sft = ecx.apicidsize;
+ /* If the thread bits are 0, then get the shift value from ecx.cpu_nthreads */
+ sft = ecx.apicid_coreid_len;
if (!sft)
- sft = get_count_order(ecx.ncores + 1);
+ sft = get_count_order(ecx.cpu_nthreads + 1);

- topology_set_dom(tscan, TOPO_CORE_DOMAIN, sft, ecx.ncores + 1);
+ topology_set_dom(tscan, TOPO_SMT_DOMAIN, sft, ecx.cpu_nthreads + 1);
return true;
}

@@ -51,17 +52,17 @@ static bool parse_8000_001e(struct topo_scan *tscan, bool has_0xb)
{
struct {
// eax
- u32 x2apic_id : 32;
+ u32 ext_apic_id : 32; // Extended APIC ID
// ebx
- u32 cuid : 8,
- threads_per_cu : 8,
- __rsvd0 : 16;
+ u32 core_id : 8, // Unique per-socket logical core unit ID
+ core_nthreads : 8, // #Threads per core (zero-based)
+ : 16; // Reserved
// ecx
- u32 nodeid : 8,
- nodes_per_pkg : 3,
- __rsvd1 : 21;
+ u32 node_id : 8, // Node (die) ID of invoking logical CPU
+ nnodes_per_socket : 3, // #nodes in invoking logical CPU's package/socket
+ : 21; // Reserved
// edx
- u32 __rsvd2 : 32;
+ u32 : 32; // Reserved
} leaf;

if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
@@ -69,27 +70,27 @@ static bool parse_8000_001e(struct topo_scan *tscan, bool has_0xb)

cpuid_leaf(0x8000001e, &leaf);

- tscan->c->topo.initial_apicid = leaf.x2apic_id;
+ tscan->c->topo.initial_apicid = leaf.ext_apic_id;

/*
* If leaf 0xb is available, then SMT shift is set already. If not
- * take it from ecx.threads_per_cu and use topo_update_dom() -
+ * take it from ecx.threads_per_core and use topo_update_dom() -
* topology_set_dom() would propagate and overwrite the already
* propagated CORE level.
*/
if (!has_0xb) {
- unsigned int nthreads = leaf.threads_per_cu + 1;
+ unsigned int nthreads = leaf.core_nthreads + 1;

topology_update_dom(tscan, TOPO_SMT_DOMAIN, get_count_order(nthreads), nthreads);
}

- store_node(tscan, leaf.nodes_per_pkg + 1, leaf.nodeid);
+ store_node(tscan, leaf.nnodes_per_socket + 1, leaf.node_id);

if (tscan->c->x86_vendor == X86_VENDOR_AMD) {
if (tscan->c->x86 == 0x15)
- tscan->c->topo.cu_id = leaf.cuid;
+ tscan->c->topo.cu_id = leaf.core_id;

- cacheinfo_amd_init_llc_id(tscan->c, leaf.nodeid);
+ cacheinfo_amd_init_llc_id(tscan->c, leaf.node_id);
} else {
/*
* Package ID is ApicId[6..] on certain Hygon CPUs. See
@@ -143,7 +144,7 @@ static void parse_topology_amd(struct topo_scan *tscan)
* try to get SMT and CORE shift from leaf 0xb first, then
* try to get the CORE shift from leaf 0x8000_0008.
*/
- if (boot_cpu_has(X86_FEATURE_TOPOEXT))
+ if (cpu_feature_enabled(X86_FEATURE_TOPOEXT))
has_0xb = cpu_parse_topology_ext(tscan);

if (!has_0xb && !parse_8000_0008(tscan))
diff --git a/arch/x86/kernel/cpu/topology_common.c b/arch/x86/kernel/cpu/topology_common.c
index 5ff862db5a3a..afea34d59598 100644
--- a/arch/x86/kernel/cpu/topology_common.c
+++ b/arch/x86/kernel/cpu/topology_common.c
@@ -26,7 +26,7 @@ void topology_set_dom(struct topo_scan *tscan, enum x86_topology_domains dom,
}
}

-static unsigned int parse_num_cores(struct cpuinfo_x86 *c)
+static unsigned int __maybe_unused parse_num_cores_legacy(struct cpuinfo_x86 *c)
{
struct {
u32 cache_type : 5,
@@ -49,7 +49,7 @@ static void parse_legacy(struct topo_scan *tscan)
unsigned int cores, core_shift, smt_shift = 0;
struct cpuinfo_x86 *c = tscan->c;

- cores = parse_num_cores(c);
+ cores = parse_num_cores_legacy(c);
core_shift = get_count_order(cores);

if (cpu_has(c, X86_FEATURE_HT)) {
@@ -97,7 +97,7 @@ static void parse_topology(struct topo_scan *tscan, bool early)
c->topo = topo_defaults;

if (fake_topology(tscan))
- return;
+ return;

/* Preset Initial APIC ID from CPUID leaf 1 */
cpuid_leaf_reg(1, CPUID_EBX, &ebx);
diff --git a/arch/x86/kernel/cpu/topology_ext.c b/arch/x86/kernel/cpu/topology_ext.c
index b9b37296d9cd..e477228cd5b2 100644
--- a/arch/x86/kernel/cpu/topology_ext.c
+++ b/arch/x86/kernel/cpu/topology_ext.c
@@ -110,7 +110,7 @@ static bool parse_topology_leaf(struct topo_scan *tscan, u32 leaf)
if (!tscan->dom_shifts[TOPO_SMT_DOMAIN] && tscan->dom_ncpus[TOPO_SMT_DOMAIN] > 1) {
unsigned int sft = get_count_order(tscan->dom_ncpus[TOPO_SMT_DOMAIN]);

- pr_warn_once(FW_BUG "CPUID leaf 0x%x subleaf 0 has shift level 0 but %u CPUs\n",
+ pr_warn_once(FW_BUG "CPUID leaf 0x%x subleaf 0 has shift level 0 but %u CPUs. Fixing it up.\n",
leaf, tscan->dom_ncpus[TOPO_SMT_DOMAIN]);
topology_update_dom(tscan, TOPO_SMT_DOMAIN, sft, tscan->dom_ncpus[TOPO_SMT_DOMAIN]);
}
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 2634f8f82867..9cdb056c37b5 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -513,7 +513,7 @@ static bool match_die(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
if (c->topo.pkg_id != o->topo.pkg_id || c->topo.die_id != o->topo.die_id)
return false;

- if (boot_cpu_has(X86_FEATURE_TOPOEXT) && topology_amd_nodes_per_pkg() > 1)
+ if (cpu_feature_enabled(X86_FEATURE_TOPOEXT) && topology_amd_nodes_per_pkg() > 1)
return c->topo.amd_node_id == o->topo.amd_node_id;

return true;



2024-02-15 16:51:21

by K Prateek Nayak

[permalink] [raw]
Subject: Re: [patch V6 00/19] x86/cpu: Rework topology evaluation

Hello Thomas,

On 2/14/2024 2:33 AM, Thomas Gleixner wrote:
> This is a follow up on V5 of this work:
>
> https://lore.kernel.org/all/[email protected]
>
> and contains only the not yet applied part which reworks the CPUID
> parsing. This is also preparatory work for the general overhaul of APIC ID
> enumeration and management.
>
> Changes vs. V5:
>
> - Fix the AMD leaf 0x8000008 parsing
> - Update to generated CPUID leaf structures
> - Address review comments (coding style, comments, changelogs, boot_cpu_has())
>
> This applies on Linus tree and is available from git:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git topo-cpuid-v6

Tested the above tree comparing the values reported by
"/sys/kernel/debug/x86/topo/cpus/X" and
"/sys/devices/system/cpu/cpuX/topology/*" with those reported by
v6.8-rc4 on the following systems:

- Dual socket 3rd Generation EPYC System (2 x 64C/128T)
- Single socket 4th Generation EPYC System (1 x 96C/192T)
- Dual socket 4th Generation EPYC System (2 x 128C/256T)

Happy to report the values from the sysfs and debugfs with the series
are consistent with values on v6.8-rc4. "amd_node_id" and
"amd_nodes_per_pkg" introduced with the series are consistent with the
values reported in CPUID leaf 0x8000001E ECX on the respective system.

Tested-by: K Prateek Nayak <[email protected]>

>
> [..snip..]
>

--
Thanks and Regards,
Prateek