Commit 9e41f010 authored by Dave Jones's avatar Dave Jones

[CPUFREQ] Fix locking [9/11]

Use the per-CPU policy->lock to lock the per-CPU "policy" data. Also,
use it to serialize the setting of new frequency policies on each CPU.
parent 86372d54
...@@ -362,6 +362,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -362,6 +362,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
policy = &cpufreq_driver->policy[cpu]; policy = &cpufreq_driver->policy[cpu];
policy->cpu = cpu; policy->cpu = cpu;
init_MUTEX_LOCKED(&policy->lock);
init_completion(&policy->kobj_unregister);
/* call driver. From then on the cpufreq must be able /* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU * to accept all calls to ->verify and ->setpolicy for this CPU
...@@ -370,15 +372,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -370,15 +372,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
if (ret) if (ret)
goto out; goto out;
/* set default policy on this CPU */ memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
down(&cpufreq_driver_sem);
memcpy(&new_policy,
policy,
sizeof(struct cpufreq_policy));
up(&cpufreq_driver_sem);
init_MUTEX(&policy->lock);
init_completion(&policy->kobj_unregister);
/* prepare interface data */ /* prepare interface data */
policy->kobj.parent = &sys_dev->kobj; policy->kobj.parent = &sys_dev->kobj;
...@@ -400,12 +394,15 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -400,12 +394,15 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
cpufreq_cpu_data[cpu] = policy; cpufreq_cpu_data[cpu] = policy;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
up(&policy->lock);
/* set default policy */ /* set default policy */
ret = cpufreq_set_policy(&new_policy); ret = cpufreq_set_policy(&new_policy);
if (ret) { if (ret) {
spin_lock_irqsave(&cpufreq_driver_lock, flags); spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_cpu_data[cpu] = NULL; cpufreq_cpu_data[cpu] = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
kobject_unregister(&policy->kobj); kobject_unregister(&policy->kobj);
wait_for_completion(&policy->kobj_unregister); wait_for_completion(&policy->kobj_unregister);
} }
...@@ -440,9 +437,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) ...@@ -440,9 +437,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
if (!kobject_get(&data->kobj)) if (!kobject_get(&data->kobj))
return -EFAULT; return -EFAULT;
down(&cpufreq_driver_sem);
kobject_unregister(&data->kobj); kobject_unregister(&data->kobj);
up(&cpufreq_driver_sem);
kobject_put(&data->kobj); kobject_put(&data->kobj);
...@@ -482,9 +477,9 @@ static int cpufreq_restore(struct sys_device * sysdev) ...@@ -482,9 +477,9 @@ static int cpufreq_restore(struct sys_device * sysdev)
cpu_policy = cpufreq_cpu_get(cpu); cpu_policy = cpufreq_cpu_get(cpu);
down(&cpufreq_driver_sem); down(&cpu_policy->lock);
memcpy(&policy, cpu_policy, sizeof(struct cpufreq_policy)); memcpy(&policy, cpu_policy, sizeof(struct cpufreq_policy));
up(&cpufreq_driver_sem); up(&cpu_policy->lock);
ret = cpufreq_set_policy(&policy); ret = cpufreq_set_policy(&policy);
...@@ -724,9 +719,9 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) ...@@ -724,9 +719,9 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
if (!cpu_policy) if (!cpu_policy)
return -EINVAL; return -EINVAL;
down(&cpufreq_driver_sem); down(&cpu_policy->lock);
memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy));
up(&cpufreq_driver_sem); up(&cpu_policy->lock);
cpufreq_cpu_put(cpu_policy); cpufreq_cpu_put(cpu_policy);
...@@ -753,11 +748,12 @@ int cpufreq_set_policy(struct cpufreq_policy *policy) ...@@ -753,11 +748,12 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
if (!data) if (!data)
return -EINVAL; return -EINVAL;
down(&cpufreq_driver_sem); /* lock this CPU */
down(&data->lock);
memcpy(&policy->cpuinfo, memcpy(&policy->cpuinfo,
&data->cpuinfo, &data->cpuinfo,
sizeof(struct cpufreq_cpuinfo)); sizeof(struct cpufreq_cpuinfo));
up(&cpufreq_driver_sem);
/* verify the cpu speed can be set within this limit */ /* verify the cpu speed can be set within this limit */
ret = cpufreq_driver->verify(policy); ret = cpufreq_driver->verify(policy);
...@@ -804,26 +800,25 @@ int cpufreq_set_policy(struct cpufreq_policy *policy) ...@@ -804,26 +800,25 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
struct cpufreq_governor *old_gov = data->governor; struct cpufreq_governor *old_gov = data->governor;
/* end old governor */ /* end old governor */
cpufreq_governor(data->cpu, CPUFREQ_GOV_STOP); __cpufreq_governor(data, CPUFREQ_GOV_STOP);
/* start new governor */ /* start new governor */
data->policy = policy->policy; data->policy = policy->policy;
data->governor = policy->governor; data->governor = policy->governor;
if (cpufreq_governor(data->cpu, CPUFREQ_GOV_START)) { if (__cpufreq_governor(data, CPUFREQ_GOV_START)) {
/* new governor failed, so re-start old one */ /* new governor failed, so re-start old one */
data->policy = old_pol; data->policy = old_pol;
data->governor = old_gov; data->governor = old_gov;
cpufreq_governor(data->cpu, CPUFREQ_GOV_START); __cpufreq_governor(data, CPUFREQ_GOV_START);
} }
/* might be a policy change, too */ /* might be a policy change, too, so fall through */
cpufreq_governor(data->cpu, CPUFREQ_GOV_LIMITS);
} else {
cpufreq_governor(data->cpu, CPUFREQ_GOV_LIMITS);
} }
__cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
} }
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
error_out: error_out:
up(&data->lock);
cpufreq_cpu_put(data); cpufreq_cpu_put(data);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment