diff options
Diffstat (limited to 'arch/x86/kernel/apic.c')
-rw-r--r-- | arch/x86/kernel/apic.c | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/arch/x86/kernel/apic.c b/arch/x86/kernel/apic.c index 8bd801db24d9..cf2ca19e62da 100644 --- a/arch/x86/kernel/apic.c +++ b/arch/x86/kernel/apic.c | |||
@@ -555,7 +555,8 @@ static void __init lapic_cal_handler(struct clock_event_device *dev) | |||
555 | } | 555 | } |
556 | } | 556 | } |
557 | 557 | ||
558 | static int __init calibrate_by_pmtimer(long deltapm, long *delta) | 558 | static int __init |
559 | calibrate_by_pmtimer(long deltapm, long *delta, long *deltatsc) | ||
559 | { | 560 | { |
560 | const long pm_100ms = PMTMR_TICKS_PER_SEC / 10; | 561 | const long pm_100ms = PMTMR_TICKS_PER_SEC / 10; |
561 | const long pm_thresh = pm_100ms / 100; | 562 | const long pm_thresh = pm_100ms / 100; |
@@ -566,7 +567,7 @@ static int __init calibrate_by_pmtimer(long deltapm, long *delta) | |||
566 | return -1; | 567 | return -1; |
567 | #endif | 568 | #endif |
568 | 569 | ||
569 | apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm); | 570 | apic_printk(APIC_VERBOSE, "... PM-Timer delta = %ld\n", deltapm); |
570 | 571 | ||
571 | /* Check, if the PM timer is available */ | 572 | /* Check, if the PM timer is available */ |
572 | if (!deltapm) | 573 | if (!deltapm) |
@@ -576,19 +577,30 @@ static int __init calibrate_by_pmtimer(long deltapm, long *delta) | |||
576 | 577 | ||
577 | if (deltapm > (pm_100ms - pm_thresh) && | 578 | if (deltapm > (pm_100ms - pm_thresh) && |
578 | deltapm < (pm_100ms + pm_thresh)) { | 579 | deltapm < (pm_100ms + pm_thresh)) { |
579 | apic_printk(APIC_VERBOSE, "... PM timer result ok\n"); | 580 | apic_printk(APIC_VERBOSE, "... PM-Timer result ok\n"); |
580 | } else { | 581 | return 0; |
581 | res = (((u64)deltapm) * mult) >> 22; | 582 | } |
582 | do_div(res, 1000000); | 583 | |
583 | pr_warning("APIC calibration not consistent " | 584 | res = (((u64)deltapm) * mult) >> 22; |
584 | "with PM Timer: %ldms instead of 100ms\n", | 585 | do_div(res, 1000000); |
585 | (long)res); | 586 | pr_warning("APIC calibration not consistent " |
586 | /* Correct the lapic counter value */ | 587 | "with PM-Timer: %ldms instead of 100ms\n",(long)res); |
587 | res = (((u64)(*delta)) * pm_100ms); | 588 | |
589 | /* Correct the lapic counter value */ | ||
590 | res = (((u64)(*delta)) * pm_100ms); | ||
591 | do_div(res, deltapm); | ||
592 | pr_info("APIC delta adjusted to PM-Timer: " | ||
593 | "%lu (%ld)\n", (unsigned long)res, *delta); | ||
594 | *delta = (long)res; | ||
595 | |||
596 | /* Correct the tsc counter value */ | ||
597 | if (cpu_has_tsc) { | ||
598 | res = (((u64)(*deltatsc)) * pm_100ms); | ||
588 | do_div(res, deltapm); | 599 | do_div(res, deltapm); |
589 | pr_info("APIC delta adjusted to PM-Timer: " | 600 | apic_printk(APIC_VERBOSE, "TSC delta adjusted to " |
590 | "%lu (%ld)\n", (unsigned long)res, *delta); | 601 | "PM-Timer: %lu (%ld) \n", |
591 | *delta = (long)res; | 602 | (unsigned long)res, *deltatsc); |
603 | *deltatsc = (long)res; | ||
592 | } | 604 | } |
593 | 605 | ||
594 | return 0; | 606 | return 0; |
@@ -599,7 +611,7 @@ static int __init calibrate_APIC_clock(void) | |||
599 | struct clock_event_device *levt = &__get_cpu_var(lapic_events); | 611 | struct clock_event_device *levt = &__get_cpu_var(lapic_events); |
600 | void (*real_handler)(struct clock_event_device *dev); | 612 | void (*real_handler)(struct clock_event_device *dev); |
601 | unsigned long deltaj; | 613 | unsigned long deltaj; |
602 | long delta; | 614 | long delta, deltatsc; |
603 | int pm_referenced = 0; | 615 | int pm_referenced = 0; |
604 | 616 | ||
605 | local_irq_disable(); | 617 | local_irq_disable(); |
@@ -629,9 +641,11 @@ static int __init calibrate_APIC_clock(void) | |||
629 | delta = lapic_cal_t1 - lapic_cal_t2; | 641 | delta = lapic_cal_t1 - lapic_cal_t2; |
630 | apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta); | 642 | apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta); |
631 | 643 | ||
644 | deltatsc = (long)(lapic_cal_tsc2 - lapic_cal_tsc1); | ||
645 | |||
632 | /* we trust the PM based calibration if possible */ | 646 | /* we trust the PM based calibration if possible */ |
633 | pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1, | 647 | pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1, |
634 | &delta); | 648 | &delta, &deltatsc); |
635 | 649 | ||
636 | /* Calculate the scaled math multiplication factor */ | 650 | /* Calculate the scaled math multiplication factor */ |
637 | lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS, | 651 | lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS, |
@@ -649,11 +663,10 @@ static int __init calibrate_APIC_clock(void) | |||
649 | calibration_result); | 663 | calibration_result); |
650 | 664 | ||
651 | if (cpu_has_tsc) { | 665 | if (cpu_has_tsc) { |
652 | delta = (long)(lapic_cal_tsc2 - lapic_cal_tsc1); | ||
653 | apic_printk(APIC_VERBOSE, "..... CPU clock speed is " | 666 | apic_printk(APIC_VERBOSE, "..... CPU clock speed is " |
654 | "%ld.%04ld MHz.\n", | 667 | "%ld.%04ld MHz.\n", |
655 | (delta / LAPIC_CAL_LOOPS) / (1000000 / HZ), | 668 | (deltatsc / LAPIC_CAL_LOOPS) / (1000000 / HZ), |
656 | (delta / LAPIC_CAL_LOOPS) % (1000000 / HZ)); | 669 | (deltatsc / LAPIC_CAL_LOOPS) % (1000000 / HZ)); |
657 | } | 670 | } |
658 | 671 | ||
659 | apic_printk(APIC_VERBOSE, "..... host bus clock speed is " | 672 | apic_printk(APIC_VERBOSE, "..... host bus clock speed is " |