diff options
Diffstat (limited to 'drivers/cpufreq/powernow-k8.c')
-rw-r--r-- | drivers/cpufreq/powernow-k8.c | 56 |
1 files changed, 29 insertions, 27 deletions
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index f6cd315..ad683ec 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -32,6 +32,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/cpumask.h> +#include <linux/sched.h> /* for current / set_cpus_allowed() */ #include <linux/io.h> #include <linux/delay.h> @@ -1131,23 +1132,16 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, return res; } -struct powernowk8_target_arg { - struct cpufreq_policy *pol; - unsigned targfreq; - unsigned relation; -}; - -static long powernowk8_target_fn(void *arg) +/* Driver entry point to switch to the target frequency */ +static int powernowk8_target(struct cpufreq_policy *pol, + unsigned targfreq, unsigned relation) { - struct powernowk8_target_arg *pta = arg; - struct cpufreq_policy *pol = pta->pol; - unsigned targfreq = pta->targfreq; - unsigned relation = pta->relation; + cpumask_var_t oldmask; struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); u32 checkfid; u32 checkvid; unsigned int newstate; - int ret; + int ret = -EIO; if (!data) return -EINVAL; @@ -1155,16 +1149,29 @@ static long powernowk8_target_fn(void *arg) checkfid = data->currfid; checkvid = data->currvid; + /* only run on specific CPU from here on. */ + /* This is poor form: use a workqueue or smp_call_function_single */ + if (!alloc_cpumask_var(&oldmask, GFP_KERNEL)) + return -ENOMEM; + + cpumask_copy(oldmask, tsk_cpus_allowed(current)); + set_cpus_allowed_ptr(current, cpumask_of(pol->cpu)); + + if (smp_processor_id() != pol->cpu) { + printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); + goto err_out; + } + if (pending_bit_stuck()) { printk(KERN_ERR PFX "failing targ, change pending bit set\n"); - return -EIO; + goto err_out; } pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", pol->cpu, targfreq, pol->min, pol->max, relation); if (query_current_values_with_pending_wait(data)) - return -EIO; + goto err_out; if (cpu_family != CPU_HW_PSTATE) { pr_debug("targ: curr fid 0x%x, vid 0x%x\n", @@ -1182,7 +1189,7 @@ static long powernowk8_target_fn(void *arg) if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate)) - return -EIO; + goto err_out; mutex_lock(&fidvid_mutex); @@ -1195,8 +1202,9 @@ static long powernowk8_target_fn(void *arg) ret = transition_frequency_fidvid(data, newstate); if (ret) { printk(KERN_ERR PFX "transition frequency failed\n"); + ret = 1; mutex_unlock(&fidvid_mutex); - return 1; + goto err_out; } mutex_unlock(&fidvid_mutex); @@ -1205,18 +1213,12 @@ static long powernowk8_target_fn(void *arg) data->powernow_table[newstate].index); else pol->cur = find_khz_freq_from_fid(data->currfid); + ret = 0; - return 0; -} - -/* Driver entry point to switch to the target frequency */ -static int powernowk8_target(struct cpufreq_policy *pol, - unsigned targfreq, unsigned relation) -{ - struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq, - .relation = relation }; - - return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta); +err_out: + set_cpus_allowed_ptr(current, oldmask); + free_cpumask_var(oldmask); + return ret; } /* Driver entry point to verify the policy and range of frequencies */ |