|
@@ -60,6 +60,8 @@ static LIST_HEAD(wakeup_sources);
|
|
|
|
|
|
static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
|
|
static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
|
|
|
|
|
|
|
|
+DEFINE_STATIC_SRCU(wakeup_srcu);
|
|
|
|
+
|
|
static struct wakeup_source deleted_ws = {
|
|
static struct wakeup_source deleted_ws = {
|
|
.name = "deleted",
|
|
.name = "deleted",
|
|
.lock = __SPIN_LOCK_UNLOCKED(deleted_ws.lock),
|
|
.lock = __SPIN_LOCK_UNLOCKED(deleted_ws.lock),
|
|
@@ -198,7 +200,7 @@ void wakeup_source_remove(struct wakeup_source *ws)
|
|
spin_lock_irqsave(&events_lock, flags);
|
|
spin_lock_irqsave(&events_lock, flags);
|
|
list_del_rcu(&ws->entry);
|
|
list_del_rcu(&ws->entry);
|
|
spin_unlock_irqrestore(&events_lock, flags);
|
|
spin_unlock_irqrestore(&events_lock, flags);
|
|
- synchronize_rcu();
|
|
|
|
|
|
+ synchronize_srcu(&wakeup_srcu);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(wakeup_source_remove);
|
|
EXPORT_SYMBOL_GPL(wakeup_source_remove);
|
|
|
|
|
|
@@ -332,12 +334,12 @@ void device_wakeup_detach_irq(struct device *dev)
|
|
void device_wakeup_arm_wake_irqs(void)
|
|
void device_wakeup_arm_wake_irqs(void)
|
|
{
|
|
{
|
|
struct wakeup_source *ws;
|
|
struct wakeup_source *ws;
|
|
|
|
+ int srcuidx;
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
|
|
|
+ srcuidx = srcu_read_lock(&wakeup_srcu);
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
|
|
dev_pm_arm_wake_irq(ws->wakeirq);
|
|
dev_pm_arm_wake_irq(ws->wakeirq);
|
|
-
|
|
|
|
- rcu_read_unlock();
|
|
|
|
|
|
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -348,12 +350,12 @@ void device_wakeup_arm_wake_irqs(void)
|
|
void device_wakeup_disarm_wake_irqs(void)
|
|
void device_wakeup_disarm_wake_irqs(void)
|
|
{
|
|
{
|
|
struct wakeup_source *ws;
|
|
struct wakeup_source *ws;
|
|
|
|
+ int srcuidx;
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
|
|
|
+ srcuidx = srcu_read_lock(&wakeup_srcu);
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
|
|
dev_pm_disarm_wake_irq(ws->wakeirq);
|
|
dev_pm_disarm_wake_irq(ws->wakeirq);
|
|
-
|
|
|
|
- rcu_read_unlock();
|
|
|
|
|
|
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -804,10 +806,10 @@ EXPORT_SYMBOL_GPL(pm_wakeup_dev_event);
|
|
void pm_print_active_wakeup_sources(void)
|
|
void pm_print_active_wakeup_sources(void)
|
|
{
|
|
{
|
|
struct wakeup_source *ws;
|
|
struct wakeup_source *ws;
|
|
- int active = 0;
|
|
|
|
|
|
+ int srcuidx, active = 0;
|
|
struct wakeup_source *last_activity_ws = NULL;
|
|
struct wakeup_source *last_activity_ws = NULL;
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
|
|
|
+ srcuidx = srcu_read_lock(&wakeup_srcu);
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
|
if (ws->active) {
|
|
if (ws->active) {
|
|
pr_debug("active wakeup source: %s\n", ws->name);
|
|
pr_debug("active wakeup source: %s\n", ws->name);
|
|
@@ -823,7 +825,7 @@ void pm_print_active_wakeup_sources(void)
|
|
if (!active && last_activity_ws)
|
|
if (!active && last_activity_ws)
|
|
pr_debug("last active wakeup source: %s\n",
|
|
pr_debug("last active wakeup source: %s\n",
|
|
last_activity_ws->name);
|
|
last_activity_ws->name);
|
|
- rcu_read_unlock();
|
|
|
|
|
|
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);
|
|
EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);
|
|
|
|
|
|
@@ -950,8 +952,9 @@ void pm_wakep_autosleep_enabled(bool set)
|
|
{
|
|
{
|
|
struct wakeup_source *ws;
|
|
struct wakeup_source *ws;
|
|
ktime_t now = ktime_get();
|
|
ktime_t now = ktime_get();
|
|
|
|
+ int srcuidx;
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
|
|
|
+ srcuidx = srcu_read_lock(&wakeup_srcu);
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
|
spin_lock_irq(&ws->lock);
|
|
spin_lock_irq(&ws->lock);
|
|
if (ws->autosleep_enabled != set) {
|
|
if (ws->autosleep_enabled != set) {
|
|
@@ -965,7 +968,7 @@ void pm_wakep_autosleep_enabled(bool set)
|
|
}
|
|
}
|
|
spin_unlock_irq(&ws->lock);
|
|
spin_unlock_irq(&ws->lock);
|
|
}
|
|
}
|
|
- rcu_read_unlock();
|
|
|
|
|
|
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
|
|
}
|
|
}
|
|
#endif /* CONFIG_PM_AUTOSLEEP */
|
|
#endif /* CONFIG_PM_AUTOSLEEP */
|
|
|
|
|
|
@@ -1026,15 +1029,16 @@ static int print_wakeup_source_stats(struct seq_file *m,
|
|
static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
|
|
static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
|
|
{
|
|
{
|
|
struct wakeup_source *ws;
|
|
struct wakeup_source *ws;
|
|
|
|
+ int srcuidx;
|
|
|
|
|
|
seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
|
|
seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
|
|
"expire_count\tactive_since\ttotal_time\tmax_time\t"
|
|
"expire_count\tactive_since\ttotal_time\tmax_time\t"
|
|
"last_change\tprevent_suspend_time\n");
|
|
"last_change\tprevent_suspend_time\n");
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
|
|
|
+ srcuidx = srcu_read_lock(&wakeup_srcu);
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
|
|
print_wakeup_source_stats(m, ws);
|
|
print_wakeup_source_stats(m, ws);
|
|
- rcu_read_unlock();
|
|
|
|
|
|
+ srcu_read_unlock(&wakeup_srcu, srcuidx);
|
|
|
|
|
|
print_wakeup_source_stats(m, &deleted_ws);
|
|
print_wakeup_source_stats(m, &deleted_ws);
|
|
|
|
|