diff options
-rw-r--r-- | drivers/base/power/domain.c | 145 | ||||
-rw-r--r-- | drivers/base/power/domain_governor.c | 20 | ||||
-rw-r--r-- | drivers/base/power/main.c | 18 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 9 | ||||
-rw-r--r-- | drivers/mmc/host/toshsd.c | 1 | ||||
-rw-r--r-- | include/linux/device.h | 5 | ||||
-rw-r--r-- | include/linux/pm.h | 2 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 6 | ||||
-rw-r--r-- | include/linux/pm_runtime.h | 6 |
9 files changed, 91 insertions, 121 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 56705b52758e..de23b648fce3 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) { @@ -372,17 +361,63 @@ 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 - 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. * * 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 (*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,21 +436,21 @@ 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. */ 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; } @@ -446,14 +481,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; @@ -491,7 +526,7 @@ static int pm_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; @@ -695,15 +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. */ - 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); - return -EBUSY; - } - if (resume_needed(dev, genpd)) pm_runtime_resume(dev); @@ -716,10 +742,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, @@ -741,7 +765,6 @@ static int pm_genpd_prepare(struct device *dev) pm_runtime_enable(dev); } - pm_runtime_put(dev); return ret; } @@ -1427,54 +1450,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. @@ -1498,8 +1473,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; @@ -1520,8 +1495,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/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/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); 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); diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c index e2cdd5fb1423..553ef41bb806 100644 --- a/drivers/mmc/host/toshsd.c +++ b/drivers/mmc/host/toshsd.c @@ -21,6 +21,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> diff --git a/include/linux/device.h b/include/linux/device.h index 002c59728dbe..b130304f9b1b 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -956,11 +956,6 @@ static inline bool device_async_suspend_enabled(struct device *dev) return !!dev->power.async_suspend; } -static inline void pm_suspend_ignore_children(struct device *dev, bool enable) -{ - dev->power.ignore_children = enable; -} - static inline void dev_pm_syscore_device(struct device *dev, bool val) { #ifdef CONFIG_PM_SLEEP diff --git a/include/linux/pm.h b/include/linux/pm.h index 6a5d654f4447..06eb353182ab 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -563,7 +563,6 @@ struct dev_pm_info { bool is_suspended:1; /* Ditto */ bool is_noirq_suspended:1; bool is_late_suspended:1; - bool ignore_children:1; bool early_init:1; /* Owned by the PM core */ bool direct_complete:1; /* Owned by the PM core */ spinlock_t lock; @@ -591,6 +590,7 @@ struct dev_pm_info { unsigned int deferred_resume:1; unsigned int run_wake:1; unsigned int runtime_auto:1; + bool ignore_children:1; unsigned int no_callbacks:1; unsigned int irq_safe:1; unsigned int use_autosuspend:1; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 49cd8890b873..39285c7bd3f5 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -28,14 +28,12 @@ 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 { 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); }; @@ -94,7 +92,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 { diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 7af093d6a4dd..2e14d2667b6c 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -56,6 +56,11 @@ extern void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns); extern void pm_runtime_set_memalloc_noio(struct device *dev, bool enable); +static inline void pm_suspend_ignore_children(struct device *dev, bool enable) +{ + dev->power.ignore_children = enable; +} + static inline bool pm_children_suspended(struct device *dev) { return dev->power.ignore_children @@ -156,6 +161,7 @@ static inline void __pm_runtime_disable(struct device *dev, bool c) {} static inline void pm_runtime_allow(struct device *dev) {} static inline void pm_runtime_forbid(struct device *dev) {} +static inline void pm_suspend_ignore_children(struct device *dev, bool enable) {} static inline bool pm_children_suspended(struct device *dev) { return false; } static inline void pm_runtime_get_noresume(struct device *dev) {} static inline void pm_runtime_put_noidle(struct device *dev) {} |