diff options
author | Guillaume Chazarain <guichaz@yahoo.fr> | 2008-01-30 07:30:06 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:30:06 -0500 |
commit | 53d517cdbaac704352b3d0c10fecb99e0b54572e (patch) | |
tree | 4056bc99a4e6077d7d968d30ea21895e425a83ef /arch/x86/kernel/tsc_32.c | |
parent | 83bd01024b1fdfc41d9b758e5669e80fca72df66 (diff) |
x86: scale cyc_2_nsec according to CPU frequency
scale the sched_clock() cyc_2_nsec scaling factor according to
CPU frequency changes.
[ mingo@elte.hu: simplified it and fixed it for SMP. ]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/tsc_32.c')
-rw-r--r-- | arch/x86/kernel/tsc_32.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/arch/x86/kernel/tsc_32.c b/arch/x86/kernel/tsc_32.c index 9ebc0dab66b4..00bb4c1c0593 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> |
@@ -80,13 +81,31 @@ EXPORT_SYMBOL_GPL(check_tsc_unstable); | |||
80 | * | 81 | * |
81 | * -johnstul@us.ibm.com "math is hard, lets go shopping!" | 82 | * -johnstul@us.ibm.com "math is hard, lets go shopping!" |
82 | */ | 83 | */ |
83 | unsigned long cyc2ns_scale __read_mostly; | ||
84 | 84 | ||
85 | #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ | 85 | DEFINE_PER_CPU(unsigned long, cyc2ns); |
86 | 86 | ||
87 | static inline void set_cyc2ns_scale(unsigned long cpu_khz) | 87 | static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) |
88 | { | 88 | { |
89 | cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz; | 89 | unsigned long flags, prev_scale, *scale; |
90 | unsigned long long tsc_now, ns_now; | ||
91 | |||
92 | local_irq_save(flags); | ||
93 | sched_clock_idle_sleep_event(); | ||
94 | |||
95 | scale = &per_cpu(cyc2ns, cpu); | ||
96 | |||
97 | rdtscll(tsc_now); | ||
98 | ns_now = __cycles_2_ns(tsc_now); | ||
99 | |||
100 | prev_scale = *scale; | ||
101 | if (cpu_khz) | ||
102 | *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz; | ||
103 | |||
104 | /* | ||
105 | * Start smoothly with the new frequency: | ||
106 | */ | ||
107 | sched_clock_idle_wakeup_event(0); | ||
108 | local_irq_restore(flags); | ||
90 | } | 109 | } |
91 | 110 | ||
92 | /* | 111 | /* |
@@ -239,7 +258,9 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) | |||
239 | ref_freq, freq->new); | 258 | ref_freq, freq->new); |
240 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) { | 259 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) { |
241 | tsc_khz = cpu_khz; | 260 | tsc_khz = cpu_khz; |
242 | set_cyc2ns_scale(cpu_khz); | 261 | preempt_disable(); |
262 | set_cyc2ns_scale(cpu_khz, smp_processor_id()); | ||
263 | preempt_enable(); | ||
243 | /* | 264 | /* |
244 | * TSC based sched_clock turns | 265 | * TSC based sched_clock turns |
245 | * to junk w/ cpufreq | 266 | * to junk w/ cpufreq |
@@ -367,6 +388,8 @@ static inline void check_geode_tsc_reliable(void) { } | |||
367 | 388 | ||
368 | void __init tsc_init(void) | 389 | void __init tsc_init(void) |
369 | { | 390 | { |
391 | int cpu; | ||
392 | |||
370 | if (!cpu_has_tsc || tsc_disable) | 393 | if (!cpu_has_tsc || tsc_disable) |
371 | goto out_no_tsc; | 394 | goto out_no_tsc; |
372 | 395 | ||
@@ -380,7 +403,15 @@ void __init tsc_init(void) | |||
380 | (unsigned long)cpu_khz / 1000, | 403 | (unsigned long)cpu_khz / 1000, |
381 | (unsigned long)cpu_khz % 1000); | 404 | (unsigned long)cpu_khz % 1000); |
382 | 405 | ||
383 | set_cyc2ns_scale(cpu_khz); | 406 | /* |
407 | * Secondary CPUs do not run through tsc_init(), so set up | ||
408 | * all the scale factors for all CPUs, assuming the same | ||
409 | * speed as the bootup CPU. (cpufreq notifiers will fix this | ||
410 | * up if their speed diverges) | ||
411 | */ | ||
412 | for_each_possible_cpu(cpu) | ||
413 | set_cyc2ns_scale(cpu_khz, cpu); | ||
414 | |||
384 | use_tsc_delay(); | 415 | use_tsc_delay(); |
385 | 416 | ||
386 | /* Check and install the TSC clocksource */ | 417 | /* Check and install the TSC clocksource */ |