Commit 73c11c16 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds

[PATCH] cpufreq: update timer notifier

- global loops_per_jiffy, x86 cpu_khz and x86
   fast_gettimeoffset_quotient can only be safely adjusted on UP
- x86 per-CPU loops_per_jiffy does not depend on TSC
- save reference values so that rounding errors do not accumulate
parent 19accb69
...@@ -189,39 +189,38 @@ static unsigned long __init calibrate_tsc(void) ...@@ -189,39 +189,38 @@ static unsigned long __init calibrate_tsc(void)
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
static unsigned int ref_freq = 0;
static unsigned long loops_per_jiffy_ref = 0;
#ifndef CONFIG_SMP
static unsigned long fast_gettimeoffset_ref = 0;
static unsigned long cpu_khz_ref = 0;
#endif
static int static int
time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data) void *data)
{ {
struct cpufreq_freqs *freq = data; struct cpufreq_freqs *freq = data;
unsigned int i;
if (!cpu_has_tsc)
return 0;
switch (val) { if (!ref_freq) {
case CPUFREQ_PRECHANGE: ref_freq = freq->old;
if ((freq->old < freq->new) && loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0))) { #ifndef CONFIG_SMP
cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new); fast_gettimeoffset_ref = fast_gettimeoffset_quotient;
fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old); cpu_khz_ref = cpu_khz;
#endif
} }
for (i=0; i<NR_CPUS; i++)
if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i)) if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new); (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
break; cpu_data[freq->cpu].loops_per_jiffy = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
#ifndef CONFIG_SMP
case CPUFREQ_POSTCHANGE: if (use_tsc) {
if ((freq->new < freq->old) && fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq);
((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0))) { cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new);
fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old);
} }
for (i=0; i<NR_CPUS; i++) #endif
if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i))
cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new);
break;
} }
return 0; return 0;
...@@ -260,6 +259,10 @@ static int init_tsc(void) ...@@ -260,6 +259,10 @@ static int init_tsc(void)
* moaned if you have the only one in the world - you fix it! * moaned if you have the only one in the world - you fix it!
*/ */
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
#endif
if (cpu_has_tsc) { if (cpu_has_tsc) {
unsigned long tsc_quotient = calibrate_tsc(); unsigned long tsc_quotient = calibrate_tsc();
if (tsc_quotient) { if (tsc_quotient) {
...@@ -282,9 +285,6 @@ static int init_tsc(void) ...@@ -282,9 +285,6 @@ static int init_tsc(void)
"0" (eax), "1" (edx)); "0" (eax), "1" (edx));
printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000);
} }
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
#endif
return 0; return 0;
} }
} }
......
...@@ -927,17 +927,27 @@ EXPORT_SYMBOL(cpufreq_set_policy); ...@@ -927,17 +927,27 @@ EXPORT_SYMBOL(cpufreq_set_policy);
* adjust_jiffies - adjust the system "loops_per_jiffy" * adjust_jiffies - adjust the system "loops_per_jiffy"
* *
* This function alters the system "loops_per_jiffy" for the clock * This function alters the system "loops_per_jiffy" for the clock
* speed change. Note that loops_per_jiffy is only updated if all * speed change. Note that loops_per_jiffy cannot be updated on SMP
* CPUs are affected - else there is a need for per-CPU loops_per_jiffy * systems as each CPU might be scaled differently. So, use the arch
* values which are provided by various architectures. * per-CPU loops_per_jiffy value wherever possible.
*/ */
#ifndef CONFIG_SMP
static unsigned long l_p_j_ref = 0;
static unsigned int l_p_j_ref_freq = 0;
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
{ {
if (!l_p_j_ref_freq) {
l_p_j_ref = loops_per_jiffy;
l_p_j_ref_freq = ci->old;
}
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
(val == CPUFREQ_POSTCHANGE && ci->old > ci->new)) (val == CPUFREQ_POSTCHANGE && ci->old > ci->new))
if (ci->cpu == CPUFREQ_ALL_CPUS) loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
loops_per_jiffy = cpufreq_scale(loops_per_jiffy, ci->old, ci->new);
} }
#else
#define adjust_jiffies(...)
#endif
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment