Prior to the topology parsing rewrite and the switchover to the new parsing logic for AMD processors in commit c749ce393b8f ("x86/cpu: Use common topology code for AMD"), the "initial_apicid" on these platforms was:
- First initialized to the LocalApicId from CPUID leaf 0x1 EBX[31:24].
- Then overwritten by the ExtendedLocalApicId in CPUID leaf 0xb EDX[31:0] on processors that supported topoext.
With the new parsing flow introduced in commit f7fb3b2dd92c ("x86/cpu: Provide an AMD/HYGON specific topology parser"), parse_8000_001e() now unconditionally overwrites the "initial_apicid" already parsed during cpu_parse_topology_ext().
Although this has not been a problem on baremetal platforms, on virtualized AMD guests that feature more than 255 cores, QEMU 0's out the CPUID leaf 0x8000001e on CPUs with "CoreID" > 255 to prevent collision of these IDs in EBX[7:0] which can only represent a maximum of 255 cores [1].
This results in the following FW_BUG being logged when booting a guest with more than 255 cores:
[Firmware Bug]: CPU 512: APIC ID mismatch. CPUID: 0x0000 APIC: 0x0200
AMD64 Architecture Programmer's Manual Volume 2: System Programming Pub. 24593 Rev. 3.42 [2] Section 16.12 "x2APIC_ID" mentions the Extended Enumeration leaf 0x8000001e (which was later superseded by the extended leaf 0x80000026) provides the full x2APIC ID under all circumstances unlike the one reported by CPUID leaf 0x8000001e EAX which depends on the mode in which APIC is configured.
Rely on the APIC ID parsed during cpu_parse_topology_ext() from CPUID leaf 0x80000026 or 0xb and only use the APIC ID from leaf 0x8000001e if cpu_parse_topology_ext() failed (has_topoext is false).
On platforms that support the 0xb leaf (Zen2 or later, AMD guests on QEMU) or the extended leaf 0x80000026 (Zen4 or later), the "initial_apicid" is now set to the value parsed from EDX[31:0].
On older AMD/Hygon platforms that does not support the 0xb leaf but supports the TOPOEXT extension (Fam 0x15, 0x16, 0x17[Zen1], and Hygon), the current behavior is retained where "initial_apicid" is set using the 0x8000001e leaf.
Cc: stable@vger.kernel.org Link: https://github.com/qemu/qemu/commit/35ac5dfbcaa4b [1] Link: https://bugzilla.kernel.org/show_bug.cgi?id=206537 [2] Debugged-by: Naveen N Rao (AMD) naveen@kernel.org Debugged-by: Sairaj Kodilkar sarunkod@amd.com Fixes: c749ce393b8f ("x86/cpu: Use common topology code for AMD") Suggested-by: Thomas Gleixner tglx@linutronix.de Tested-by: Naveen N Rao (AMD) naveen@kernel.org Signed-off-by: K Prateek Nayak kprateek.nayak@amd.com --- Changelog v3..v4:
o Refreshed the diff based on Thomas' suggestion. The tags have been retained since there are no functional changes - only comments around the code has changed.
o Quoted relevant section of APM justifying the changes.
o Moved this patch up ahead.
o Cc'd stable. --- arch/x86/kernel/cpu/topology_amd.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c index 843b1655ab45..827dd0dbb6e9 100644 --- a/arch/x86/kernel/cpu/topology_amd.c +++ b/arch/x86/kernel/cpu/topology_amd.c @@ -81,20 +81,25 @@ static bool parse_8000_001e(struct topo_scan *tscan, bool has_topoext)
cpuid_leaf(0x8000001e, &leaf);
- tscan->c->topo.initial_apicid = leaf.ext_apic_id; - /* - * If leaf 0xb is available, then the domain shifts are set - * already and nothing to do here. Only valid for family >= 0x17. + * If leaf 0xb/0x26 is available, then the APIC ID and the domain + * shifts are set already. */ - if (!has_topoext && tscan->c->x86 >= 0x17) { + if (!has_topoext) { + tscan->c->topo.initial_apicid = leaf.ext_apic_id; + /* - * Leaf 0x80000008 set the CORE domain shift already. - * Update the SMT domain, but do not propagate it. + * Leaf 0x8000008 sets the CORE domain shift but not the + * SMT domain shift. On CPUs with family >= 0x17, there + * might be hyperthreads. */ - unsigned int nthreads = leaf.core_nthreads + 1; + if (tscan->c->x86 >= 0x17) { + /* Update the SMT domain, but do not propagate it. */ + unsigned int nthreads = leaf.core_nthreads + 1;
- topology_update_dom(tscan, TOPO_SMT_DOMAIN, get_count_order(nthreads), nthreads); + topology_update_dom(tscan, TOPO_SMT_DOMAIN, + get_count_order(nthreads), nthreads); + } }
store_node(tscan, leaf.nnodes_per_socket + 1, leaf.node_id);
On 8/25/2025 1:27 PM, K Prateek Nayak wrote:
AMD64 Architecture Programmer's Manual Volume 2: System Programming Pub. 24593 Rev. 3.42 [2] Section 16.12 "x2APIC_ID" mentions the Extended Enumeration leaf 0x8000001e (which was later superseded by the extended
The above should have been CPUID leaf 0xb (Fn0000_000B_EDX[31:0]) and not 0x8000001e. Sorry for the oversight.
leaf 0x80000026) provides the full x2APIC ID under all circumstances unlike the one reported by CPUID leaf 0x8000001e EAX which depends on the mode in which APIC is configured.
The following commit has been merged into the x86/urgent branch of tip:
Commit-ID: c2415c407a2cde01290d52ce2a1f81b0616379a3 Gitweb: https://git.kernel.org/tip/c2415c407a2cde01290d52ce2a1f81b0616379a3 Author: K Prateek Nayak kprateek.nayak@amd.com AuthorDate: Mon, 25 Aug 2025 07:57:29 Committer: Borislav Petkov (AMD) bp@alien8.de CommitterDate: Wed, 27 Aug 2025 11:31:11 +02:00
x86/cpu/topology: Use initial APIC ID from XTOPOLOGY leaf on AMD/HYGON
Prior to the topology parsing rewrite and the switchover to the new parsing logic for AMD processors in
c749ce393b8f ("x86/cpu: Use common topology code for AMD"),
the initial_apicid on these platforms was:
- First initialized to the LocalApicId from CPUID leaf 0x1 EBX[31:24].
- Then overwritten by the ExtendedLocalApicId in CPUID leaf 0xb EDX[31:0] on processors that supported topoext.
With the new parsing flow introduced in
f7fb3b2dd92c ("x86/cpu: Provide an AMD/HYGON specific topology parser"),
parse_8000_001e() now unconditionally overwrites the initial_apicid already parsed during cpu_parse_topology_ext().
Although this has not been a problem on baremetal platforms, on virtualized AMD guests that feature more than 255 cores, QEMU zeros out the CPUID leaf 0x8000001e on CPUs with CoreID > 255 to prevent collision of these IDs in EBX[7:0] which can only represent a maximum of 255 cores [1].
This results in the following FW_BUG being logged when booting a guest with more than 255 cores:
[Firmware Bug]: CPU 512: APIC ID mismatch. CPUID: 0x0000 APIC: 0x0200
AMD64 Architecture Programmer's Manual Volume 2: System Programming Pub. 24593 Rev. 3.42 [2] Section 16.12 "x2APIC_ID" mentions the Extended Enumeration leaf 0xb (Fn0000_000B_EDX[31:0])(which was later superseded by the extended leaf 0x80000026) provides the full x2APIC ID under all circumstances unlike the one reported by CPUID leaf 0x8000001e EAX which depends on the mode in which APIC is configured.
Rely on the APIC ID parsed during cpu_parse_topology_ext() from CPUID leaf 0x80000026 or 0xb and only use the APIC ID from leaf 0x8000001e if cpu_parse_topology_ext() failed (has_topoext is false).
On platforms that support the 0xb leaf (Zen2 or later, AMD guests on QEMU) or the extended leaf 0x80000026 (Zen4 or later), the initial_apicid is now set to the value parsed from EDX[31:0].
On older AMD/Hygon platforms that do not support the 0xb leaf but support the TOPOEXT extension (families 0x15, 0x16, 0x17[Zen1], and Hygon), retain current behavior where the initial_apicid is set using the 0x8000001e leaf.
Issue debugged by Naveen N Rao (AMD) naveen@kernel.org and Sairaj Kodilkar sarunkod@amd.com.
[ bp: Massage commit message. ]
Fixes: c749ce393b8f ("x86/cpu: Use common topology code for AMD") Suggested-by: Thomas Gleixner tglx@linutronix.de Signed-off-by: K Prateek Nayak kprateek.nayak@amd.com Signed-off-by: Borislav Petkov (AMD) bp@alien8.de Tested-by: Naveen N Rao (AMD) naveen@kernel.org Cc: stable@vger.kernel.org Link: https://github.com/qemu/qemu/commit/35ac5dfbcaa4b [1] Link: https://bugzilla.kernel.org/show_bug.cgi?id=206537 [2] Link: https://lore.kernel.org/20250825075732.10694-2-kprateek.nayak@amd.com --- arch/x86/kernel/cpu/topology_amd.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c index 843b165..827dd0d 100644 --- a/arch/x86/kernel/cpu/topology_amd.c +++ b/arch/x86/kernel/cpu/topology_amd.c @@ -81,20 +81,25 @@ static bool parse_8000_001e(struct topo_scan *tscan, bool has_topoext)
cpuid_leaf(0x8000001e, &leaf);
- tscan->c->topo.initial_apicid = leaf.ext_apic_id; - /* - * If leaf 0xb is available, then the domain shifts are set - * already and nothing to do here. Only valid for family >= 0x17. + * If leaf 0xb/0x26 is available, then the APIC ID and the domain + * shifts are set already. */ - if (!has_topoext && tscan->c->x86 >= 0x17) { + if (!has_topoext) { + tscan->c->topo.initial_apicid = leaf.ext_apic_id; + /* - * Leaf 0x80000008 set the CORE domain shift already. - * Update the SMT domain, but do not propagate it. + * Leaf 0x8000008 sets the CORE domain shift but not the + * SMT domain shift. On CPUs with family >= 0x17, there + * might be hyperthreads. */ - unsigned int nthreads = leaf.core_nthreads + 1; + if (tscan->c->x86 >= 0x17) { + /* Update the SMT domain, but do not propagate it. */ + unsigned int nthreads = leaf.core_nthreads + 1;
- topology_update_dom(tscan, TOPO_SMT_DOMAIN, get_count_order(nthreads), nthreads); + topology_update_dom(tscan, TOPO_SMT_DOMAIN, + get_count_order(nthreads), nthreads); + } }
store_node(tscan, leaf.nnodes_per_socket + 1, leaf.node_id);
linux-stable-mirror@lists.linaro.org