cpufreq: update timer notifier
PATCH 1/1 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
arch/i386/kernel/timers/timer_tsc.c | 54 ++++++++++++++++++------------------ kernel/cpufreq.c | 20 ++++++++++--- 2 files changed, 42 insertions(+), 32 deletions(-)
arch/i386/kernel/timers/timer_tsc.c +27 -27
@@ -189,39 +189,38 @@#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 time_cpufreq_notifier (struct notifier_block *nb,unsigned long val,void *data) {struct cpufreq_freqs *freq = data; -unsigned int i; -if (!cpu_has_tsc) -return 0 ; +if (!ref_freq) { + ref_freq = freq->old; + loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy; +#ifndef CONFIG_SMP + fast_gettimeoffset_ref = fast_gettimeoffset_quotient; + cpu_khz_ref = cpu_khz; +#endif + } -switch (val) { -case CPUFREQ_PRECHANGE : -if ((freq->old < freq->new) && - ((freq->cpu ==CPUFREQ_ALL_CPUS ) || (freq->cpu ==0 ))) { - 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++) -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 ; - -case CPUFREQ_POSTCHANGE : -if ((freq->new < freq->old) && - ((freq->cpu ==CPUFREQ_ALL_CPUS ) || (freq->cpu ==0 ))) { - cpu_khz =cpufreq_scale (cpu_khz, freq->old, freq->new); - fast_gettimeoffset_quotient =cpufreq_scale (fast_gettimeoffset_quotient, freq->new, freq->old); +if ((val ==CPUFREQ_PRECHANGE && freq->old < freq->new) || + (val ==CPUFREQ_POSTCHANGE && freq->old > freq->new)) { + cpu_data[freq->cpu].loops_per_jiffy =cpufreq_scale (loops_per_jiffy_ref, ref_freq, freq->new); +#ifndef CONFIG_SMP +if (use_tsc) { + fast_gettimeoffset_quotient =cpufreq_scale (fast_gettimeoffset_ref, freq->new, ref_freq); + cpu_khz =cpufreq_scale (cpu_khz_ref, ref_freq, freq->new); } -for (i=0 ; i<NR_CPUS ; i++) -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 ; +#endif }return 0 ;
@@ -260,6 +259,10 @@* 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) {unsigned long tsc_quotient =calibrate_tsc ();if (tsc_quotient) {
@@ -282,9 +285,6 @@ "0" (eax), "1" (edx));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 ; } }
kernel/cpufreq.c +15 -5
@@ -927,17 +927,27 @@* adjust_jiffies - adjust the system "loops_per_jiffy" * * This function alters the system "loops_per_jiffy" for the clock -* speed change. Note that loops_per_jiffy is only updated if all -* CPUs are affected - else there is a need for per-CPU loops_per_jiffy -* values which are provided by various architectures. +* speed change. Note that loops_per_jiffy cannot be updated on SMP +* systems as each CPU might be scaled differently. So, use the arch +* 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) { +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) || (val ==CPUFREQ_POSTCHANGE && ci->old > ci->new)) -if (ci->cpu ==CPUFREQ_ALL_CPUS ) - loops_per_jiffy =cpufreq_scale (loops_per_jiffy, ci->old, ci->new); + loops_per_jiffy =cpufreq_scale (l_p_j_ref, l_p_j_ref_freq, ci->new); } +#else +#define adjust_jiffies (...) +#endif /**
kernel/cpufreq.c line 950
Quoted 4 lines · Dominik Brodowski
kernel/cpufreq.c +3
-0+#else +#define adjust_jiffies (...) +#endif
This will fail to compile on gcc-2.91.66. It's OK on 2.95.3.
sparc64 requires a compiler of similar vintage (2.92.11), so I am trying to keep 2.91.66-on-x86 limping along so that breakage can be detected more easily.
Please use
#define adjust_jiffies(x...) do {} while (0)here. Or an empty inline, which tends to be nicer, because you
still get argument type checking.
PATCH 1/1 cpufreq: make gcc-2.91.66 happy (Was: Re: [PATCH 2.5.54] cpufreq: update timer notifier)
This patch updates the cpufreq #defines so that gcc-2.91.66 should work happily with cpufreq.
Quoted 12 lines · Andrew Morton
Review
Quoted 4 lines · Dominik Brodowski
(quoted diff) +3
-0+#else +#define adjust_jiffies(...) +#endifThis will fail to compile on gcc-2.91.66. It's OK on 2.95.3.
sparc64 requires a compiler of similar vintage (2.92.11), so I am trying to keep 2.91.66-on-x86 limping along so that breakage can be detected more easily.
Quoted 6 lines
Please use
#define adjust_jiffies(x...) do {} while (0)here. Or an empty inline, which tends to be nicer, because you
still get argument type checking.
kernel/cpufreq.c +4 -4
@@ -734,8 +734,8 @@ }#else -#define cpufreq_sysctl_init () -#define cpufreq_sysctl_exit () +#define cpufreq_sysctl_init () do {} while(0) +#define cpufreq_sysctl_exit () do {} while(0)#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_CPU_FREQ_24_API */
@@ -946,7 +946,7 @@ loops_per_jiffy =cpufreq_scale (l_p_j_ref, l_p_j_ref_freq, ci->new); }#else -#define adjust_jiffies (...) +#define adjust_jiffies(x...) do {} while (0)#endif
@@ -1131,6 +1131,6 @@ }EXPORT_SYMBOL_GPL (cpufreq_restore);#else -#define cpufreq_restore () +#define cpufreq_restore () do {} while (0)#endif /* CONFIG_PM */