aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2007-03-18 05:26:13 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-18 14:35:08 -0400
commitca1b940ce6495541efe76499b3de39aa5e4941ed (patch)
tree8838e6f5f730f23a5e514180125f712cba091e2e
parent303cd1535f6257b9fd8214534ca87b1a1567a2c5 (diff)
[PATCH] i386: trust the PM-Timer calibration of the local APIC timer
When PM-Timer is available for local APIC timer calibration we can skip the verification of the calibrated time value. The resulting error is quite small on a bunch of evaluated platforms and is less harming than the observed false positives. We need to keep the verification on systems, which have no PM-Timer to avoid bogus local APIC timer calibrations in the range of factor 2-10, which can be observed when swicthing off the PM-timer support in the kernel configuration. The wrong calibration values are probably caused by SMM code trying to emulate a PS/2 keyboard from a (maybe connected or not) USB keyboard. This prohibits the accurate delivery of PIT interrupts, which are used to calibrate the local APIC timer. Unfortunately we have no way to disable this BIOS misfeature in the early boot process. Add also the dropped cpu_relax() back to the wait loops. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Ingo Molnar <mingo@elte.hu> Acked-by: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/i386/kernel/apic.c78
1 files changed, 27 insertions, 51 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 2383bcf18c5d..5cff7970911e 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -338,6 +338,7 @@ void __init setup_boot_APIC_clock(void)
338 void (*real_handler)(struct clock_event_device *dev); 338 void (*real_handler)(struct clock_event_device *dev);
339 unsigned long deltaj; 339 unsigned long deltaj;
340 long delta, deltapm; 340 long delta, deltapm;
341 int pm_referenced = 0;
341 342
342 apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" 343 apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
343 "calibrating APIC timer ...\n"); 344 "calibrating APIC timer ...\n");
@@ -357,7 +358,8 @@ void __init setup_boot_APIC_clock(void)
357 /* Let the interrupts run */ 358 /* Let the interrupts run */
358 local_irq_enable(); 359 local_irq_enable();
359 360
360 while(lapic_cal_loops <= LAPIC_CAL_LOOPS); 361 while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
362 cpu_relax();
361 363
362 local_irq_disable(); 364 local_irq_disable();
363 365
@@ -394,6 +396,7 @@ void __init setup_boot_APIC_clock(void)
394 "%lu (%ld)\n", (unsigned long) res, delta); 396 "%lu (%ld)\n", (unsigned long) res, delta);
395 delta = (long) res; 397 delta = (long) res;
396 } 398 }
399 pm_referenced = 1;
397 } 400 }
398 401
399 /* Calculate the scaled math multiplication factor */ 402 /* Calculate the scaled math multiplication factor */
@@ -423,68 +426,41 @@ void __init setup_boot_APIC_clock(void)
423 calibration_result / (1000000 / HZ), 426 calibration_result / (1000000 / HZ),
424 calibration_result % (1000000 / HZ)); 427 calibration_result % (1000000 / HZ));
425 428
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; 429 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 430
437 /* Let the interrupts run */ 431 /* We trust the pm timer based calibration */
438 local_irq_enable(); 432 if (!pm_referenced) {
433 apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
439 434
440 while(lapic_cal_loops <= LAPIC_CAL_LOOPS); 435 /*
436 * Setup the apic timer manually
437 */
438 levt->event_handler = lapic_cal_handler;
439 lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
440 lapic_cal_loops = -1;
441 441
442 local_irq_disable(); 442 /* Let the interrupts run */
443 local_irq_enable();
443 444
444 /* Stop the lapic timer */ 445 while(lapic_cal_loops <= LAPIC_CAL_LOOPS)
445 lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt); 446 cpu_relax();
446 447
447 local_irq_enable(); 448 local_irq_disable();
448 449
449 /* Jiffies delta */ 450 /* Stop the lapic timer */
450 deltaj = lapic_cal_j2 - lapic_cal_j1; 451 lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
451 apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
452 452
453 /* Check, if the PM timer is available */ 453 local_irq_enable();
454 deltapm = lapic_cal_pm2 - lapic_cal_pm1;
455 apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm);
456 454
457 local_apic_timer_verify_ok = 0; 455 /* Jiffies delta */
456 deltaj = lapic_cal_j2 - lapic_cal_j1;
457 apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
458 458
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 */ 459 /* Check, if the jiffies result is consistent */
483 if (deltaj >= LAPIC_CAL_LOOPS-2 && 460 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"); 461 apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
486 local_apic_timer_verify_ok = 1; 462 else
487 } 463 local_apic_timer_verify_ok = 0;
488 } 464 }
489 465
490 if (!local_apic_timer_verify_ok) { 466 if (!local_apic_timer_verify_ok) {