aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2007-04-02 06:14:12 -0400
committerAndi Kleen <andi@basil.nowhere.org>2007-04-02 06:14:12 -0400
commit3556ddfa9284a86a59a9b78fe5894430f6ab4eef (patch)
treef85b5acde48b6ffa7f1c9abbb3ea2ff4a2e92b4b /arch/i386
parent2e175a90047a2dbc76fde169c990164895b25dfc (diff)
[PATCH] x86-64: Disable local APIC timer use on AMD systems with C1E
AMD dual core laptops with C1E do not run the APIC timer correctly when they go idle. Previously the code assumed this only happened on C2 or deeper. But not all of these systems report support C2. Use a AMD supplied snippet to detect C1E being enabled and then disable local apic timer use. This supercedes an earlier workaround using DMI detection of specific systems. Thanks to Mark Langsdorf for the detection snippet. Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/kernel/apic.c32
-rw-r--r--arch/i386/kernel/cpu/amd.c34
2 files changed, 37 insertions, 29 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index e88415282a6f..93aa911646ad 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -272,32 +272,6 @@ static void __devinit setup_APIC_timer(void)
272} 272}
273 273
274/* 274/*
275 * Detect systems with known broken BIOS implementations
276 */
277static int __init lapic_check_broken_bios(struct dmi_system_id *d)
278{
279 printk(KERN_NOTICE "%s detected: disabling lapic timer.\n",
280 d->ident);
281 local_apic_timer_disabled = 1;
282 return 0;
283}
284
285static struct dmi_system_id __initdata broken_bios_dmi_table[] = {
286 {
287 /*
288 * BIOS exports only C1 state, but uses deeper power
289 * modes behind the kernels back.
290 */
291 .callback = lapic_check_broken_bios,
292 .ident = "HP nx6325",
293 .matches = {
294 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
295 },
296 },
297 {}
298};
299
300/*
301 * In this functions we calibrate APIC bus clocks to the external timer. 275 * In this functions we calibrate APIC bus clocks to the external timer.
302 * 276 *
303 * We want to do the calibration only once since we want to have local timer 277 * We want to do the calibration only once since we want to have local timer
@@ -372,12 +346,12 @@ void __init setup_boot_APIC_clock(void)
372 long delta, deltapm; 346 long delta, deltapm;
373 int pm_referenced = 0; 347 int pm_referenced = 0;
374 348
375 /* Detect know broken systems */ 349 if (boot_cpu_has(X86_FEATURE_LAPIC_TIMER_BROKEN))
376 dmi_check_system(broken_bios_dmi_table); 350 local_apic_timer_disabled = 1;
377 351
378 /* 352 /*
379 * The local apic timer can be disabled via the kernel 353 * The local apic timer can be disabled via the kernel
380 * commandline or from the dmi quirk above. Register the lapic 354 * commandline or from the test above. Register the lapic
381 * timer as a dummy clock event source on SMP systems, so the 355 * timer as a dummy clock event source on SMP systems, so the
382 * broadcast mechanism is used. On UP systems simply ignore it. 356 * broadcast mechanism is used. On UP systems simply ignore it.
383 */ 357 */
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index 41cfea57232b..2d47db482972 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -22,6 +22,37 @@
22extern void vide(void); 22extern void vide(void);
23__asm__(".align 4\nvide: ret"); 23__asm__(".align 4\nvide: ret");
24 24
25#define ENABLE_C1E_MASK 0x18000000
26#define CPUID_PROCESSOR_SIGNATURE 1
27#define CPUID_XFAM 0x0ff00000
28#define CPUID_XFAM_K8 0x00000000
29#define CPUID_XFAM_10H 0x00100000
30#define CPUID_XFAM_11H 0x00200000
31#define CPUID_XMOD 0x000f0000
32#define CPUID_XMOD_REV_F 0x00040000
33
34/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
35static __cpuinit int amd_apic_timer_broken(void)
36{
37 u32 lo, hi;
38 u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
39 switch (eax & CPUID_XFAM) {
40 case CPUID_XFAM_K8:
41 if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
42 break;
43 case CPUID_XFAM_10H:
44 case CPUID_XFAM_11H:
45 rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
46 if (lo & ENABLE_C1E_MASK)
47 return 1;
48 break;
49 default:
50 /* err on the side of caution */
51 return 1;
52 }
53 return 0;
54}
55
25static void __cpuinit init_amd(struct cpuinfo_x86 *c) 56static void __cpuinit init_amd(struct cpuinfo_x86 *c)
26{ 57{
27 u32 l, h; 58 u32 l, h;
@@ -241,6 +272,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
241 272
242 if (cpuid_eax(0x80000000) >= 0x80000006) 273 if (cpuid_eax(0x80000000) >= 0x80000006)
243 num_cache_leaves = 3; 274 num_cache_leaves = 3;
275
276 if (amd_apic_timer_broken())
277 set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
244} 278}
245 279
246static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 * c, unsigned int size) 280static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)