aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandra Yates <alexandra.yates@linux.intel.com>2015-09-15 13:32:46 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-09-16 08:20:41 -0400
commita6f5f0dd4e21191ce35030dd4d6421e1cca10ee4 (patch)
treed11055309f1b697fe91aadaf327dace3412b31f1
parent6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff)
PM / sleep: Report interrupt that caused system wakeup
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>
-rw-r--r--Documentation/ABI/testing/sysfs-power12
-rw-r--r--drivers/base/power/wakeup.c12
-rw-r--r--include/linux/suspend.h3
-rw-r--r--kernel/irq/pm.c2
-rw-r--r--kernel/power/main.c17
5 files changed, 45 insertions, 1 deletions
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index f4551816329e..50b368d490b5 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -256,3 +256,15 @@ Description:
256 Writing a "1" enables this printing while writing a "0" 256 Writing a "1" enables this printing while writing a "0"
257 disables it. The default value is "0". Reading from this file 257 disables it. The default value is "0". Reading from this file
258 will display the current value. 258 will display the current value.
259
260What: /sys/power/pm_wakeup_irq
261Date: April 2015
262Contact: Alexandra Yates <alexandra.yates@linux.intel.org>
263Description:
264 The /sys/power/pm_wakeup_irq file reports to user space the IRQ
265 number of the first wakeup interrupt (that is, the first
266 interrupt from an IRQ line armed for system wakeup) seen by the
267 kernel during the most recent system suspend/resume cycle.
268
269 This output is useful for system wakeup diagnostics of spurious
270 wakeup interrupts.
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 51f15bc15774..3b361ecfaffc 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -25,6 +25,9 @@
25 */ 25 */
26bool events_check_enabled __read_mostly; 26bool events_check_enabled __read_mostly;
27 27
28/* First wakeup IRQ seen by the kernel in the last cycle. */
29unsigned int pm_wakeup_irq __read_mostly;
30
28/* If set and the system is suspending, terminate the suspend. */ 31/* If set and the system is suspending, terminate the suspend. */
29static bool pm_abort_suspend __read_mostly; 32static bool pm_abort_suspend __read_mostly;
30 33
@@ -868,6 +871,15 @@ EXPORT_SYMBOL_GPL(pm_system_wakeup);
868void pm_wakeup_clear(void) 871void pm_wakeup_clear(void)
869{ 872{
870 pm_abort_suspend = false; 873 pm_abort_suspend = false;
874 pm_wakeup_irq = 0;
875}
876
877void pm_system_irq_wakeup(unsigned int irq_number)
878{
879 if (pm_wakeup_irq == 0) {
880 pm_wakeup_irq = irq_number;
881 pm_system_wakeup();
882 }
871} 883}
872 884
873/** 885/**
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 5efe743ce1e8..33aaf9a9596c 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -387,10 +387,12 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
387 387
388/* drivers/base/power/wakeup.c */ 388/* drivers/base/power/wakeup.c */
389extern bool events_check_enabled; 389extern bool events_check_enabled;
390extern unsigned int pm_wakeup_irq;
390 391
391extern bool pm_wakeup_pending(void); 392extern bool pm_wakeup_pending(void);
392extern void pm_system_wakeup(void); 393extern void pm_system_wakeup(void);
393extern void pm_wakeup_clear(void); 394extern void pm_wakeup_clear(void);
395extern void pm_system_irq_wakeup(unsigned int irq_number);
394extern bool pm_get_wakeup_count(unsigned int *count, bool block); 396extern bool pm_get_wakeup_count(unsigned int *count, bool block);
395extern bool pm_save_wakeup_count(unsigned int count); 397extern bool pm_save_wakeup_count(unsigned int count);
396extern void pm_wakep_autosleep_enabled(bool set); 398extern void pm_wakep_autosleep_enabled(bool set);
@@ -440,6 +442,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
440static inline bool pm_wakeup_pending(void) { return false; } 442static inline bool pm_wakeup_pending(void) { return false; }
441static inline void pm_system_wakeup(void) {} 443static inline void pm_system_wakeup(void) {}
442static inline void pm_wakeup_clear(void) {} 444static inline void pm_wakeup_clear(void) {}
445static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
443 446
444static inline void lock_system_sleep(void) {} 447static inline void lock_system_sleep(void) {}
445static inline void unlock_system_sleep(void) {} 448static inline void unlock_system_sleep(void) {}
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index 21c62617a35a..e80c4400118a 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -21,7 +21,7 @@ bool irq_pm_check_wakeup(struct irq_desc *desc)
21 desc->istate |= IRQS_SUSPENDED | IRQS_PENDING; 21 desc->istate |= IRQS_SUSPENDED | IRQS_PENDING;
22 desc->depth++; 22 desc->depth++;
23 irq_disable(desc); 23 irq_disable(desc);
24 pm_system_wakeup(); 24 pm_system_irq_wakeup(irq_desc_get_irq(desc));
25 return true; 25 return true;
26 } 26 }
27 return false; 27 return false;
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 63d395b5df93..b2dd4d999900 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -272,6 +272,22 @@ static inline void pm_print_times_init(void)
272{ 272{
273 pm_print_times_enabled = !!initcall_debug; 273 pm_print_times_enabled = !!initcall_debug;
274} 274}
275
276static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
277 struct kobj_attribute *attr,
278 char *buf)
279{
280 return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA;
281}
282
283static ssize_t pm_wakeup_irq_store(struct kobject *kobj,
284 struct kobj_attribute *attr,
285 const char *buf, size_t n)
286{
287 return -EINVAL;
288}
289power_attr(pm_wakeup_irq);
290
275#else /* !CONFIG_PM_SLEEP_DEBUG */ 291#else /* !CONFIG_PM_SLEEP_DEBUG */
276static inline void pm_print_times_init(void) {} 292static inline void pm_print_times_init(void) {}
277#endif /* CONFIG_PM_SLEEP_DEBUG */ 293#endif /* CONFIG_PM_SLEEP_DEBUG */
@@ -604,6 +620,7 @@ static struct attribute * g[] = {
604#endif 620#endif
605#ifdef CONFIG_PM_SLEEP_DEBUG 621#ifdef CONFIG_PM_SLEEP_DEBUG
606 &pm_print_times_attr.attr, 622 &pm_print_times_attr.attr,
623 &pm_wakeup_irq_attr.attr,
607#endif 624#endif
608#endif 625#endif
609#ifdef CONFIG_FREEZER 626#ifdef CONFIG_FREEZER