Ensure that the hot-cpu-callback path in cpufreq is free from any
(un)lock_cpu_hotplug calls.
Signed-off-by : Gautham R Shenoy <[email protected]>
---
drivers/cpufreq/cpufreq.c | 83 +++++++++++++++++++++++++++-------------
drivers/cpufreq/cpufreq_stats.c | 4 +
include/linux/cpufreq.h | 1
3 files changed, 61 insertions(+), 27 deletions(-)
Index: hotplug/drivers/cpufreq/cpufreq.c
===================================================================
--- hotplug.orig/drivers/cpufreq/cpufreq.c
+++ hotplug/drivers/cpufreq/cpufreq.c
@@ -642,6 +642,7 @@ static struct kobj_type ktype_cpufreq =
};
+int _cpufreq_set_policy(struct cpufreq_policy *);
/**
* cpufreq_add_dev - add a CPU device
*
@@ -776,11 +777,11 @@ static int cpufreq_add_dev (struct sys_d
}
policy->governor = NULL; /* to assure that the starting sequence is
- * run in cpufreq_set_policy */
+ * run in _cpufreq_set_policy */
mutex_unlock(&policy->lock);
/* set default policy */
- ret = cpufreq_set_policy(&new_policy);
+ ret = _cpufreq_set_policy(&new_policy);
if (ret) {
dprintk("setting policy failed\n");
goto err_out_unregister;
@@ -1284,7 +1285,9 @@ int __cpufreq_driver_target(struct cpufr
}
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
-int cpufreq_driver_target(struct cpufreq_policy *policy,
+/*Locking: Must be called with lock_cpu_hotplug held, except from the
+hotcpu callback path */
+int _cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
@@ -1294,17 +1297,27 @@ int cpufreq_driver_target(struct cpufreq
if (!policy)
return -EINVAL;
- lock_cpu_hotplug();
mutex_lock(&policy->lock);
ret = __cpufreq_driver_target(policy, target_freq, relation);
mutex_unlock(&policy->lock);
- unlock_cpu_hotplug();
cpufreq_cpu_put(policy);
return ret;
}
+int cpufreq_driver_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ int ret;
+
+ lock_cpu_hotplug();
+ ret = _cpufreq_driver_target(policy, target_freq, relation);
+ unlock_cpu_hotplug();
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
int cpufreq_driver_getavg(struct cpufreq_policy *policy)
@@ -1511,13 +1524,8 @@ error_out:
return ret;
}
-/**
- * cpufreq_set_policy - set a new CPUFreq policy
- * @policy: policy to be set.
- *
- * Sets a new CPU frequency and voltage scaling policy.
- */
-int cpufreq_set_policy(struct cpufreq_policy *policy)
+/* Locking: To be called with lock_cpu_hotplug held. */
+int _cpufreq_set_policy(struct cpufreq_policy *policy)
{
int ret = 0;
struct cpufreq_policy *data;
@@ -1529,8 +1537,6 @@ int cpufreq_set_policy(struct cpufreq_po
if (!data)
return -EINVAL;
- lock_cpu_hotplug();
-
/* lock this CPU */
mutex_lock(&data->lock);
@@ -1541,23 +1547,32 @@ int cpufreq_set_policy(struct cpufreq_po
data->user_policy.governor = data->governor;
mutex_unlock(&data->lock);
-
- unlock_cpu_hotplug();
cpufreq_cpu_put(data);
return ret;
}
-EXPORT_SYMBOL(cpufreq_set_policy);
-
/**
- * cpufreq_update_policy - re-evaluate an existing cpufreq policy
- * @cpu: CPU which shall be re-evaluated
+ * cpufreq_set_policy - set a new CPUFreq policy
+ * @policy: policy to be set.
*
- * Usefull for policy notifiers which have different necessities
- * at different times.
+ * Sets a new CPU frequency and voltage scaling policy.
*/
-int cpufreq_update_policy(unsigned int cpu)
+int cpufreq_set_policy(struct cpufreq_policy *policy)
+{
+ int ret;
+
+ lock_cpu_hotplug();
+ ret = _cpufreq_set_policy(policy);
+ unlock_cpu_hotplug();
+
+ return ret;
+}
+EXPORT_SYMBOL(cpufreq_set_policy);
+
+
+/* Locking: to be called with lock_cpu_hotplug held. */
+int __cpufreq_update_policy(unsigned int cpu)
{
struct cpufreq_policy *data = cpufreq_cpu_get(cpu);
struct cpufreq_policy policy;
@@ -1566,7 +1581,6 @@ int cpufreq_update_policy(unsigned int c
if (!data)
return -ENODEV;
- lock_cpu_hotplug();
mutex_lock(&data->lock);
dprintk("updating policy for CPU %u\n", cpu);
@@ -1593,10 +1607,27 @@ int cpufreq_update_policy(unsigned int c
ret = __cpufreq_set_policy(data, &policy);
mutex_unlock(&data->lock);
- unlock_cpu_hotplug();
cpufreq_cpu_put(data);
return ret;
}
+
+/**
+ * cpufreq_update_policy - re-evaluate an existing cpufreq policy
+ * @cpu: CPU which shall be re-evaluated
+ *
+ * Usefull for policy notifiers which have different necessities
+ * at different times.
+ */
+int cpufreq_update_policy(unsigned int cpu)
+{
+ int ret;
+
+ lock_cpu_hotplug();
+ ret = __cpufreq_update_policy(cpu);
+ unlock_cpu_hotplug();
+
+ return ret;
+}
EXPORT_SYMBOL(cpufreq_update_policy);
#ifdef CONFIG_HOTPLUG_CPU
@@ -1623,7 +1654,7 @@ static int cpufreq_cpu_callback(struct n
*/
policy = cpufreq_cpu_data[cpu];
if (policy) {
- cpufreq_driver_target(policy, policy->min,
+ _cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_H);
}
break;
Index: hotplug/drivers/cpufreq/cpufreq_stats.c
===================================================================
--- hotplug.orig/drivers/cpufreq/cpufreq_stats.c
+++ hotplug/drivers/cpufreq/cpufreq_stats.c
@@ -309,7 +309,7 @@ static int cpufreq_stat_cpu_callback(str
switch (action) {
case CPU_ONLINE:
- cpufreq_update_policy(cpu);
+ __cpufreq_update_policy(cpu);
break;
case CPU_DEAD:
cpufreq_stats_free_table(cpu);
@@ -350,10 +350,12 @@ __init cpufreq_stats_init(void)
}
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
+ lock_cpu_hotplug();
for_each_online_cpu(cpu) {
cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
CPU_ONLINE, (void *)(long)cpu);
}
+ unlock_cpu_hotplug();
return 0;
}
static void
Index: hotplug/include/linux/cpufreq.h
===================================================================
--- hotplug.orig/include/linux/cpufreq.h
+++ hotplug/include/linux/cpufreq.h
@@ -258,6 +258,7 @@ struct freq_attr {
int cpufreq_set_policy(struct cpufreq_policy *policy);
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
int cpufreq_update_policy(unsigned int cpu);
+int __cpufreq_update_policy(unsigned int cpu);
/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
unsigned int cpufreq_get(unsigned int cpu);
--
Gautham R Shenoy
Linux Technology Center
IBM India.
"Freedom comes with a price tag of responsibility, which is still a bargain,
because Freedom is priceless!"
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]