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.c117
1 files changed, 65 insertions, 52 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 2383bcf18c5d..93aa911646ad 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
@@ -338,6 +344,23 @@ void __init setup_boot_APIC_clock(void)
338 void (*real_handler)(struct clock_event_device *dev); 344 void (*real_handler)(struct clock_event_device *dev);
339 unsigned long deltaj; 345 unsigned long deltaj;
340 long delta, deltapm; 346 long delta, deltapm;
347 int pm_referenced = 0;
348
349 if (boot_cpu_has(X86_FEATURE_LAPIC_TIMER_BROKEN))
350 local_apic_timer_disabled = 1;
351
352 /*
353 * The local apic timer can be disabled via the kernel
354 * commandline or from the test above. Register the lapic
355 * timer as a dummy clock event source on SMP systems, so the
356 * broadcast mechanism is used. On UP systems simply ignore it.
357 */
358 if (local_apic_timer_disabled) {
359 /* No broadcast on UP ! */
360 if (num_possible_cpus() > 1)
361 setup_APIC_timer();
362 return;
363 }
341 364
342 apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" 365 apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
343 "calibrating APIC timer ...\n"); 366 "calibrating APIC timer ...\n");
@@ -357,7 +380,8 @@ void __init setup_boot_APIC_clock(void)
357 /* Let the interrupts run */ 380 /* Let the interrupts run */
358 local_irq_enable(); 381 local_irq_enable();
359 382
360 while(lapic_cal_loops <= LAPIC_CAL_LOOPS); 383 while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
384 cpu_relax();
361 385
362 local_irq_disable(); 386 local_irq_disable();
363 387
@@ -394,6 +418,7 @@ void __init setup_boot_APIC_clock(void)
394 "%lu (%ld)\n", (unsigned long) res, delta); 418 "%lu (%ld)\n", (unsigned long) res, delta);
395 delta = (long) res; 419 delta = (long) res;
396 } 420 }
421 pm_referenced = 1;
397 } 422 }
398 423
399 /* Calculate the scaled math multiplication factor */ 424 /* Calculate the scaled math multiplication factor */
@@ -423,69 +448,43 @@ void __init setup_boot_APIC_clock(void)
423 calibration_result / (1000000 / HZ), 448 calibration_result / (1000000 / HZ),
424 calibration_result % (1000000 / HZ)); 449 calibration_result % (1000000 / HZ));
425 450
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; 451 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 452
437 /* Let the interrupts run */ 453 /* We trust the pm timer based calibration */
438 local_irq_enable(); 454 if (!pm_referenced) {
455 apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
439 456
440 while(lapic_cal_loops <= LAPIC_CAL_LOOPS); 457 /*
458 * Setup the apic timer manually
459 */
460 levt->event_handler = lapic_cal_handler;
461 lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
462 lapic_cal_loops = -1;
441 463
442 local_irq_disable(); 464 /* Let the interrupts run */
465 local_irq_enable();
443 466
444 /* Stop the lapic timer */ 467 while(lapic_cal_loops <= LAPIC_CAL_LOOPS)
445 lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt); 468 cpu_relax();
446 469
447 local_irq_enable(); 470 local_irq_disable();
448 471
449 /* Jiffies delta */ 472 /* Stop the lapic timer */
450 deltaj = lapic_cal_j2 - lapic_cal_j1; 473 lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
451 apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
452 474
453 /* Check, if the PM timer is available */ 475 local_irq_enable();
454 deltapm = lapic_cal_pm2 - lapic_cal_pm1;
455 apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm);
456 476
457 local_apic_timer_verify_ok = 0; 477 /* Jiffies delta */
478 deltaj = lapic_cal_j2 - lapic_cal_j1;
479 apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
458 480
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 */ 481 /* Check, if the jiffies result is consistent */
483 if (deltaj >= LAPIC_CAL_LOOPS-2 && 482 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"); 483 apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
486 local_apic_timer_verify_ok = 1; 484 else
487 } 485 local_apic_timer_verify_ok = 0;
488 } 486 } else
487 local_irq_enable();
489 488
490 if (!local_apic_timer_verify_ok) { 489 if (!local_apic_timer_verify_ok) {
491 printk(KERN_WARNING 490 printk(KERN_WARNING
@@ -1203,6 +1202,20 @@ static int __init parse_nolapic(char *arg)
1203} 1202}
1204early_param("nolapic", parse_nolapic); 1203early_param("nolapic", parse_nolapic);
1205 1204
1205static int __init parse_disable_lapic_timer(char *arg)
1206{
1207 local_apic_timer_disabled = 1;
1208 return 0;
1209}
1210early_param("nolapic_timer", parse_disable_lapic_timer);
1211
1212static int __init parse_lapic_timer_c2_ok(char *arg)
1213{
1214 local_apic_timer_c2_ok = 1;
1215 return 0;
1216}
1217early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
1218
1206static int __init apic_set_verbosity(char *str) 1219static int __init apic_set_verbosity(char *str)
1207{ 1220{
1208 if (strcmp("debug", str) == 0) 1221 if (strcmp("debug", str) == 0)