aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorTodd Poynor <toddpoynor@google.com>2012-08-11 18:17:02 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-08-17 13:40:50 -0400
commita938da0682c2487f6aafc9a7c3caa8d675acdb38 (patch)
tree9315bdea7427d9a5f4ede253f0c46be780a21d5e /drivers/base
parentd9875690d9b89a866022ff49e3fcea892345ad92 (diff)
PM / Sleep: Print name of wakeup source that aborts suspend
A driver or app may repeatedly request a wakeup source while the system is attempting to enter suspend, which may indicate a bug or at least point out a highly active system component that is responsible for decreased battery life on a mobile device. Even when the incidence of suspend abort is not severe, identifying wakeup sources that frequently abort suspend can be a useful clue for power management analysis. In some cases the existing stats can point out the offender where there is an unexpectedly high activation count that stands out from the others, but in other cases the wakeup source frequently taken just after the rest of the system thinks its time to suspend might not stand out in the overall stats. It is also often useful to have information about what's been happening recently, rather than totals of all activity for the system boot. It's suggested to dump a line about which wakeup source aborted suspend to aid analysis of these situations. Signed-off-by: Todd Poynor <toddpoynor@google.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/wakeup.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index cbb463b3a750..8a0a9ca6ad65 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -649,6 +649,31 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
649} 649}
650EXPORT_SYMBOL_GPL(pm_wakeup_event); 650EXPORT_SYMBOL_GPL(pm_wakeup_event);
651 651
652static void print_active_wakeup_sources(void)
653{
654 struct wakeup_source *ws;
655 int active = 0;
656 struct wakeup_source *last_activity_ws = NULL;
657
658 rcu_read_lock();
659 list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
660 if (ws->active) {
661 pr_info("active wakeup source: %s\n", ws->name);
662 active = 1;
663 } else if (!active &&
664 (!last_activity_ws ||
665 ktime_to_ns(ws->last_time) >
666 ktime_to_ns(last_activity_ws->last_time))) {
667 last_activity_ws = ws;
668 }
669 }
670
671 if (!active && last_activity_ws)
672 pr_info("last active wakeup source: %s\n",
673 last_activity_ws->name);
674 rcu_read_unlock();
675}
676
652/** 677/**
653 * pm_wakeup_pending - Check if power transition in progress should be aborted. 678 * pm_wakeup_pending - Check if power transition in progress should be aborted.
654 * 679 *
@@ -671,6 +696,10 @@ bool pm_wakeup_pending(void)
671 events_check_enabled = !ret; 696 events_check_enabled = !ret;
672 } 697 }
673 spin_unlock_irqrestore(&events_lock, flags); 698 spin_unlock_irqrestore(&events_lock, flags);
699
700 if (ret)
701 print_active_wakeup_sources();
702
674 return ret; 703 return ret;
675} 704}
676 705