diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-08-24 05:01:54 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:53:03 -0400 |
commit | 2f04fa888d270951b9e0fe9e641ddd560d77ad1b (patch) | |
tree | 7206b41bb6b072187640f2cb1cfb273ef2f2dbf0 /arch/x86/kernel/apic_32.c | |
parent | dc1528dd864a0b79fa67b60b3ca5674fe94fdce5 (diff) |
x86: apic copy calibrate_APIC_clock to each other in apic_32/64.c
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/apic_32.c')
-rw-r--r-- | arch/x86/kernel/apic_32.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index 60a901b2d4fe..05498c37f8d9 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c | |||
@@ -424,6 +424,90 @@ static void __cpuinit setup_APIC_timer(void) | |||
424 | clockevents_register_device(levt); | 424 | clockevents_register_device(levt); |
425 | } | 425 | } |
426 | 426 | ||
427 | #ifdef CONFIG_X86_64 | ||
428 | /* | ||
429 | * In this function we calibrate APIC bus clocks to the external | ||
430 | * timer. Unfortunately we cannot use jiffies and the timer irq | ||
431 | * to calibrate, since some later bootup code depends on getting | ||
432 | * the first irq? Ugh. | ||
433 | * | ||
434 | * We want to do the calibration only once since we | ||
435 | * want to have local timer irqs syncron. CPUs connected | ||
436 | * by the same APIC bus have the very same bus frequency. | ||
437 | * And we want to have irqs off anyways, no accidental | ||
438 | * APIC irq that way. | ||
439 | */ | ||
440 | |||
441 | #define TICK_COUNT 100000000 | ||
442 | |||
443 | static int __init calibrate_APIC_clock(void) | ||
444 | { | ||
445 | unsigned apic, apic_start; | ||
446 | unsigned long tsc, tsc_start; | ||
447 | int result; | ||
448 | |||
449 | local_irq_disable(); | ||
450 | |||
451 | /* | ||
452 | * Put whatever arbitrary (but long enough) timeout | ||
453 | * value into the APIC clock, we just want to get the | ||
454 | * counter running for calibration. | ||
455 | * | ||
456 | * No interrupt enable ! | ||
457 | */ | ||
458 | __setup_APIC_LVTT(250000000, 0, 0); | ||
459 | |||
460 | apic_start = apic_read(APIC_TMCCT); | ||
461 | #ifdef CONFIG_X86_PM_TIMER | ||
462 | if (apic_calibrate_pmtmr && pmtmr_ioport) { | ||
463 | pmtimer_wait(5000); /* 5ms wait */ | ||
464 | apic = apic_read(APIC_TMCCT); | ||
465 | result = (apic_start - apic) * 1000L / 5; | ||
466 | } else | ||
467 | #endif | ||
468 | { | ||
469 | rdtscll(tsc_start); | ||
470 | |||
471 | do { | ||
472 | apic = apic_read(APIC_TMCCT); | ||
473 | rdtscll(tsc); | ||
474 | } while ((tsc - tsc_start) < TICK_COUNT && | ||
475 | (apic_start - apic) < TICK_COUNT); | ||
476 | |||
477 | result = (apic_start - apic) * 1000L * tsc_khz / | ||
478 | (tsc - tsc_start); | ||
479 | } | ||
480 | |||
481 | local_irq_enable(); | ||
482 | |||
483 | printk(KERN_DEBUG "APIC timer calibration result %d\n", result); | ||
484 | |||
485 | printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", | ||
486 | result / 1000 / 1000, result / 1000 % 1000); | ||
487 | |||
488 | /* Calculate the scaled math multiplication factor */ | ||
489 | lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, | ||
490 | lapic_clockevent.shift); | ||
491 | lapic_clockevent.max_delta_ns = | ||
492 | clockevent_delta2ns(0x7FFFFF, &lapic_clockevent); | ||
493 | lapic_clockevent.min_delta_ns = | ||
494 | clockevent_delta2ns(0xF, &lapic_clockevent); | ||
495 | |||
496 | calibration_result = (result * APIC_DIVISOR) / HZ; | ||
497 | |||
498 | /* | ||
499 | * Do a sanity check on the APIC calibration result | ||
500 | */ | ||
501 | if (calibration_result < (1000000 / HZ)) { | ||
502 | printk(KERN_WARNING | ||
503 | "APIC frequency too slow, disabling apic timer\n"); | ||
504 | return -1; | ||
505 | } | ||
506 | |||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | #else | ||
427 | /* | 511 | /* |
428 | * In this functions we calibrate APIC bus clocks to the external timer. | 512 | * In this functions we calibrate APIC bus clocks to the external timer. |
429 | * | 513 | * |
@@ -635,6 +719,8 @@ static int __init calibrate_APIC_clock(void) | |||
635 | return 0; | 719 | return 0; |
636 | } | 720 | } |
637 | 721 | ||
722 | #endif | ||
723 | |||
638 | /* | 724 | /* |
639 | * Setup the boot APIC | 725 | * Setup the boot APIC |
640 | * | 726 | * |