aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/tsc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/tsc.c')
-rw-r--r--arch/i386/kernel/tsc.c195
1 files changed, 64 insertions, 131 deletions
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index 2cfc7b09b925..3082a418635c 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -23,6 +23,7 @@
23 * an extra value to store the TSC freq 23 * an extra value to store the TSC freq
24 */ 24 */
25unsigned int tsc_khz; 25unsigned int tsc_khz;
26unsigned long long (*custom_sched_clock)(void);
26 27
27int tsc_disable; 28int tsc_disable;
28 29
@@ -59,12 +60,6 @@ static inline int check_tsc_unstable(void)
59 return tsc_unstable; 60 return tsc_unstable;
60} 61}
61 62
62void mark_tsc_unstable(void)
63{
64 tsc_unstable = 1;
65}
66EXPORT_SYMBOL_GPL(mark_tsc_unstable);
67
68/* Accellerators for sched_clock() 63/* Accellerators for sched_clock()
69 * convert from cycles(64bits) => nanoseconds (64bits) 64 * convert from cycles(64bits) => nanoseconds (64bits)
70 * basic equation: 65 * basic equation:
@@ -107,14 +102,14 @@ unsigned long long sched_clock(void)
107{ 102{
108 unsigned long long this_offset; 103 unsigned long long this_offset;
109 104
105 if (unlikely(custom_sched_clock))
106 return (*custom_sched_clock)();
107
110 /* 108 /*
111 * in the NUMA case we dont use the TSC as they are not 109 * Fall back to jiffies if there's no TSC available:
112 * synchronized across all CPUs.
113 */ 110 */
114#ifndef CONFIG_NUMA 111 if (unlikely(tsc_disable))
115 if (!cpu_khz || check_tsc_unstable()) 112 /* No locking but a rare wrong value is not a big deal: */
116#endif
117 /* no locking but a rare wrong value is not a big deal */
118 return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ); 113 return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
119 114
120 /* read the Time Stamp Counter: */ 115 /* read the Time Stamp Counter: */
@@ -194,13 +189,13 @@ EXPORT_SYMBOL(recalibrate_cpu_khz);
194void __init tsc_init(void) 189void __init tsc_init(void)
195{ 190{
196 if (!cpu_has_tsc || tsc_disable) 191 if (!cpu_has_tsc || tsc_disable)
197 return; 192 goto out_no_tsc;
198 193
199 cpu_khz = calculate_cpu_khz(); 194 cpu_khz = calculate_cpu_khz();
200 tsc_khz = cpu_khz; 195 tsc_khz = cpu_khz;
201 196
202 if (!cpu_khz) 197 if (!cpu_khz)
203 return; 198 goto out_no_tsc;
204 199
205 printk("Detected %lu.%03lu MHz processor.\n", 200 printk("Detected %lu.%03lu MHz processor.\n",
206 (unsigned long)cpu_khz / 1000, 201 (unsigned long)cpu_khz / 1000,
@@ -208,37 +203,18 @@ void __init tsc_init(void)
208 203
209 set_cyc2ns_scale(cpu_khz); 204 set_cyc2ns_scale(cpu_khz);
210 use_tsc_delay(); 205 use_tsc_delay();
211} 206 return;
212 207
213#ifdef CONFIG_CPU_FREQ 208out_no_tsc:
214 209 /*
215static unsigned int cpufreq_delayed_issched = 0; 210 * Set the tsc_disable flag if there's no TSC support, this
216static unsigned int cpufreq_init = 0; 211 * makes it a fast flag for the kernel to see whether it
217static struct work_struct cpufreq_delayed_get_work; 212 * should be using the TSC.
218 213 */
219static void handle_cpufreq_delayed_get(struct work_struct *work) 214 tsc_disable = 1;
220{
221 unsigned int cpu;
222
223 for_each_online_cpu(cpu)
224 cpufreq_get(cpu);
225
226 cpufreq_delayed_issched = 0;
227} 215}
228 216
229/* 217#ifdef CONFIG_CPU_FREQ
230 * if we notice cpufreq oddness, schedule a call to cpufreq_get() as it tries
231 * to verify the CPU frequency the timing core thinks the CPU is running
232 * at is still correct.
233 */
234static inline void cpufreq_delayed_get(void)
235{
236 if (cpufreq_init && !cpufreq_delayed_issched) {
237 cpufreq_delayed_issched = 1;
238 printk(KERN_DEBUG "Checking if CPU frequency changed.\n");
239 schedule_work(&cpufreq_delayed_get_work);
240 }
241}
242 218
243/* 219/*
244 * if the CPU frequency is scaled, TSC-based delays will need a different 220 * if the CPU frequency is scaled, TSC-based delays will need a different
@@ -303,17 +279,9 @@ static struct notifier_block time_cpufreq_notifier_block = {
303 279
304static int __init cpufreq_tsc(void) 280static int __init cpufreq_tsc(void)
305{ 281{
306 int ret; 282 return cpufreq_register_notifier(&time_cpufreq_notifier_block,
307 283 CPUFREQ_TRANSITION_NOTIFIER);
308 INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get);
309 ret = cpufreq_register_notifier(&time_cpufreq_notifier_block,
310 CPUFREQ_TRANSITION_NOTIFIER);
311 if (!ret)
312 cpufreq_init = 1;
313
314 return ret;
315} 284}
316
317core_initcall(cpufreq_tsc); 285core_initcall(cpufreq_tsc);
318 286
319#endif 287#endif
@@ -321,7 +289,6 @@ core_initcall(cpufreq_tsc);
321/* clock source code */ 289/* clock source code */
322 290
323static unsigned long current_tsc_khz = 0; 291static unsigned long current_tsc_khz = 0;
324static int tsc_update_callback(void);
325 292
326static cycle_t read_tsc(void) 293static cycle_t read_tsc(void)
327{ 294{
@@ -339,37 +306,28 @@ static struct clocksource clocksource_tsc = {
339 .mask = CLOCKSOURCE_MASK(64), 306 .mask = CLOCKSOURCE_MASK(64),
340 .mult = 0, /* to be set */ 307 .mult = 0, /* to be set */
341 .shift = 22, 308 .shift = 22,
342 .update_callback = tsc_update_callback, 309 .flags = CLOCK_SOURCE_IS_CONTINUOUS |
343 .is_continuous = 1, 310 CLOCK_SOURCE_MUST_VERIFY,
344}; 311};
345 312
346static int tsc_update_callback(void) 313void mark_tsc_unstable(void)
347{ 314{
348 int change = 0; 315 if (!tsc_unstable) {
349 316 tsc_unstable = 1;
350 /* check to see if we should switch to the safe clocksource: */ 317 /* Can be called before registration */
351 if (clocksource_tsc.rating != 0 && check_tsc_unstable()) { 318 if (clocksource_tsc.mult)
352 clocksource_tsc.rating = 0; 319 clocksource_change_rating(&clocksource_tsc, 0);
353 clocksource_reselect(); 320 else
354 change = 1; 321 clocksource_tsc.rating = 0;
355 }
356
357 /* only update if tsc_khz has changed: */
358 if (current_tsc_khz != tsc_khz) {
359 current_tsc_khz = tsc_khz;
360 clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
361 clocksource_tsc.shift);
362 change = 1;
363 } 322 }
364
365 return change;
366} 323}
324EXPORT_SYMBOL_GPL(mark_tsc_unstable);
367 325
368static int __init dmi_mark_tsc_unstable(struct dmi_system_id *d) 326static int __init dmi_mark_tsc_unstable(struct dmi_system_id *d)
369{ 327{
370 printk(KERN_NOTICE "%s detected: marking TSC unstable.\n", 328 printk(KERN_NOTICE "%s detected: marking TSC unstable.\n",
371 d->ident); 329 d->ident);
372 mark_tsc_unstable(); 330 tsc_unstable = 1;
373 return 0; 331 return 0;
374} 332}
375 333
@@ -386,65 +344,44 @@ static struct dmi_system_id __initdata bad_tsc_dmi_table[] = {
386 {} 344 {}
387}; 345};
388 346
389#define TSC_FREQ_CHECK_INTERVAL (10*MSEC_PER_SEC) /* 10sec in MS */
390static struct timer_list verify_tsc_freq_timer;
391
392/* XXX - Probably should add locking */
393static void verify_tsc_freq(unsigned long unused)
394{
395 static u64 last_tsc;
396 static unsigned long last_jiffies;
397
398 u64 now_tsc, interval_tsc;
399 unsigned long now_jiffies, interval_jiffies;
400
401
402 if (check_tsc_unstable())
403 return;
404
405 rdtscll(now_tsc);
406 now_jiffies = jiffies;
407
408 if (!last_jiffies) {
409 goto out;
410 }
411
412 interval_jiffies = now_jiffies - last_jiffies;
413 interval_tsc = now_tsc - last_tsc;
414 interval_tsc *= HZ;
415 do_div(interval_tsc, cpu_khz*1000);
416
417 if (interval_tsc < (interval_jiffies * 3 / 4)) {
418 printk("TSC appears to be running slowly. "
419 "Marking it as unstable\n");
420 mark_tsc_unstable();
421 return;
422 }
423
424out:
425 last_tsc = now_tsc;
426 last_jiffies = now_jiffies;
427 /* set us up to go off on the next interval: */
428 mod_timer(&verify_tsc_freq_timer,
429 jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL));
430}
431
432/* 347/*
433 * Make an educated guess if the TSC is trustworthy and synchronized 348 * Make an educated guess if the TSC is trustworthy and synchronized
434 * over all CPUs. 349 * over all CPUs.
435 */ 350 */
436static __init int unsynchronized_tsc(void) 351__cpuinit int unsynchronized_tsc(void)
437{ 352{
353 if (!cpu_has_tsc || tsc_unstable)
354 return 1;
438 /* 355 /*
439 * Intel systems are normally all synchronized. 356 * Intel systems are normally all synchronized.
440 * Exceptions must mark TSC as unstable: 357 * Exceptions must mark TSC as unstable:
441 */ 358 */
442 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) 359 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
443 return 0; 360 /* assume multi socket systems are not synchronized: */
361 if (num_possible_cpus() > 1)
362 tsc_unstable = 1;
363 }
364 return tsc_unstable;
365}
366
367/*
368 * Geode_LX - the OLPC CPU has a possibly a very reliable TSC
369 */
370#ifdef CONFIG_MGEODE_LX
371/* RTSC counts during suspend */
372#define RTSC_SUSP 0x100
373
374static void __init check_geode_tsc_reliable(void)
375{
376 unsigned long val;
444 377
445 /* assume multi socket systems are not synchronized: */ 378 rdmsrl(MSR_GEODE_BUSCONT_CONF0, val);
446 return num_possible_cpus() > 1; 379 if ((val & RTSC_SUSP))
380 clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
447} 381}
382#else
383static inline void check_geode_tsc_reliable(void) { }
384#endif
448 385
449static int __init init_tsc_clocksource(void) 386static int __init init_tsc_clocksource(void)
450{ 387{
@@ -453,20 +390,16 @@ static int __init init_tsc_clocksource(void)
453 /* check blacklist */ 390 /* check blacklist */
454 dmi_check_system(bad_tsc_dmi_table); 391 dmi_check_system(bad_tsc_dmi_table);
455 392
456 if (unsynchronized_tsc()) /* mark unstable if unsynced */ 393 unsynchronized_tsc();
457 mark_tsc_unstable(); 394 check_geode_tsc_reliable();
458 current_tsc_khz = tsc_khz; 395 current_tsc_khz = tsc_khz;
459 clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz, 396 clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
460 clocksource_tsc.shift); 397 clocksource_tsc.shift);
461 /* lower the rating if we already know its unstable: */ 398 /* lower the rating if we already know its unstable: */
462 if (check_tsc_unstable()) 399 if (check_tsc_unstable()) {
463 clocksource_tsc.rating = 0; 400 clocksource_tsc.rating = 0;
464 401 clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
465 init_timer(&verify_tsc_freq_timer); 402 }
466 verify_tsc_freq_timer.function = verify_tsc_freq;
467 verify_tsc_freq_timer.expires =
468 jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL);
469 add_timer(&verify_tsc_freq_timer);
470 403
471 return clocksource_register(&clocksource_tsc); 404 return clocksource_register(&clocksource_tsc);
472 } 405 }