Commit b4dfdbb3 authored by Alan Stern's avatar Alan Stern Committed by Linus Torvalds

[PATCH] cpufreq: make the transition_notifier chain use SRCU

This patch (as762) changes the cpufreq_transition_notifier_list from a
blocking_notifier_head to an srcu_notifier_head.  This will prevent errors
caused attempting to call down_read() to access the notifier chain at a
time when interrupts must remain disabled, during system suspend.

It's not clear to me whether this is really necessary; perhaps the chain
could be made into an atomic_notifier.  However a couple of the callout
routines do use blocking operations, so this approach seems safer.

The head of the notifier chain needs to be initialized before use; this is
done by an __init routine at core_initcall time.  If this turns out not to
be a good choice, it can easily be changed.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Cc: "Paul E. McKenney" <paulmck@us.ibm.com>
Cc: Jesse Brandeburg <jesse.brandeburg@gmail.com>
Cc: Dave Jones <davej@codemonkey.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent e6a92013
...@@ -52,8 +52,14 @@ static void handle_update(void *data); ...@@ -52,8 +52,14 @@ static void handle_update(void *data);
* The mutex locks both lists. * The mutex locks both lists.
*/ */
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list); static struct srcu_notifier_head cpufreq_transition_notifier_list;
static int __init init_cpufreq_transition_notifier_list(void)
{
srcu_init_notifier_head(&cpufreq_transition_notifier_list);
return 0;
}
core_initcall(init_cpufreq_transition_notifier_list);
static LIST_HEAD(cpufreq_governor_list); static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX (cpufreq_governor_mutex); static DEFINE_MUTEX (cpufreq_governor_mutex);
...@@ -262,14 +268,14 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) ...@@ -262,14 +268,14 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
freqs->old = policy->cur; freqs->old = policy->cur;
} }
} }
blocking_notifier_call_chain(&cpufreq_transition_notifier_list, srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_PRECHANGE, freqs); CPUFREQ_PRECHANGE, freqs);
adjust_jiffies(CPUFREQ_PRECHANGE, freqs); adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
break; break;
case CPUFREQ_POSTCHANGE: case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
blocking_notifier_call_chain(&cpufreq_transition_notifier_list, srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs); CPUFREQ_POSTCHANGE, freqs);
if (likely(policy) && likely(policy->cpu == freqs->cpu)) if (likely(policy) && likely(policy->cpu == freqs->cpu))
policy->cur = freqs->new; policy->cur = freqs->new;
...@@ -1049,7 +1055,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) ...@@ -1049,7 +1055,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
freqs.old = cpu_policy->cur; freqs.old = cpu_policy->cur;
freqs.new = cur_freq; freqs.new = cur_freq;
blocking_notifier_call_chain(&cpufreq_transition_notifier_list, srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_SUSPENDCHANGE, &freqs); CPUFREQ_SUSPENDCHANGE, &freqs);
adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
...@@ -1130,7 +1136,7 @@ static int cpufreq_resume(struct sys_device * sysdev) ...@@ -1130,7 +1136,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
freqs.old = cpu_policy->cur; freqs.old = cpu_policy->cur;
freqs.new = cur_freq; freqs.new = cur_freq;
blocking_notifier_call_chain( srcu_notifier_call_chain(
&cpufreq_transition_notifier_list, &cpufreq_transition_notifier_list,
CPUFREQ_RESUMECHANGE, &freqs); CPUFREQ_RESUMECHANGE, &freqs);
adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
...@@ -1176,7 +1182,7 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) ...@@ -1176,7 +1182,7 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
switch (list) { switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER: case CPUFREQ_TRANSITION_NOTIFIER:
ret = blocking_notifier_chain_register( ret = srcu_notifier_chain_register(
&cpufreq_transition_notifier_list, nb); &cpufreq_transition_notifier_list, nb);
break; break;
case CPUFREQ_POLICY_NOTIFIER: case CPUFREQ_POLICY_NOTIFIER:
...@@ -1208,7 +1214,7 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) ...@@ -1208,7 +1214,7 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
switch (list) { switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER: case CPUFREQ_TRANSITION_NOTIFIER:
ret = blocking_notifier_chain_unregister( ret = srcu_notifier_chain_unregister(
&cpufreq_transition_notifier_list, nb); &cpufreq_transition_notifier_list, nb);
break; break;
case CPUFREQ_POLICY_NOTIFIER: case CPUFREQ_POLICY_NOTIFIER:
......
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