From: Alexandra Yates <alexandra.yates@linux.intel.com>
To: tglx@linutronix.de, rjw@rjwysocki.net,
kristen.c.accardi@intel.com, linux-pm@vger.kernel.org
Cc: Alexandra Yates <alexandra.yates@linux.intel.com>
Subject: [PATCH V6] Report interrupt(s) that caused system wakeup
Date: Thu, 27 Aug 2015 13:00:43 -0700 [thread overview]
Message-ID: <1440705643-3092-2-git-send-email-alexandra.yates@linux.intel.com> (raw)
In-Reply-To: <1440705643-3092-1-git-send-email-alexandra.yates@linux.intel.com>
This feature reports which IRQs cause the system to wakeup from sleep last
time it was suspended.
It adds a new sysfs attribute under /sys/power/ named: pm_last_wakeup_irqs
when read, will return a list of IRQs that caused the system to wakeup.
That will be useful for system wakeup diagnostics.
Signed-off-by: Alexandra Yates <alexandra.yates@linux.intel.com>
---
Documentation/ABI/testing/sysfs-power | 11 +++++++++++
drivers/base/power/wakeup.c | 33 ++++++++++++++++++++++++++++++++-
include/linux/suspend.h | 5 +++--
kernel/irq/pm.c | 2 +-
kernel/power/main.c | 23 +++++++++++++++++++++++
5 files changed, 70 insertions(+), 4 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index f455181..4f9cc3a 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -256,3 +256,14 @@ Description:
Writing a "1" enables this printing while writing a "0"
disables it. The default value is "0". Reading from this file
will display the current value.
+
+What: /sys/power/pm_last_wakeup_irqs
+Date: April 2015
+Contact: Alexandra Yates <alexandra.yates@linux.intel.org>
+Description:
+ The /sys/power/pm_last_wakeup_irqs file allows user space
+ to identify and report the IRQs responsible for waking the
+ system up from sleep. The IRQD_WAKEUP_TRIGGERED flag is set and
+ reported when the given IRQ fires after it has been armed for
+ system wakeup. This output is useful for system wakeup
+ diagnostics.
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 51f15bc..0f6cc55 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -28,6 +28,9 @@ bool events_check_enabled __read_mostly;
/* If set and the system is suspending, terminate the suspend. */
static bool pm_abort_suspend __read_mostly;
+/* IRQ number which causes system wakeup */
+static unsigned int wakeup_irq;
+
/*
* Combined counters of registered wakeup events and wakeup events in progress.
* They need to be modified together atomically, so it's better to use one
@@ -858,8 +861,9 @@ bool pm_wakeup_pending(void)
return ret || pm_abort_suspend;
}
-void pm_system_wakeup(void)
+void pm_system_irq_wakeup(unsigned int irq_number)
{
+ wakeup_irq = irq_number;
pm_abort_suspend = true;
freeze_wake();
}
@@ -870,6 +874,33 @@ void pm_wakeup_clear(void)
pm_abort_suspend = false;
}
+#ifdef CONFIG_PM_SLEEP_DEBUG
+/*
+ * pm_get_last_wakeup_irqs - gets interrupt number that
+ * caused the system to wake up from suspend-to-idle.
+ * @buf: keeps track of the irqs that casued the system to wakeup
+ */
+ssize_t pm_get_last_wakeup_irqs(char *buf, size_t size)
+{
+ char *str = buf;
+ char *end = buf + size;
+
+ if (!pm_abort_suspend)
+ return 0;
+
+ /* If pm_abort_suspend is not set, the previous suspend was aborted
+ * before arming the wakeup IRQs, so avoid printing stale information
+ * in that case.
+ */
+ str += scnprintf(str, end - str, "%d ", wakeup_irq);
+
+ if (str != buf)
+ str--;
+
+ return (str - buf);
+}
+#endif /* CONFIG_PM_SLEEP_DEBUG */
+
/**
* pm_get_wakeup_count - Read the number of registered wakeup events.
* @count: Address to store the value at.
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 5efe743..86ab316 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -378,6 +378,7 @@ void restore_processor_state(void);
/* kernel/power/main.c */
extern int register_pm_notifier(struct notifier_block *nb);
extern int unregister_pm_notifier(struct notifier_block *nb);
+extern ssize_t pm_get_last_wakeup_irqs(char *buf, size_t size);
#define pm_notifier(fn, pri) { \
static struct notifier_block fn##_nb = \
@@ -389,7 +390,7 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
extern bool events_check_enabled;
extern bool pm_wakeup_pending(void);
-extern void pm_system_wakeup(void);
+extern void pm_system_irq_wakeup(unsigned int);
extern void pm_wakeup_clear(void);
extern bool pm_get_wakeup_count(unsigned int *count, bool block);
extern bool pm_save_wakeup_count(unsigned int count);
@@ -438,7 +439,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
#define pm_notifier(fn, pri) do { (void)(fn); } while (0)
static inline bool pm_wakeup_pending(void) { return false; }
-static inline void pm_system_wakeup(void) {}
+static inline void pm_system_irq_wakeup(unsigned int) {}
static inline void pm_wakeup_clear(void) {}
static inline void lock_system_sleep(void) {}
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index d22786a..46068a1 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -21,7 +21,7 @@ bool irq_pm_check_wakeup(struct irq_desc *desc)
desc->istate |= IRQS_SUSPENDED | IRQS_PENDING;
desc->depth++;
irq_disable(desc);
- pm_system_wakeup();
+ pm_system_irq_wakeup(irq_desc_get_irq(desc));
return true;
}
return false;
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 63d395b..6e550c0 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -272,6 +272,28 @@ static inline void pm_print_times_init(void)
{
pm_print_times_enabled = !!initcall_debug;
}
+
+static ssize_t pm_last_wakeup_irqs_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ size_t ret;
+
+ ret = pm_get_last_wakeup_irqs(buf, PAGE_SIZE);
+ if (ret)
+ buf[ret++] = '\n';
+
+ return ret;
+}
+
+static ssize_t pm_last_wakeup_irqs_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ return -EINVAL;
+}
+power_attr(pm_last_wakeup_irqs);
+
#else /* !CONFIG_PM_SLEEP_DEBUG */
static inline void pm_print_times_init(void) {}
#endif /* CONFIG_PM_SLEEP_DEBUG */
@@ -604,6 +626,7 @@ static struct attribute * g[] = {
#endif
#ifdef CONFIG_PM_SLEEP_DEBUG
&pm_print_times_attr.attr,
+ &pm_last_wakeup_irqs_attr.attr,
#endif
#endif
#ifdef CONFIG_FREEZER
--
1.9.1
next prev parent reply other threads:[~2015-08-27 19:59 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <[PATCH V6] Report interrupt(s) that caused system wakeup>
2015-08-27 20:00 ` [PATCH V6] Report interrupt(s) that caused system wakeup Alexandra Yates
2015-08-27 20:00 ` Alexandra Yates [this message]
2015-09-07 22:16 ` Rafael J. Wysocki
2015-09-08 14:18 ` Alan Stern
2015-09-08 15:09 ` Rafael J. Wysocki
2015-09-09 0:56 ` Rafael J. Wysocki
2015-09-10 2:57 ` Alexandra Yates
2015-08-28 7:40 ` Thomas Gleixner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1440705643-3092-2-git-send-email-alexandra.yates@linux.intel.com \
--to=alexandra.yates@linux.intel.com \
--cc=kristen.c.accardi@intel.com \
--cc=linux-pm@vger.kernel.org \
--cc=rjw@rjwysocki.net \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).