diff options
Diffstat (limited to 'arch/x86/kernel/tsc_32.c')
-rw-r--r-- | arch/x86/kernel/tsc_32.c | 62 |
1 files changed, 45 insertions, 17 deletions
diff --git a/arch/x86/kernel/tsc_32.c b/arch/x86/kernel/tsc_32.c index 9ebc0dab66b..43517e324be 100644 --- a/arch/x86/kernel/tsc_32.c +++ b/arch/x86/kernel/tsc_32.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/jiffies.h> | 5 | #include <linux/jiffies.h> |
6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
7 | #include <linux/dmi.h> | 7 | #include <linux/dmi.h> |
8 | #include <linux/percpu.h> | ||
8 | 9 | ||
9 | #include <asm/delay.h> | 10 | #include <asm/delay.h> |
10 | #include <asm/tsc.h> | 11 | #include <asm/tsc.h> |
@@ -23,8 +24,6 @@ static int tsc_enabled; | |||
23 | unsigned int tsc_khz; | 24 | unsigned int tsc_khz; |
24 | EXPORT_SYMBOL_GPL(tsc_khz); | 25 | EXPORT_SYMBOL_GPL(tsc_khz); |
25 | 26 | ||
26 | int tsc_disable; | ||
27 | |||
28 | #ifdef CONFIG_X86_TSC | 27 | #ifdef CONFIG_X86_TSC |
29 | static int __init tsc_setup(char *str) | 28 | static int __init tsc_setup(char *str) |
30 | { | 29 | { |
@@ -39,8 +38,7 @@ static int __init tsc_setup(char *str) | |||
39 | */ | 38 | */ |
40 | static int __init tsc_setup(char *str) | 39 | static int __init tsc_setup(char *str) |
41 | { | 40 | { |
42 | tsc_disable = 1; | 41 | setup_clear_cpu_cap(X86_FEATURE_TSC); |
43 | |||
44 | return 1; | 42 | return 1; |
45 | } | 43 | } |
46 | #endif | 44 | #endif |
@@ -80,13 +78,31 @@ EXPORT_SYMBOL_GPL(check_tsc_unstable); | |||
80 | * | 78 | * |
81 | * -johnstul@us.ibm.com "math is hard, lets go shopping!" | 79 | * -johnstul@us.ibm.com "math is hard, lets go shopping!" |
82 | */ | 80 | */ |
83 | unsigned long cyc2ns_scale __read_mostly; | ||
84 | 81 | ||
85 | #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ | 82 | DEFINE_PER_CPU(unsigned long, cyc2ns); |
86 | 83 | ||
87 | static inline void set_cyc2ns_scale(unsigned long cpu_khz) | 84 | static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) |
88 | { | 85 | { |
89 | cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz; | 86 | unsigned long flags, prev_scale, *scale; |
87 | unsigned long long tsc_now, ns_now; | ||
88 | |||
89 | local_irq_save(flags); | ||
90 | sched_clock_idle_sleep_event(); | ||
91 | |||
92 | scale = &per_cpu(cyc2ns, cpu); | ||
93 | |||
94 | rdtscll(tsc_now); | ||
95 | ns_now = __cycles_2_ns(tsc_now); | ||
96 | |||
97 | prev_scale = *scale; | ||
98 | if (cpu_khz) | ||
99 | *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz; | ||
100 | |||
101 | /* | ||
102 | * Start smoothly with the new frequency: | ||
103 | */ | ||
104 | sched_clock_idle_wakeup_event(0); | ||
105 | local_irq_restore(flags); | ||
90 | } | 106 | } |
91 | 107 | ||
92 | /* | 108 | /* |
@@ -239,7 +255,9 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) | |||
239 | ref_freq, freq->new); | 255 | ref_freq, freq->new); |
240 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) { | 256 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) { |
241 | tsc_khz = cpu_khz; | 257 | tsc_khz = cpu_khz; |
242 | set_cyc2ns_scale(cpu_khz); | 258 | preempt_disable(); |
259 | set_cyc2ns_scale(cpu_khz, smp_processor_id()); | ||
260 | preempt_enable(); | ||
243 | /* | 261 | /* |
244 | * TSC based sched_clock turns | 262 | * TSC based sched_clock turns |
245 | * to junk w/ cpufreq | 263 | * to junk w/ cpufreq |
@@ -333,6 +351,11 @@ __cpuinit int unsynchronized_tsc(void) | |||
333 | { | 351 | { |
334 | if (!cpu_has_tsc || tsc_unstable) | 352 | if (!cpu_has_tsc || tsc_unstable) |
335 | return 1; | 353 | return 1; |
354 | |||
355 | /* Anything with constant TSC should be synchronized */ | ||
356 | if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) | ||
357 | return 0; | ||
358 | |||
336 | /* | 359 | /* |
337 | * Intel systems are normally all synchronized. | 360 | * Intel systems are normally all synchronized. |
338 | * Exceptions must mark TSC as unstable: | 361 | * Exceptions must mark TSC as unstable: |
@@ -367,7 +390,9 @@ static inline void check_geode_tsc_reliable(void) { } | |||
367 | 390 | ||
368 | void __init tsc_init(void) | 391 | void __init tsc_init(void) |
369 | { | 392 | { |
370 | if (!cpu_has_tsc || tsc_disable) | 393 | int cpu; |
394 | |||
395 | if (!cpu_has_tsc) | ||
371 | goto out_no_tsc; | 396 | goto out_no_tsc; |
372 | 397 | ||
373 | cpu_khz = calculate_cpu_khz(); | 398 | cpu_khz = calculate_cpu_khz(); |
@@ -380,7 +405,15 @@ void __init tsc_init(void) | |||
380 | (unsigned long)cpu_khz / 1000, | 405 | (unsigned long)cpu_khz / 1000, |
381 | (unsigned long)cpu_khz % 1000); | 406 | (unsigned long)cpu_khz % 1000); |
382 | 407 | ||
383 | set_cyc2ns_scale(cpu_khz); | 408 | /* |
409 | * Secondary CPUs do not run through tsc_init(), so set up | ||
410 | * all the scale factors for all CPUs, assuming the same | ||
411 | * speed as the bootup CPU. (cpufreq notifiers will fix this | ||
412 | * up if their speed diverges) | ||
413 | */ | ||
414 | for_each_possible_cpu(cpu) | ||
415 | set_cyc2ns_scale(cpu_khz, cpu); | ||
416 | |||
384 | use_tsc_delay(); | 417 | use_tsc_delay(); |
385 | 418 | ||
386 | /* Check and install the TSC clocksource */ | 419 | /* Check and install the TSC clocksource */ |
@@ -403,10 +436,5 @@ void __init tsc_init(void) | |||
403 | return; | 436 | return; |
404 | 437 | ||
405 | out_no_tsc: | 438 | out_no_tsc: |
406 | /* | 439 | setup_clear_cpu_cap(X86_FEATURE_TSC); |
407 | * Set the tsc_disable flag if there's no TSC support, this | ||
408 | * makes it a fast flag for the kernel to see whether it | ||
409 | * should be using the TSC. | ||
410 | */ | ||
411 | tsc_disable = 1; | ||
412 | } | 440 | } |