X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fkernel%2Fcpu%2Fcpufreq%2Fp4-clockmod.c;h=ebe1848163f064b4ae8765fadb0b63334603492e;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=b5daeccfaa2073e0cb0d20c6de804797d1448c90;hpb=8fe849edaaabd915f060b3744165ff7f95a2b34e;p=linux-2.6.git diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index b5daeccfa..ebe184816 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include /* current / set_cpus_allowed() */ #include #include @@ -35,6 +37,7 @@ #include "speedstep-lib.h" #define PFX "p4-clockmod: " +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "p4-clockmod", msg) /* * Duty Cycle (3bits), note DC_DISABLE is not specified in @@ -49,6 +52,7 @@ enum { static int has_N44_O17_errata[NR_CPUS]; +static int has_N60_errata[NR_CPUS]; static unsigned int stock_freq; static struct cpufreq_driver p4clockmod_driver; static unsigned int cpufreq_p4_get(unsigned int cpu); @@ -61,20 +65,20 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) return -EINVAL; rdmsr(MSR_IA32_THERM_STATUS, l, h); -#if 0 + if (l & 0x01) - printk(KERN_DEBUG PFX "CPU#%d currently thermal throttled\n", cpu); -#endif + dprintk("CPU#%d currently thermal throttled\n", cpu); + if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT)) newstate = DC_38PT; rdmsr(MSR_IA32_THERM_CONTROL, l, h); if (newstate == DC_DISABLE) { - /* printk(KERN_INFO PFX "CPU#%d disabling modulation\n", cpu); */ + dprintk("CPU#%d disabling modulation\n", cpu); wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); } else { - /* printk(KERN_INFO PFX "CPU#%d setting duty cycle to %d%%\n", - cpu, ((125 * newstate) / 10)); */ + dprintk("CPU#%d setting duty cycle to %d%%\n", + cpu, ((125 * newstate) / 10)); /* bits 63 - 5 : reserved * bit 4 : enable/disable * bits 3-1 : duty cycle @@ -109,7 +113,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, { unsigned int newstate = DC_RESV; struct cpufreq_freqs freqs; - cpumask_t cpus_allowed, affected_cpu_map; + cpumask_t cpus_allowed; int i; if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate)) @@ -121,45 +125,31 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, if (freqs.new == freqs.old) return 0; - /* switch to physical CPU where state is to be changed*/ - cpus_allowed = current->cpus_allowed; - - /* only run on CPU to be set, or on its sibling */ -#ifdef CONFIG_SMP - affected_cpu_map = cpu_sibling_map[policy->cpu]; -#else - affected_cpu_map = cpumask_of_cpu(policy->cpu); -#endif - /* notifiers */ - for_each_cpu(i) { - if (cpu_isset(i, affected_cpu_map)) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - } + for_each_cpu_mask(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); } /* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software * Developer's Manual, Volume 3 */ - for_each_cpu(i) { - if (cpu_isset(i, affected_cpu_map)) { - cpumask_t this_cpu = cpumask_of_cpu(i); + cpus_allowed = current->cpus_allowed; + + for_each_cpu_mask(i, policy->cpus) { + cpumask_t this_cpu = cpumask_of_cpu(i); - set_cpus_allowed(current, this_cpu); - BUG_ON(smp_processor_id() != i); + set_cpus_allowed(current, this_cpu); + BUG_ON(smp_processor_id() != i); - cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); - } + cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); } set_cpus_allowed(current, cpus_allowed); /* notifiers */ - for_each_cpu(i) { - if (cpu_isset(i, affected_cpu_map)) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } + for_each_cpu_mask(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } return 0; @@ -183,13 +173,13 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); } - if ((c->x86 == 0x06) && (c->x86_model == 0x13)) { + if ((c->x86 == 0x06) && (c->x86_model == 0x0D)) { /* Pentium M (Dothan) */ printk(KERN_WARNING PFX "Warning: Pentium M detected. " "The speedstep_centrino module offers voltage scaling" " in addition of frequency scaling. You should use " "that instead of p4-clockmod, if possible.\n"); - /* on P-4s, the TSC runs with constant frequency independent wether + /* on P-4s, the TSC runs with constant frequency independent whether * throttling is active or not. */ p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); @@ -200,7 +190,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) return 0; } - /* on P-4s, the TSC runs with constant frequency independent wether + /* on P-4s, the TSC runs with constant frequency independent whether * throttling is active or not. */ p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; @@ -224,6 +214,10 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) int cpuid = 0; unsigned int i; +#ifdef CONFIG_SMP + policy->cpus = cpu_sibling_map[policy->cpu]; +#endif + /* Errata workaround */ cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; switch (cpuid) { @@ -232,6 +226,13 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) case 0x0f11: case 0x0f12: has_N44_O17_errata[policy->cpu] = 1; + dprintk("has errata -- disabling low frequencies\n"); + break; + + case 0x0f29: + has_N60_errata[policy->cpu] = 1; + dprintk("has errata -- disabling frequencies lower than 2ghz\n"); + break; } /* get max frequency */ @@ -243,6 +244,8 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) { if ((i<2) && (has_N44_O17_errata[policy->cpu])) p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID; + else if (has_N60_errata[policy->cpu] && ((stock_freq * i)/8) < 2000000) + p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID; else p4clockmod_table[i].frequency = (stock_freq * i)/8; } @@ -265,14 +268,13 @@ static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy) static unsigned int cpufreq_p4_get(unsigned int cpu) { - cpumask_t cpus_allowed, affected_cpu_map; + cpumask_t cpus_allowed; u32 l, h; cpus_allowed = current->cpus_allowed; - affected_cpu_map = cpumask_of_cpu(cpu); - set_cpus_allowed(current, affected_cpu_map); - BUG_ON(!cpu_isset(smp_processor_id(), affected_cpu_map)); + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + BUG_ON(smp_processor_id() != cpu); rdmsr(MSR_IA32_THERM_CONTROL, l, h); @@ -310,6 +312,7 @@ static struct cpufreq_driver p4clockmod_driver = { static int __init cpufreq_p4_init(void) { struct cpuinfo_x86 *c = cpu_data; + int ret; /* * THERM_CONTROL is architectural for IA32 now, so @@ -322,9 +325,11 @@ static int __init cpufreq_p4_init(void) !test_bit(X86_FEATURE_ACC, c->x86_capability)) return -ENODEV; - printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n"); + ret = cpufreq_register_driver(&p4clockmod_driver); + if (!ret) + printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n"); - return cpufreq_register_driver(&p4clockmod_driver); + return (ret); } @@ -340,4 +345,3 @@ MODULE_LICENSE ("GPL"); late_initcall(cpufreq_p4_init); module_exit(cpufreq_p4_exit); -