aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDave Johnson <djohnson@sw.starentnetworks.com>2007-10-23 16:37:22 -0400
committerThomas Gleixner <tglx@linutronix.de>2007-10-23 16:37:22 -0400
commit8c660065383976f09fbdae86c33448c8da643d4e (patch)
tree2d5dd9da1abdeb2678693c88a3c05fd80c0a2e0e /arch
parentedaf420fdc122e7a42326fe39274c8b8c9b19d41 (diff)
x86: fix more TSC clock source calibration errors
The previous patch wasn't correctly handling the 'count' variable. If a CPU gave bad results on the 1st or 2nd run but good results on the 3rd, it wouldn't do the correct thing. No idea if any such CPU exists, but the patch below handles that case by discarding the bad runs. If a bad result (too quick, or too slow) occurs on any of the 3 runs it will be discarded. Also updated some comments to explain what's going on. Signed-off-by: Dave Johnson <djohnson@sw.starentnetworks.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/tsc_32.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/arch/x86/kernel/tsc_32.c b/arch/x86/kernel/tsc_32.c
index f04d08a7d022..9ebc0dab66b4 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)
137 137
138 local_irq_save(flags); 138 local_irq_save(flags);
139 139
140 /* run 3 times to ensure the cache is warm */ 140 /* run 3 times to ensure the cache is warm and to get an accurate reading */
141 for (i = 0; i < 3; i++) { 141 for (i = 0; i < 3; i++) {
142 mach_prepare_counter(); 142 mach_prepare_counter();
143 rdtscll(start); 143 rdtscll(start);
144 mach_countup(&count); 144 mach_countup(&count);
145 rdtscll(end); 145 rdtscll(end);
146
147 /*
148 * Error: ECTCNEVERSET
149 * The CTC wasn't reliable: we got a hit on the very first read,
150 * or the CPU was so fast/slow that the quotient wouldn't fit in
151 * 32 bits..
152 */
153 if (count <= 1)
154 continue;
155
156 /* cpu freq too slow: */
157 if ((end - start) <= CALIBRATE_TIME_MSEC)
158 continue;
159
160 /*
161 * We want the minimum time of all runs in case one of them
162 * is inaccurate due to SMI or other delay
163 */
146 delta64 = min(delta64, (end - start)); 164 delta64 = min(delta64, (end - start));
147 } 165 }
148 /*
149 * Error: ECTCNEVERSET
150 * The CTC wasn't reliable: we got a hit on the very first read,
151 * or the CPU was so fast/slow that the quotient wouldn't fit in
152 * 32 bits..
153 */
154 if (count <= 1)
155 goto err;
156 166
157 /* cpu freq too fast: */ 167 /* cpu freq too fast (or every run was bad): */
158 if (delta64 > (1ULL<<32)) 168 if (delta64 > (1ULL<<32))
159 goto err; 169 goto err;
160 170
161 /* cpu freq too slow: */
162 if (delta64 <= CALIBRATE_TIME_MSEC)
163 goto err;
164
165 delta64 += CALIBRATE_TIME_MSEC/2; /* round for do_div */ 171 delta64 += CALIBRATE_TIME_MSEC/2; /* round for do_div */
166 do_div(delta64,CALIBRATE_TIME_MSEC); 172 do_div(delta64,CALIBRATE_TIME_MSEC);
167 173