Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alexandra Yates and committed by
Rafael J. Wysocki
a6f5f0dd 6ff33f39

+45 -1
+12
Documentation/ABI/testing/sysfs-power
··· 256 256 Writing a "1" enables this printing while writing a "0" 257 257 disables it. The default value is "0". Reading from this file 258 258 will display the current value. 259 + 260 + What: /sys/power/pm_wakeup_irq 261 + Date: April 2015 262 + Contact: Alexandra Yates <alexandra.yates@linux.intel.org> 263 + Description: 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.
+12
drivers/base/power/wakeup.c
··· 25 25 */ 26 26 bool events_check_enabled __read_mostly; 27 27 28 + /* First wakeup IRQ seen by the kernel in the last cycle. */ 29 + unsigned int pm_wakeup_irq __read_mostly; 30 + 28 31 /* If set and the system is suspending, terminate the suspend. */ 29 32 static bool pm_abort_suspend __read_mostly; 30 33 ··· 871 868 void pm_wakeup_clear(void) 872 869 { 873 870 pm_abort_suspend = false; 871 + pm_wakeup_irq = 0; 872 + } 873 + 874 + void pm_system_irq_wakeup(unsigned int irq_number) 875 + { 876 + if (pm_wakeup_irq == 0) { 877 + pm_wakeup_irq = irq_number; 878 + pm_system_wakeup(); 879 + } 874 880 } 875 881 876 882 /**
+3
include/linux/suspend.h
··· 387 387 388 388 /* drivers/base/power/wakeup.c */ 389 389 extern bool events_check_enabled; 390 + extern unsigned int pm_wakeup_irq; 390 391 391 392 extern bool pm_wakeup_pending(void); 392 393 extern void pm_system_wakeup(void); 393 394 extern void pm_wakeup_clear(void); 395 + extern void pm_system_irq_wakeup(unsigned int irq_number); 394 396 extern bool pm_get_wakeup_count(unsigned int *count, bool block); 395 397 extern bool pm_save_wakeup_count(unsigned int count); 396 398 extern void pm_wakep_autosleep_enabled(bool set); ··· 442 440 static inline bool pm_wakeup_pending(void) { return false; } 443 441 static inline void pm_system_wakeup(void) {} 444 442 static inline void pm_wakeup_clear(void) {} 443 + static inline void pm_system_irq_wakeup(unsigned int irq_number) {} 445 444 446 445 static inline void lock_system_sleep(void) {} 447 446 static inline void unlock_system_sleep(void) {}
+1 -1
kernel/irq/pm.c
··· 21 21 desc->istate |= IRQS_SUSPENDED | IRQS_PENDING; 22 22 desc->depth++; 23 23 irq_disable(desc); 24 - pm_system_wakeup(); 24 + pm_system_irq_wakeup(irq_desc_get_irq(desc)); 25 25 return true; 26 26 } 27 27 return false;
+17
kernel/power/main.c
··· 272 272 { 273 273 pm_print_times_enabled = !!initcall_debug; 274 274 } 275 + 276 + static 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 + 283 + static 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 + } 289 + power_attr(pm_wakeup_irq); 290 + 275 291 #else /* !CONFIG_PM_SLEEP_DEBUG */ 276 292 static inline void pm_print_times_init(void) {} 277 293 #endif /* CONFIG_PM_SLEEP_DEBUG */ ··· 620 604 #endif 621 605 #ifdef CONFIG_PM_SLEEP_DEBUG 622 606 &pm_print_times_attr.attr, 607 + &pm_wakeup_irq_attr.attr, 623 608 #endif 624 609 #endif 625 610 #ifdef CONFIG_FREEZER