From 0ae3aeefabbeef26294e7a349b51f1c761d46c9f Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 8 Apr 2016 13:10:23 +0200 Subject: PM / Runtime: Fix error path in pm_runtime_force_resume() As pm_runtime_set_active() may fail because the device's parent isn't active, we can end up executing the ->runtime_resume() callback for the device when it isn't allowed. Fix this by invoking pm_runtime_set_active() before running the callback and let's also deal with the error code. Fixes: 37f204164dfb (PM: Add pm_runtime_suspend|resume_force functions) Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Cc: 3.15+ # 3.15+ Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 4c7055009bd6..b74690418504 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1506,11 +1506,16 @@ int pm_runtime_force_resume(struct device *dev) goto out; } - ret = callback(dev); + ret = pm_runtime_set_active(dev); if (ret) goto out; - pm_runtime_set_active(dev); + ret = callback(dev); + if (ret) { + pm_runtime_set_suspended(dev); + goto out; + } + pm_runtime_mark_last_busy(dev); out: pm_runtime_enable(dev); -- cgit v1.2.3 From 9df3921e026532eb3bd2904745d990c0a9f0b4e4 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 31 Mar 2016 11:21:25 +0200 Subject: PM / Domains: Rename stop_ok to suspend_ok for the genpd governor The genpd governor validates the latency constraints to find out whether it's acceptable to runtime suspend a device. Earlier this validation was made to know whether it was okay to invoke the ->stop() callback for the device, hence the governor used the name "stop_ok" for the related variables. To clarify the code around this, let's rename these variables from "stop_ok" to "suspend_ok". Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 6 +++--- drivers/base/power/domain_governor.c | 20 ++++++++++---------- include/linux/pm_domain.h | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 56705b52758e..c62687d9fa5a 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -382,7 +382,7 @@ static void genpd_power_off_work_fn(struct work_struct *work) static int pm_genpd_runtime_suspend(struct device *dev) { struct generic_pm_domain *genpd; - bool (*stop_ok)(struct device *__dev); + bool (*suspend_ok)(struct device *__dev); struct gpd_timing_data *td = &dev_gpd_data(dev)->td; bool runtime_pm = pm_runtime_enabled(dev); ktime_t time_start; @@ -401,8 +401,8 @@ static int pm_genpd_runtime_suspend(struct device *dev) * runtime PM is disabled. Under these circumstances, we shall skip * validating/measuring the PM QoS latency. */ - stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; - if (runtime_pm && stop_ok && !stop_ok(dev)) + suspend_ok = genpd->gov ? genpd->gov->suspend_ok : NULL; + if (runtime_pm && suspend_ok && !suspend_ok(dev)) return -EBUSY; /* Measure suspend latency. */ diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index 00a5436dd44b..2e0fce711135 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c @@ -37,10 +37,10 @@ static int dev_update_qos_constraint(struct device *dev, void *data) } /** - * default_stop_ok - Default PM domain governor routine for stopping devices. + * default_suspend_ok - Default PM domain governor routine to suspend devices. * @dev: Device to check. */ -static bool default_stop_ok(struct device *dev) +static bool default_suspend_ok(struct device *dev) { struct gpd_timing_data *td = &dev_gpd_data(dev)->td; unsigned long flags; @@ -51,13 +51,13 @@ static bool default_stop_ok(struct device *dev) spin_lock_irqsave(&dev->power.lock, flags); if (!td->constraint_changed) { - bool ret = td->cached_stop_ok; + bool ret = td->cached_suspend_ok; spin_unlock_irqrestore(&dev->power.lock, flags); return ret; } td->constraint_changed = false; - td->cached_stop_ok = false; + td->cached_suspend_ok = false; td->effective_constraint_ns = -1; constraint_ns = __dev_pm_qos_read_value(dev); @@ -83,13 +83,13 @@ static bool default_stop_ok(struct device *dev) return false; } td->effective_constraint_ns = constraint_ns; - td->cached_stop_ok = constraint_ns >= 0; + td->cached_suspend_ok = constraint_ns >= 0; /* * The children have been suspended already, so we don't need to take - * their stop latencies into account here. + * their suspend latencies into account here. */ - return td->cached_stop_ok; + return td->cached_suspend_ok; } /** @@ -150,7 +150,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd, */ td = &to_gpd_data(pdd)->td; constraint_ns = td->effective_constraint_ns; - /* default_stop_ok() need not be called before us. */ + /* default_suspend_ok() need not be called before us. */ if (constraint_ns < 0) { constraint_ns = dev_pm_qos_read_value(pdd->dev); constraint_ns *= NSEC_PER_USEC; @@ -227,7 +227,7 @@ static bool always_on_power_down_ok(struct dev_pm_domain *domain) } struct dev_power_governor simple_qos_governor = { - .stop_ok = default_stop_ok, + .suspend_ok = default_suspend_ok, .power_down_ok = default_power_down_ok, }; @@ -236,5 +236,5 @@ struct dev_power_governor simple_qos_governor = { */ struct dev_power_governor pm_domain_always_on_gov = { .power_down_ok = always_on_power_down_ok, - .stop_ok = default_stop_ok, + .suspend_ok = default_suspend_ok, }; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 49cd8890b873..e91393954384 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -28,7 +28,7 @@ enum gpd_status { struct dev_power_governor { bool (*power_down_ok)(struct dev_pm_domain *domain); - bool (*stop_ok)(struct device *dev); + bool (*suspend_ok)(struct device *dev); }; struct gpd_dev_ops { @@ -94,7 +94,7 @@ struct gpd_timing_data { s64 resume_latency_ns; s64 effective_constraint_ns; bool constraint_changed; - bool cached_stop_ok; + bool cached_suspend_ok; }; struct pm_domain_data { -- cgit v1.2.3 From 795bd2e7e86967ced927948eff08fe8201ba5fc3 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 31 Mar 2016 11:21:26 +0200 Subject: PM / Domains: Rename pm_genpd_runtime_suspend|resume() Follow genpd's rule for names of static functions, by renaming pm_genpd_runtime_suspend|resume() to genpd_runtime_suspend|resume(). Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index c62687d9fa5a..75b994a63e71 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -372,14 +372,14 @@ static void genpd_power_off_work_fn(struct work_struct *work) } /** - * pm_genpd_runtime_suspend - Suspend a device belonging to I/O PM domain. + * genpd_runtime_suspend - Suspend a device belonging to I/O PM domain. * @dev: Device to suspend. * * Carry out a runtime suspend of a device under the assumption that its * pm_domain field points to the domain member of an object of type * struct generic_pm_domain representing a PM domain consisting of I/O devices. */ -static int pm_genpd_runtime_suspend(struct device *dev) +static int genpd_runtime_suspend(struct device *dev) { struct generic_pm_domain *genpd; bool (*suspend_ok)(struct device *__dev); @@ -446,14 +446,14 @@ static int pm_genpd_runtime_suspend(struct device *dev) } /** - * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain. + * genpd_runtime_resume - Resume a device belonging to I/O PM domain. * @dev: Device to resume. * * Carry out a runtime resume of a device under the assumption that its * pm_domain field points to the domain member of an object of type * struct generic_pm_domain representing a PM domain consisting of I/O devices. */ -static int pm_genpd_runtime_resume(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; @@ -1498,8 +1498,8 @@ void pm_genpd_init(struct generic_pm_domain *genpd, genpd->device_count = 0; genpd->max_off_time_ns = -1; genpd->max_off_time_changed = true; - genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; - genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; + genpd->domain.ops.runtime_suspend = genpd_runtime_suspend; + genpd->domain.ops.runtime_resume = genpd_runtime_resume; genpd->domain.ops.prepare = pm_genpd_prepare; genpd->domain.ops.suspend = pm_genpd_suspend; genpd->domain.ops.suspend_late = pm_genpd_suspend_late; -- cgit v1.2.3 From 54eeddbf92d0de297d78f7419dde00079d553dec Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 31 Mar 2016 11:21:27 +0200 Subject: PM / Domains: Remove ->save|restore_state() callbacks As a part of the ongoing consolidation of genpd, it's become questionable whether clients actually needs to be able to assign their own set of ->save|restore_state() callbacks. Currently all users copes fine with the default callbacks, so let's remove the configuration option and stick to the default ones. This enables further clarifications of the related code and let's also rename pm_genpd_default_save|restore_state() into __genpd_runtime_suspend|resume() to apply the rule of static functionnames in genpd. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 113 +++++++++++++++++++------------------------- include/linux/pm_domain.h | 2 - 2 files changed, 49 insertions(+), 66 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 75b994a63e71..4ce4ce0a2730 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -229,17 +229,6 @@ static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth) return ret; } -static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, save_state, dev); -} - -static int genpd_restore_dev(struct generic_pm_domain *genpd, - struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev); -} - static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, unsigned long val, void *ptr) { @@ -371,6 +360,52 @@ static void genpd_power_off_work_fn(struct work_struct *work) mutex_unlock(&genpd->lock); } +/** + * __genpd_runtime_suspend - walk the hierarchy of ->runtime_suspend() callbacks + * @dev: Device to handle. + */ +static int __genpd_runtime_suspend(struct device *dev) +{ + int (*cb)(struct device *__dev); + + if (dev->type && dev->type->pm) + cb = dev->type->pm->runtime_suspend; + else if (dev->class && dev->class->pm) + cb = dev->class->pm->runtime_suspend; + else if (dev->bus && dev->bus->pm) + cb = dev->bus->pm->runtime_suspend; + else + cb = NULL; + + if (!cb && dev->driver && dev->driver->pm) + cb = dev->driver->pm->runtime_suspend; + + return cb ? cb(dev) : 0; +} + +/** + * __genpd_runtime_resume - walk the hierarchy of ->runtime_resume() callbacks + * @dev: Device to handle. + */ +static int __genpd_runtime_resume(struct device *dev) +{ + int (*cb)(struct device *__dev); + + if (dev->type && dev->type->pm) + cb = dev->type->pm->runtime_resume; + else if (dev->class && dev->class->pm) + cb = dev->class->pm->runtime_resume; + else if (dev->bus && dev->bus->pm) + cb = dev->bus->pm->runtime_resume; + else + cb = NULL; + + if (!cb && dev->driver && dev->driver->pm) + cb = dev->driver->pm->runtime_resume; + + return cb ? cb(dev) : 0; +} + /** * genpd_runtime_suspend - Suspend a device belonging to I/O PM domain. * @dev: Device to suspend. @@ -409,13 +444,13 @@ static int genpd_runtime_suspend(struct device *dev) if (runtime_pm) time_start = ktime_get(); - ret = genpd_save_dev(genpd, dev); + ret = __genpd_runtime_suspend(dev); if (ret) return ret; ret = genpd_stop_dev(genpd, dev); if (ret) { - genpd_restore_dev(genpd, dev); + __genpd_runtime_resume(dev); return ret; } @@ -491,7 +526,7 @@ static int genpd_runtime_resume(struct device *dev) if (ret) goto err_poweroff; - ret = genpd_restore_dev(genpd, dev); + ret = __genpd_runtime_resume(dev); if (ret) goto err_stop; @@ -1427,54 +1462,6 @@ out: } EXPORT_SYMBOL_GPL(pm_genpd_remove_subdomain); -/* Default device callbacks for generic PM domains. */ - -/** - * pm_genpd_default_save_state - Default "save device state" for PM domains. - * @dev: Device to handle. - */ -static int pm_genpd_default_save_state(struct device *dev) -{ - int (*cb)(struct device *__dev); - - if (dev->type && dev->type->pm) - cb = dev->type->pm->runtime_suspend; - else if (dev->class && dev->class->pm) - cb = dev->class->pm->runtime_suspend; - else if (dev->bus && dev->bus->pm) - cb = dev->bus->pm->runtime_suspend; - else - cb = NULL; - - if (!cb && dev->driver && dev->driver->pm) - cb = dev->driver->pm->runtime_suspend; - - return cb ? cb(dev) : 0; -} - -/** - * pm_genpd_default_restore_state - Default PM domains "restore device state". - * @dev: Device to handle. - */ -static int pm_genpd_default_restore_state(struct device *dev) -{ - int (*cb)(struct device *__dev); - - if (dev->type && dev->type->pm) - cb = dev->type->pm->runtime_resume; - else if (dev->class && dev->class->pm) - cb = dev->class->pm->runtime_resume; - else if (dev->bus && dev->bus->pm) - cb = dev->bus->pm->runtime_resume; - else - cb = NULL; - - if (!cb && dev->driver && dev->driver->pm) - cb = dev->driver->pm->runtime_resume; - - return cb ? cb(dev) : 0; -} - /** * pm_genpd_init - Initialize a generic I/O PM domain object. * @genpd: PM domain object to initialize. @@ -1520,8 +1507,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd, genpd->domain.ops.restore_early = pm_genpd_resume_early; genpd->domain.ops.restore = pm_genpd_resume; genpd->domain.ops.complete = pm_genpd_complete; - genpd->dev_ops.save_state = pm_genpd_default_save_state; - genpd->dev_ops.restore_state = pm_genpd_default_restore_state; if (genpd->flags & GENPD_FLAG_PM_CLK) { genpd->dev_ops.stop = pm_clk_suspend; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index e91393954384..39285c7bd3f5 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -34,8 +34,6 @@ struct dev_power_governor { struct gpd_dev_ops { int (*start)(struct device *dev); int (*stop)(struct device *dev); - int (*save_state)(struct device *dev); - int (*restore_state)(struct device *dev); bool (*active_wakeup)(struct device *dev); }; -- cgit v1.2.3 From 624c8df7d2823ec0df9609025480309322886ed3 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 26 Apr 2016 08:47:17 +0200 Subject: PM / Domains: Remove redundant pm_runtime_get|put*() in pm_genpd_prepare() The PM core increases and decreases the runtime PM usage count in the system PM prepare phase. This makes some of the pm_runtime_get|put*() calls in pm_genpd_prepare() redundant, so let's remove them. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Reviewed-by: Laurent Pinchart Reviewed-by: Laurent Pinchart Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 4ce4ce0a2730..60a357386705 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -730,14 +730,11 @@ static int pm_genpd_prepare(struct device *dev) * at this point and a system wakeup event should be reported if it's * set up to wake up the system from sleep states. */ - 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(dev); + if (pm_wakeup_pending()) return -EBUSY; - } if (resume_needed(dev, genpd)) pm_runtime_resume(dev); @@ -751,10 +748,8 @@ static int pm_genpd_prepare(struct device *dev) mutex_unlock(&genpd->lock); - if (genpd->suspend_power_off) { - pm_runtime_put_noidle(dev); + if (genpd->suspend_power_off) return 0; - } /* * The PM domain must be in the GPD_STATE_ACTIVE state at this point, @@ -776,7 +771,6 @@ static int pm_genpd_prepare(struct device *dev) pm_runtime_enable(dev); } - pm_runtime_put(dev); return ret; } -- cgit v1.2.3 From 164a2159a2d6789bc7e3c4b126dde7f3ce865992 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 26 Apr 2016 08:47:18 +0200 Subject: PM / Domains: Drop unnecessary wakeup code from pm_genpd_prepare() As the PM core already have wakeup management during the system PM phase, it seems reasonable that genpd and its users should be able to rely on that. Therefore let's remove this from pm_genpd_prepare(). Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 60a357386705..de23b648fce3 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -730,12 +730,6 @@ static int pm_genpd_prepare(struct device *dev) * at this point and a system wakeup event should be reported if it's * set up to wake up the system from sleep states. */ - if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) - pm_wakeup_event(dev, 0); - - if (pm_wakeup_pending()) - return -EBUSY; - if (resume_needed(dev, genpd)) pm_runtime_resume(dev); -- cgit v1.2.3 From fba1fbf56383073d286e6e3657bff36ee0f410e8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 28 Apr 2016 14:42:34 +0200 Subject: PM / sleep: Drop unused `info' variable Commit 32e8d689dc12 (PM / sleep: trace_device_pm_callback coverage in dpm_prepare/complete) removed all users of this variable but forgot to remove the variable itself. Signed-off-by: Thierry Reding [ rjw: Subject ] Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 6e7c3ccea24b..c81667d4bb60 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1556,7 +1556,6 @@ int dpm_suspend(pm_message_t state) static int device_prepare(struct device *dev, pm_message_t state) { int (*callback)(struct device *) = NULL; - char *info = NULL; int ret = 0; if (dev->power.syscore) @@ -1579,24 +1578,17 @@ static int device_prepare(struct device *dev, pm_message_t state) goto unlock; } - if (dev->pm_domain) { - info = "preparing power domain "; + if (dev->pm_domain) callback = dev->pm_domain->ops.prepare; - } else if (dev->type && dev->type->pm) { - info = "preparing type "; + else if (dev->type && dev->type->pm) callback = dev->type->pm->prepare; - } else if (dev->class && dev->class->pm) { - info = "preparing class "; + else if (dev->class && dev->class->pm) callback = dev->class->pm->prepare; - } else if (dev->bus && dev->bus->pm) { - info = "preparing bus "; + else if (dev->bus && dev->bus->pm) callback = dev->bus->pm->prepare; - } - if (!callback && dev->driver && dev->driver->pm) { - info = "preparing driver "; + if (!callback && dev->driver && dev->driver->pm) callback = dev->driver->pm->prepare; - } if (callback) ret = callback(dev); -- cgit v1.2.3