[PATCH] x86/topology: Add helper to ignore bogus MADT entries

From: Yazen Ghannam
Date: Fri Oct 24 2025 - 17:19:26 EST


Some older Intel and AMD systems include bogus ACPI MADT entries. These
entries show as "disabled". And it's not clear if they are physically
present but offline, i.e halted. Or if they are not physically present
at all.

Ideally, if they are not physically present, then they should not be
listed in MADT. There doesn't seem to be any explicit x86 topology info
that can be used to verify if the entries are bogus or not.

Add a helper function to collect vendor-specific checks to ignore bogus
APIC IDs. Start with known quirks for an Intel SNB model and older AMD
K10 models.

Fixes: f0551af02130 ("x86/topology: Ignore non-present APIC IDs in a present package")
Signed-off-by: Yazen Ghannam <yazen.ghannam@xxxxxxx>
---
arch/x86/kernel/cpu/topology.c | 52 ++++++++++++++++++++++++++--------
1 file changed, 40 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/cpu/topology.c b/arch/x86/kernel/cpu/topology.c
index 6073a16628f9..704788b92395 100644
--- a/arch/x86/kernel/cpu/topology.c
+++ b/arch/x86/kernel/cpu/topology.c
@@ -219,6 +219,45 @@ static unsigned int topo_unit_count(u32 lvlid, enum x86_topology_domains at_leve
return cnt;
}

+/*
+ * Some older BIOSes include extra entries in MADT.
+ * Do some vendor-specific checks to ignore them.
+ */
+static bool ignore_extra_apic_entry(u32 apic_id)
+{
+ u32 pkgid = topo_apicid(apic_id, TOPO_PKG_DOMAIN);
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+
+ /* Allow "physically not possible" cases if in a guest. */
+ if (!hypervisor_is_type(X86_HYPER_NATIVE))
+ return false;
+
+ /* This model only supports 8 threads in a package. */
+ if (c->x86_vendor == X86_VENDOR_INTEL &&
+ c->x86 == 0x6 && c->x86_model == 0x2d) {
+ if (topo_unit_count(pkgid, TOPO_PKG_DOMAIN, phys_cpu_present_map) >= 8)
+ goto reject;
+ }
+
+ /*
+ * Various older models have extra entries. A common trait is that the
+ * package ID derived from the APIC ID would be more than was ever supported.
+ */
+ if (c->x86_vendor == X86_VENDOR_AMD && c->x86 < 0x17) {
+ pkgid >>= x86_topo_system.dom_shifts[TOPO_PKG_DOMAIN - 1];
+
+ if (pkgid >= 8)
+ goto reject;
+ }
+
+ return false;
+
+reject:
+ pr_info_once("Ignoring hot-pluggable APIC ID %x.\n", apic_id);
+ topo_info.nr_rejected_cpus++;
+ return true;
+}
+
static __init void topo_register_apic(u32 apic_id, u32 acpi_id, bool present)
{
int cpu, dom;
@@ -240,19 +279,8 @@ static __init void topo_register_apic(u32 apic_id, u32 acpi_id, bool present)
cpuid_to_apicid[cpu] = apic_id;
topo_set_cpuids(cpu, apic_id, acpi_id);
} else {
- u32 pkgid = topo_apicid(apic_id, TOPO_PKG_DOMAIN);
-
- /*
- * Check for present APICs in the same package when running
- * on bare metal. Allow the bogosity in a guest.
- */
- if (hypervisor_is_type(X86_HYPER_NATIVE) &&
- topo_unit_count(pkgid, TOPO_PKG_DOMAIN, phys_cpu_present_map)) {
- pr_info_once("Ignoring hot-pluggable APIC ID %x in present package.\n",
- apic_id);
- topo_info.nr_rejected_cpus++;
+ if (ignore_extra_apic_entry(apic_id))
return;
- }

topo_info.nr_disabled_cpus++;
}
--
2.51.1