aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/tsc.c
diff options
context:
space:
mode:
authorjohn stultz <johnstul@us.ibm.com>2007-03-05 03:30:50 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-05 10:57:53 -0500
commit6bb74df481223731af6c7e0ff3adb31f6442cfcd (patch)
tree2aa0b0cfa55cb4b9a9236bd94b723d83eb0bdaa8 /arch/i386/kernel/tsc.c
parent4540768011352d38afb89d400eacb3e261507b70 (diff)
[PATCH] clocksource init adjustments (fix bug #7426)
This patch resolves the issue found here: http://bugme.osdl.org/show_bug.cgi?id=7426 The basic summary is: Currently we register most of i386/x86_64 clocksources at module_init time. Then we enable clocksource selection at late_initcall time. This causes some problems for drivers that use gettimeofday for init calibration routines (specifically the es1968 driver in this case), where durring module_init, the only clocksource available is the low-res jiffies clocksource. This may cause slight calibration errors, due to the small sampling time used. It should be noted that drivers that require fine grained time may not function on architectures that do not have better then jiffies resolution timekeeping (there are a few). However, this does not discount the reasonable need for such fine-grained timekeeping at init time. Thus the solution here is to register clocksources earlier (ideally when the hardware is being initialized), and then we enable clocksource selection at fs_initcall (before device_initcall). This patch should probably get some testing time in -mm, since clocksource selection is one of the most important issues for correct timekeeping, and I've only been able to test this on a few of my own boxes. Signed-off-by: John Stultz <johnstul@us.ibm.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@elte.hu> Cc: "David S. Miller" <davem@davemloft.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/i386/kernel/tsc.c')
-rw-r--r--arch/i386/kernel/tsc.c83
1 files changed, 37 insertions, 46 deletions
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index 59222a04234b..875d8a6ecc02 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -184,34 +184,6 @@ int recalibrate_cpu_khz(void)
184 184
185EXPORT_SYMBOL(recalibrate_cpu_khz); 185EXPORT_SYMBOL(recalibrate_cpu_khz);
186 186
187void __init tsc_init(void)
188{
189 if (!cpu_has_tsc || tsc_disable)
190 goto out_no_tsc;
191
192 cpu_khz = calculate_cpu_khz();
193 tsc_khz = cpu_khz;
194
195 if (!cpu_khz)
196 goto out_no_tsc;
197
198 printk("Detected %lu.%03lu MHz processor.\n",
199 (unsigned long)cpu_khz / 1000,
200 (unsigned long)cpu_khz % 1000);
201
202 set_cyc2ns_scale(cpu_khz);
203 use_tsc_delay();
204 return;
205
206out_no_tsc:
207 /*
208 * Set the tsc_disable flag if there's no TSC support, this
209 * makes it a fast flag for the kernel to see whether it
210 * should be using the TSC.
211 */
212 tsc_disable = 1;
213}
214
215#ifdef CONFIG_CPU_FREQ 187#ifdef CONFIG_CPU_FREQ
216 188
217/* 189/*
@@ -381,28 +353,47 @@ static void __init check_geode_tsc_reliable(void)
381static inline void check_geode_tsc_reliable(void) { } 353static inline void check_geode_tsc_reliable(void) { }
382#endif 354#endif
383 355
384static int __init init_tsc_clocksource(void) 356
357void __init tsc_init(void)
385{ 358{
359 if (!cpu_has_tsc || tsc_disable)
360 goto out_no_tsc;
386 361
387 if (cpu_has_tsc && tsc_khz && !tsc_disable) { 362 cpu_khz = calculate_cpu_khz();
388 /* check blacklist */ 363 tsc_khz = cpu_khz;
389 dmi_check_system(bad_tsc_dmi_table);
390 364
391 unsynchronized_tsc(); 365 if (!cpu_khz)
392 check_geode_tsc_reliable(); 366 goto out_no_tsc;
393 current_tsc_khz = tsc_khz;
394 clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
395 clocksource_tsc.shift);
396 /* lower the rating if we already know its unstable: */
397 if (check_tsc_unstable()) {
398 clocksource_tsc.rating = 0;
399 clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
400 }
401 367
402 return clocksource_register(&clocksource_tsc); 368 printk("Detected %lu.%03lu MHz processor.\n",
369 (unsigned long)cpu_khz / 1000,
370 (unsigned long)cpu_khz % 1000);
371
372 set_cyc2ns_scale(cpu_khz);
373 use_tsc_delay();
374
375 /* Check and install the TSC clocksource */
376 dmi_check_system(bad_tsc_dmi_table);
377
378 unsynchronized_tsc();
379 check_geode_tsc_reliable();
380 current_tsc_khz = tsc_khz;
381 clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
382 clocksource_tsc.shift);
383 /* lower the rating if we already know its unstable: */
384 if (check_tsc_unstable()) {
385 clocksource_tsc.rating = 0;
386 clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
403 } 387 }
388 clocksource_register(&clocksource_tsc);
404 389
405 return 0; 390 return;
406}
407 391
408module_init(init_tsc_clocksource); 392out_no_tsc:
393 /*
394 * Set the tsc_disable flag if there's no TSC support, this
395 * makes it a fast flag for the kernel to see whether it
396 * should be using the TSC.
397 */
398 tsc_disable = 1;
399}