Commit e45335e8 authored by Dave Jones's avatar Dave Jones

[CPUFREQ] Fix locking [7/11]

Finally implement the two different cpufreq_driver_target callbacks --
the one called while the per-CPU lock is held, the other while
not. While we're at it, clean up cpufreq_governor.
parent 2717cc0d
......@@ -135,21 +135,21 @@ CPUfreq core to ensure proper locking.
The CPUfreq governor may call the CPU processor driver using one of
these two functions:
inline int cpufreq_driver_target(struct cpufreq_policy *policy,
int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
inline int cpufreq_driver_target_l(struct cpufreq_policy *policy,
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
target_freq must be within policy->min and policy->max, of course.
What's the difference between these two functions? When your governor
still is in a direct code path of a call to governor->governor, the
cpufreq_driver_sem lock is still held in the cpufreq core, and there's
per-CPU cpufreq lock is still held in the cpufreq core, and there's
no need to lock it again (in fact, this would cause a deadlock). So
use cpufreq_driver_target only in these cases. In all other cases (for
example, when there's a "daemonized" function that wakes up every
second), use cpufreq_driver_target_l to lock the cpufreq_driver_sem
before the command is passed to the cpufreq processor driver.
use __cpufreq_driver_target only in these cases. In all other cases
(for example, when there's a "daemonized" function that wakes up
every second), use cpufreq_driver_target to lock the cpufreq per-CPU
lock before the command is passed to the cpufreq processor driver.
......@@ -524,10 +524,10 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
cpu_min_freq[cpu] = policy->min;
cpu_max_freq[cpu] = policy->max;
if (policy->max < cpu_cur_freq[cpu])
cpufreq_driver_target(&current_policy[cpu], policy->max,
__cpufreq_driver_target(&current_policy[cpu], policy->max,
CPUFREQ_RELATION_H);
else if (policy->min > cpu_cur_freq[cpu])
cpufreq_driver_target(&current_policy[cpu], policy->min,
__cpufreq_driver_target(&current_policy[cpu], policy->min,
CPUFREQ_RELATION_L);
memcpy (&current_policy[cpu], policy, sizeof(struct cpufreq_policy));
up(&userspace_sem);
......
......@@ -137,9 +137,13 @@ struct cpufreq_governor {
/* pass a target to the cpufreq driver
*/
inline int cpufreq_driver_target(struct cpufreq_policy *policy,
extern int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
extern int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
/* pass an event to the cpufreq governor */
int cpufreq_governor(unsigned int cpu, unsigned int event);
......
......@@ -575,9 +575,19 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
* GOVERNORS *
*********************************************************************/
inline int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
return cpufreq_driver->target(policy, target_freq, relation);
}
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int ret;
......@@ -587,7 +597,7 @@ inline int cpufreq_driver_target(struct cpufreq_policy *policy,
down(&policy->lock);
ret = cpufreq_driver->target(policy, target_freq, relation);
ret = __cpufreq_driver_target(policy, target_freq, relation);
up(&policy->lock);
......@@ -606,36 +616,36 @@ int cpufreq_governor(unsigned int cpu, unsigned int event)
if (!policy)
return -EINVAL;
down(&policy->lock);
switch (policy->policy) {
case CPUFREQ_POLICY_POWERSAVE:
if ((event == CPUFREQ_GOV_LIMITS) || (event == CPUFREQ_GOV_START)) {
down(&cpufreq_driver->policy[cpu].lock);
ret = cpufreq_driver->target(policy, policy->min, CPUFREQ_RELATION_L);
up(&cpufreq_driver->policy[cpu].lock);
ret = __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
}
break;
case CPUFREQ_POLICY_PERFORMANCE:
if ((event == CPUFREQ_GOV_LIMITS) || (event == CPUFREQ_GOV_START)) {
down(&cpufreq_driver->policy[cpu].lock);
ret = cpufreq_driver->target(policy, policy->max, CPUFREQ_RELATION_H);
up(&cpufreq_driver->policy[cpu].lock);
ret = __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
}
break;
case CPUFREQ_POLICY_GOVERNOR:
ret = -EINVAL;
if (!try_module_get(cpufreq_driver->policy[cpu].governor->owner))
if (!try_module_get(policy->governor->owner))
break;
ret = cpufreq_driver->policy[cpu].governor->governor(policy, event);
ret = policy->governor->governor(policy, event);
/* we keep one module reference alive for each CPU governed by this CPU */
if ((event != CPUFREQ_GOV_START) || ret)
module_put(cpufreq_driver->policy[cpu].governor->owner);
module_put(policy->governor->owner);
if ((event == CPUFREQ_GOV_STOP) && !ret)
module_put(cpufreq_driver->policy[cpu].governor->owner);
module_put(policy->governor->owner);
break;
default:
ret = -EINVAL;
}
up(&policy->lock);
cpufreq_cpu_put(policy);
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