Skip to content

Commit 275d4be

Browse files
KAGA-KOKOgregkh
authored andcommitted
PM / wakeirq: Convert to SRCU
commit ea0212f40c6bc0594c8eff79266759e3ecd4bacc upstream. The wakeirq infrastructure uses RCU to protect the list of wakeirqs. That breaks the irq bus locking infrastructure, which is allows sleeping functions to be called so interrupt controllers behind slow busses, e.g. i2c, can be handled. The wakeirq functions hold rcu_read_lock and call into irq functions, which in case of interrupts using the irq bus locking will trigger a might_sleep() splat. Convert the wakeirq infrastructure to Sleepable RCU and unbreak it. Fixes: 4990d4f (PM / Wakeirq: Add automated device wake IRQ handling) Reported-by: Brian Norris <briannorris@chromium.org> Suggested-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Tested-by: Tony Lindgren <tony@atomide.com> Tested-by: Brian Norris <briannorris@chromium.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 988067e commit 275d4be

1 file changed

Lines changed: 18 additions & 12 deletions

File tree

drivers/base/power/wakeup.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ static LIST_HEAD(wakeup_sources);
6060

6161
static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
6262

63+
DEFINE_STATIC_SRCU(wakeup_srcu);
64+
6365
static struct wakeup_source deleted_ws = {
6466
.name = "deleted",
6567
.lock = __SPIN_LOCK_UNLOCKED(deleted_ws.lock),
@@ -198,7 +200,7 @@ void wakeup_source_remove(struct wakeup_source *ws)
198200
spin_lock_irqsave(&events_lock, flags);
199201
list_del_rcu(&ws->entry);
200202
spin_unlock_irqrestore(&events_lock, flags);
201-
synchronize_rcu();
203+
synchronize_srcu(&wakeup_srcu);
202204
}
203205
EXPORT_SYMBOL_GPL(wakeup_source_remove);
204206

@@ -330,13 +332,14 @@ void device_wakeup_detach_irq(struct device *dev)
330332
void device_wakeup_arm_wake_irqs(void)
331333
{
332334
struct wakeup_source *ws;
335+
int srcuidx;
333336

334-
rcu_read_lock();
337+
srcuidx = srcu_read_lock(&wakeup_srcu);
335338
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
336339
if (ws->wakeirq)
337340
dev_pm_arm_wake_irq(ws->wakeirq);
338341
}
339-
rcu_read_unlock();
342+
srcu_read_unlock(&wakeup_srcu, srcuidx);
340343
}
341344

342345
/**
@@ -347,13 +350,14 @@ void device_wakeup_arm_wake_irqs(void)
347350
void device_wakeup_disarm_wake_irqs(void)
348351
{
349352
struct wakeup_source *ws;
353+
int srcuidx;
350354

351-
rcu_read_lock();
355+
srcuidx = srcu_read_lock(&wakeup_srcu);
352356
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
353357
if (ws->wakeirq)
354358
dev_pm_disarm_wake_irq(ws->wakeirq);
355359
}
356-
rcu_read_unlock();
360+
srcu_read_unlock(&wakeup_srcu, srcuidx);
357361
}
358362

359363
/**
@@ -807,10 +811,10 @@ EXPORT_SYMBOL_GPL(pm_wakeup_event);
807811
void pm_print_active_wakeup_sources(void)
808812
{
809813
struct wakeup_source *ws;
810-
int active = 0;
814+
int srcuidx, active = 0;
811815
struct wakeup_source *last_activity_ws = NULL;
812816

813-
rcu_read_lock();
817+
srcuidx = srcu_read_lock(&wakeup_srcu);
814818
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
815819
if (ws->active) {
816820
pr_info("active wakeup source: %s\n", ws->name);
@@ -826,7 +830,7 @@ void pm_print_active_wakeup_sources(void)
826830
if (!active && last_activity_ws)
827831
pr_info("last active wakeup source: %s\n",
828832
last_activity_ws->name);
829-
rcu_read_unlock();
833+
srcu_read_unlock(&wakeup_srcu, srcuidx);
830834
}
831835
EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);
832836

@@ -953,8 +957,9 @@ void pm_wakep_autosleep_enabled(bool set)
953957
{
954958
struct wakeup_source *ws;
955959
ktime_t now = ktime_get();
960+
int srcuidx;
956961

957-
rcu_read_lock();
962+
srcuidx = srcu_read_lock(&wakeup_srcu);
958963
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
959964
spin_lock_irq(&ws->lock);
960965
if (ws->autosleep_enabled != set) {
@@ -968,7 +973,7 @@ void pm_wakep_autosleep_enabled(bool set)
968973
}
969974
spin_unlock_irq(&ws->lock);
970975
}
971-
rcu_read_unlock();
976+
srcu_read_unlock(&wakeup_srcu, srcuidx);
972977
}
973978
#endif /* CONFIG_PM_AUTOSLEEP */
974979

@@ -1029,15 +1034,16 @@ static int print_wakeup_source_stats(struct seq_file *m,
10291034
static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
10301035
{
10311036
struct wakeup_source *ws;
1037+
int srcuidx;
10321038

10331039
seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
10341040
"expire_count\tactive_since\ttotal_time\tmax_time\t"
10351041
"last_change\tprevent_suspend_time\n");
10361042

1037-
rcu_read_lock();
1043+
srcuidx = srcu_read_lock(&wakeup_srcu);
10381044
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
10391045
print_wakeup_source_stats(m, ws);
1040-
rcu_read_unlock();
1046+
srcu_read_unlock(&wakeup_srcu, srcuidx);
10411047

10421048
print_wakeup_source_stats(m, &deleted_ws);
10431049

0 commit comments

Comments
 (0)