diff options
author | Andreas Herrmann <andreas.herrmann3@amd.com> | 2009-06-08 09:55:09 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-09 09:28:46 -0400 |
commit | 42937e81a82b6bbc51a309c83da140b3a7ca5945 (patch) | |
tree | c6562f38f91de06e00bd12280044e31733ff5ee4 | |
parent | c9690998ef48ffefeccb91c70a7739eebdea57f9 (diff) |
x86: Detect use of extended APIC ID for AMD CPUs
Booting a 32-bit kernel on Magny-Cours results in the following panic:
...
Using APIC driver default
...
Overriding APIC driver with bigsmp
...
Getting VERSION: 80050010
Getting VERSION: 80050010
Getting ID: 10000000
Getting ID: ef000000
Getting LVT0: 700
Getting LVT1: 10000
Kernel panic - not syncing: Boot APIC ID in local APIC unexpected (16 vs 0)
Pid: 1, comm: swapper Not tainted 2.6.30-rcX #2
Call Trace:
[<c05194da>] ? panic+0x38/0xd3
[<c0743102>] ? native_smp_prepare_cpus+0x259/0x31f
[<c073b19d>] ? kernel_init+0x3e/0x141
[<c073b15f>] ? kernel_init+0x0/0x141
[<c020325f>] ? kernel_thread_helper+0x7/0x10
The reason is that default_get_apic_id handled extension of local APIC
ID field just in case of XAPIC.
Thus for this AMD CPU, default_get_apic_id() returns 0 and
bigsmp_get_apic_id() returns 16 which leads to the respective kernel
panic.
This patch introduces a Linux specific feature flag to indicate
support for extended APIC id (8 bits instead of 4 bits width) and sets
the flag on AMD CPUs if applicable.
Signed-off-by: Andreas Herrmann <andreas.herrmann3@amd.com>
Cc: <stable@kernel.org>
LKML-Reference: <20090608135509.GA12431@alberich.amd.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/include/asm/apic.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/cpufeature.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/amd.c | 10 |
3 files changed, 12 insertions, 1 deletions
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 42f2f8377422..9b2c04910e0d 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h | |||
@@ -410,7 +410,7 @@ static inline unsigned default_get_apic_id(unsigned long x) | |||
410 | { | 410 | { |
411 | unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR)); | 411 | unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR)); |
412 | 412 | ||
413 | if (APIC_XAPIC(ver)) | 413 | if (APIC_XAPIC(ver) || boot_cpu_has(X86_FEATURE_EXTD_APICID)) |
414 | return (x >> 24) & 0xFF; | 414 | return (x >> 24) & 0xFF; |
415 | else | 415 | else |
416 | return (x >> 24) & 0x0F; | 416 | return (x >> 24) & 0x0F; |
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index bb83b1c397aa..78dee4f0f7aa 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h | |||
@@ -94,6 +94,7 @@ | |||
94 | #define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */ | 94 | #define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */ |
95 | #define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */ | 95 | #define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */ |
96 | #define X86_FEATURE_CLFLUSH_MONITOR (3*32+25) /* "" clflush reqd with monitor */ | 96 | #define X86_FEATURE_CLFLUSH_MONITOR (3*32+25) /* "" clflush reqd with monitor */ |
97 | #define X86_FEATURE_EXTD_APICID (3*32+26) /* has extended APICID (8 bits) */ | ||
97 | 98 | ||
98 | /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ | 99 | /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ |
99 | #define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */ | 100 | #define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */ |
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 7e4a459daa64..0802e151c2c9 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <asm/processor.h> | 6 | #include <asm/processor.h> |
7 | #include <asm/apic.h> | 7 | #include <asm/apic.h> |
8 | #include <asm/cpu.h> | 8 | #include <asm/cpu.h> |
9 | #include <asm/pci-direct.h> | ||
9 | 10 | ||
10 | #ifdef CONFIG_X86_64 | 11 | #ifdef CONFIG_X86_64 |
11 | # include <asm/numa_64.h> | 12 | # include <asm/numa_64.h> |
@@ -351,6 +352,15 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) | |||
351 | (c->x86_model == 8 && c->x86_mask >= 8)) | 352 | (c->x86_model == 8 && c->x86_mask >= 8)) |
352 | set_cpu_cap(c, X86_FEATURE_K6_MTRR); | 353 | set_cpu_cap(c, X86_FEATURE_K6_MTRR); |
353 | #endif | 354 | #endif |
355 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI) | ||
356 | /* check CPU config space for extended APIC ID */ | ||
357 | if (c->x86 >= 0xf) { | ||
358 | unsigned int val; | ||
359 | val = read_pci_config(0, 24, 0, 0x68); | ||
360 | if ((val & ((1 << 17) | (1 << 18))) == ((1 << 17) | (1 << 18))) | ||
361 | set_cpu_cap(c, X86_FEATURE_EXTD_APICID); | ||
362 | } | ||
363 | #endif | ||
354 | } | 364 | } |
355 | 365 | ||
356 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) | 366 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) |