]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
PM / sleep: Report interrupt that caused system wakeup
authorAlexandra Yates <alexandra.yates@linux.intel.com>
Tue, 15 Sep 2015 17:32:46 +0000 (10:32 -0700)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 16 Sep 2015 12:20:41 +0000 (14:20 +0200)
Add a sysfs attribute, /sys/power/pm_wakeup_irq, reporting the IRQ
number of the first wakeup interrupt (that is, the first interrupt
from an IRQ line armed for system wakeup) seen by the kernel during
the most recent system suspend/resume cycle.

This feature will be useful for system wakeup diagnostics of
spurious wakeup interrupts.

Signed-off-by: Alexandra Yates <alexandra.yates@linux.intel.com>
[ rjw: Fixed up pm_wakeup_irq definition ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Documentation/ABI/testing/sysfs-power
drivers/base/power/wakeup.c
include/linux/suspend.h
kernel/irq/pm.c
kernel/power/main.c

index f4551816329e17ae8020a256211b499776c19e4b..50b368d490b599f29809e55bbdd0a29535163fa4 100644 (file)
@@ -256,3 +256,15 @@ 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_wakeup_irq
+Date:          April 2015
+Contact:       Alexandra Yates <alexandra.yates@linux.intel.org>
+Description:
+               The /sys/power/pm_wakeup_irq file reports to user space the IRQ
+               number of the first wakeup interrupt (that is, the first
+               interrupt from an IRQ line armed for system wakeup) seen by the
+               kernel during the most recent system suspend/resume cycle.
+
+               This output is useful for system wakeup diagnostics of spurious
+               wakeup interrupts.
index 51f15bc15774250a203b46c44b5682b36f450f1d..3b361ecfaffcbb5186e4bd73ced3034bb3b02dfd 100644 (file)
@@ -25,6 +25,9 @@
  */
 bool events_check_enabled __read_mostly;
 
+/* First wakeup IRQ seen by the kernel in the last cycle. */
+unsigned int pm_wakeup_irq __read_mostly;
+
 /* If set and the system is suspending, terminate the suspend. */
 static bool pm_abort_suspend __read_mostly;
 
@@ -868,6 +871,15 @@ EXPORT_SYMBOL_GPL(pm_system_wakeup);
 void pm_wakeup_clear(void)
 {
        pm_abort_suspend = false;
+       pm_wakeup_irq = 0;
+}
+
+void pm_system_irq_wakeup(unsigned int irq_number)
+{
+       if (pm_wakeup_irq == 0) {
+               pm_wakeup_irq = irq_number;
+               pm_system_wakeup();
+       }
 }
 
 /**
index 5efe743ce1e88fc544cd4d98b2100861f1774105..33aaf9a9596c1d86381880132cc11226949495e6 100644 (file)
@@ -387,10 +387,12 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
 
 /* drivers/base/power/wakeup.c */
 extern bool events_check_enabled;
+extern unsigned int pm_wakeup_irq;
 
 extern bool pm_wakeup_pending(void);
 extern void pm_system_wakeup(void);
 extern void pm_wakeup_clear(void);
+extern void pm_system_irq_wakeup(unsigned int irq_number);
 extern bool pm_get_wakeup_count(unsigned int *count, bool block);
 extern bool pm_save_wakeup_count(unsigned int count);
 extern void pm_wakep_autosleep_enabled(bool set);
@@ -440,6 +442,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
 static inline bool pm_wakeup_pending(void) { return false; }
 static inline void pm_system_wakeup(void) {}
 static inline void pm_wakeup_clear(void) {}
+static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
 
 static inline void lock_system_sleep(void) {}
 static inline void unlock_system_sleep(void) {}
index 21c62617a35a6dae316b22221b3b4896317faedd..e80c4400118ae7a8e3f09476964260490fccf01a 100644 (file)
@@ -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;
index 63d395b5df9305b0033e6e294e209bf101e0937b..b2dd4d999900a26edd9cd26fb952b84b98ee411f 100644 (file)
@@ -272,6 +272,22 @@ static inline void pm_print_times_init(void)
 {
        pm_print_times_enabled = !!initcall_debug;
 }
+
+static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       char *buf)
+{
+       return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA;
+}
+
+static ssize_t pm_wakeup_irq_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buf, size_t n)
+{
+       return -EINVAL;
+}
+power_attr(pm_wakeup_irq);
+
 #else /* !CONFIG_PM_SLEEP_DEBUG */
 static inline void pm_print_times_init(void) {}
 #endif /* CONFIG_PM_SLEEP_DEBUG */
@@ -604,6 +620,7 @@ static struct attribute * g[] = {
 #endif
 #ifdef CONFIG_PM_SLEEP_DEBUG
        &pm_print_times_attr.attr,
+       &pm_wakeup_irq_attr.attr,
 #endif
 #endif
 #ifdef CONFIG_FREEZER