aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/apic.c')
-rw-r--r--arch/i386/kernel/apic.c52
1 files changed, 52 insertions, 0 deletions
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 */
63static int local_apic_timer_verify_ok; 64static int local_apic_timer_verify_ok;
65/* Disable local APIC timer from the kernel commandline or via dmi quirk */
66static 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 */
274static 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
282static 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}
1180early_param("nolapic", parse_nolapic); 1225early_param("nolapic", parse_nolapic);
1181 1226
1227static int __init parse_disable_lapic_timer(char *arg)
1228{
1229 local_apic_timer_disabled = 1;
1230 return 0;
1231}
1232early_param("nolapic_timer", parse_disable_lapic_timer);
1233
1182static int __init apic_set_verbosity(char *str) 1234static int __init apic_set_verbosity(char *str)
1183{ 1235{
1184 if (strcmp("debug", str) == 0) 1236 if (strcmp("debug", str) == 0)