Merge back earlier 'pm-sleep' material for v4.4.
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 12 Oct 2015 20:30:57 +0000 (22:30 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 12 Oct 2015 20:30:57 +0000 (22:30 +0200)
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..a1e0b9ab847a345c6a09adab3ff9f2fd9af3ad3e 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;
 
@@ -91,7 +94,7 @@ struct wakeup_source *wakeup_source_create(const char *name)
        if (!ws)
                return NULL;
 
-       wakeup_source_prepare(ws, name ? kstrdup(name, GFP_KERNEL) : NULL);
+       wakeup_source_prepare(ws, name ? kstrdup_const(name, GFP_KERNEL) : NULL);
        return ws;
 }
 EXPORT_SYMBOL_GPL(wakeup_source_create);
@@ -154,7 +157,7 @@ void wakeup_source_destroy(struct wakeup_source *ws)
 
        wakeup_source_drop(ws);
        wakeup_source_record(ws);
-       kfree(ws->name);
+       kfree_const(ws->name);
        kfree(ws);
 }
 EXPORT_SYMBOL_GPL(wakeup_source_destroy);
@@ -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