|
@@ -21,7 +21,7 @@
|
|
|
* If set, the suspend/hibernate code will abort transitions to a sleep state
|
|
|
* if wakeup events are registered during or immediately before the transition.
|
|
|
*/
|
|
|
-bool events_check_enabled;
|
|
|
+bool events_check_enabled __read_mostly;
|
|
|
|
|
|
/*
|
|
|
* Combined counters of registered wakeup events and wakeup events in progress.
|
|
@@ -382,6 +382,21 @@ static void wakeup_source_activate(struct wakeup_source *ws)
|
|
|
atomic_inc(&combined_event_count);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * wakeup_source_report_event - Report wakeup event using the given source.
|
|
|
+ * @ws: Wakeup source to report the event for.
|
|
|
+ */
|
|
|
+static void wakeup_source_report_event(struct wakeup_source *ws)
|
|
|
+{
|
|
|
+ ws->event_count++;
|
|
|
+ /* This is racy, but the counter is approximate anyway. */
|
|
|
+ if (events_check_enabled)
|
|
|
+ ws->wakeup_count++;
|
|
|
+
|
|
|
+ if (!ws->active)
|
|
|
+ wakeup_source_activate(ws);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* __pm_stay_awake - Notify the PM core of a wakeup event.
|
|
|
* @ws: Wakeup source object associated with the source of the event.
|
|
@@ -397,10 +412,7 @@ void __pm_stay_awake(struct wakeup_source *ws)
|
|
|
|
|
|
spin_lock_irqsave(&ws->lock, flags);
|
|
|
|
|
|
- ws->event_count++;
|
|
|
- if (!ws->active)
|
|
|
- wakeup_source_activate(ws);
|
|
|
-
|
|
|
+ wakeup_source_report_event(ws);
|
|
|
del_timer(&ws->timer);
|
|
|
ws->timer_expires = 0;
|
|
|
|
|
@@ -469,6 +481,7 @@ static void wakeup_source_deactivate(struct wakeup_source *ws)
|
|
|
if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
|
|
|
ws->max_time = duration;
|
|
|
|
|
|
+ ws->last_time = now;
|
|
|
del_timer(&ws->timer);
|
|
|
ws->timer_expires = 0;
|
|
|
|
|
@@ -541,8 +554,10 @@ static void pm_wakeup_timer_fn(unsigned long data)
|
|
|
spin_lock_irqsave(&ws->lock, flags);
|
|
|
|
|
|
if (ws->active && ws->timer_expires
|
|
|
- && time_after_eq(jiffies, ws->timer_expires))
|
|
|
+ && time_after_eq(jiffies, ws->timer_expires)) {
|
|
|
wakeup_source_deactivate(ws);
|
|
|
+ ws->expire_count++;
|
|
|
+ }
|
|
|
|
|
|
spin_unlock_irqrestore(&ws->lock, flags);
|
|
|
}
|
|
@@ -569,9 +584,7 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
|
|
|
|
|
|
spin_lock_irqsave(&ws->lock, flags);
|
|
|
|
|
|
- ws->event_count++;
|
|
|
- if (!ws->active)
|
|
|
- wakeup_source_activate(ws);
|
|
|
+ wakeup_source_report_event(ws);
|
|
|
|
|
|
if (!msec) {
|
|
|
wakeup_source_deactivate(ws);
|
|
@@ -613,24 +626,6 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(pm_wakeup_event);
|
|
|
|
|
|
-/**
|
|
|
- * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources.
|
|
|
- */
|
|
|
-static void pm_wakeup_update_hit_counts(void)
|
|
|
-{
|
|
|
- unsigned long flags;
|
|
|
- struct wakeup_source *ws;
|
|
|
-
|
|
|
- rcu_read_lock();
|
|
|
- list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
|
|
- spin_lock_irqsave(&ws->lock, flags);
|
|
|
- if (ws->active)
|
|
|
- ws->hit_count++;
|
|
|
- spin_unlock_irqrestore(&ws->lock, flags);
|
|
|
- }
|
|
|
- rcu_read_unlock();
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* pm_wakeup_pending - Check if power transition in progress should be aborted.
|
|
|
*
|
|
@@ -653,8 +648,6 @@ bool pm_wakeup_pending(void)
|
|
|
events_check_enabled = !ret;
|
|
|
}
|
|
|
spin_unlock_irqrestore(&events_lock, flags);
|
|
|
- if (ret)
|
|
|
- pm_wakeup_update_hit_counts();
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -680,7 +673,6 @@ bool pm_get_wakeup_count(unsigned int *count)
|
|
|
split_counters(&cnt, &inpr);
|
|
|
if (inpr == 0 || signal_pending(current))
|
|
|
break;
|
|
|
- pm_wakeup_update_hit_counts();
|
|
|
|
|
|
schedule();
|
|
|
}
|
|
@@ -713,8 +705,6 @@ bool pm_save_wakeup_count(unsigned int count)
|
|
|
events_check_enabled = true;
|
|
|
}
|
|
|
spin_unlock_irq(&events_lock);
|
|
|
- if (!events_check_enabled)
|
|
|
- pm_wakeup_update_hit_counts();
|
|
|
return events_check_enabled;
|
|
|
}
|
|
|
|
|
@@ -749,9 +739,10 @@ static int print_wakeup_source_stats(struct seq_file *m,
|
|
|
active_time = ktime_set(0, 0);
|
|
|
}
|
|
|
|
|
|
- ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t"
|
|
|
+ ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
|
|
|
"%lld\t\t%lld\t\t%lld\t\t%lld\n",
|
|
|
- ws->name, active_count, ws->event_count, ws->hit_count,
|
|
|
+ ws->name, active_count, ws->event_count,
|
|
|
+ ws->wakeup_count, ws->expire_count,
|
|
|
ktime_to_ms(active_time), ktime_to_ms(total_time),
|
|
|
ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
|
|
|
|
|
@@ -768,8 +759,9 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
|
|
|
{
|
|
|
struct wakeup_source *ws;
|
|
|
|
|
|
- seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t"
|
|
|
- "active_since\ttotal_time\tmax_time\tlast_change\n");
|
|
|
+ seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
|
|
|
+ "expire_count\tactive_since\ttotal_time\tmax_time\t"
|
|
|
+ "last_change\n");
|
|
|
|
|
|
rcu_read_lock();
|
|
|
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
|