[PATCH RFC] x86/cpu: read processor's APIC id from local APIC

From: Vitaly Kuznetsov
Date: Wed Aug 30 2017 - 07:57:48 EST


Initial APIC ID and APIC ID don't necessarily match when we're not in
x2apic mode. Intel 64 and IA-32 Architectures Software Developer's Manual
(Volume 3A: System Programming Guide, Part 1, March 2017) says:

"Section 8.4.5 Identifying Logical Processors in an MP System
...
Read Initial APIC ID (If the process does not support CPUID leaf 0BH) - An
APIC ID is assigned to a logical processor during power up. This is the
initial APIC ID reported by CPUID.1:EBX[31:24] and may be different from
the current value read from the local APIC."

Same section states that we can always get the current APIC id from
APIC register (xapic) or by doing rdmsr (x2apic). In x2apic mode this is
always equivalent to getting it from extended topology (CPUID leaf 0BH).

I'm trying to address an issue with Hyper-V guests with weird NUMA
configurations. E.g. 2 node guest with 5 CPUs on each node get the
following initial APIC ids:
0 1 2 3 4 8 9 10 11 12
firmware, however, changes their effective APIC ids to
0 1 2 3 4 5 6 7 8 9
In ACPI tables processors are described with these real ACPI ids and it
seems that this complies to the specification. However, during boot these
guests report
...
Switched APIC routing to physical flat.
...
[Firmware Bug]: CPU5: APIC id mismatch. Firmware: 5 APIC: 8
#6
[Firmware Bug]: CPU6: APIC id mismatch. Firmware: 6 APIC: 9
#7
...

which is mesleading: APIC id for CPU5 is actually 5, not 8. And this
matches MADT.

Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx>
---
RFC part:
- It may happen that Hyper-V is actually breaking some spec here, I'm just
failing to see which.
- I'm probably opening pandora's box, I know :-) This code was there for
more than a decade at least, something will probably break.
---
arch/x86/kernel/cpu/common.c | 2 +-
arch/x86/kernel/cpu/topology.c | 4 ----
2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index c8b39870f33e..0951b4f40aa8 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1102,7 +1102,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
apply_forced_caps(c);

#ifdef CONFIG_X86_64
- c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
+ c->apicid = read_apic_id();
#endif

/*
diff --git a/arch/x86/kernel/cpu/topology.c b/arch/x86/kernel/cpu/topology.c
index cd531355e838..02b43685acb6 100644
--- a/arch/x86/kernel/cpu/topology.c
+++ b/arch/x86/kernel/cpu/topology.c
@@ -79,10 +79,6 @@ void detect_extended_topology(struct cpuinfo_x86 *c)
c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, ht_mask_width)
& core_select_mask;
c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, core_plus_mask_width);
- /*
- * Reinit the apicid, now that we have extended initial_apicid.
- */
- c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);

c->x86_max_cores = (core_level_siblings / smp_num_siblings);

--
2.13.5