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