diff options
Diffstat (limited to 'drivers/cpufreq/speedstep-ich.c')
-rw-r--r-- | drivers/cpufreq/speedstep-ich.c | 85 |
1 files changed, 75 insertions, 10 deletions
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c index 7639b2b..5355abb 100644 --- a/drivers/cpufreq/speedstep-ich.c +++ b/drivers/cpufreq/speedstep-ich.c @@ -251,23 +251,56 @@ static unsigned int speedstep_get(unsigned int cpu) /** * speedstep_target - set a new CPUFreq policy * @policy: new policy - * @index: index of target frequency + * @target_freq: the target frequency + * @relation: how that frequency relates to achieved frequency + * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) * * Sets a new CPUFreq policy. */ -static int speedstep_target(struct cpufreq_policy *policy, unsigned int index) +static int speedstep_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) { - unsigned int policy_cpu; + unsigned int newstate = 0, policy_cpu; + struct cpufreq_freqs freqs; + + if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], + target_freq, relation, &newstate)) + return -EINVAL; policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); + freqs.old = speedstep_get(policy_cpu); + freqs.new = speedstep_freqs[newstate].frequency; + + pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new); + + /* no transition necessary */ + if (freqs.old == freqs.new) + return 0; - smp_call_function_single(policy_cpu, _speedstep_set_state, &index, + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + + smp_call_function_single(policy_cpu, _speedstep_set_state, &newstate, true); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + return 0; } +/** + * speedstep_verify - verifies a new CPUFreq policy + * @policy: new policy + * + * Limit must be within speedstep_low_freq and speedstep_high_freq, with + * at least one border included. + */ +static int speedstep_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); +} + struct get_freqs { struct cpufreq_policy *policy; int ret; @@ -287,7 +320,8 @@ static void get_freqs_on_cpu(void *_get_freqs) static int speedstep_cpu_init(struct cpufreq_policy *policy) { - unsigned int policy_cpu; + int result; + unsigned int policy_cpu, speed; struct get_freqs gf; /* only run on CPU to be set, or on its sibling */ @@ -302,18 +336,49 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) if (gf.ret) return gf.ret; - return cpufreq_table_validate_and_show(policy, speedstep_freqs); + /* get current speed setting */ + speed = speedstep_get(policy_cpu); + if (!speed) + return -EIO; + + pr_debug("currently at %s speed setting - %i MHz\n", + (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) + ? "low" : "high", + (speed / 1000)); + + /* cpuinfo and default policy values */ + policy->cur = speed; + + result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); + if (result) + return result; + + cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu); + + return 0; } +static int speedstep_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static struct freq_attr *speedstep_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + + static struct cpufreq_driver speedstep_driver = { .name = "speedstep-ich", - .verify = cpufreq_generic_frequency_table_verify, - .target_index = speedstep_target, + .verify = speedstep_verify, + .target = speedstep_target, .init = speedstep_cpu_init, - .exit = cpufreq_generic_exit, + .exit = speedstep_cpu_exit, .get = speedstep_get, - .attr = cpufreq_generic_attr, + .attr = speedstep_attr, }; static const struct x86_cpu_id ss_smi_ids[] = { |