diff options
| -rw-r--r-- | arch/x86/kernel/apic.c | 47 |
1 files changed, 30 insertions, 17 deletions
diff --git a/arch/x86/kernel/apic.c b/arch/x86/kernel/apic.c index 4b6df2469fe3..7bcd746d704c 100644 --- a/arch/x86/kernel/apic.c +++ b/arch/x86/kernel/apic.c | |||
| @@ -535,7 +535,8 @@ static void __init lapic_cal_handler(struct clock_event_device *dev) | |||
| 535 | } | 535 | } |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | static int __init calibrate_by_pmtimer(long deltapm, long *delta) | 538 | static int __init |
| 539 | calibrate_by_pmtimer(long deltapm, long *delta, long *deltatsc) | ||
| 539 | { | 540 | { |
| 540 | const long pm_100ms = PMTMR_TICKS_PER_SEC / 10; | 541 | const long pm_100ms = PMTMR_TICKS_PER_SEC / 10; |
| 541 | const long pm_thresh = pm_100ms / 100; | 542 | const long pm_thresh = pm_100ms / 100; |
| @@ -557,18 +558,29 @@ static int __init calibrate_by_pmtimer(long deltapm, long *delta) | |||
| 557 | if (deltapm > (pm_100ms - pm_thresh) && | 558 | if (deltapm > (pm_100ms - pm_thresh) && |
| 558 | deltapm < (pm_100ms + pm_thresh)) { | 559 | deltapm < (pm_100ms + pm_thresh)) { |
| 559 | apic_printk(APIC_VERBOSE, "... PM timer result ok\n"); | 560 | apic_printk(APIC_VERBOSE, "... PM timer result ok\n"); |
| 560 | } else { | 561 | return 0; |
| 561 | res = (((u64)deltapm) * mult) >> 22; | 562 | } |
| 562 | do_div(res, 1000000); | 563 | |
| 563 | pr_warning("APIC calibration not consistent " | 564 | res = (((u64)deltapm) * mult) >> 22; |
| 564 | "with PM Timer: %ldms instead of 100ms\n", | 565 | do_div(res, 1000000); |
| 565 | (long)res); | 566 | pr_warning("APIC calibration not consistent " |
| 566 | /* Correct the lapic counter value */ | 567 | "with PM Timer: %ldms instead of 100ms\n",(long)res); |
| 567 | res = (((u64)(*delta)) * pm_100ms); | 568 | |
| 569 | /* Correct the lapic counter value */ | ||
| 570 | res = (((u64)(*delta)) * pm_100ms); | ||
| 571 | do_div(res, deltapm); | ||
| 572 | pr_info("APIC delta adjusted to PM-Timer: " | ||
| 573 | "%lu (%ld)\n", (unsigned long)res, *delta); | ||
| 574 | *delta = (long)res; | ||
| 575 | |||
| 576 | /* Correct the tsc counter value */ | ||
| 577 | if (cpu_has_tsc) { | ||
| 578 | res = (((u64)(*deltatsc)) * pm_100ms); | ||
| 568 | do_div(res, deltapm); | 579 | do_div(res, deltapm); |
| 569 | pr_info("APIC delta adjusted to PM-Timer: " | 580 | apic_printk(APIC_VERBOSE, "TSC delta adjusted to " |
| 570 | "%lu (%ld)\n", (unsigned long)res, *delta); | 581 | "PM-Timer: %lu (%ld) \n", |
| 571 | *delta = (long)res; | 582 | (unsigned long)res, *deltatsc); |
| 583 | *deltatsc = (long)res; | ||
| 572 | } | 584 | } |
| 573 | 585 | ||
| 574 | return 0; | 586 | return 0; |
| @@ -579,7 +591,7 @@ static int __init calibrate_APIC_clock(void) | |||
| 579 | struct clock_event_device *levt = &__get_cpu_var(lapic_events); | 591 | struct clock_event_device *levt = &__get_cpu_var(lapic_events); |
| 580 | void (*real_handler)(struct clock_event_device *dev); | 592 | void (*real_handler)(struct clock_event_device *dev); |
| 581 | unsigned long deltaj; | 593 | unsigned long deltaj; |
| 582 | long delta; | 594 | long delta, deltatsc; |
| 583 | int pm_referenced = 0; | 595 | int pm_referenced = 0; |
| 584 | 596 | ||
| 585 | local_irq_disable(); | 597 | local_irq_disable(); |
| @@ -609,9 +621,11 @@ static int __init calibrate_APIC_clock(void) | |||
| 609 | delta = lapic_cal_t1 - lapic_cal_t2; | 621 | delta = lapic_cal_t1 - lapic_cal_t2; |
| 610 | apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta); | 622 | apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta); |
| 611 | 623 | ||
| 624 | deltatsc = (long)(lapic_cal_tsc2 - lapic_cal_tsc1); | ||
| 625 | |||
| 612 | /* we trust the PM based calibration if possible */ | 626 | /* we trust the PM based calibration if possible */ |
| 613 | pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1, | 627 | pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1, |
| 614 | &delta); | 628 | &delta, &deltatsc); |
| 615 | 629 | ||
| 616 | /* Calculate the scaled math multiplication factor */ | 630 | /* Calculate the scaled math multiplication factor */ |
| 617 | lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS, | 631 | lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS, |
| @@ -629,11 +643,10 @@ static int __init calibrate_APIC_clock(void) | |||
| 629 | calibration_result); | 643 | calibration_result); |
| 630 | 644 | ||
| 631 | if (cpu_has_tsc) { | 645 | if (cpu_has_tsc) { |
| 632 | delta = (long)(lapic_cal_tsc2 - lapic_cal_tsc1); | ||
| 633 | apic_printk(APIC_VERBOSE, "..... CPU clock speed is " | 646 | apic_printk(APIC_VERBOSE, "..... CPU clock speed is " |
| 634 | "%ld.%04ld MHz.\n", | 647 | "%ld.%04ld MHz.\n", |
| 635 | (delta / LAPIC_CAL_LOOPS) / (1000000 / HZ), | 648 | (deltatsc / LAPIC_CAL_LOOPS) / (1000000 / HZ), |
| 636 | (delta / LAPIC_CAL_LOOPS) % (1000000 / HZ)); | 649 | (deltatsc / LAPIC_CAL_LOOPS) % (1000000 / HZ)); |
| 637 | } | 650 | } |
| 638 | 651 | ||
| 639 | apic_printk(APIC_VERBOSE, "..... host bus clock speed is " | 652 | apic_printk(APIC_VERBOSE, "..... host bus clock speed is " |
