commit cba4262a19afae21665ee242b3404bcede5a94d7 upstream.
Support for parsing the topology on AMD/Hygon processors using CPUID leaf 0xb was added in
3986a0a805e6 ("x86/CPU/AMD: Derive CPU topology from CPUID function 0xB when available").
In an effort to keep all the topology parsing bits in one place, this commit also introduced a pseudo dependency on the TOPOEXT feature to parse the CPUID leaf 0xb.
The TOPOEXT feature (CPUID 0x80000001 ECX[22]) advertises the support for Cache Properties leaf 0x8000001d and the CPUID leaf 0x8000001e EAX for "Extended APIC ID" however support for 0xb was introduced alongside the x2APIC support not only on AMD [1], but also historically on x86 [2].
The support for the 0xb leaf is expected to be confirmed by ensuring
leaf <= max supported cpuid_level
and then parsing the level 0 of the leaf to confirm EBX[15:0] (LogProcAtThisLevel) is non-zero as stated in the definition of "CPUID_Fn0000000B_EAX_x00 [Extended Topology Enumeration] (Core::X86::Cpuid::ExtTopEnumEax0)" in Processor Programming Reference (PPR) for AMD Family 19h Model 01h Rev B1 Vol1 [3] Sec. 2.1.15.1 "CPUID Instruction Functions".
This has not been a problem on baremetal platforms since support for TOPOEXT (Fam 0x15 and later) predates the support for CPUID leaf 0xb (Fam 0x17[Zen2] and later), however, for AMD guests on QEMU, the "x2apic" feature can be enabled independent of the "topoext" feature where QEMU expects topology and the initial APICID to be parsed using the CPUID leaf 0xb (especially when number of cores > 255) which is populated independent of the "topoext" feature flag.
Unconditionally call detect_extended_topology() on AMD processors to first parse the topology using the extended topology leaf 0xb before using the TOPOEXT leaf (0x8000001e).
Parsing of "DIE_TYPE" in detect_extended_topology() is specific to CPUID leaf 0x1f which is only supported on Intel platforms. Continue using the TOPOEXT leaf (0x8000001e) to derive the "cpu_die_id" on AMD platforms.
[ prateek: Adapted the fix from the original commit to stable kernel which doesn't contain the x86 topology rewrite, renamed cpu_parse_topology_ext() with the erstwhile detect_extended_topology() function in commit message, dropped references to extended topology leaf 0x80000026 which the stable kernels aren't aware of, make a note of "cpu_die_id" parsing nuances in detect_extended_topology() and why AMD processors should still rely on TOPOEXT leaf for "cpu_die_id". ]
Fixes: 3986a0a805e6 ("x86/CPU/AMD: Derive CPU topology from CPUID function 0xB when available") Suggested-by: Naveen N Rao (AMD) naveen@kernel.org Signed-off-by: K Prateek Nayak kprateek.nayak@amd.com Signed-off-by: Borislav Petkov (AMD) bp@alien8.de Link: https://lore.kernel.org/lkml/1529686927-7665-1-git-send-email-suravee.suthik... [1] Link: https://lore.kernel.org/lkml/20080818181435.523309000@linux-os.sc.intel.com/ [2] Link: https://bugzilla.kernel.org/show_bug.cgi?id=206537 [3] --- Hello Greg,
This will need a review from the x86 folks. Once they are okay with the changes, I'll attach the same patch on v5.15.y, v5.10.y, and v5.4.y stable backport threads.
I wasn't sure what the exact procedure is when the backport patch is different from the upstream fix due to large changes. I've retained Boris' S-o-b and added the "commit cba4262a19afae21665ee242b3404bcede5a94d7 upstream." message nonetheless.
Let me know if any of this should be changed and I'll send out a follow-up version.
Changes have been tested on Zen1 (contains TOPOEXT but not 0xb leaf), Zen3 (contains both TOPOEXT and 0xb leaf) and Zen4 (contains TOPOEXT, 0xb leaf, and the extended leaf 0x80000026) based EPYC platforms.
No difference was observed in c->x86_max_cores, c->x86_coreid_bits, c->phys_proc_id, c->apicid, c->initial_apicid, __max_die_per_package after applying the patch on the above platforms. --- arch/x86/kernel/cpu/amd.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 864d62e94614..3c247ea85d8b 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -391,11 +391,20 @@ static void legacy_fixup_core_id(struct cpuinfo_x86 *c) */ static void amd_get_topology(struct cpuinfo_x86 *c) { + /* + * Try to get the topology information from the 0xb leaf first. + * If detect_extended_topology() returns 0, parsing was successful + * and APIC ID, cpu_core_id, phys_proc_id, __max_die_per_package + * are already populated. + */ + bool has_extended_topology = !detect_extended_topology(c); int cpu = smp_processor_id();
+ if (has_extended_topology) + c->x86_coreid_bits = get_count_order(c->x86_max_cores); + /* get information required for multi-node processors */ if (boot_cpu_has(X86_FEATURE_TOPOEXT)) { - int err; u32 eax, ebx, ecx, edx;
cpuid(0x8000001e, &eax, &ebx, &ecx, &edx); @@ -405,21 +414,17 @@ static void amd_get_topology(struct cpuinfo_x86 *c) if (c->x86 == 0x15) c->cu_id = ebx & 0xff;
- if (c->x86 >= 0x17) { + /* + * It the extended topology leaf 0xb leaf doesn't exits, + * derive CORE information from the 0x8000001e leaf. + */ + if (!has_extended_topology && c->x86 >= 0x17) { c->cpu_core_id = ebx & 0xff;
if (smp_num_siblings > 1) c->x86_max_cores /= smp_num_siblings; }
- /* - * In case leaf B is available, use it to derive - * topology information. - */ - err = detect_extended_topology(c); - if (!err) - c->x86_coreid_bits = get_count_order(c->x86_max_cores); - cacheinfo_amd_init_llc_id(c, cpu);
} else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {