From 107d47b2b95ef478d71f3bf36201886d7475427a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Apr 2020 18:29:30 +0200 Subject: PM: sleep: core: Simplify the SMART_SUSPEND flag handling The code to handle the SMART_SUSPEND driver PM flag is hard to follow and somewhat inconsistent with respect to devices without middle-layer (subsystem) callbacks. Namely, for those devices the core takes the role of a middle layer in providing the expected ordering of execution of callbacks (under the assumption that the drivers setting SMART_SUSPEND can reuse their PM-runtime callbacks directly for system-wide suspend). To that end, it prevents driver ->suspend_late and ->suspend_noirq callbacks from being executed for devices that are still runtime-suspended in __device_suspend_late(), because running the same callback funtion that was previously run by PM-runtime for them may be invalid. However, it does that only for devices without any middle-layer callbacks for the late/noirq/early suspend/resume phases even though it would be simpler and more consistent to skip the driver-lavel callbacks for all devices with SMART_SUSPEND set that are runtime-suspended in __device_suspend_late(). Simplify the code in accordance with the above observation. Suggested-by: Alan Stern Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern --- drivers/base/power/main.c | 118 +++++++++++++++------------------------------- 1 file changed, 39 insertions(+), 79 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index fdd508a78ffd..5d0225573bbe 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -561,24 +561,6 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) /*------------------------- Resume routines -------------------------*/ -/** - * suspend_event - Return a "suspend" message for given "resume" one. - * @resume_msg: PM message representing a system-wide resume transition. - */ -static pm_message_t suspend_event(pm_message_t resume_msg) -{ - switch (resume_msg.event) { - case PM_EVENT_RESUME: - return PMSG_SUSPEND; - case PM_EVENT_THAW: - case PM_EVENT_RESTORE: - return PMSG_FREEZE; - case PM_EVENT_RECOVER: - return PMSG_HIBERNATE; - } - return PMSG_ON; -} - /** * dev_pm_may_skip_resume - System-wide device resume optimization check. * @dev: Target device. @@ -656,37 +638,36 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn if (!dpm_wait_for_superior(dev, async)) goto Out; - skip_resume = dev_pm_may_skip_resume(dev); - callback = dpm_subsys_resume_noirq_cb(dev, state, &info); - if (callback) + if (callback) { + skip_resume = false; goto Run; + } + skip_resume = dev_pm_may_skip_resume(dev); if (skip_resume) goto Skip; - if (dev_pm_smart_suspend_and_suspended(dev)) { - pm_message_t suspend_msg = suspend_event(state); - - /* - * If "freeze" callbacks have been skipped during a transition - * related to hibernation, the subsequent "thaw" callbacks must - * be skipped too or bad things may happen. Otherwise, resume - * callbacks are going to be run for the device, so its runtime - * PM status must be changed to reflect the new state after the - * transition under way. - */ - if (!dpm_subsys_suspend_late_cb(dev, suspend_msg, NULL) && - !dpm_subsys_suspend_noirq_cb(dev, suspend_msg, NULL)) { - if (state.event == PM_EVENT_THAW) { - skip_resume = true; - goto Skip; - } else { - pm_runtime_set_active(dev); - } - } + /* + * If "freeze" driver callbacks have been skipped during hibernation, + * because the device was runtime-suspended in __device_suspend_late(), + * the corresponding "thaw" callbacks must be skipped too, because + * running them for a runtime-suspended device may not be valid. + */ + if (dev_pm_smart_suspend_and_suspended(dev) && + state.event == PM_EVENT_THAW) { + skip_resume = true; + goto Skip; } + /* + * The device is going to be resumed, so set its PM-runtime status to + * "active", but do that only if DPM_FLAG_SMART_SUSPEND is set to avoid + * confusing drivers that don't use it. + */ + if (dev_pm_smart_suspend_and_suspended(dev)) + pm_runtime_set_active(dev); + if (dev->driver && dev->driver->pm) { info = "noirq driver "; callback = pm_noirq_op(dev->driver->pm, state); @@ -1274,32 +1255,6 @@ static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, return callback; } -static bool device_must_resume(struct device *dev, pm_message_t state, - bool no_subsys_suspend_noirq) -{ - pm_message_t resume_msg = resume_event(state); - - /* - * If all of the device driver's "noirq", "late" and "early" callbacks - * are invoked directly by the core, the decision to allow the device to - * stay in suspend can be based on its current runtime PM status and its - * wakeup settings. - */ - if (no_subsys_suspend_noirq && - !dpm_subsys_suspend_late_cb(dev, state, NULL) && - !dpm_subsys_resume_early_cb(dev, resume_msg, NULL) && - !dpm_subsys_resume_noirq_cb(dev, resume_msg, NULL)) - return !pm_runtime_status_suspended(dev) && - (resume_msg.event != PM_EVENT_RESUME || - (device_can_wakeup(dev) && !device_may_wakeup(dev))); - - /* - * The only safe strategy here is to require that if the device may not - * be left in suspend, resume callbacks must be invoked for it. - */ - return !dev->power.may_skip_resume; -} - /** * __device_suspend_noirq - Execute a "noirq suspend" callback for given device. * @dev: Device to handle. @@ -1313,7 +1268,6 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a { pm_callback_t callback; const char *info; - bool no_subsys_cb = false; int error = 0; TRACE_DEVICE(dev); @@ -1331,9 +1285,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a if (callback) goto Run; - no_subsys_cb = !dpm_subsys_suspend_late_cb(dev, state, NULL); - - if (dev_pm_smart_suspend_and_suspended(dev) && no_subsys_cb) + if (dev_pm_smart_suspend_and_suspended(dev)) goto Skip; if (dev->driver && dev->driver->pm) { @@ -1351,13 +1303,16 @@ Run: Skip: dev->power.is_noirq_suspended = true; - if (dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED)) { - dev->power.must_resume = dev->power.must_resume || - atomic_read(&dev->power.usage_count) > 1 || - device_must_resume(dev, state, no_subsys_cb); - } else { + /* + * Skipping the resume of devices that were in use right before the + * system suspend (as indicated by their PM-runtime usage counters) + * would be suboptimal. Also resume them if doing that is not allowed + * to be skipped. + */ + if (atomic_read(&dev->power.usage_count) > 1 || + !(dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED) && + dev->power.may_skip_resume)) dev->power.must_resume = true; - } if (dev->power.must_resume) dpm_superior_set_must_resume(dev); @@ -1539,9 +1494,14 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as if (callback) goto Run; - if (dev_pm_smart_suspend_and_suspended(dev) && - !dpm_subsys_suspend_noirq_cb(dev, state, NULL)) + if (dev_pm_smart_suspend_and_suspended(dev)) { + /* + * In principle, the resume of the device may be skippend if it + * remains in runtime suspend at this point. + */ + dev->power.may_skip_resume = true; goto Skip; + } if (dev->driver && dev->driver->pm) { info = "late driver "; -- cgit v1.2.3 From 30205377ddbb717ee451e872fd59511f4f76373d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Apr 2020 18:51:44 +0200 Subject: PM: sleep: core: Fold functions into their callers Fold four functions in the PM core that each have only one caller now into their callers. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern --- drivers/base/power/main.c | 198 ++++++++++++++-------------------------------- 1 file changed, 60 insertions(+), 138 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 5d0225573bbe..75d7cdb4de9c 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -573,43 +573,6 @@ bool dev_pm_may_skip_resume(struct device *dev) return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE; } -static pm_callback_t dpm_subsys_resume_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; -} - -static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, - pm_message_t state, - const char **info_p); - -static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, - pm_message_t state, - const char **info_p); - /** * device_resume_noirq - Execute a "noirq resume" callback for given device. * @dev: Device to handle. @@ -621,8 +584,8 @@ static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, */ static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback; - const char *info; + pm_callback_t callback = NULL; + const char *info = NULL; bool skip_resume; int error = 0; @@ -638,7 +601,19 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn if (!dpm_wait_for_superior(dev, async)) goto Out; - callback = dpm_subsys_resume_noirq_cb(dev, state, &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); + } if (callback) { skip_resume = false; goto Run; @@ -791,35 +766,6 @@ void dpm_resume_noirq(pm_message_t state) cpuidle_resume(); } -static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev, - pm_message_t state, - const char **info_p) -{ - pm_callback_t callback; - const char *info; - - if (dev->pm_domain) { - info = "early power domain "; - callback = pm_late_early_op(&dev->pm_domain->ops, state); - } else if (dev->type && dev->type->pm) { - info = "early type "; - callback = pm_late_early_op(dev->type->pm, state); - } else if (dev->class && dev->class->pm) { - info = "early class "; - callback = pm_late_early_op(dev->class->pm, state); - } 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. @@ -830,8 +776,8 @@ static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev, */ static int device_resume_early(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback; - const char *info; + pm_callback_t callback = NULL; + const char *info = NULL; int error = 0; TRACE_DEVICE(dev); @@ -846,9 +792,19 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn if (!dpm_wait_for_superior(dev, async)) goto Out; - callback = dpm_subsys_resume_early_cb(dev, state, &info); - - if (!callback && dev->driver && dev->driver->pm) { + if (dev->pm_domain) { + info = "early power domain "; + callback = pm_late_early_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "early type "; + callback = pm_late_early_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "early class "; + callback = pm_late_early_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "early bus "; + callback = pm_late_early_op(dev->bus->pm, state); + } else if (dev->driver && dev->driver->pm) { info = "early driver "; callback = pm_late_early_op(dev->driver->pm, state); } @@ -1226,35 +1182,6 @@ 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. @@ -1266,8 +1193,8 @@ static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, */ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback; - const char *info; + pm_callback_t callback = NULL; + const char *info = NULL; int error = 0; TRACE_DEVICE(dev); @@ -1281,7 +1208,19 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a if (dev->power.syscore || dev->power.direct_complete) goto Complete; - callback = dpm_subsys_suspend_noirq_cb(dev, state, &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); + } if (callback) goto Run; @@ -1429,35 +1368,6 @@ static void dpm_propagate_wakeup_to_parent(struct device *dev) spin_unlock_irq(&parent->power.lock); } -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. @@ -1468,8 +1378,8 @@ static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, */ static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback; - const char *info; + pm_callback_t callback = NULL; + const char *info = NULL; int error = 0; TRACE_DEVICE(dev); @@ -1490,7 +1400,19 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as if (dev->power.syscore || dev->power.direct_complete) goto Complete; - callback = dpm_subsys_suspend_late_cb(dev, state, &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); + } if (callback) goto Run; -- cgit v1.2.3 From 6e176bf8d46194353163c2cb660808bc633b45d9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Apr 2020 18:52:08 +0200 Subject: PM: sleep: core: Do not skip callbacks in the resume phase The current code in device_resume_noirq() causes the entire early resume and resume phases of device suspend to be skipped for devices for which the noirq resume phase have been skipped (due to the LEAVE_SUSPENDED flag being set) on the premise that those devices should stay in runtime-suspend after system-wide resume. However, that may not be correct in two situations. First, the middle layer (subsystem) noirq resume callback may be missing for a given device, but its early resume callback may be present and it may need to do something even if it decides to skip the driver callback. Second, if the device's wakeup settings were adjusted in the suspend phase without resuming the device (that was in runtime suspend at that time), they most likely need to be adjusted again in the resume phase and so the driver callback in that phase needs to be run. For the above reason, modify the core to allow the middle layer ->resume_late callback to run even if its ->resume_noirq callback is missing (and the core has skipped the driver-level callback in that phase) and to allow all device callbacks to run in the resume phase. Also make the core set the PM-runtime status of devices with SMART_SUSPEND set whose resume callbacks are not skipped to "active" in the "noirq" resume phase and update the affected subsystems (PCI and ACPI) accordingly. After this change, middle-layer (subsystem) callbacks will always be invoked in all phases of system suspend and resume and driver callbacks will always run in the prepare, suspend, resume, and complete phases for all devices. For devices with SMART_SUSPEND set, driver callbacks will be skipped in the late and noirq phases of system suspend if those devices remain in runtime suspend in __device_suspend_late(). Driver callbacks will also be skipped for them during the noirq and early phases of the "thaw" transition related to hibernation in that case. Setting LEAVE_SUSPENDED means that the driver allows its callbacks to be skipped in the noirq and early phases of system resume, but some additional conditions need to be met for that to happen (among other things, the power.may_skip_resume flag needs to be set for the device during system suspend for the driver callbacks to be skipped during the subsequent resume transition). For all devices with SMART_SUSPEND set whose driver callbacks are invoked during system resume, the PM-runtime status will be set to "active" (by the core). Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern Acked-by: Bjorn Helgaas --- drivers/base/power/main.c | 85 +++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 43 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 75d7cdb4de9c..25b0302188d8 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -565,12 +565,22 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) * dev_pm_may_skip_resume - System-wide device resume optimization check. * @dev: Target device. * - * Checks whether or not the device may be left in suspend after a system-wide - * transition to the working state. + * Return: + * - %false if the transition under way is RESTORE. + * - The return value of dev_pm_smart_suspend_and_suspended() if the transition + * under way is THAW. + * - The logical negation of %power.must_resume otherwise (that is, when the + * transition under way is RESUME). */ bool dev_pm_may_skip_resume(struct device *dev) { - return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE; + if (pm_transition.event == PM_EVENT_RESTORE) + return false; + + if (pm_transition.event == PM_EVENT_THAW) + return dev_pm_smart_suspend_and_suspended(dev); + + return !dev->power.must_resume; } /** @@ -601,6 +611,22 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn if (!dpm_wait_for_superior(dev, async)) goto Out; + skip_resume = dev_pm_may_skip_resume(dev); + /* + * If the driver callback is skipped below or by the middle layer + * callback and device_resume_early() also skips the driver callback for + * this device later, it needs to appear as "suspended" to PM-runtime, + * so change its status accordingly. + * + * Otherwise, the device is going to be resumed, so set its PM-runtime + * status to "active", but do that only if DPM_FLAG_SMART_SUSPEND is set + * to avoid confusing drivers that don't use it. + */ + if (skip_resume) + pm_runtime_set_suspended(dev); + else if (dev_pm_smart_suspend_and_suspended(dev)) + pm_runtime_set_active(dev); + if (dev->pm_domain) { info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); @@ -614,35 +640,12 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn info = "noirq bus "; callback = pm_noirq_op(dev->bus->pm, state); } - if (callback) { - skip_resume = false; + if (callback) goto Run; - } - skip_resume = dev_pm_may_skip_resume(dev); if (skip_resume) goto Skip; - /* - * If "freeze" driver callbacks have been skipped during hibernation, - * because the device was runtime-suspended in __device_suspend_late(), - * the corresponding "thaw" callbacks must be skipped too, because - * running them for a runtime-suspended device may not be valid. - */ - if (dev_pm_smart_suspend_and_suspended(dev) && - state.event == PM_EVENT_THAW) { - skip_resume = true; - goto Skip; - } - - /* - * The device is going to be resumed, so set its PM-runtime status to - * "active", but do that only if DPM_FLAG_SMART_SUSPEND is set to avoid - * confusing drivers that don't use it. - */ - if (dev_pm_smart_suspend_and_suspended(dev)) - pm_runtime_set_active(dev); - if (dev->driver && dev->driver->pm) { info = "noirq driver "; callback = pm_noirq_op(dev->driver->pm, state); @@ -654,20 +657,6 @@ Run: Skip: dev->power.is_noirq_suspended = false; - if (skip_resume) { - /* Make the next phases of resume skip the device. */ - dev->power.is_late_suspended = false; - dev->power.is_suspended = false; - /* - * The device is going to be left in suspend, but it might not - * have been in runtime suspend before the system suspended, so - * its runtime PM status needs to be updated to avoid confusing - * the runtime PM framework when runtime PM is enabled for the - * device again. - */ - pm_runtime_set_suspended(dev); - } - Out: complete_all(&dev->power.completion); TRACE_RESUME(error); @@ -804,15 +793,25 @@ 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 if (dev->driver && dev->driver->pm) { + } + if (callback) + goto Run; + + if (dev_pm_may_skip_resume(dev)) + goto Skip; + + if (dev->driver && dev->driver->pm) { info = "early driver "; callback = pm_late_early_op(dev->driver->pm, state); } +Run: error = dpm_run_callback(callback, dev, state, info); + +Skip: dev->power.is_late_suspended = false; - Out: +Out: TRACE_RESUME(error); pm_runtime_enable(dev); -- cgit v1.2.3 From 0fe8a1be599ab97f840ba22d98cb8f24a9f9e872 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Apr 2020 18:52:19 +0200 Subject: PM: sleep: core: Rework the power.may_skip_resume handling Because the power.may_skip_resume device status bit is taken into account in combination with the DPM_FLAG_LEAVE_SUSPENDED driver flag, it can be set to 'true' for all devices in the "suspend" phase of a suspend-resume cycle, so do that. Then, neither the PM core nor the middle-layer (sybsystem) code handling it needs to set it to 'true' any more and it just has to be cleared if there is a reason to avoid skipping the "noirq" and "early" resume callbacks provided by the driver, so update the code in question accordingly. Suggested-by: Alan Stern Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern Acked-by: Bjorn Helgaas --- drivers/base/power/main.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 25b0302188d8..5adf0be6aa47 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1415,14 +1415,8 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as if (callback) goto Run; - if (dev_pm_smart_suspend_and_suspended(dev)) { - /* - * In principle, the resume of the device may be skippend if it - * remains in runtime suspend at this point. - */ - dev->power.may_skip_resume = true; + if (dev_pm_smart_suspend_and_suspended(dev)) goto Skip; - } if (dev->driver && dev->driver->pm) { info = "late driver "; @@ -1647,7 +1641,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) dev->power.direct_complete = false; } - dev->power.may_skip_resume = false; + dev->power.may_skip_resume = true; dev->power.must_resume = false; dpm_watchdog_set(&wd, dev); -- cgit v1.2.3 From 76c70cb58ce30264af4b714109ee756da25d830a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Apr 2020 18:52:30 +0200 Subject: PM: sleep: core: Rename dev_pm_may_skip_resume() The name of dev_pm_may_skip_resume() may be easily confused with the power.may_skip_resume flag which is not checked by that function, so rename the former as dev_pm_skip_resume(). No functional impact. Suggested-by: Alan Stern Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern Acked-by: Bjorn Helgaas --- drivers/base/power/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 5adf0be6aa47..f98eced0f200 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -562,7 +562,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) /*------------------------- Resume routines -------------------------*/ /** - * dev_pm_may_skip_resume - System-wide device resume optimization check. + * dev_pm_skip_resume - System-wide device resume optimization check. * @dev: Target device. * * Return: @@ -572,7 +572,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) * - The logical negation of %power.must_resume otherwise (that is, when the * transition under way is RESUME). */ -bool dev_pm_may_skip_resume(struct device *dev) +bool dev_pm_skip_resume(struct device *dev) { if (pm_transition.event == PM_EVENT_RESTORE) return false; @@ -611,7 +611,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn if (!dpm_wait_for_superior(dev, async)) goto Out; - skip_resume = dev_pm_may_skip_resume(dev); + skip_resume = dev_pm_skip_resume(dev); /* * If the driver callback is skipped below or by the middle layer * callback and device_resume_early() also skips the driver callback for @@ -797,7 +797,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn if (callback) goto Run; - if (dev_pm_may_skip_resume(dev)) + if (dev_pm_skip_resume(dev)) goto Skip; if (dev->driver && dev->driver->pm) { -- cgit v1.2.3 From fa2bfead910322e44e7e0bb74364ac198a2abd32 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Apr 2020 18:52:48 +0200 Subject: PM: sleep: core: Rename dev_pm_smart_suspend_and_suspended() Because all callers of dev_pm_smart_suspend_and_suspended use it only for checking whether or not to skip driver suspend callbacks for a device, rename it to dev_pm_skip_suspend() in analogy with dev_pm_skip_resume(). No functional impact. Suggested-by: Alan Stern Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern Acked-by: Bjorn Helgaas --- drivers/base/power/main.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index f98eced0f200..3170d93e29f9 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -567,8 +567,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) * * Return: * - %false if the transition under way is RESTORE. - * - The return value of dev_pm_smart_suspend_and_suspended() if the transition - * under way is THAW. + * - Return value of dev_pm_skip_suspend() if the transition under way is THAW. * - The logical negation of %power.must_resume otherwise (that is, when the * transition under way is RESUME). */ @@ -578,7 +577,7 @@ bool dev_pm_skip_resume(struct device *dev) return false; if (pm_transition.event == PM_EVENT_THAW) - return dev_pm_smart_suspend_and_suspended(dev); + return dev_pm_skip_suspend(dev); return !dev->power.must_resume; } @@ -624,7 +623,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn */ if (skip_resume) pm_runtime_set_suspended(dev); - else if (dev_pm_smart_suspend_and_suspended(dev)) + else if (dev_pm_skip_suspend(dev)) pm_runtime_set_active(dev); if (dev->pm_domain) { @@ -1223,7 +1222,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a if (callback) goto Run; - if (dev_pm_smart_suspend_and_suspended(dev)) + if (dev_pm_skip_suspend(dev)) goto Skip; if (dev->driver && dev->driver->pm) { @@ -1415,7 +1414,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as if (callback) goto Run; - if (dev_pm_smart_suspend_and_suspended(dev)) + if (dev_pm_skip_suspend(dev)) goto Skip; if (dev->driver && dev->driver->pm) { @@ -2003,7 +2002,7 @@ void device_pm_check_callbacks(struct device *dev) spin_unlock_irq(&dev->power.lock); } -bool dev_pm_smart_suspend_and_suspended(struct device *dev) +bool dev_pm_skip_suspend(struct device *dev) { return dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) && pm_runtime_status_suspended(dev); -- cgit v1.2.3 From e07515563d010d8b32967634e8dc2fdc732c1aa6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Apr 2020 18:53:01 +0200 Subject: PM: sleep: core: Rename DPM_FLAG_NEVER_SKIP Rename DPM_FLAG_NEVER_SKIP to DPM_FLAG_NO_DIRECT_COMPLETE which matches its purpose more closely. No functional impact. Suggested-by: Alan Stern Signed-off-by: Rafael J. Wysocki Acked-by: Bjorn Helgaas # for PCI parts Acked-by: Jeff Kirsher Acked-by: Alan Stern Acked-by: Bjorn Helgaas Acked-by: Alex Deucher --- drivers/base/power/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 3170d93e29f9..dbc1e5e7346b 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1844,7 +1844,7 @@ unlock: spin_lock_irq(&dev->power.lock); dev->power.direct_complete = state.event == PM_EVENT_SUSPEND && (ret > 0 || dev->power.no_pm_callbacks) && - !dev_pm_test_driver_flags(dev, DPM_FLAG_NEVER_SKIP); + !dev_pm_test_driver_flags(dev, DPM_FLAG_NO_DIRECT_COMPLETE); spin_unlock_irq(&dev->power.lock); return 0; } -- cgit v1.2.3 From 2a3f34750b8b07df42ab4b30b70e029d46e0d7f3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Apr 2020 18:53:20 +0200 Subject: PM: sleep: core: Rename DPM_FLAG_LEAVE_SUSPENDED Rename DPM_FLAG_LEAVE_SUSPENDED to DPM_FLAG_MAY_SKIP_RESUME which matches its purpose more closely. No functional impact. Suggested-by: Alan Stern Signed-off-by: Rafael J. Wysocki Acked-by: Wolfram Sang # for I2C Acked-by: Alan Stern Acked-by: Bjorn Helgaas --- drivers/base/power/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index dbc1e5e7346b..aaa4aaf41d27 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1247,7 +1247,7 @@ Skip: * to be skipped. */ if (atomic_read(&dev->power.usage_count) > 1 || - !(dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED) && + !(dev_pm_test_driver_flags(dev, DPM_FLAG_MAY_SKIP_RESUME) && dev->power.may_skip_resume)) dev->power.must_resume = true; -- cgit v1.2.3 From 3618bbaaa898cf48e859736120a775fcb56f3838 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 May 2020 18:09:55 +0300 Subject: PM: runtime: Make clear what we do when conditions are wrong in rpm_suspend() rpm_suspend() simple bails out when conditions are wrong. But this is not immediately obvious from the code. Make it clear what we do when conditions are wrong in rpm_suspend(). Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 99c7da112c95..9f62790f644c 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -523,13 +523,11 @@ static int rpm_suspend(struct device *dev, int rpmflags) repeat: retval = rpm_check_suspend_allowed(dev); - if (retval < 0) - ; /* Conditions are wrong. */ + goto out; /* Conditions are wrong. */ /* Synchronous suspends are not allowed in the RPM_RESUMING state. */ - else if (dev->power.runtime_status == RPM_RESUMING && - !(rpmflags & RPM_ASYNC)) + if (dev->power.runtime_status == RPM_RESUMING && !(rpmflags & RPM_ASYNC)) retval = -EAGAIN; if (retval) goto out; -- cgit v1.2.3 From 9a7875461fd0427dc86e3a87e93bd5723679b8b1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 May 2020 16:45:14 +0200 Subject: PM: runtime: Replace pm_runtime_callbacks_present() The name of pm_runtime_callbacks_present() is confusing, because it suggests that the device has PM-runtime callbacks if 'true' is returned by that function, but in fact that may not be the case, so replace it with pm_runtime_has_no_callbacks() which is not ambiguous. No functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Ulf Hansson --- drivers/base/power/sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 2b99fe1eb207..24d25cf8ab14 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -666,7 +666,7 @@ int dpm_sysfs_add(struct device *dev) if (rc) return rc; - if (pm_runtime_callbacks_present(dev)) { + if (!pm_runtime_has_no_callbacks(dev)) { rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group); if (rc) goto err_out; @@ -709,7 +709,7 @@ int dpm_sysfs_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) if (rc) return rc; - if (pm_runtime_callbacks_present(dev)) { + if (!pm_runtime_has_no_callbacks(dev)) { rc = sysfs_group_change_owner( &dev->kobj, &pm_runtime_attr_group, kuid, kgid); if (rc) -- cgit v1.2.3