Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[pandora-kernel.git] / drivers / base / power / main.c
index a854591..c3d2dfc 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/device.h>
 #include <linux/kallsyms.h>
+#include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
@@ -46,6 +47,7 @@ LIST_HEAD(dpm_prepared_list);
 LIST_HEAD(dpm_suspended_list);
 LIST_HEAD(dpm_noirq_list);
 
+struct suspend_stats suspend_stats;
 static DEFINE_MUTEX(dpm_list_mtx);
 static pm_message_t pm_transition;
 
@@ -65,6 +67,7 @@ void device_pm_init(struct device *dev)
        spin_lock_init(&dev->power.lock);
        pm_runtime_init(dev);
        INIT_LIST_HEAD(&dev->power.entry);
+       dev->power.power_state = PMSG_INVALID;
 }
 
 /**
@@ -96,6 +99,7 @@ void device_pm_add(struct device *dev)
                dev_warn(dev, "parent %s should not be sleeping\n",
                        dev_name(dev->parent));
        list_add_tail(&dev->power.entry, &dpm_list);
+       dev_pm_qos_constraints_init(dev);
        mutex_unlock(&dpm_list_mtx);
 }
 
@@ -109,6 +113,7 @@ void device_pm_remove(struct device *dev)
                 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
        complete_all(&dev->power.completion);
        mutex_lock(&dpm_list_mtx);
+       dev_pm_qos_constraints_destroy(dev);
        list_del_init(&dev->power.entry);
        mutex_unlock(&dpm_list_mtx);
        device_wakeup_disable(dev);
@@ -464,8 +469,12 @@ void dpm_resume_noirq(pm_message_t state)
                mutex_unlock(&dpm_list_mtx);
 
                error = device_resume_noirq(dev, state);
-               if (error)
+               if (error) {
+                       suspend_stats.failed_resume_noirq++;
+                       dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
+                       dpm_save_failed_dev(dev_name(dev));
                        pm_dev_err(dev, state, " early", error);
+               }
 
                mutex_lock(&dpm_list_mtx);
                put_device(dev);
@@ -626,8 +635,12 @@ void dpm_resume(pm_message_t state)
                        mutex_unlock(&dpm_list_mtx);
 
                        error = device_resume(dev, state, false);
-                       if (error)
+                       if (error) {
+                               suspend_stats.failed_resume++;
+                               dpm_save_failed_step(SUSPEND_RESUME);
+                               dpm_save_failed_dev(dev_name(dev));
                                pm_dev_err(dev, state, "", error);
+                       }
 
                        mutex_lock(&dpm_list_mtx);
                }
@@ -802,6 +815,9 @@ int dpm_suspend_noirq(pm_message_t state)
                mutex_lock(&dpm_list_mtx);
                if (error) {
                        pm_dev_err(dev, state, " late", error);
+                       suspend_stats.failed_suspend_noirq++;
+                       dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
+                       dpm_save_failed_dev(dev_name(dev));
                        put_device(dev);
                        break;
                }
@@ -902,7 +918,12 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
        }
 
  End:
-       dev->power.is_suspended = !error;
+       if (!error) {
+               dev->power.is_suspended = true;
+               if (dev->power.wakeup_path
+                   && dev->parent && !dev->parent->power.ignore_children)
+                       dev->parent->power.wakeup_path = true;
+       }
 
        device_unlock(dev);
        complete_all(&dev->power.completion);
@@ -923,8 +944,10 @@ static void async_suspend(void *data, async_cookie_t cookie)
        int error;
 
        error = __device_suspend(dev, pm_transition, true);
-       if (error)
+       if (error) {
+               dpm_save_failed_dev(dev_name(dev));
                pm_dev_err(dev, pm_transition, " async", error);
+       }
 
        put_device(dev);
 }
@@ -967,6 +990,7 @@ int dpm_suspend(pm_message_t state)
                mutex_lock(&dpm_list_mtx);
                if (error) {
                        pm_dev_err(dev, state, "", error);
+                       dpm_save_failed_dev(dev_name(dev));
                        put_device(dev);
                        break;
                }
@@ -980,7 +1004,10 @@ int dpm_suspend(pm_message_t state)
        async_synchronize_full();
        if (!error)
                error = async_error;
-       if (!error)
+       if (error) {
+               suspend_stats.failed_suspend++;
+               dpm_save_failed_step(SUSPEND_SUSPEND);
+       } else
                dpm_show_time(starttime, state, NULL);
        return error;
 }
@@ -999,6 +1026,8 @@ static int device_prepare(struct device *dev, pm_message_t state)
 
        device_lock(dev);
 
+       dev->power.wakeup_path = device_may_wakeup(dev);
+
        if (dev->pm_domain) {
                pm_dev_dbg(dev, state, "preparing power domain ");
                if (dev->pm_domain->ops.prepare)
@@ -1088,7 +1117,10 @@ int dpm_suspend_start(pm_message_t state)
        int error;
 
        error = dpm_prepare(state);
-       if (!error)
+       if (error) {
+               suspend_stats.failed_prepare++;
+               dpm_save_failed_step(SUSPEND_PREPARE);
+       } else
                error = dpm_suspend(state);
        return error;
 }