aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/x86_64/boot-options.txt5
-rw-r--r--arch/x86_64/kernel/apic.c33
-rw-r--r--arch/x86_64/kernel/pmtimer.c20
-rw-r--r--include/asm-x86_64/proto.h1
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
50Early Console 55Early 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
41int apic_verbosity; 41int apic_verbosity;
42int apic_runs_main_timer; 42int apic_runs_main_timer;
43int apic_calibrate_pmtmr __initdata;
43 44
44int disable_apic_timer __initdata; 45int 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
1132static __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
83static 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 */
94void 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
83void pmtimer_resume(void) 103void 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);
42extern void time_init_gtod(void); 42extern void time_init_gtod(void);
43extern int pmtimer_mark_offset(void); 43extern int pmtimer_mark_offset(void);
44extern void pmtimer_resume(void); 44extern void pmtimer_resume(void);
45extern void pmtimer_wait(unsigned);
45extern unsigned int do_gettimeoffset_pm(void); 46extern unsigned int do_gettimeoffset_pm(void);
46#ifdef CONFIG_X86_PM_TIMER 47#ifdef CONFIG_X86_PM_TIMER
47extern u32 pmtmr_ioport; 48extern u32 pmtmr_ioport;