aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/tsc.c132
1 files changed, 71 insertions, 61 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index ac79bd143da8..346cae5ac423 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -122,15 +122,75 @@ static u64 tsc_read_refs(u64 *pm, u64 *hpet)
122 return ULLONG_MAX; 122 return ULLONG_MAX;
123} 123}
124 124
125/*
126 * Try to calibrate the TSC against the Programmable
127 * Interrupt Timer and return the frequency of the TSC
128 * in kHz.
129 *
130 * Return ULONG_MAX on failure to calibrate.
131 */
132static unsigned long pit_calibrate_tsc(void)
133{
134 u64 tsc, t1, t2, delta;
135 unsigned long tscmin, tscmax;
136 int pitcnt;
137
138 /* Set the Gate high, disable speaker */
139 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
140
141 /*
142 * Setup CTC channel 2* for mode 0, (interrupt on terminal
143 * count mode), binary count. Set the latch register to 50ms
144 * (LSB then MSB) to begin countdown.
145 */
146 outb(0xb0, 0x43);
147 outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
148 outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
149
150 tsc = t1 = t2 = get_cycles();
151
152 pitcnt = 0;
153 tscmax = 0;
154 tscmin = ULONG_MAX;
155 while ((inb(0x61) & 0x20) == 0) {
156 t2 = get_cycles();
157 delta = t2 - tsc;
158 tsc = t2;
159 if ((unsigned long) delta < tscmin)
160 tscmin = (unsigned int) delta;
161 if ((unsigned long) delta > tscmax)
162 tscmax = (unsigned int) delta;
163 pitcnt++;
164 }
165
166 /*
167 * Sanity checks:
168 *
169 * If we were not able to read the PIT more than 5000
170 * times, then we have been hit by a massive SMI
171 *
172 * If the maximum is 10 times larger than the minimum,
173 * then we got hit by an SMI as well.
174 */
175 if (pitcnt < 5000 || tscmax > 10 * tscmin)
176 return ULONG_MAX;
177
178 /* Calculate the PIT value */
179 delta = t2 - t1;
180 do_div(delta, 50);
181 return delta;
182}
183
184
125/** 185/**
126 * native_calibrate_tsc - calibrate the tsc on boot 186 * native_calibrate_tsc - calibrate the tsc on boot
127 */ 187 */
128unsigned long native_calibrate_tsc(void) 188unsigned long native_calibrate_tsc(void)
129{ 189{
130 u64 tsc1, tsc2, tr1, tr2, tsc, delta, pm1, pm2, hpet1, hpet2; 190 u64 tsc1, tsc2, delta, pm1, pm2, hpet1, hpet2;
131 unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; 191 unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX;
132 unsigned long flags, tscmin, tscmax; 192 unsigned long flags;
133 int hpet = is_hpet_enabled(), pitcnt, i; 193 int hpet = is_hpet_enabled(), i;
134 194
135 /* 195 /*
136 * Run 5 calibration loops to get the lowest frequency value 196 * Run 5 calibration loops to get the lowest frequency value
@@ -157,72 +217,22 @@ unsigned long native_calibrate_tsc(void)
157 * amount of time anyway. 217 * amount of time anyway.
158 */ 218 */
159 for (i = 0; i < 5; i++) { 219 for (i = 0; i < 5; i++) {
160 220 unsigned long tsc_pit_khz;
161 tscmin = ULONG_MAX;
162 tscmax = 0;
163 pitcnt = 0;
164
165 local_irq_save(flags);
166 221
167 /* 222 /*
168 * Read the start value and the reference count of 223 * Read the start value and the reference count of
169 * hpet/pmtimer when available: 224 * hpet/pmtimer when available. Then do the PIT
225 * calibration, which will take at least 50ms, and
226 * read the end value.
170 */ 227 */
228 local_irq_save(flags);
171 tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); 229 tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
172 230 tsc_pit_khz = pit_calibrate_tsc();
173 /* Set the Gate high, disable speaker */
174 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
175
176 /*
177 * Setup CTC channel 2* for mode 0, (interrupt on terminal
178 * count mode), binary count. Set the latch register to 50ms
179 * (LSB then MSB) to begin countdown.
180 *
181 * Some devices need a delay here.
182 */
183 outb(0xb0, 0x43);
184 outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
185 outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
186
187 tsc = tr1 = tr2 = get_cycles();
188
189 while ((inb(0x61) & 0x20) == 0) {
190 tr2 = get_cycles();
191 delta = tr2 - tsc;
192 tsc = tr2;
193 if ((unsigned int) delta < tscmin)
194 tscmin = (unsigned int) delta;
195 if ((unsigned int) delta > tscmax)
196 tscmax = (unsigned int) delta;
197 pitcnt++;
198 }
199
200 /*
201 * We waited at least 50ms above. Now read
202 * pmtimer/hpet reference again
203 */
204 tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); 231 tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
205
206 local_irq_restore(flags); 232 local_irq_restore(flags);
207 233
208 /* 234 /* Pick the lowest PIT TSC calibration so far */
209 * Sanity checks: 235 tsc_pit_min = min(tsc_pit_min, tsc_pit_khz);
210 *
211 * If we were not able to read the PIT more than 5000
212 * times, then we have been hit by a massive SMI
213 *
214 * If the maximum is 10 times larger than the minimum,
215 * then we got hit by an SMI as well.
216 */
217 if (pitcnt > 5000 && tscmax < 10 * tscmin) {
218
219 /* Calculate the PIT value */
220 delta = tr2 - tr1;
221 do_div(delta, 50);
222
223 /* We take the smallest value into account */
224 tsc_pit_min = min(tsc_pit_min, (unsigned long) delta);
225 }
226 236
227 /* hpet or pmtimer available ? */ 237 /* hpet or pmtimer available ? */
228 if (!hpet && !pm1 && !pm2) 238 if (!hpet && !pm1 && !pm2)