diff options
| -rw-r--r-- | Documentation/x86_64/boot-options.txt | 5 | ||||
| -rw-r--r-- | arch/x86_64/kernel/apic.c | 33 | ||||
| -rw-r--r-- | arch/x86_64/kernel/pmtimer.c | 20 | ||||
| -rw-r--r-- | include/asm-x86_64/proto.h | 1 |
4 files changed, 53 insertions, 6 deletions
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt index 654ea4fccff8..153740f460a6 100644 --- a/Documentation/x86_64/boot-options.txt +++ b/Documentation/x86_64/boot-options.txt | |||
| @@ -47,6 +47,11 @@ APICs | |||
| 47 | noapicmaintimer Don't do time keeping using the APIC timer. | 47 | noapicmaintimer Don't do time keeping using the APIC timer. |
| 48 | Useful when this option was auto selected, but doesn't work. | 48 | Useful when this option was auto selected, but doesn't work. |
| 49 | 49 | ||
| 50 | apicpmtimer | ||
| 51 | Do APIC timer calibration using the pmtimer. Implies | ||
| 52 | apicmaintimer. Useful when your PIT timer is totally | ||
| 53 | broken. | ||
| 54 | |||
| 50 | Early Console | 55 | Early Console |
| 51 | 56 | ||
| 52 | syntax: earlyprintk=vga | 57 | syntax: earlyprintk=vga |
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 673a2fe9923c..c02218b3ae2b 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | 40 | ||
| 41 | int apic_verbosity; | 41 | int apic_verbosity; |
| 42 | int apic_runs_main_timer; | 42 | int apic_runs_main_timer; |
| 43 | int apic_calibrate_pmtmr __initdata; | ||
| 43 | 44 | ||
| 44 | int disable_apic_timer __initdata; | 45 | int disable_apic_timer __initdata; |
| 45 | 46 | ||
| @@ -746,14 +747,27 @@ static int __init calibrate_APIC_clock(void) | |||
| 746 | __setup_APIC_LVTT(1000000000); | 747 | __setup_APIC_LVTT(1000000000); |
| 747 | 748 | ||
| 748 | apic_start = apic_read(APIC_TMCCT); | 749 | apic_start = apic_read(APIC_TMCCT); |
| 749 | rdtscl(tsc_start); | 750 | #ifdef CONFIG_X86_PM_TIMER |
| 750 | 751 | if (apic_calibrate_pmtmr && pmtmr_ioport) { | |
| 751 | do { | 752 | pmtimer_wait(5000); /* 5ms wait */ |
| 752 | apic = apic_read(APIC_TMCCT); | 753 | apic = apic_read(APIC_TMCCT); |
| 753 | rdtscl(tsc); | 754 | result = (apic_start - apic) * 1000L / 5; |
| 754 | } while ((tsc - tsc_start) < TICK_COUNT && (apic - apic_start) < TICK_COUNT); | 755 | } else |
| 756 | #endif | ||
| 757 | { | ||
| 758 | rdtscl(tsc_start); | ||
| 759 | |||
| 760 | do { | ||
| 761 | apic = apic_read(APIC_TMCCT); | ||
| 762 | rdtscl(tsc); | ||
| 763 | } while ((tsc - tsc_start) < TICK_COUNT && | ||
| 764 | (apic - apic_start) < TICK_COUNT); | ||
| 765 | |||
| 766 | result = (apic_start - apic) * 1000L * cpu_khz / | ||
| 767 | (tsc - tsc_start); | ||
| 768 | } | ||
| 769 | printk("result %d\n", result); | ||
| 755 | 770 | ||
| 756 | result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start); | ||
| 757 | 771 | ||
| 758 | printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", | 772 | printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", |
| 759 | result / 1000 / 1000, result / 1000 % 1000); | 773 | result / 1000 / 1000, result / 1000 % 1000); |
| @@ -1115,6 +1129,13 @@ static __init int setup_noapicmaintimer(char *str) | |||
| 1115 | } | 1129 | } |
| 1116 | __setup("noapicmaintimer", setup_noapicmaintimer); | 1130 | __setup("noapicmaintimer", setup_noapicmaintimer); |
| 1117 | 1131 | ||
| 1132 | static __init int setup_apicpmtimer(char *s) | ||
| 1133 | { | ||
| 1134 | apic_calibrate_pmtmr = 1; | ||
| 1135 | return setup_apicmaintimer(NULL); | ||
| 1136 | } | ||
| 1137 | __setup("apicpmtimer", setup_apicpmtimer); | ||
| 1138 | |||
| 1118 | /* dummy parsing: see setup.c */ | 1139 | /* dummy parsing: see setup.c */ |
| 1119 | 1140 | ||
| 1120 | __setup("disableapic", setup_disableapic); | 1141 | __setup("disableapic", setup_disableapic); |
diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c index 8b2655ae4e61..5c51d10408a6 100644 --- a/arch/x86_64/kernel/pmtimer.c +++ b/arch/x86_64/kernel/pmtimer.c | |||
| @@ -80,6 +80,26 @@ int pmtimer_mark_offset(void) | |||
| 80 | return lost - 1; | 80 | return lost - 1; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | static unsigned pmtimer_wait_tick(void) | ||
| 84 | { | ||
| 85 | u32 a, b; | ||
| 86 | for (a = b = inl(pmtmr_ioport) & ACPI_PM_MASK; | ||
| 87 | a == b; | ||
| 88 | b = inl(pmtmr_ioport) & ACPI_PM_MASK) | ||
| 89 | ; | ||
| 90 | return b; | ||
| 91 | } | ||
| 92 | |||
| 93 | /* note: wait time is rounded up to one tick */ | ||
| 94 | void pmtimer_wait(unsigned us) | ||
| 95 | { | ||
| 96 | u32 a, b; | ||
| 97 | a = pmtimer_wait_tick(); | ||
| 98 | do { | ||
| 99 | b = inl(pmtmr_ioport); | ||
| 100 | } while (cyc2us(b - a) < us); | ||
| 101 | } | ||
| 102 | |||
| 83 | void pmtimer_resume(void) | 103 | void pmtimer_resume(void) |
| 84 | { | 104 | { |
| 85 | last_pmtmr_tick = inl(pmtmr_ioport); | 105 | last_pmtmr_tick = inl(pmtmr_ioport); |
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index a6748b9568fe..c99832e7bf3f 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h | |||
| @@ -42,6 +42,7 @@ extern void iommu_hole_init(void); | |||
| 42 | extern void time_init_gtod(void); | 42 | extern void time_init_gtod(void); |
| 43 | extern int pmtimer_mark_offset(void); | 43 | extern int pmtimer_mark_offset(void); |
| 44 | extern void pmtimer_resume(void); | 44 | extern void pmtimer_resume(void); |
| 45 | extern void pmtimer_wait(unsigned); | ||
| 45 | extern unsigned int do_gettimeoffset_pm(void); | 46 | extern unsigned int do_gettimeoffset_pm(void); |
| 46 | #ifdef CONFIG_X86_PM_TIMER | 47 | #ifdef CONFIG_X86_PM_TIMER |
| 47 | extern u32 pmtmr_ioport; | 48 | extern u32 pmtmr_ioport; |
