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; |