aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorYinghai Lu <yhlu.kernel@gmail.com>2008-08-24 05:01:54 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-16 10:53:03 -0400
commit2f04fa888d270951b9e0fe9e641ddd560d77ad1b (patch)
tree7206b41bb6b072187640f2cb1cfb273ef2f2dbf0 /arch
parentdc1528dd864a0b79fa67b60b3ca5674fe94fdce5 (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')
-rw-r--r--arch/x86/kernel/apic_32.c86
-rw-r--r--arch/x86/kernel/apic_64.c215
2 files changed, 301 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
443static 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 *
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index c728885e4f4a..6e99af5ce678 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -478,6 +478,7 @@ static void __cpuinit setup_APIC_timer(void)
478 clockevents_register_device(levt); 478 clockevents_register_device(levt);
479} 479}
480 480
481#ifdef CONFIG_X86_64
481/* 482/*
482 * In this function we calibrate APIC bus clocks to the external 483 * In this function we calibrate APIC bus clocks to the external
483 * timer. Unfortunately we cannot use jiffies and the timer irq 484 * timer. Unfortunately we cannot use jiffies and the timer irq
@@ -560,6 +561,220 @@ static int __init calibrate_APIC_clock(void)
560 return 0; 561 return 0;
561} 562}
562 563
564#else
565/*
566 * In this functions we calibrate APIC bus clocks to the external timer.
567 *
568 * We want to do the calibration only once since we want to have local timer
569 * irqs syncron. CPUs connected by the same APIC bus have the very same bus
570 * frequency.
571 *
572 * This was previously done by reading the PIT/HPET and waiting for a wrap
573 * around to find out, that a tick has elapsed. I have a box, where the PIT
574 * readout is broken, so it never gets out of the wait loop again. This was
575 * also reported by others.
576 *
577 * Monitoring the jiffies value is inaccurate and the clockevents
578 * infrastructure allows us to do a simple substitution of the interrupt
579 * handler.
580 *
581 * The calibration routine also uses the pm_timer when possible, as the PIT
582 * happens to run way too slow (factor 2.3 on my VAIO CoreDuo, which goes
583 * back to normal later in the boot process).
584 */
585
586#define LAPIC_CAL_LOOPS (HZ/10)
587
588static __initdata int lapic_cal_loops = -1;
589static __initdata long lapic_cal_t1, lapic_cal_t2;
590static __initdata unsigned long long lapic_cal_tsc1, lapic_cal_tsc2;
591static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2;
592static __initdata unsigned long lapic_cal_j1, lapic_cal_j2;
593
594/*
595 * Temporary interrupt handler.
596 */
597static void __init lapic_cal_handler(struct clock_event_device *dev)
598{
599 unsigned long long tsc = 0;
600 long tapic = apic_read(APIC_TMCCT);
601 unsigned long pm = acpi_pm_read_early();
602
603 if (cpu_has_tsc)
604 rdtscll(tsc);
605
606 switch (lapic_cal_loops++) {
607 case 0:
608 lapic_cal_t1 = tapic;
609 lapic_cal_tsc1 = tsc;
610 lapic_cal_pm1 = pm;
611 lapic_cal_j1 = jiffies;
612 break;
613
614 case LAPIC_CAL_LOOPS:
615 lapic_cal_t2 = tapic;
616 lapic_cal_tsc2 = tsc;
617 if (pm < lapic_cal_pm1)
618 pm += ACPI_PM_OVRRUN;
619 lapic_cal_pm2 = pm;
620 lapic_cal_j2 = jiffies;
621 break;
622 }
623}
624
625static int __init calibrate_APIC_clock(void)
626{
627 struct clock_event_device *levt = &__get_cpu_var(lapic_events);
628 const long pm_100ms = PMTMR_TICKS_PER_SEC/10;
629 const long pm_thresh = pm_100ms/100;
630 void (*real_handler)(struct clock_event_device *dev);
631 unsigned long deltaj;
632 long delta, deltapm;
633 int pm_referenced = 0;
634
635 local_irq_disable();
636
637 /* Replace the global interrupt handler */
638 real_handler = global_clock_event->event_handler;
639 global_clock_event->event_handler = lapic_cal_handler;
640
641 /*
642 * Setup the APIC counter to 1e9. There is no way the lapic
643 * can underflow in the 100ms detection time frame
644 */
645 __setup_APIC_LVTT(1000000000, 0, 0);
646
647 /* Let the interrupts run */
648 local_irq_enable();
649
650 while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
651 cpu_relax();
652
653 local_irq_disable();
654
655 /* Restore the real event handler */
656 global_clock_event->event_handler = real_handler;
657
658 /* Build delta t1-t2 as apic timer counts down */
659 delta = lapic_cal_t1 - lapic_cal_t2;
660 apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta);
661
662 /* Check, if the PM timer is available */
663 deltapm = lapic_cal_pm2 - lapic_cal_pm1;
664 apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm);
665
666 if (deltapm) {
667 unsigned long mult;
668 u64 res;
669
670 mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC, 22);
671
672 if (deltapm > (pm_100ms - pm_thresh) &&
673 deltapm < (pm_100ms + pm_thresh)) {
674 apic_printk(APIC_VERBOSE, "... PM timer result ok\n");
675 } else {
676 res = (((u64) deltapm) * mult) >> 22;
677 do_div(res, 1000000);
678 printk(KERN_WARNING "APIC calibration not consistent "
679 "with PM Timer: %ldms instead of 100ms\n",
680 (long)res);
681 /* Correct the lapic counter value */
682 res = (((u64) delta) * pm_100ms);
683 do_div(res, deltapm);
684 printk(KERN_INFO "APIC delta adjusted to PM-Timer: "
685 "%lu (%ld)\n", (unsigned long) res, delta);
686 delta = (long) res;
687 }
688 pm_referenced = 1;
689 }
690
691 /* Calculate the scaled math multiplication factor */
692 lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS,
693 lapic_clockevent.shift);
694 lapic_clockevent.max_delta_ns =
695 clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
696 lapic_clockevent.min_delta_ns =
697 clockevent_delta2ns(0xF, &lapic_clockevent);
698
699 calibration_result = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
700
701 apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
702 apic_printk(APIC_VERBOSE, "..... mult: %ld\n", lapic_clockevent.mult);
703 apic_printk(APIC_VERBOSE, "..... calibration result: %u\n",
704 calibration_result);
705
706 if (cpu_has_tsc) {
707 delta = (long)(lapic_cal_tsc2 - lapic_cal_tsc1);
708 apic_printk(APIC_VERBOSE, "..... CPU clock speed is "
709 "%ld.%04ld MHz.\n",
710 (delta / LAPIC_CAL_LOOPS) / (1000000 / HZ),
711 (delta / LAPIC_CAL_LOOPS) % (1000000 / HZ));
712 }
713
714 apic_printk(APIC_VERBOSE, "..... host bus clock speed is "
715 "%u.%04u MHz.\n",
716 calibration_result / (1000000 / HZ),
717 calibration_result % (1000000 / HZ));
718
719 /*
720 * Do a sanity check on the APIC calibration result
721 */
722 if (calibration_result < (1000000 / HZ)) {
723 local_irq_enable();
724 printk(KERN_WARNING
725 "APIC frequency too slow, disabling apic timer\n");
726 return -1;
727 }
728
729 levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
730
731 /* We trust the pm timer based calibration */
732 if (!pm_referenced) {
733 apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
734
735 /*
736 * Setup the apic timer manually
737 */
738 levt->event_handler = lapic_cal_handler;
739 lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
740 lapic_cal_loops = -1;
741
742 /* Let the interrupts run */
743 local_irq_enable();
744
745 while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
746 cpu_relax();
747
748 local_irq_disable();
749
750 /* Stop the lapic timer */
751 lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
752
753 local_irq_enable();
754
755 /* Jiffies delta */
756 deltaj = lapic_cal_j2 - lapic_cal_j1;
757 apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
758
759 /* Check, if the jiffies result is consistent */
760 if (deltaj >= LAPIC_CAL_LOOPS-2 && deltaj <= LAPIC_CAL_LOOPS+2)
761 apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
762 else
763 levt->features |= CLOCK_EVT_FEAT_DUMMY;
764 } else
765 local_irq_enable();
766
767 if (levt->features & CLOCK_EVT_FEAT_DUMMY) {
768 printk(KERN_WARNING
769 "APIC timer disabled due to verification failure.\n");
770 return -1;
771 }
772
773 return 0;
774}
775
776#endif
777
563/* 778/*
564 * Setup the boot APIC 779 * Setup the boot APIC
565 * 780 *