diff options
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/tsc_32.c | 34 |
1 files changed, 20 insertions, 14 deletions
diff --git a/arch/x86/kernel/tsc_32.c b/arch/x86/kernel/tsc_32.c index f04d08a7d02..9ebc0dab66b 100644 --- a/arch/x86/kernel/tsc_32.c +++ b/arch/x86/kernel/tsc_32.c @@ -137,31 +137,37 @@ unsigned long native_calculate_cpu_khz(void) local_irq_save(flags); - /* run 3 times to ensure the cache is warm */ + /* run 3 times to ensure the cache is warm and to get an accurate reading */ for (i = 0; i < 3; i++) { mach_prepare_counter(); rdtscll(start); mach_countup(&count); rdtscll(end); + + /* + * Error: ECTCNEVERSET + * The CTC wasn't reliable: we got a hit on the very first read, + * or the CPU was so fast/slow that the quotient wouldn't fit in + * 32 bits.. + */ + if (count <= 1) + continue; + + /* cpu freq too slow: */ + if ((end - start) <= CALIBRATE_TIME_MSEC) + continue; + + /* + * We want the minimum time of all runs in case one of them + * is inaccurate due to SMI or other delay + */ delta64 = min(delta64, (end - start)); } - /* - * Error: ECTCNEVERSET - * The CTC wasn't reliable: we got a hit on the very first read, - * or the CPU was so fast/slow that the quotient wouldn't fit in - * 32 bits.. - */ - if (count <= 1) - goto err; - /* cpu freq too fast: */ + /* cpu freq too fast (or every run was bad): */ if (delta64 > (1ULL<<32)) goto err; - /* cpu freq too slow: */ - if (delta64 <= CALIBRATE_TIME_MSEC) - goto err; - delta64 += CALIBRATE_TIME_MSEC/2; /* round for do_div */ do_div(delta64,CALIBRATE_TIME_MSEC); |