aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/tsc.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-09-04 11:18:59 -0400
committerIngo Molnar <mingo@elte.hu>2008-09-04 11:35:35 -0400
commita977c400957451f3bd92b9ed6022f5fe8a6cbbf5 (patch)
treeee44967e668e9ee58c7df6ebb09453ceb525c69e /arch/x86/kernel/tsc.c
parent827014be05e4515fa0dfc32e3100c4dab2070a98 (diff)
x86: TSC make the calibration loop smarter
The last changes made the calibration loop 250ms long which is far too much. Try to do that more clever. Experiments have shown that using a 10ms delay for the PIT based calibration gives us a good enough value. If we have a reference (HPET/PMTIMER) and the result of the PIT and the reference is close enough, then we can break out of the calibration loop on a match right away and use the reference value. Otherwise we just loop 3 times and decide then, which value to take. One caveat is that for virtualized environments the PIT calibration often does not work at all and I found out that 10us is a bit too short as well for the reference to give a sane result. The solution here is to make the last loop longer when the first two PIT calibrations failed. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/tsc.c')
-rw-r--r--arch/x86/kernel/tsc.c95
1 files changed, 58 insertions, 37 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 52284d31fc9c..da033b5b3e19 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -159,9 +159,14 @@ static unsigned long calc_pmtimer_ref(u64 deltatsc, u64 pm1, u64 pm2)
159 return (unsigned long) deltatsc; 159 return (unsigned long) deltatsc;
160} 160}
161 161
162#define CAL_MS 50 162#define CAL_MS 10
163#define CAL_LATCH (CLOCK_TICK_RATE / (1000 / CAL_MS)) 163#define CAL_LATCH (CLOCK_TICK_RATE / (1000 / CAL_MS))
164#define CAL_PIT_LOOPS 5000 164#define CAL_PIT_LOOPS 1000
165
166#define CAL2_MS 50
167#define CAL2_LATCH (CLOCK_TICK_RATE / (1000 / CAL2_MS))
168#define CAL2_PIT_LOOPS 5000
169
165 170
166/* 171/*
167 * Try to calibrate the TSC against the Programmable 172 * Try to calibrate the TSC against the Programmable
@@ -170,7 +175,7 @@ static unsigned long calc_pmtimer_ref(u64 deltatsc, u64 pm1, u64 pm2)
170 * 175 *
171 * Return ULONG_MAX on failure to calibrate. 176 * Return ULONG_MAX on failure to calibrate.
172 */ 177 */
173static unsigned long pit_calibrate_tsc(void) 178static unsigned long pit_calibrate_tsc(u32 latch, unsigned long ms, int loopmin)
174{ 179{
175 u64 tsc, t1, t2, delta; 180 u64 tsc, t1, t2, delta;
176 unsigned long tscmin, tscmax; 181 unsigned long tscmin, tscmax;
@@ -185,8 +190,8 @@ static unsigned long pit_calibrate_tsc(void)
185 * (LSB then MSB) to begin countdown. 190 * (LSB then MSB) to begin countdown.
186 */ 191 */
187 outb(0xb0, 0x43); 192 outb(0xb0, 0x43);
188 outb(CAL_LATCH & 0xff, 0x42); 193 outb(latch & 0xff, 0x42);
189 outb(CAL_LATCH >> 8, 0x42); 194 outb(latch >> 8, 0x42);
190 195
191 tsc = t1 = t2 = get_cycles(); 196 tsc = t1 = t2 = get_cycles();
192 197
@@ -207,18 +212,18 @@ static unsigned long pit_calibrate_tsc(void)
207 /* 212 /*
208 * Sanity checks: 213 * Sanity checks:
209 * 214 *
210 * If we were not able to read the PIT more than PIT_MIN_LOOPS 215 * If we were not able to read the PIT more than loopmin
211 * times, then we have been hit by a massive SMI 216 * times, then we have been hit by a massive SMI
212 * 217 *
213 * If the maximum is 10 times larger than the minimum, 218 * If the maximum is 10 times larger than the minimum,
214 * then we got hit by an SMI as well. 219 * then we got hit by an SMI as well.
215 */ 220 */
216 if (pitcnt < CAL_PIT_LOOPS || tscmax > 10 * tscmin) 221 if (pitcnt < loopmin || tscmax > 10 * tscmin)
217 return ULONG_MAX; 222 return ULONG_MAX;
218 223
219 /* Calculate the PIT value */ 224 /* Calculate the PIT value */
220 delta = t2 - t1; 225 delta = t2 - t1;
221 do_div(delta, CAL_MS); 226 do_div(delta, ms);
222 return delta; 227 return delta;
223} 228}
224 229
@@ -230,8 +235,8 @@ unsigned long native_calibrate_tsc(void)
230{ 235{
231 u64 tsc1, tsc2, delta, ref1, ref2; 236 u64 tsc1, tsc2, delta, ref1, ref2;
232 unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; 237 unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX;
233 unsigned long flags; 238 unsigned long flags, latch, ms;
234 int hpet = is_hpet_enabled(), i; 239 int hpet = is_hpet_enabled(), i, loopmin;
235 240
236 /* 241 /*
237 * Run 5 calibration loops to get the lowest frequency value 242 * Run 5 calibration loops to get the lowest frequency value
@@ -257,7 +262,13 @@ unsigned long native_calibrate_tsc(void)
257 * calibration delay loop as we have to wait for a certain 262 * calibration delay loop as we have to wait for a certain
258 * amount of time anyway. 263 * amount of time anyway.
259 */ 264 */
260 for (i = 0; i < 5; i++) { 265
266 /* Preset PIT loop values */
267 latch = CAL_LATCH;
268 ms = CAL_MS;
269 loopmin = CAL_PIT_LOOPS;
270
271 for (i = 0; i < 3; i++) {
261 unsigned long tsc_pit_khz; 272 unsigned long tsc_pit_khz;
262 273
263 /* 274 /*
@@ -268,7 +279,7 @@ unsigned long native_calibrate_tsc(void)
268 */ 279 */
269 local_irq_save(flags); 280 local_irq_save(flags);
270 tsc1 = tsc_read_refs(&ref1, hpet); 281 tsc1 = tsc_read_refs(&ref1, hpet);
271 tsc_pit_khz = pit_calibrate_tsc(); 282 tsc_pit_khz = pit_calibrate_tsc(latch, ms, loopmin);
272 tsc2 = tsc_read_refs(&ref2, hpet); 283 tsc2 = tsc_read_refs(&ref2, hpet);
273 local_irq_restore(flags); 284 local_irq_restore(flags);
274 285
@@ -290,6 +301,35 @@ unsigned long native_calibrate_tsc(void)
290 tsc2 = calc_pmtimer_ref(tsc2, ref1, ref2); 301 tsc2 = calc_pmtimer_ref(tsc2, ref1, ref2);
291 302
292 tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2); 303 tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2);
304
305 /* Check the reference deviation */
306 delta = ((u64) tsc_pit_min) * 100;
307 do_div(delta, tsc_ref_min);
308
309 /*
310 * If both calibration results are inside a 10% window
311 * then we can be sure, that the calibration
312 * succeeded. We break out of the loop right away. We
313 * use the reference value, as it is more precise.
314 */
315 if (delta >= 90 && delta <= 110) {
316 printk(KERN_INFO
317 "TSC: PIT calibration matches %s. %d loops\n",
318 hpet ? "HPET" : "PMTIMER", i + 1);
319 return tsc_ref_min;
320 }
321
322 /*
323 * Check whether PIT failed more than once. This
324 * happens in virtualized environments. We need to
325 * give the virtual PC a slightly longer timeframe for
326 * the HPET/PMTIMER to make the result precise.
327 */
328 if (i == 1 && tsc_pit_min == ULONG_MAX) {
329 latch = CAL2_LATCH;
330 ms = CAL2_MS;
331 loopmin = CAL2_PIT_LOOPS;
332 }
293 } 333 }
294 334
295 /* 335 /*
@@ -309,7 +349,7 @@ unsigned long native_calibrate_tsc(void)
309 /* The alternative source failed as well, disable TSC */ 349 /* The alternative source failed as well, disable TSC */
310 if (tsc_ref_min == ULONG_MAX) { 350 if (tsc_ref_min == ULONG_MAX) {
311 printk(KERN_WARNING "TSC: HPET/PMTIMER calibration " 351 printk(KERN_WARNING "TSC: HPET/PMTIMER calibration "
312 "failed due to SMI disturbance.\n"); 352 "failed.\n");
313 return 0; 353 return 0;
314 } 354 }
315 355
@@ -328,37 +368,18 @@ unsigned long native_calibrate_tsc(void)
328 368
329 /* The alternative source failed, use the PIT calibration value */ 369 /* The alternative source failed, use the PIT calibration value */
330 if (tsc_ref_min == ULONG_MAX) { 370 if (tsc_ref_min == ULONG_MAX) {
331 printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed due " 371 printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed. "
332 "to SMI disturbance. Using PIT calibration\n"); 372 "Using PIT calibration\n");
333 return tsc_pit_min; 373 return tsc_pit_min;
334 } 374 }
335 375
336 /* Check the reference deviation */
337 delta = ((u64) tsc_pit_min) * 100;
338 do_div(delta, tsc_ref_min);
339
340 /*
341 * If both calibration results are inside a 5% window, the we
342 * use the lower frequency of those as it is probably the
343 * closest estimate.
344 */
345 if (delta >= 95 && delta <= 105) {
346 printk(KERN_INFO "TSC: PIT calibration confirmed by %s.\n",
347 hpet ? "HPET" : "PMTIMER");
348 printk(KERN_INFO "TSC: using %s calibration value\n",
349 tsc_pit_min <= tsc_ref_min ? "PIT" :
350 hpet ? "HPET" : "PMTIMER");
351 return tsc_pit_min <= tsc_ref_min ? tsc_pit_min : tsc_ref_min;
352 }
353
354 printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n",
355 hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
356
357 /* 376 /*
358 * The calibration values differ too much. In doubt, we use 377 * The calibration values differ too much. In doubt, we use
359 * the PIT value as we know that there are PMTIMERs around 378 * the PIT value as we know that there are PMTIMERs around
360 * running at double speed. 379 * running at double speed. At least we let the user know:
361 */ 380 */
381 printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n",
382 hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
362 printk(KERN_INFO "TSC: Using PIT calibration value\n"); 383 printk(KERN_INFO "TSC: Using PIT calibration value\n");
363 return tsc_pit_min; 384 return tsc_pit_min;
364} 385}