cpufreq updates for cpufreq-bk
Subsystems (3)
PATCH 1/1 cpufreq updates for cpufreq-bk
The following patches, all tested on two test systems (speedstep-smi and p4-clockmod), are not yet merged into cpufreq-bk. Dave, could you merge them, please? And push them -- along the other pieces in bk already -- to Andrew and Linus for 2.6.1, please?
cpufreq-2.6.0-tsc
- [i386-timing] on P4s no TSC adjustment is necessary
cpufreq-2.6.0-speedstep-smi-disable_debug_output
- [speedstep-smi] Disable debug output
cpufreq-2.6.0-speedstep-smi-spelling_fix
- [speedstep-smi] Spelling fix
cpufreq-2.6.0-speedstep-smi-bugfix-1422
- [speedstep-smi] Disable smi_detect_freqs() call on systems which do not support it [BUG #1422]
cpufreq-2.6.0-speedstep-lib-533mhz_fsb
- [speedstep-lib] Support for 533 MHz FSB
cpufreq-2.6.0-p4_clockmod-detect_speed
- [p4-clockmod] Detect CPU speed without relying on cpu_khz
cpufreq-2.6.0-clean_headers
- [core] remove unneeded #ifdefs in include/linux/cpufreq.h
cpufreq-2.6.0-latency
- [drivers] latency in nanoseconds -- sometimes nanoseconds are used, sometimes microseconds, sometimes even something else.
cpufreq-2.6.0-speedstep-smi-reduce_failures
- [speedstep-smi] Do something about "cpufreq: change failed"
Dominik
There's no need for some #ifdefs in cpufreq.h
include/linux/cpufreq.h | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-)
include/linux/cpufreq.h +4 -6
@@ -231,17 +231,18 @@/* the proc_intf.c needs this */ int cpufreq_parse_governor (char *str_governor,unsigned int *policy,struct cpufreq_governor **governor); -#if defined(CONFIG_CPU_FREQ_GOV_USERSPACE ) || defined(CONFIG_CPU_FREQ_GOV_USERSPACE_MODULE ) +/********************************************************************* * CPUFREQ USERSPACE GOVERNOR * *********************************************************************/ int cpufreq_gov_userspace_init (void ); +#ifdef CONFIG_CPU_FREQ_24_API +int cpufreq_setmax (unsigned int cpu);int cpufreq_set (unsigned int kHz,unsigned int cpu);unsigned int cpufreq_get (unsigned int cpu); -#ifdef CONFIG_CPU_FREQ_24_API /* /proc/sys/cpu */ enum {
@@ -289,8 +290,6 @@#endif /* CONFIG_CPU_FREQ_24_API */ -#endif /* CONFIG_CPU_FREQ_GOV_USERSPACE */ -/********************************************************************* * CPUFREQ DEFAULT GOVERNOR *
@@ -305,6 +304,7 @@#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_userspace#endif +/********************************************************************* * FREQUENCY TABLE HELPERS * *********************************************************************/
@@ -318,7 +318,6 @@* order */ }; -#if defined(CONFIG_CPU_FREQ_TABLE ) || defined(CONFIG_CPU_FREQ_TABLE_MODULE )int cpufreq_frequency_table_cpuinfo (struct cpufreq_policy *policy,struct cpufreq_frequency_table *table);
@@ -340,5 +339,4 @@void cpufreq_frequency_table_put_attr (unsigned int cpu); -#endif /* CONFIG_CPU_FREQ_TABLE */ #endif /* _LINUX_CPUFREQ_H */
Even though the core stated that cpuinfo.transition_latency needs to be in 10^(-9) s, hardly any driver set it to nanoseconds but to microseconds. So, fix up the drivers.
arch/arm/mach-integrator/cpu.c | 2 +- arch/i386/kernel/cpu/cpufreq/acpi.c | 4 ++-- arch/i386/kernel/cpu/cpufreq/p4-clockmod.c | 2 +- arch/i386/kernel/cpu/cpufreq/powernow-k7.c | 6 +++++- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 7 ++++--- include/linux/cpufreq.h | 2 +- 6 files changed, 14 insertions(+), 9 deletions(-)
arch/arm/mach-integrator/cpu.c +1 -1
@@ -172,7 +172,7 @@ policy->governor =CPUFREQ_DEFAULT_GOVERNOR ; policy->cpuinfo.max_freq =160000 ; policy->cpuinfo.min_freq =12000 ; - policy->cpuinfo.transition_latency =1000 ;/* 1 ms, assumed */ + policy->cpuinfo.transition_latency =1000000 ;/* 1 ms, assumed */ policy->cur = policy->min = policy->max =icst525_khz (&cclk_params, vco);/* current freq */
arch/i386/kernel/cpu/cpufreq/acpi.c +2 -2
@@ -578,8 +578,8 @@/* detect transition latency */ policy->cpuinfo.transition_latency =0 ;for (i=0 ;i<perf->state_count;i++) { -if (perf->states[i].transition_latency > policy->cpuinfo.transition_latency) - policy->cpuinfo.transition_latency = perf->states[i].transition_latency; +if ((perf->states[i].transition_latency *1000 ) > policy->cpuinfo.transition_latency) + policy->cpuinfo.transition_latency = perf->states[i].transition_latency *1000 ; } policy->governor =CPUFREQ_DEFAULT_GOVERNOR ; policy->cur = perf->states[pr->limit.state.px].core_frequency *1000 ;
arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +1 -1
@@ -255,7 +255,7 @@/* cpuinfo and default policy values */ policy->governor =CPUFREQ_DEFAULT_GOVERNOR ; - policy->cpuinfo.transition_latency =1000 ; + policy->cpuinfo.transition_latency =1000000 ;/* assumed */ policy->cur = stock_freq;return cpufreq_frequency_table_cpuinfo (policy, &p4clockmod_table[0 ]);
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +5 -1
@@ -386,7 +386,11 @@ minimum_speed, maximum_speed); policy->governor =CPUFREQ_DEFAULT_GOVERNOR ; - policy->cpuinfo.transition_latency = latency; + +/* latency is in 10 ns (look for SGTC above) for each VID +* and FID transition, so multiply that value with 20 */ + policy->cpuinfo.transition_latency = latency *20 ; + policy->cur = maximum_speed;return cpufreq_frequency_table_cpuinfo (policy, powernow_table);
arch/i386/kernel/cpu/cpufreq/powernow-k8.c +4 -3
@@ -957,9 +957,10 @@ pol->governor =CPUFREQ_DEFAULT_GOVERNOR ; -/* Take a crude guess here. */ - pol->cpuinfo.transition_latency = ((rvo +8 ) * vstable *VST_UNITS_20US ) - + (3 * (1 << irt) *10 ); +/* Take a crude guess here. +* That guess was in microseconds, so multply with 1000 */ + pol->cpuinfo.transition_latency = (((rvo +8 ) * vstable *VST_UNITS_20US ) + + (3 * (1 << irt) *10 )) *1000 ;if (query_current_values_with_pending_wait ())return -EIO ;
include/linux/cpufreq.h +1 -1
@@ -57,7 +57,7 @@struct cpufreq_cpuinfo {unsigned int max_freq;unsigned int min_freq; -unsigned int transition_latency;/* in 10^(-9) s */ +unsigned int transition_latency;/* in 10^(-9) s = nanoseconds */ };struct cpufreq_real_policy {
Other cpufreq drivers don't rely on cpu_khz, but use the "decoded"/theoretical CPU frequency as base for all calculations.
arch/i386/kernel/cpu/cpufreq/p4-clockmod.c | 66 +++++++++++++++++++++++------ 1 files changed, 53 insertions(+), 13 deletions(-)
arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +53 -13
90 lines not on this page · raw message
I don't know whether there's a P4-M with 533 or 800 MHz FSB out there yet, but let's prepare the speedstep-lib for these FSBs anyways.
arch/i386/kernel/cpu/cpufreq/speedstep-lib.c | 37 ++++++++++++++++++++++++--- arch/i386/kernel/cpu/cpufreq/speedstep-lib.h | 2 - 2 files changed, 35 insertions(+), 4 deletions(-)
arch/i386/kernel/cpu/cpufreq/speedstep-lib.c +34 -3
@@ -106,14 +106,45 @@static unsigned int pentium4_get_frequency (void ) { -u32 msr_lo, msr_hi; +struct cpuinfo_x86 *c = &boot_cpu_data; +u32 msr_lo, msr_hi, mult; +unsigned int fsb =0 ;rdmsr (0x2c , msr_lo, msr_hi);dprintk (KERN_DEBUG "speedstep-lib: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n" , msr_lo, msr_hi); - msr_lo >>=24 ; -return (msr_lo *100000 ); +/* decode the FSB: see IA-32 Intel (C) Architecture Software +* Developer's Manual, Volume 3: System Prgramming Guide, +* revision #12 in Table B-1: MSRs in the Pentium 4 and +* Intel Xeon Processors, on page B-4 and B-5. +*/ +if (c->x86_model <2 ) + fsb =100 *1000 ; +else { +u8 fsb_code = (msr_lo >>16 ) &0x7 ; +switch (fsb_code) { +case 0 : + fsb =100 *1000 ; +break ; +case 1 : + fsb =13333 *10 ; +break ; +case 2 : + fsb =200 *1000 ; +break ; + } + } + +if (!fsb) +printk (KERN_DEBUG "speedstep-lib: couldn't detect FSB speed. Please send an e-mail to <[email protected]>\n" ); + +/* Multiplier. */ + mult = msr_lo >>24 ; + +dprintk (KERN_DEBUG "speedstep-lib: P4 - FSB %u kHz; Multiplier %u\n" , fsb, mult); + +return (fsb * mult); }
arch/i386/kernel/cpu/cpufreq/speedstep-lib.h +1 -1
@@ -15,7 +15,7 @@#define SPEEDSTEP_PROCESSOR_PIII_C_EARLY 0x00000001/* Coppermine core */ #define SPEEDSTEP_PROCESSOR_PIII_C 0x00000002/* Coppermine core */ #define SPEEDSTEP_PROCESSOR_PIII_T 0x00000003/* Tualatin core */ -#define SPEEDSTEP_PROCESSOR_P4M 0x00000004/* P4-M with 100 MHz FSB */ +#define SPEEDSTEP_PROCESSOR_P4M 0x00000004/* P4-M */ /* speedstep states -- only two of them */
The SMI call in speedstep_smi_get_freqs causes hangs on certain notebooks. A failure of the function itself is non-critical, as a workaround exists.
arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 6 ++++++ 1 files changed, 6 insertions(+)
arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +6 -0
@@ -85,6 +85,9 @@/** * speedstep_smi_get_freqs - get SpeedStep preferred & current freq. +* Only available on later SpeedStep-enabled systems, returns false results or +* even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing +* shows that the latter occurs if !(ist_info.event & 0xFFFF). * */ static int speedstep_smi_get_freqs (unsigned int *low,unsigned int *high)
@@ -93,6 +96,9 @@u32 state=0 ;u32 function =GET_SPEEDSTEP_FREQS ; +if (!(ist_info.event &0xFFFF )) +return -ENODEV ; + command = (smi_sig &0xffffff00 ) | (smi_cmd &0xff ); __asm__ __volatile__("movl $0, %%edi\n"
speedstep-smi is getting more and more stable, so disable verbose debug output.
arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-)
arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +1 -1
@@ -54,7 +54,7 @@/* DEBUG * Define it if you want verbose debug output, e.g. for bug reporting */ -#define SPEEDSTEP_DEBUG +//#define SPEEDSTEP_DEBUG #ifdef SPEEDSTEP_DEBUG #define dprintk(msg...) printk(msg)
Transitions initiated by speedstep-smi currently fail often if system load is high. Bruno Ducrot and I have found out that the failures disappear if DMA is disabled. As disabling (U)DMA isn't something nice, here's a workaround which (almost) always works: retrying the SMI call up to five times, and waiting some time before doing so. Please note that this will completely mess up real-time-critical tasks or dynamic scaling. But speedstep-smi (1st generation of speedstep) wasn't meant to be used for that anyway.
arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 32 +++++++++++++++++++-------- 1 files changed, 23 insertions(+), 9 deletions(-)
arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +23 -9
@@ -19,6 +19,7 @@#include <linux/cpufreq.h> #include <linux/pci.h> #include <linux/slab.h> +#include <linux/delay.h> #include <asm/ist.h> #include "speedstep-lib.h"
@@ -51,6 +52,10 @@#define SET_SPEEDSTEP_STATE 2#define GET_SPEEDSTEP_FREQS 4 +/* how often shall the SMI call be tried if it failed, e.g. because +* of DMA activity going on? */ +#define SMI_TRIES 5 +/* DEBUG * Define it if you want verbose debug output, e.g. for bug reporting */
@@ -140,10 +145,11 @@*/ static void speedstep_set_state (unsigned int state,unsigned int notify) { -unsigned int old_state, result, command, new_state; +unsigned int old_state, result =0 , command, new_state;unsigned long flags;struct cpufreq_freqs freqs;unsigned int function=SET_SPEEDSTEP_STATE ; +unsigned int retry =0 ;if (state >0x1 )return ;
@@ -163,20 +169,28 @@local_irq_save (flags); command = (smi_sig &0xffffff00 ) | (smi_cmd &0xff ); - __asm__ __volatile__( -"movl $0, %%edi\n" -"out %%al, (%%dx)\n" - :"=b" (new_state),"=D" (result) - :"a" (command),"b" (function),"c" (state),"d" (smi_port),"S" (0 ) - ); + +do { +if (retry) { +dprintk (KERN_INFO "cpufreq: retry %u, previous result %u\n" , retry, result); +mdelay (retry *50 ); + } + retry++; + __asm__ __volatile__( +"movl $0, %%edi\n" +"out %%al, (%%dx)\n" + :"=b" (new_state),"=D" (result) + :"a" (command),"b" (function),"c" (state),"d" (smi_port),"S" (0 ) + ); + }while ((new_state != state) && (retry <=SMI_TRIES ));/* enable IRQs */ local_irq_restore (flags);if (new_state == state) { -dprintk (KERN_INFO "cpufreq: change to %u MHz succeeded\n" , (freqs.new /1000 )); +dprintk (KERN_INFO "cpufreq: change to %u MHz succeeded after %u tries with result %u\n" , (freqs.new /1000 ), retry, result); }else { -printk (KERN_ERR "cpufreq: change failed\n" ); +printk (KERN_ERR "cpufreq: change failed with new_state %u and result %u\n" , new_state, result); }if (notify)
The reporter of bug 1422 noted this spelling fix -- thanks!
arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-)
arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +1 -1
@@ -168,7 +168,7 @@local_irq_restore (flags);if (new_state == state) { -dprintk (KERN_INFO "cpufreq: change to %u MHz succeded\n" , (freqs.new /1000 )); +dprintk (KERN_INFO "cpufreq: change to %u MHz succeeded\n" , (freqs.new /1000 )); }else {printk (KERN_ERR "cpufreq: change failed\n" ); }
Quoted 3 lines · Shaohua
TSC frequency doesn't change under P4 and above when CPU frequency changes, which caused some problems. Attached patch will handle this problem. How about it?
A few cleanups were added to this patch:
- cpufreq_register_notifier() shouldn't be called during time_init() because it shouldn't be called while we're in atomic context
- the p4 detection code should only be used when cpufreq is used
- also cyc2us and loops_per_jiffy are affected (I think)
- the patch had an invalid header
timer_tsc.c | 35 +++++++++++++++++++++++++++-------- 1 files changed, 27 insertions(+), 8 deletions(-)
arch/i386/kernel/timers/timer_tsc.c +27 -8
@@ -306,9 +306,17 @@ }#endif +#ifdef CONFIG_CPU_FREQ +/* If the CPU frequency is scaled, TSC-based delays will need a different +* loops_per_jiffy value to function properly. An exception to this +* are modern Intel Pentium 4 processors, where the TSC runs at a constant +* speed independent of frequency scaling. +*/ +static unsigned int ref_freq =0 ;static unsigned long loops_per_jiffy_ref =0 ; +static unsigned int variable_tsc =1 ;#ifndef CONFIG_SMP static unsigned long fast_gettimeoffset_ref =0 ;
@@ -333,12 +341,15 @@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); +if (variable_tsc) + 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); -set_cyc2ns_scale (cpu_khz/1000 ); +if (variable_tsc) { + fast_gettimeoffset_quotient =cpufreq_scale (fast_gettimeoffset_ref, freq->new, ref_freq); +set_cyc2ns_scale (cpu_khz/1000 ); + } }#endif }
@@ -350,7 +361,19 @@static struct notifier_block time_cpufreq_notifier_block = { .notifier_call = time_cpufreq_notifier }; -#endif + + +static int __init cpufreq_tsc (void ) +{ +/* P4 and above CPU TSC freq doesn't change when CPU frequency changes*/ +if ((boot_cpu_data.x86 >=15 ) && (boot_cpu_data.x86_vendor ==X86_VENDOR_INTEL )) + variable_tsc =0 ; + +return cpufreq_register_notifier (&time_cpufreq_notifier_block,CPUFREQ_TRANSITION_NOTIFIER ); +} +core_initcall (cpufreq_tsc); + +#endif static int __init init_tsc (char * override)
@@ -392,10 +415,6 @@* some CPU's have a TSC. Thats never worked and nobody has * 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 count2 =LATCH ;/* initialize counter for mark_offset_tsc() */
_______________________________________________
Cpufreq mailing list
[email protected]
http://www.linux.org.uk/mailman/listinfo/cpufreq