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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.