diff options
Diffstat (limited to 'drivers/base/power/runtime.c')
-rw-r--r-- | drivers/base/power/runtime.c | 88 |
1 files changed, 68 insertions, 20 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index a770498a74e..f8b044e8aef 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -85,6 +85,19 @@ static int __pm_runtime_idle(struct device *dev) dev->bus->pm->runtime_idle(dev); spin_lock_irq(&dev->power.lock); + } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) { + spin_unlock_irq(&dev->power.lock); + + dev->type->pm->runtime_idle(dev); + + spin_lock_irq(&dev->power.lock); + } else if (dev->class && dev->class->pm + && dev->class->pm->runtime_idle) { + spin_unlock_irq(&dev->power.lock); + + dev->class->pm->runtime_idle(dev); + + spin_lock_irq(&dev->power.lock); } dev->power.idle_notification = false; @@ -185,6 +198,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) } dev->power.runtime_status = RPM_SUSPENDING; + dev->power.deferred_resume = false; if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { spin_unlock_irq(&dev->power.lock); @@ -193,6 +207,22 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) spin_lock_irq(&dev->power.lock); dev->power.runtime_error = retval; + } else if (dev->type && dev->type->pm + && dev->type->pm->runtime_suspend) { + spin_unlock_irq(&dev->power.lock); + + retval = dev->type->pm->runtime_suspend(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else if (dev->class && dev->class->pm + && dev->class->pm->runtime_suspend) { + spin_unlock_irq(&dev->power.lock); + + retval = dev->class->pm->runtime_suspend(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; } else { retval = -ENOSYS; } @@ -200,7 +230,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) if (retval) { dev->power.runtime_status = RPM_ACTIVE; pm_runtime_cancel_pending(dev); - dev->power.deferred_resume = false; if (retval == -EAGAIN || retval == -EBUSY) { notify = true; @@ -217,7 +246,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) wake_up_all(&dev->power.wait_queue); if (dev->power.deferred_resume) { - dev->power.deferred_resume = false; __pm_runtime_resume(dev, false); retval = -EAGAIN; goto out; @@ -328,11 +356,11 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) * necessary. */ parent = dev->parent; - spin_unlock_irq(&dev->power.lock); + spin_unlock(&dev->power.lock); pm_runtime_get_noresume(parent); - spin_lock_irq(&parent->power.lock); + spin_lock(&parent->power.lock); /* * We can resume if the parent's run-time PM is disabled or it * is set to ignore children. @@ -343,9 +371,9 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) if (parent->power.runtime_status != RPM_ACTIVE) retval = -EBUSY; } - spin_unlock_irq(&parent->power.lock); + spin_unlock(&parent->power.lock); - spin_lock_irq(&dev->power.lock); + spin_lock(&dev->power.lock); if (retval) goto out; goto repeat; @@ -360,6 +388,22 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) spin_lock_irq(&dev->power.lock); dev->power.runtime_error = retval; + } else if (dev->type && dev->type->pm + && dev->type->pm->runtime_resume) { + spin_unlock_irq(&dev->power.lock); + + retval = dev->type->pm->runtime_resume(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else if (dev->class && dev->class->pm + && dev->class->pm->runtime_resume) { + spin_unlock_irq(&dev->power.lock); + + retval = dev->class->pm->runtime_resume(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; } else { retval = -ENOSYS; } @@ -626,6 +670,8 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay) goto out; dev->power.timer_expires = jiffies + msecs_to_jiffies(delay); + if (!dev->power.timer_expires) + dev->power.timer_expires = 1; mod_timer(&dev->power.suspend_timer, dev->power.timer_expires); out: @@ -659,13 +705,17 @@ static int __pm_request_resume(struct device *dev) pm_runtime_deactivate_timer(dev); + if (dev->power.runtime_status == RPM_SUSPENDING) { + dev->power.deferred_resume = true; + return retval; + } if (dev->power.request_pending) { /* If non-resume request is pending, we can overtake it. */ dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME; return retval; - } else if (retval) { - return retval; } + if (retval) + return retval; dev->power.request = RPM_REQ_RESUME; dev->power.request_pending = true; @@ -696,15 +746,15 @@ EXPORT_SYMBOL_GPL(pm_request_resume); * @dev: Device to handle. * @sync: If set and the device is suspended, resume it synchronously. * - * Increment the usage count of the device and if it was zero previously, - * resume it or submit a resume request for it, depending on the value of @sync. + * Increment the usage count of the device and resume it or submit a resume + * request for it, depending on the value of @sync. */ int __pm_runtime_get(struct device *dev, bool sync) { - int retval = 1; + int retval; - if (atomic_add_return(1, &dev->power.usage_count) == 1) - retval = sync ? pm_runtime_resume(dev) : pm_request_resume(dev); + atomic_inc(&dev->power.usage_count); + retval = sync ? pm_runtime_resume(dev) : pm_request_resume(dev); return retval; } @@ -777,7 +827,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) } if (parent) { - spin_lock_irq(&parent->power.lock); + spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING); /* * It is invalid to put an active child under a parent that is @@ -786,14 +836,12 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) */ if (!parent->power.disable_depth && !parent->power.ignore_children - && parent->power.runtime_status != RPM_ACTIVE) { + && parent->power.runtime_status != RPM_ACTIVE) error = -EBUSY; - } else { - if (dev->power.runtime_status == RPM_SUSPENDED) - atomic_inc(&parent->power.child_count); - } + else if (dev->power.runtime_status == RPM_SUSPENDED) + atomic_inc(&parent->power.child_count); - spin_unlock_irq(&parent->power.lock); + spin_unlock(&parent->power.lock); if (error) goto out; |