diff options
Diffstat (limited to 'drivers/base/power')
-rw-r--r-- | drivers/base/power/domain.c | 64 | ||||
-rw-r--r-- | drivers/base/power/domain_governor.c | 1 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 18 | ||||
-rw-r--r-- | drivers/base/power/wakeirq.c | 4 |
4 files changed, 60 insertions, 27 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index b6a782c31613..ab0b740cc0f1 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -379,6 +379,44 @@ err: return ret; } +static int genpd_set_performance_state(struct device *dev, unsigned int state) +{ + struct generic_pm_domain *genpd = dev_to_genpd(dev); + struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev); + unsigned int prev_state; + int ret; + + prev_state = gpd_data->performance_state; + if (prev_state == state) + return 0; + + gpd_data->performance_state = state; + state = _genpd_reeval_performance_state(genpd, state); + + ret = _genpd_set_performance_state(genpd, state, 0); + if (ret) + gpd_data->performance_state = prev_state; + + return ret; +} + +static int genpd_drop_performance_state(struct device *dev) +{ + unsigned int prev_state = dev_gpd_data(dev)->performance_state; + + if (!genpd_set_performance_state(dev, 0)) + return prev_state; + + return 0; +} + +static void genpd_restore_performance_state(struct device *dev, + unsigned int state) +{ + if (state) + genpd_set_performance_state(dev, state); +} + /** * dev_pm_genpd_set_performance_state- Set performance state of device's power * domain. @@ -397,8 +435,6 @@ err: int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) { struct generic_pm_domain *genpd; - struct generic_pm_domain_data *gpd_data; - unsigned int prev; int ret; genpd = dev_to_genpd_safe(dev); @@ -410,16 +446,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) return -EINVAL; genpd_lock(genpd); - - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - prev = gpd_data->performance_state; - gpd_data->performance_state = state; - - state = _genpd_reeval_performance_state(genpd, state); - ret = _genpd_set_performance_state(genpd, state, 0); - if (ret) - gpd_data->performance_state = prev; - + ret = genpd_set_performance_state(dev, state); genpd_unlock(genpd); return ret; @@ -572,6 +599,7 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) * RPM status of the releated device is in an intermediate state, not yet turned * into RPM_SUSPENDED. This means genpd_power_off() must allow one device to not * be RPM_SUSPENDED, while it tries to power off the PM domain. + * @depth: nesting count for lockdep. * * If all of the @genpd's devices have been suspended and all of its subdomains * have been powered down, remove power from @genpd. @@ -832,7 +860,8 @@ static int genpd_runtime_suspend(struct device *dev) { struct generic_pm_domain *genpd; bool (*suspend_ok)(struct device *__dev); - struct gpd_timing_data *td = &dev_gpd_data(dev)->td; + struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev); + struct gpd_timing_data *td = &gpd_data->td; bool runtime_pm = pm_runtime_enabled(dev); ktime_t time_start; s64 elapsed_ns; @@ -889,6 +918,7 @@ static int genpd_runtime_suspend(struct device *dev) return 0; genpd_lock(genpd); + gpd_data->rpm_pstate = genpd_drop_performance_state(dev); genpd_power_off(genpd, true, 0); genpd_unlock(genpd); @@ -906,7 +936,8 @@ static int genpd_runtime_suspend(struct device *dev) static int genpd_runtime_resume(struct device *dev) { struct generic_pm_domain *genpd; - struct gpd_timing_data *td = &dev_gpd_data(dev)->td; + struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev); + struct gpd_timing_data *td = &gpd_data->td; bool runtime_pm = pm_runtime_enabled(dev); ktime_t time_start; s64 elapsed_ns; @@ -930,6 +961,8 @@ static int genpd_runtime_resume(struct device *dev) genpd_lock(genpd); ret = genpd_power_on(genpd, 0); + if (!ret) + genpd_restore_performance_state(dev, gpd_data->rpm_pstate); genpd_unlock(genpd); if (ret) @@ -968,6 +1001,7 @@ err_stop: err_poweroff: if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) { genpd_lock(genpd); + gpd_data->rpm_pstate = genpd_drop_performance_state(dev); genpd_power_off(genpd, true, 0); genpd_unlock(genpd); } @@ -2505,7 +2539,7 @@ EXPORT_SYMBOL_GPL(of_genpd_remove_subdomain); /** * of_genpd_remove_last - Remove the last PM domain registered for a provider - * @provider: Pointer to device structure associated with provider + * @np: Pointer to device node associated with provider * * Find the last PM domain that was added by a particular provider and * remove this PM domain from the list of PM domains. The provider is diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index c6c218758f0b..cd08c5885190 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c @@ -252,6 +252,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd, /** * _default_power_down_ok - Default generic PM domain power off governor routine. * @pd: PM domain to check. + * @now: current ktime. * * This routine must be executed under the PM domain's lock. */ diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index b570848d23e0..8a66eaf731e4 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -345,7 +345,7 @@ static void rpm_suspend_suppliers(struct device *dev) static int __rpm_callback(int (*cb)(struct device *), struct device *dev) __releases(&dev->power.lock) __acquires(&dev->power.lock) { - int retval, idx; + int retval = 0, idx; bool use_links = dev->power.links_count > 0; if (dev->power.irq_safe) { @@ -373,7 +373,8 @@ static int __rpm_callback(int (*cb)(struct device *), struct device *dev) } } - retval = cb(dev); + if (cb) + retval = cb(dev); if (dev->power.irq_safe) { spin_lock(&dev->power.lock); @@ -446,7 +447,10 @@ static int rpm_idle(struct device *dev, int rpmflags) /* Pending requests need to be canceled. */ dev->power.request = RPM_REQ_NONE; - if (dev->power.no_callbacks) + callback = RPM_GET_CALLBACK(dev, runtime_idle); + + /* If no callback assume success. */ + if (!callback || dev->power.no_callbacks) goto out; /* Carry out an asynchronous or a synchronous idle notification. */ @@ -462,10 +466,7 @@ static int rpm_idle(struct device *dev, int rpmflags) dev->power.idle_notification = true; - callback = RPM_GET_CALLBACK(dev, runtime_idle); - - if (callback) - retval = __rpm_callback(callback, dev); + retval = __rpm_callback(callback, dev); dev->power.idle_notification = false; wake_up_all(&dev->power.wait_queue); @@ -484,9 +485,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) { int retval; - if (!cb) - return -ENOSYS; - if (dev->power.memalloc_noio) { unsigned int noio_flag; diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index 8e021082dba8..3bad3266a2ad 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -182,7 +182,6 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) wirq->dev = dev; wirq->irq = irq; - irq_set_status_flags(irq, IRQ_NOAUTOEN); /* Prevent deferred spurious wakeirqs with disable_irq_nosync() */ irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); @@ -192,7 +191,8 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) * so we use a threaded irq. */ err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq, - IRQF_ONESHOT, wirq->name, wirq); + IRQF_ONESHOT | IRQF_NO_AUTOEN, + wirq->name, wirq); if (err) goto err_free_name; |