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.c143
1 files changed, 91 insertions, 52 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 2383bcf18c5..e88415282a6 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,11 @@ 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;
67/* Local APIC timer works in C2 */
68int local_apic_timer_c2_ok;
69EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
64 70
65/* 71/*
66 * Debug level, exported for io_apic.c 72 * Debug level, exported for io_apic.c
@@ -266,6 +272,32 @@ static void __devinit setup_APIC_timer(void)
266} 272}
267 273
268/* 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/*
269 * In this functions we calibrate APIC bus clocks to the external timer. 301 * In this functions we calibrate APIC bus clocks to the external timer.
270 * 302 *
271 * We want to do the calibration only once since we want to have local timer 303 * We want to do the calibration only once since we want to have local timer
@@ -338,6 +370,23 @@ void __init setup_boot_APIC_clock(void)
338 void (*real_handler)(struct clock_event_device *dev); 370 void (*real_handler)(struct clock_event_device *dev);
339 unsigned long deltaj; 371 unsigned long deltaj;
340 long delta, deltapm; 372 long delta, deltapm;
373 int pm_referenced = 0;
374
375 /* Detect know broken systems */
376 dmi_check_system(broken_bios_dmi_table);
377
378 /*
379 * The local apic timer can be disabled via the kernel
380 * commandline or from the dmi quirk above. Register the lapic
381 * timer as a dummy clock event source on SMP systems, so the
382 * broadcast mechanism is used. On UP systems simply ignore it.
383 */
384 if (local_apic_timer_disabled) {
385 /* No broadcast on UP ! */
386 if (num_possible_cpus() > 1)
387 setup_APIC_timer();
388 return;
389 }
341 390
342 apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" 391 apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
343 "calibrating APIC timer ...\n"); 392 "calibrating APIC timer ...\n");
@@ -357,7 +406,8 @@ void __init setup_boot_APIC_clock(void)
357 /* Let the interrupts run */ 406 /* Let the interrupts run */
358 local_irq_enable(); 407 local_irq_enable();
359 408
360 while(lapic_cal_loops <= LAPIC_CAL_LOOPS); 409 while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
410 cpu_relax();
361 411
362 local_irq_disable(); 412 local_irq_disable();
363 413
@@ -394,6 +444,7 @@ void __init setup_boot_APIC_clock(void)
394 "%lu (%ld)\n", (unsigned long) res, delta); 444 "%lu (%ld)\n", (unsigned long) res, delta);
395 delta = (long) res; 445 delta = (long) res;
396 } 446 }
447 pm_referenced = 1;
397 } 448 }
398 449
399 /* Calculate the scaled math multiplication factor */ 450 /* Calculate the scaled math multiplication factor */
@@ -423,69 +474,43 @@ void __init setup_boot_APIC_clock(void)
423 calibration_result / (1000000 / HZ), 474 calibration_result / (1000000 / HZ),
424 calibration_result % (1000000 / HZ)); 475 calibration_result % (1000000 / HZ));
425 476
426
427 apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
428
429 /*
430 * Setup the apic timer manually
431 */
432 local_apic_timer_verify_ok = 1; 477 local_apic_timer_verify_ok = 1;
433 levt->event_handler = lapic_cal_handler;
434 lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
435 lapic_cal_loops = -1;
436 478
437 /* Let the interrupts run */ 479 /* We trust the pm timer based calibration */
438 local_irq_enable(); 480 if (!pm_referenced) {
481 apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
439 482
440 while(lapic_cal_loops <= LAPIC_CAL_LOOPS); 483 /*
484 * Setup the apic timer manually
485 */
486 levt->event_handler = lapic_cal_handler;
487 lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
488 lapic_cal_loops = -1;
441 489
442 local_irq_disable(); 490 /* Let the interrupts run */
491 local_irq_enable();
443 492
444 /* Stop the lapic timer */ 493 while(lapic_cal_loops <= LAPIC_CAL_LOOPS)
445 lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt); 494 cpu_relax();
446 495
447 local_irq_enable(); 496 local_irq_disable();
448 497
449 /* Jiffies delta */ 498 /* Stop the lapic timer */
450 deltaj = lapic_cal_j2 - lapic_cal_j1; 499 lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
451 apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
452 500
453 /* Check, if the PM timer is available */ 501 local_irq_enable();
454 deltapm = lapic_cal_pm2 - lapic_cal_pm1;
455 apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm);
456 502
457 local_apic_timer_verify_ok = 0; 503 /* Jiffies delta */
504 deltaj = lapic_cal_j2 - lapic_cal_j1;
505 apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
458 506
459 if (deltapm) {
460 if (deltapm > (pm_100ms - pm_thresh) &&
461 deltapm < (pm_100ms + pm_thresh)) {
462 apic_printk(APIC_VERBOSE, "... PM timer result ok\n");
463 /* Check, if the jiffies result is consistent */
464 if (deltaj < LAPIC_CAL_LOOPS-2 ||
465 deltaj > LAPIC_CAL_LOOPS+2) {
466 /*
467 * Not sure, what we can do about this one.
468 * When high resultion timers are active
469 * and the lapic timer does not stop in C3
470 * we are fine. Otherwise more trouble might
471 * be waiting. -- tglx
472 */
473 printk(KERN_WARNING "Global event device %s "
474 "has wrong frequency "
475 "(%lu ticks instead of %d)\n",
476 global_clock_event->name, deltaj,
477 LAPIC_CAL_LOOPS);
478 }
479 local_apic_timer_verify_ok = 1;
480 }
481 } else {
482 /* Check, if the jiffies result is consistent */ 507 /* Check, if the jiffies result is consistent */
483 if (deltaj >= LAPIC_CAL_LOOPS-2 && 508 if (deltaj >= LAPIC_CAL_LOOPS-2 && deltaj <= LAPIC_CAL_LOOPS+2)
484 deltaj <= LAPIC_CAL_LOOPS+2) {
485 apic_printk(APIC_VERBOSE, "... jiffies result ok\n"); 509 apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
486 local_apic_timer_verify_ok = 1; 510 else
487 } 511 local_apic_timer_verify_ok = 0;
488 } 512 } else
513 local_irq_enable();
489 514
490 if (!local_apic_timer_verify_ok) { 515 if (!local_apic_timer_verify_ok) {
491 printk(KERN_WARNING 516 printk(KERN_WARNING
@@ -1203,6 +1228,20 @@ static int __init parse_nolapic(char *arg)
1203} 1228}
1204early_param("nolapic", parse_nolapic); 1229early_param("nolapic", parse_nolapic);
1205 1230
1231static int __init parse_disable_lapic_timer(char *arg)
1232{
1233 local_apic_timer_disabled = 1;
1234 return 0;
1235}
1236early_param("nolapic_timer", parse_disable_lapic_timer);
1237
1238static int __init parse_lapic_timer_c2_ok(char *arg)
1239{
1240 local_apic_timer_c2_ok = 1;
1241 return 0;
1242}
1243early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
1244
1206static int __init apic_set_verbosity(char *str) 1245static int __init apic_set_verbosity(char *str)
1207{ 1246{
1208 if (strcmp("debug", str) == 0) 1247 if (strcmp("debug", str) == 0)