PM / Domains: Move syscore flag from subsys data to struct device
[cascardo/linux.git] / drivers / base / power / main.c
index 9cb845e..57f5814 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/sched.h>
 #include <linux/async.h>
 #include <linux/suspend.h>
-
+#include <linux/cpuidle.h>
 #include "../base.h"
 #include "power.h"
 
@@ -45,10 +45,10 @@ typedef int (*pm_callback_t)(struct device *);
  */
 
 LIST_HEAD(dpm_list);
-LIST_HEAD(dpm_prepared_list);
-LIST_HEAD(dpm_suspended_list);
-LIST_HEAD(dpm_late_early_list);
-LIST_HEAD(dpm_noirq_list);
+static LIST_HEAD(dpm_prepared_list);
+static LIST_HEAD(dpm_suspended_list);
+static LIST_HEAD(dpm_late_early_list);
+static LIST_HEAD(dpm_noirq_list);
 
 struct suspend_stats suspend_stats;
 static DEFINE_MUTEX(dpm_list_mtx);
@@ -57,20 +57,17 @@ static pm_message_t pm_transition;
 static int async_error;
 
 /**
- * device_pm_init - Initialize the PM-related part of a device object.
+ * device_pm_sleep_init - Initialize system suspend-related device fields.
  * @dev: Device object being initialized.
  */
-void device_pm_init(struct device *dev)
+void device_pm_sleep_init(struct device *dev)
 {
        dev->power.is_prepared = false;
        dev->power.is_suspended = false;
        init_completion(&dev->power.completion);
        complete_all(&dev->power.completion);
        dev->power.wakeup = NULL;
-       spin_lock_init(&dev->power.lock);
-       pm_runtime_init(dev);
        INIT_LIST_HEAD(&dev->power.entry);
-       dev->power.power_state = PMSG_INVALID;
 }
 
 /**
@@ -166,7 +163,7 @@ static ktime_t initcall_debug_start(struct device *dev)
 {
        ktime_t calltime = ktime_set(0, 0);
 
-       if (initcall_debug) {
+       if (pm_print_times_enabled) {
                pr_info("calling  %s+ @ %i, parent: %s\n",
                        dev_name(dev), task_pid_nr(current),
                        dev->parent ? dev_name(dev->parent) : "none");
@@ -181,7 +178,7 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime,
 {
        ktime_t delta, rettime;
 
-       if (initcall_debug) {
+       if (pm_print_times_enabled) {
                rettime = ktime_get();
                delta = ktime_sub(rettime, calltime);
                pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
@@ -408,6 +405,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
        TRACE_DEVICE(dev);
        TRACE_RESUME(0);
 
+       if (dev->power.syscore)
+               goto Out;
+
        if (dev->pm_domain) {
                info = "noirq power domain ";
                callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -429,6 +429,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
 
        error = dpm_run_callback(callback, dev, state, info);
 
+ Out:
        TRACE_RESUME(error);
        return error;
 }
@@ -467,6 +468,7 @@ static void dpm_resume_noirq(pm_message_t state)
        mutex_unlock(&dpm_list_mtx);
        dpm_show_time(starttime, state, "noirq");
        resume_device_irqs();
+       cpuidle_resume();
 }
 
 /**
@@ -485,6 +487,9 @@ static int device_resume_early(struct device *dev, pm_message_t state)
        TRACE_DEVICE(dev);
        TRACE_RESUME(0);
 
+       if (dev->power.syscore)
+               goto Out;
+
        if (dev->pm_domain) {
                info = "early power domain ";
                callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -506,6 +511,7 @@ static int device_resume_early(struct device *dev, pm_message_t state)
 
        error = dpm_run_callback(callback, dev, state, info);
 
+ Out:
        TRACE_RESUME(error);
        return error;
 }
@@ -569,6 +575,9 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
        TRACE_DEVICE(dev);
        TRACE_RESUME(0);
 
+       if (dev->power.syscore)
+               goto Complete;
+
        dpm_wait(dev->parent, async);
        device_lock(dev);
 
@@ -631,6 +640,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 
  Unlock:
        device_unlock(dev);
+
+ Complete:
        complete_all(&dev->power.completion);
 
        TRACE_RESUME(error);
@@ -721,6 +732,9 @@ static void device_complete(struct device *dev, pm_message_t state)
        void (*callback)(struct device *) = NULL;
        char *info = NULL;
 
+       if (dev->power.syscore)
+               return;
+
        device_lock(dev);
 
        if (dev->pm_domain) {
@@ -833,6 +847,9 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
        pm_callback_t callback = NULL;
        char *info = NULL;
 
+       if (dev->power.syscore)
+               return 0;
+
        if (dev->pm_domain) {
                info = "noirq power domain ";
                callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -867,6 +884,7 @@ static int dpm_suspend_noirq(pm_message_t state)
        ktime_t starttime = ktime_get();
        int error = 0;
 
+       cpuidle_pause();
        suspend_device_irqs();
        mutex_lock(&dpm_list_mtx);
        while (!list_empty(&dpm_late_early_list)) {
@@ -915,6 +933,9 @@ static int device_suspend_late(struct device *dev, pm_message_t state)
        pm_callback_t callback = NULL;
        char *info = NULL;
 
+       if (dev->power.syscore)
+               return 0;
+
        if (dev->pm_domain) {
                info = "late power domain ";
                callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -989,8 +1010,16 @@ static int dpm_suspend_late(pm_message_t state)
 int dpm_suspend_end(pm_message_t state)
 {
        int error = dpm_suspend_late(state);
+       if (error)
+               return error;
+
+       error = dpm_suspend_noirq(state);
+       if (error) {
+               dpm_resume_early(state);
+               return error;
+       }
 
-       return error ? : dpm_suspend_noirq(state);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(dpm_suspend_end);
 
@@ -1043,6 +1072,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                goto Complete;
        }
 
+       if (dev->power.syscore)
+               goto Complete;
+
        device_lock(dev);
 
        if (dev->pm_domain) {
@@ -1199,6 +1231,9 @@ static int device_prepare(struct device *dev, pm_message_t state)
        char *info = NULL;
        int error = 0;
 
+       if (dev->power.syscore)
+               return 0;
+
        device_lock(dev);
 
        dev->power.wakeup_path = device_may_wakeup(dev);