Skip to content

Commit f0551af

Browse files
committed
x86/topology: Ignore non-present APIC IDs in a present package
Borislav reported that one of his systems has a broken MADT table which advertises eight present APICs and 24 non-present APICs in the same package. The non-present ones are considered hot-pluggable by the topology evaluation code, which is obviously bogus as there is no way to hot-plug within the same package. As the topology evaluation code accounts for hot-pluggable CPUs in a package, the maximum number of cores per package is computed wrong, which in turn causes the uncore performance counter driver to access non-existing MSRs. It will probably confuse other entities which rely on the maximum number of cores and threads per package too. Cure this by ignoring hot-pluggable APIC IDs within a present package. In theory it would be reasonable to just do this unconditionally, but then there is this thing called reality^Wvirtualization which ruins everything. Virtualization is the only existing user of "physical" hotplug and the virtualization tools allow the above scenario. Whether that is actually in use or not is unknown. As it can be argued that the virtualization case is not affected by the issues which exposed the reported problem, allow the bogosity if the kernel determined that it is running in a VM for now. Fixes: 89b0f15 ("x86/cpu/topology: Get rid of cpuinfo::x86_max_cores") Reported-by: Borislav Petkov (AMD) <bp@alien8.de> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lore.kernel.org/r/87a5nbvccx.ffs@tglx
1 parent 9b9c280 commit f0551af

File tree

1 file changed

+30
-9
lines changed

1 file changed

+30
-9
lines changed

arch/x86/kernel/cpu/topology.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <xen/xen.h>
2828

2929
#include <asm/apic.h>
30+
#include <asm/hypervisor.h>
3031
#include <asm/io_apic.h>
3132
#include <asm/mpspec.h>
3233
#include <asm/smp.h>
@@ -157,6 +158,20 @@ static __init bool check_for_real_bsp(u32 apic_id)
157158
return true;
158159
}
159160

161+
static unsigned int topo_unit_count(u32 lvlid, enum x86_topology_domains at_level,
162+
unsigned long *map)
163+
{
164+
unsigned int id, end, cnt = 0;
165+
166+
/* Calculate the exclusive end */
167+
end = lvlid + (1U << x86_topo_system.dom_shifts[at_level]);
168+
169+
/* Unfortunately there is no bitmap_weight_range() */
170+
for (id = find_next_bit(map, end, lvlid); id < end; id = find_next_bit(map, end, ++id))
171+
cnt++;
172+
return cnt;
173+
}
174+
160175
static __init void topo_register_apic(u32 apic_id, u32 acpi_id, bool present)
161176
{
162177
int cpu, dom;
@@ -178,6 +193,20 @@ static __init void topo_register_apic(u32 apic_id, u32 acpi_id, bool present)
178193
cpuid_to_apicid[cpu] = apic_id;
179194
topo_set_cpuids(cpu, apic_id, acpi_id);
180195
} else {
196+
u32 pkgid = topo_apicid(apic_id, TOPO_PKG_DOMAIN);
197+
198+
/*
199+
* Check for present APICs in the same package when running
200+
* on bare metal. Allow the bogosity in a guest.
201+
*/
202+
if (hypervisor_is_type(X86_HYPER_NATIVE) &&
203+
topo_unit_count(pkgid, TOPO_PKG_DOMAIN, phys_cpu_present_map)) {
204+
pr_info_once("Ignoring hot-pluggable APIC ID %x in present package.\n",
205+
apic_id);
206+
topo_info.nr_rejected_cpus++;
207+
return;
208+
}
209+
181210
topo_info.nr_disabled_cpus++;
182211
}
183212

@@ -280,7 +309,6 @@ unsigned int topology_unit_count(u32 apicid, enum x86_topology_domains which_uni
280309
{
281310
/* Remove the bits below @at_level to get the proper level ID of @apicid */
282311
unsigned int lvlid = topo_apicid(apicid, at_level);
283-
unsigned int id, end, cnt = 0;
284312

285313
if (lvlid >= MAX_LOCAL_APIC)
286314
return 0;
@@ -290,14 +318,7 @@ unsigned int topology_unit_count(u32 apicid, enum x86_topology_domains which_uni
290318
return 0;
291319
if (which_units == at_level)
292320
return 1;
293-
294-
/* Calculate the exclusive end */
295-
end = lvlid + (1U << x86_topo_system.dom_shifts[at_level]);
296-
/* Unfortunately there is no bitmap_weight_range() */
297-
for (id = find_next_bit(apic_maps[which_units].map, end, lvlid);
298-
id < end; id = find_next_bit(apic_maps[which_units].map, end, ++id))
299-
cnt++;
300-
return cnt;
321+
return topo_unit_count(lvlid, at_level, apic_maps[which_units].map);
301322
}
302323

303324
#ifdef CONFIG_ACPI_HOTPLUG_CPU

0 commit comments

Comments
 (0)