RE: [PATCH 4/6] x86/cpufreq: use cpumask_copy instead of =

Langsdorf, Mark
2009-06-10T19:42:31Z

> powernow_k8_target is problematic: it grabs a mutex. cpufreq
> people, is this called often?

Yes. It's the function that makes a frequency change
happen, so 5+ times per second per core isn't
unreasonable.

-Mark Langsdorf
Operating System Research Center
AMD

> Subject: cpumask: avoid playing with cpus_allowed in powernow-k8.c
> From: Rusty Russell <rusty@rustcorp.com.au>
>
> It's generally a very bad idea to mug some process's cpumask: it could
> legitimately and reasonably be changed by root, which could break us
> (if done before our code) or them (if we restore the wrong value).
>
> I use work_on_cpu, which is slightly less efficient than the old code,
> but the code is complex enough that using smp_call_function_single()
> is not trivial.

> -/* Driver entry point to switch to the target frequency */
> -static int powernowk8_target(struct cpufreq_policy *pol,
> - unsigned targfreq, unsigned relation)
> +struct target_data {
> + struct cpufreq_policy *pol;
> + unsigned targfreq;
> + unsigned relation;
> +};
> +
> +static long powernowk8_target_on_cpu(void *_tdata)
> {
> - cpumask_t oldmask;
> + struct target_data *tdata = _tdata;
> + struct cpufreq_policy *pol = tdata->pol;
> struct powernow_k8_data *data = per_cpu(powernow_data,
> pol->cpu);
> u32 checkfid;
> u32 checkvid;
> @@ -1158,22 +1152,13 @@ static int powernowk8_target(struct cpuf
> checkfid = data->currfid;
> checkvid = data->currvid;
>
> - /* only run on specific CPU from here on */
> - oldmask = current->cpus_allowed;
> - set_cpus_allowed_ptr(current, &cpumask_of_cpu(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");
> goto err_out;
> }
>
> dprintk("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
> - pol->cpu, targfreq, pol->min, pol->max, relation);
> + pol->cpu, tdata->targfreq, pol->min, pol->max,
> tdata->relation);
>
> if (query_current_values_with_pending_wait(data))
> goto err_out;
> @@ -1193,7 +1178,8 @@ static int powernowk8_target(struct cpuf
> }
>
> if (cpufreq_frequency_table_target(pol, data->powernow_table,
> - targfreq, relation, &newstate))
> + tdata->targfreq,
> tdata->relation,
> + &newstate))
> goto err_out;
>
> mutex_lock(&fidvid_mutex);
> @@ -1220,10 +1206,19 @@ static int powernowk8_target(struct cpuf
> ret = 0;
>
> err_out:
> - set_cpus_allowed_ptr(current, &oldmask);
> return ret;
> }
>
> +/* Driver entry point to switch to the target frequency */
> +static int powernowk8_target(struct cpufreq_policy *pol,
> + unsigned targfreq, unsigned relation)
> +{
> + struct target_data tdata = { .pol = pol,
> + .targfreq = targfreq,
> + .relation = relation };
> + return work_on_cpu(pol->cpu, powernowk8_target_on_cpu, &tdata);
> +}
> +
> /* Driver entry point to verify the policy and range of
> frequencies */
> static int powernowk8_verify(struct cpufreq_policy *pol)
> {