diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 6e8cc5de93fd..3c5fdf155c91 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -551,31 +551,12 @@ bool dev_pm_may_skip_resume(struct device *dev) return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE; } -/** - * device_resume_noirq - Execute a "noirq resume" callback for given device. - * @dev: Device to handle. - * @state: PM transition of the system being carried out. - * @async: If true, the device is being resumed asynchronously. - * - * The driver of @dev will not receive interrupts while this function is being - * executed. - */ -static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) +static pm_callback_t dpm_subsys_resume_noirq_cb(struct device *dev, + pm_message_t state, + const char **info_p) { - pm_callback_t callback = NULL; - const char *info = NULL; - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - - if (dev->power.syscore || dev->power.direct_complete) - goto Out; - - if (!dev->power.is_noirq_suspended) - goto Out; - - dpm_wait_for_superior(dev, async); + pm_callback_t callback; + const char *info; if (dev->pm_domain) { info = "noirq power domain "; @@ -589,8 +570,44 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn } else if (dev->bus && dev->bus->pm) { info = "noirq bus "; callback = pm_noirq_op(dev->bus->pm, state); + } else { + return NULL; } + if (info_p) + *info_p = info; + + return callback; +} + +/** + * device_resume_noirq - Execute a "noirq resume" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * @async: If true, the device is being resumed asynchronously. + * + * The driver of @dev will not receive interrupts while this function is being + * executed. + */ +static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) +{ + pm_callback_t callback; + const char *info; + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + if (dev->power.syscore || dev->power.direct_complete) + goto Out; + + if (!dev->power.is_noirq_suspended) + goto Out; + + dpm_wait_for_superior(dev, async); + + callback = dpm_subsys_resume_noirq_cb(dev, state, &info); + if (!callback && dev->driver && dev->driver->pm) { info = "noirq driver "; callback = pm_noirq_op(dev->driver->pm, state); @@ -704,30 +721,12 @@ void dpm_resume_noirq(pm_message_t state) dpm_noirq_end(); } -/** - * device_resume_early - Execute an "early resume" callback for given device. - * @dev: Device to handle. - * @state: PM transition of the system being carried out. - * @async: If true, the device is being resumed asynchronously. - * - * Runtime PM is disabled for @dev while this function is being executed. - */ -static int device_resume_early(struct device *dev, pm_message_t state, bool async) +static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev, + pm_message_t state, + const char **info_p) { - pm_callback_t callback = NULL; - const char *info = NULL; - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - - if (dev->power.syscore || dev->power.direct_complete) - goto Out; - - if (!dev->power.is_late_suspended) - goto Out; - - dpm_wait_for_superior(dev, async); + pm_callback_t callback; + const char *info; if (dev->pm_domain) { info = "early power domain "; @@ -741,8 +740,43 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn } else if (dev->bus && dev->bus->pm) { info = "early bus "; callback = pm_late_early_op(dev->bus->pm, state); + } else { + return NULL; } + if (info_p) + *info_p = info; + + return callback; +} + +/** + * device_resume_early - Execute an "early resume" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * @async: If true, the device is being resumed asynchronously. + * + * Runtime PM is disabled for @dev while this function is being executed. + */ +static int device_resume_early(struct device *dev, pm_message_t state, bool async) +{ + pm_callback_t callback; + const char *info; + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + if (dev->power.syscore || dev->power.direct_complete) + goto Out; + + if (!dev->power.is_late_suspended) + goto Out; + + dpm_wait_for_superior(dev, async); + + callback = dpm_subsys_resume_early_cb(dev, state, &info); + if (!callback && dev->driver && dev->driver->pm) { info = "early driver "; callback = pm_late_early_op(dev->driver->pm, state); @@ -1128,6 +1162,35 @@ static void dpm_superior_set_must_resume(struct device *dev) device_links_read_unlock(idx); } +static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, + pm_message_t state, + const char **info_p) +{ + pm_callback_t callback; + const char *info; + + if (dev->pm_domain) { + info = "noirq power domain "; + callback = pm_noirq_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "noirq type "; + callback = pm_noirq_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "noirq class "; + callback = pm_noirq_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "noirq bus "; + callback = pm_noirq_op(dev->bus->pm, state); + } else { + return NULL; + } + + if (info_p) + *info_p = info; + + return callback; +} + /** * __device_suspend_noirq - Execute a "noirq suspend" callback for given device. * @dev: Device to handle. @@ -1139,8 +1202,8 @@ static void dpm_superior_set_must_resume(struct device *dev) */ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback = NULL; - const char *info = NULL; + pm_callback_t callback; + const char *info; int error = 0; TRACE_DEVICE(dev); @@ -1159,19 +1222,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a if (dev->power.syscore || dev->power.direct_complete) goto Complete; - if (dev->pm_domain) { - info = "noirq power domain "; - callback = pm_noirq_op(&dev->pm_domain->ops, state); - } else if (dev->type && dev->type->pm) { - info = "noirq type "; - callback = pm_noirq_op(dev->type->pm, state); - } else if (dev->class && dev->class->pm) { - info = "noirq class "; - callback = pm_noirq_op(dev->class->pm, state); - } else if (dev->bus && dev->bus->pm) { - info = "noirq bus "; - callback = pm_noirq_op(dev->bus->pm, state); - } + callback = dpm_subsys_suspend_noirq_cb(dev, state, &info); if (!callback && dev->driver && dev->driver->pm) { info = "noirq driver "; @@ -1306,6 +1357,35 @@ int dpm_suspend_noirq(pm_message_t state) return ret; } +static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, + pm_message_t state, + const char **info_p) +{ + pm_callback_t callback; + const char *info; + + if (dev->pm_domain) { + info = "late power domain "; + callback = pm_late_early_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "late type "; + callback = pm_late_early_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "late class "; + callback = pm_late_early_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "late bus "; + callback = pm_late_early_op(dev->bus->pm, state); + } else { + return NULL; + } + + if (info_p) + *info_p = info; + + return callback; +} + /** * __device_suspend_late - Execute a "late suspend" callback for given device. * @dev: Device to handle. @@ -1316,8 +1396,8 @@ int dpm_suspend_noirq(pm_message_t state) */ static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback = NULL; - const char *info = NULL; + pm_callback_t callback; + const char *info; int error = 0; TRACE_DEVICE(dev); @@ -1338,19 +1418,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as if (dev->power.syscore || dev->power.direct_complete) goto Complete; - if (dev->pm_domain) { - info = "late power domain "; - callback = pm_late_early_op(&dev->pm_domain->ops, state); - } else if (dev->type && dev->type->pm) { - info = "late type "; - callback = pm_late_early_op(dev->type->pm, state); - } else if (dev->class && dev->class->pm) { - info = "late class "; - callback = pm_late_early_op(dev->class->pm, state); - } else if (dev->bus && dev->bus->pm) { - info = "late bus "; - callback = pm_late_early_op(dev->bus->pm, state); - } + callback = dpm_subsys_suspend_late_cb(dev, state, &info); if (!callback && dev->driver && dev->driver->pm) { info = "late driver ";