diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 2 | ||||
-rw-r--r-- | arch/i386/kernel/apic.c | 52 |
2 files changed, 54 insertions, 0 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 856c8b114e71..06377c76e734 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1117,6 +1117,8 @@ and is between 256 and 4096 characters. It is defined in the file | |||
1117 | 1117 | ||
1118 | nolapic [IA-32,APIC] Do not enable or use the local APIC. | 1118 | nolapic [IA-32,APIC] Do not enable or use the local APIC. |
1119 | 1119 | ||
1120 | nolapic_timer [IA-32,APIC] Do not use the local APIC timer. | ||
1121 | |||
1120 | noltlbs [PPC] Do not use large page/tlb entries for kernel | 1122 | noltlbs [PPC] Do not use large page/tlb entries for kernel |
1121 | lowmem mapping on PPC40x. | 1123 | lowmem mapping on PPC40x. |
1122 | 1124 | ||
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 5cff7970911e..36825117835d 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/clockchips.h> | 28 | #include <linux/clockchips.h> |
29 | #include <linux/acpi_pmtmr.h> | 29 | #include <linux/acpi_pmtmr.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/dmi.h> | ||
31 | 32 | ||
32 | #include <asm/atomic.h> | 33 | #include <asm/atomic.h> |
33 | #include <asm/smp.h> | 34 | #include <asm/smp.h> |
@@ -61,6 +62,8 @@ static int enable_local_apic __initdata = 0; | |||
61 | 62 | ||
62 | /* Local APIC timer verification ok */ | 63 | /* Local APIC timer verification ok */ |
63 | static int local_apic_timer_verify_ok; | 64 | static int local_apic_timer_verify_ok; |
65 | /* Disable local APIC timer from the kernel commandline or via dmi quirk */ | ||
66 | static int local_apic_timer_disabled; | ||
64 | 67 | ||
65 | /* | 68 | /* |
66 | * Debug level, exported for io_apic.c | 69 | * Debug level, exported for io_apic.c |
@@ -266,6 +269,32 @@ static void __devinit setup_APIC_timer(void) | |||
266 | } | 269 | } |
267 | 270 | ||
268 | /* | 271 | /* |
272 | * Detect systems with known broken BIOS implementations | ||
273 | */ | ||
274 | static int __init lapic_check_broken_bios(struct dmi_system_id *d) | ||
275 | { | ||
276 | printk(KERN_NOTICE "%s detected: disabling lapic timer.\n", | ||
277 | d->ident); | ||
278 | local_apic_timer_disabled = 1; | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static struct dmi_system_id __initdata broken_bios_dmi_table[] = { | ||
283 | { | ||
284 | /* | ||
285 | * BIOS exports only C1 state, but uses deeper power | ||
286 | * modes behind the kernels back. | ||
287 | */ | ||
288 | .callback = lapic_check_broken_bios, | ||
289 | .ident = "HP nx6325", | ||
290 | .matches = { | ||
291 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"), | ||
292 | }, | ||
293 | }, | ||
294 | {} | ||
295 | }; | ||
296 | |||
297 | /* | ||
269 | * In this functions we calibrate APIC bus clocks to the external timer. | 298 | * In this functions we calibrate APIC bus clocks to the external timer. |
270 | * | 299 | * |
271 | * We want to do the calibration only once since we want to have local timer | 300 | * We want to do the calibration only once since we want to have local timer |
@@ -340,6 +369,22 @@ void __init setup_boot_APIC_clock(void) | |||
340 | long delta, deltapm; | 369 | long delta, deltapm; |
341 | int pm_referenced = 0; | 370 | int pm_referenced = 0; |
342 | 371 | ||
372 | /* Detect know broken systems */ | ||
373 | dmi_check_system(broken_bios_dmi_table); | ||
374 | |||
375 | /* | ||
376 | * The local apic timer can be disabled via the kernel | ||
377 | * commandline or from the dmi quirk above. Register the lapic | ||
378 | * timer as a dummy clock event source on SMP systems, so the | ||
379 | * broadcast mechanism is used. On UP systems simply ignore it. | ||
380 | */ | ||
381 | if (local_apic_timer_disabled) { | ||
382 | /* No broadcast on UP ! */ | ||
383 | if (num_possible_cpus() > 1) | ||
384 | setup_APIC_timer(); | ||
385 | return; | ||
386 | } | ||
387 | |||
343 | apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" | 388 | apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" |
344 | "calibrating APIC timer ...\n"); | 389 | "calibrating APIC timer ...\n"); |
345 | 390 | ||
@@ -1179,6 +1224,13 @@ static int __init parse_nolapic(char *arg) | |||
1179 | } | 1224 | } |
1180 | early_param("nolapic", parse_nolapic); | 1225 | early_param("nolapic", parse_nolapic); |
1181 | 1226 | ||
1227 | static int __init parse_disable_lapic_timer(char *arg) | ||
1228 | { | ||
1229 | local_apic_timer_disabled = 1; | ||
1230 | return 0; | ||
1231 | } | ||
1232 | early_param("nolapic_timer", parse_disable_lapic_timer); | ||
1233 | |||
1182 | static int __init apic_set_verbosity(char *str) | 1234 | static int __init apic_set_verbosity(char *str) |
1183 | { | 1235 | { |
1184 | if (strcmp("debug", str) == 0) | 1236 | if (strcmp("debug", str) == 0) |