]> Git Repo - linux.git/commitdiff
Merge branch 'pm-sleep'
authorRafael J. Wysocki <[email protected]>
Mon, 24 Sep 2012 11:31:38 +0000 (13:31 +0200)
committerRafael J. Wysocki <[email protected]>
Mon, 24 Sep 2012 11:31:38 +0000 (13:31 +0200)
* pm-sleep:
  PM: Prevent runtime suspend during system resume
  PM / Sleep: use resume event when call dpm_resume_early

Conflicts:
drivers/base/power/main.c (trivial)

1  2 
drivers/base/power/main.c
drivers/pci/pci-driver.c

index 57f5814c2732783d7c4f06c756728465f185fa2c,077b9756fd8fd5580714bad627634467030bd3bb..008e6786ae7919e3e4165e6b605cb6a7836ad4c6
@@@ -57,17 -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;
  }
  
  /**
@@@ -405,9 -408,6 +405,9 @@@ static int device_resume_noirq(struct d
        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);
  
        error = dpm_run_callback(callback, dev, state, info);
  
 + Out:
        TRACE_RESUME(error);
        return error;
  }
@@@ -487,9 -486,6 +487,9 @@@ static int device_resume_early(struct d
        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);
  
        error = dpm_run_callback(callback, dev, state, info);
  
 + Out:
        TRACE_RESUME(error);
        return error;
  }
@@@ -570,14 -565,10 +570,13 @@@ static int device_resume(struct device 
        pm_callback_t callback = NULL;
        char *info = NULL;
        int error = 0;
-       bool put = false;
  
        TRACE_DEVICE(dev);
        TRACE_RESUME(0);
  
 +      if (dev->power.syscore)
 +              goto Complete;
 +
        dpm_wait(dev->parent, async);
        device_lock(dev);
  
                goto Unlock;
  
        pm_runtime_enable(dev);
-       put = true;
  
        if (dev->pm_domain) {
                info = "power domain ";
  
   Unlock:
        device_unlock(dev);
 +
 + Complete:
        complete_all(&dev->power.completion);
  
        TRACE_RESUME(error);
  
-       if (put)
-               pm_runtime_put_sync(dev);
        return error;
  }
  
@@@ -732,9 -717,6 +727,9 @@@ static void device_complete(struct devi
        void (*callback)(struct device *) = NULL;
        char *info = NULL;
  
 +      if (dev->power.syscore)
 +              return;
 +
        device_lock(dev);
  
        if (dev->pm_domain) {
        }
  
        device_unlock(dev);
+       pm_runtime_put_sync(dev);
  }
  
  /**
@@@ -847,9 -831,6 +844,9 @@@ static int device_suspend_noirq(struct 
        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);
@@@ -933,9 -914,6 +930,9 @@@ static int device_suspend_late(struct d
        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);
@@@ -1015,7 -993,7 +1012,7 @@@ int dpm_suspend_end(pm_message_t state
  
        error = dpm_suspend_noirq(state);
        if (error) {
-               dpm_resume_early(state);
+               dpm_resume_early(resume_event(state));
                return error;
        }
  
@@@ -1062,19 -1040,20 +1059,23 @@@ static int __device_suspend(struct devi
        if (async_error)
                goto Complete;
  
-       pm_runtime_get_noresume(dev);
+       /*
+        * If a device configured to wake up the system from sleep states
+        * has been suspended at run time and there's a resume request pending
+        * for it, this is equivalent to the device signaling wakeup, so the
+        * system suspend operation should be aborted.
+        */
        if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
                pm_wakeup_event(dev, 0);
  
        if (pm_wakeup_pending()) {
-               pm_runtime_put_sync(dev);
                async_error = -EBUSY;
                goto Complete;
        }
  
 +      if (dev->power.syscore)
 +              goto Complete;
 +
        device_lock(dev);
  
        if (dev->pm_domain) {
   Complete:
        complete_all(&dev->power.completion);
  
-       if (error) {
-               pm_runtime_put_sync(dev);
+       if (error)
                async_error = error;
-       } else if (dev->power.is_suspended) {
+       else if (dev->power.is_suspended)
                __pm_runtime_disable(dev, false);
-       }
  
        return error;
  }
@@@ -1231,9 -1208,14 +1230,17 @@@ static int device_prepare(struct devic
        char *info = NULL;
        int error = 0;
  
 +      if (dev->power.syscore)
 +              return 0;
 +
+       /*
+        * If a device's parent goes into runtime suspend at the wrong time,
+        * it won't be possible to resume the device.  To prevent this we
+        * block runtime suspend here, during the prepare phase, and allow
+        * it again during the complete phase.
+        */
+       pm_runtime_get_noresume(dev);
        device_lock(dev);
  
        dev->power.wakeup_path = device_may_wakeup(dev);
diff --combined drivers/pci/pci-driver.c
index d6fd6b6d9d4b575c26eb0041e503ddb10ddb9d64,51cd90bcdd4c6a5eae03f8f1196d2d03451fa11d..0862b727d7c3689d2e796ac6cf4beb3aeb5add45
@@@ -280,12 -280,8 +280,12 @@@ static long local_pci_probe(void *_ddi
  {
        struct drv_dev_and_id *ddi = _ddi;
        struct device *dev = &ddi->dev->dev;
 +      struct device *parent = dev->parent;
        int rc;
  
 +      /* The parent bridge must be in active state when probing */
 +      if (parent)
 +              pm_runtime_get_sync(parent);
        /* Unbound PCI devices are always set to disabled and suspended.
         * During probe, the device is set to enabled and active and the
         * usage count is incremented.  If the driver supports runtime PM,
                pm_runtime_set_suspended(dev);
                pm_runtime_put_noidle(dev);
        }
 +      if (parent)
 +              pm_runtime_put(parent);
        return rc;
  }
  
@@@ -629,21 -623,6 +629,6 @@@ static int pci_pm_prepare(struct devic
        struct device_driver *drv = dev->driver;
        int error = 0;
  
-       /*
-        * If a PCI device configured to wake up the system from sleep states
-        * has been suspended at run time and there's a resume request pending
-        * for it, this is equivalent to the device signaling wakeup, so the
-        * system suspend operation should be aborted.
-        */
-       pm_runtime_get_noresume(dev);
-       if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
-               pm_wakeup_event(dev, 0);
-       if (pm_wakeup_pending()) {
-               pm_runtime_put_sync(dev);
-               return -EBUSY;
-       }
        /*
         * PCI devices suspended at run time need to be resumed at this
         * point, because in general it is necessary to reconfigure them for
@@@ -667,8 -646,6 +652,6 @@@ static void pci_pm_complete(struct devi
  
        if (drv && drv->pm && drv->pm->complete)
                drv->pm->complete(dev);
-       pm_runtime_put_sync(dev);
  }
  
  #else /* !CONFIG_PM_SLEEP */
@@@ -965,13 -942,6 +948,13 @@@ static int pci_pm_poweroff_noirq(struc
        if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
                pci_prepare_to_sleep(pci_dev);
  
 +      /*
 +       * The reason for doing this here is the same as for the analogous code
 +       * in pci_pm_suspend_noirq().
 +       */
 +      if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
 +              pci_write_config_word(pci_dev, PCI_COMMAND, 0);
 +
        return 0;
  }
  
This page took 0.078573 seconds and 4 git commands to generate.