PM: Change dpm watchdog to support async suspend
authorBenoit Goby <benoit@android.com>
Thu, 27 Jan 2011 02:28:33 +0000 (18:28 -0800)
committermgross <mark.gross@intel.com>
Wed, 9 Nov 2011 20:06:52 +0000 (12:06 -0800)
Exclude from the watchdog the time spent waiting for children that
are resumed asynchronously and time every devices, whether or not they
resumed synchronously.

Change-Id: I84209dfd5df72842e045096c906fd61e20e6d183
Signed-off-by: Benoit Goby <benoit@android.com>
drivers/base/power/main.c

index e8e8c05..43daa4b 100644 (file)
@@ -51,11 +51,10 @@ static DEFINE_MUTEX(dpm_list_mtx);
 static pm_message_t pm_transition;
 
 static void dpm_drv_timeout(unsigned long data);
-static DEFINE_TIMER(dpm_drv_wd, dpm_drv_timeout, 0, 0);
-static struct {
+struct dpm_drv_wd_data {
        struct device *dev;
        struct task_struct *tsk;
-} dpm_drv_wd_data;
+};
 
 static int async_error;
 
@@ -603,8 +602,9 @@ static bool is_async(struct device *dev)
  */
 static void dpm_drv_timeout(unsigned long data)
 {
-       struct device *dev = dpm_drv_wd_data.dev;
-       struct task_struct *tsk = dpm_drv_wd_data.tsk;
+       struct dpm_drv_wd_data *wd_data = (void *)data;
+       struct device *dev = wd_data->dev;
+       struct task_struct *tsk = wd_data->tsk;
 
        printk(KERN_EMERG "**** DPM device timeout: %s (%s)\n", dev_name(dev),
               (dev->driver ? dev->driver->name : "no driver"));
@@ -616,29 +616,6 @@ static void dpm_drv_timeout(unsigned long data)
 }
 
 /**
- *     dpm_drv_wdset - Sets up driver suspend/resume watchdog timer.
- *     @dev: struct device which we're guarding.
- *
- */
-static void dpm_drv_wdset(struct device *dev)
-{
-       dpm_drv_wd_data.dev = dev;
-       dpm_drv_wd_data.tsk = get_current();
-       dpm_drv_wd.data = (unsigned long) &dpm_drv_wd_data;
-       mod_timer(&dpm_drv_wd, jiffies + (HZ * 3));
-}
-
-/**
- *     dpm_drv_wdclr - clears driver suspend/resume watchdog timer.
- *     @dev: struct device which we're no longer guarding.
- *
- */
-static void dpm_drv_wdclr(struct device *dev)
-{
-       del_timer_sync(&dpm_drv_wd);
-}
-
-/**
  * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
  * @state: PM transition of the system being carried out.
  *
@@ -896,8 +873,19 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
 static int __device_suspend(struct device *dev, pm_message_t state, bool async)
 {
        int error = 0;
+       struct timer_list timer;
+       struct dpm_drv_wd_data data;
 
        dpm_wait_for_children(dev, async);
+
+       data.dev = dev;
+       data.tsk = get_current();
+       init_timer_on_stack(&timer);
+       timer.expires = jiffies + HZ * 3;
+       timer.function = dpm_drv_timeout;
+       timer.data = (unsigned long)&data;
+       add_timer(&timer);
+
        device_lock(dev);
 
        if (async_error)
@@ -947,6 +935,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
 
  Unlock:
        device_unlock(dev);
+
+       del_timer_sync(&timer);
+       destroy_timer_on_stack(&timer);
+
        complete_all(&dev->power.completion);
 
        if (error)
@@ -1000,9 +992,7 @@ int dpm_suspend(pm_message_t state)
                get_device(dev);
                mutex_unlock(&dpm_list_mtx);
 
-               dpm_drv_wdset(dev);
                error = device_suspend(dev);
-               dpm_drv_wdclr(dev);
 
                mutex_lock(&dpm_list_mtx);
                if (error) {