[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <12852589.O9o76ZdvQC@rafael.j.wysocki>
Date: Tue, 03 Feb 2026 21:37:40 +0100
From: "Rafael J. Wysocki" <rafael@...nel.org>
To: Linux PM <linux-pm@...r.kernel.org>
Cc: LKML <linux-kernel@...r.kernel.org>, Ulf Hansson <ulf.hansson@...aro.org>,
Saravana Kannan <saravanak@...gle.com>, Xuewen Yan <xuewen.yan@...soc.com>
Subject:
[PATCH v1] PM: sleep: core: Clear device async state upfront during suspend
From: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
In all of the system suspend transition phases, async state of all
devices needs to be cleared before starting async processing for any of
them because the latter may race with power.work_in_progress updates for
the device's parent or suppliers and if it touches bit fields from the
same group (for example, power.must_resume or power.wakeup_path), bit
field corruption is possible.
Rearrange the code accordingly.
Fixes: aa7a9275ab81 ("PM: sleep: Suspend async parents after suspending children")
Fixes: 443046d1ad66 ("PM: sleep: Make suspend of devices more asynchronous")
Reported-by: Xuewen Yan <xuewen.yan@...soc.com>
Closes: https://lore.kernel.org/linux-pm/20260203063459.12808-1-xuewen.yan@unisoc.com/
Cc: All applicable <stable@...r.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
---
drivers/base/power/main.c | 33 ++++++++++++++++++++++++++++++---
1 file changed, 30 insertions(+), 3 deletions(-)
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1527,11 +1527,20 @@ static int dpm_noirq_suspend_devices(pm_
mutex_lock(&dpm_list_mtx);
/*
+ * Clear the async state for all devices upfront to prevent the
+ * power.work_in_progress updates from racing with power.must_resume
+ * updates carried out by dpm_superior_set_must_resume(), since these
+ * flags belong to the same group of bit fields and they should not be
+ * updated at the same time without synchronization.
+ */
+ list_for_each_entry_reverse(dev, &dpm_late_early_list, power.entry)
+ dpm_clear_async_state(dev);
+
+ /*
* Start processing "async" leaf devices upfront so they don't need to
* wait for the "sync" devices they don't depend on.
*/
list_for_each_entry_reverse(dev, &dpm_late_early_list, power.entry) {
- dpm_clear_async_state(dev);
if (dpm_leaf_device(dev))
dpm_async_with_cleanup(dev, async_suspend_noirq);
}
@@ -1732,11 +1741,20 @@ int dpm_suspend_late(pm_message_t state)
mutex_lock(&dpm_list_mtx);
/*
+ * Clear the async state for all devices upfront to prevent the
+ * power.work_in_progress updates from racing with power.wakeup_path
+ * updates carried out by dpm_propagate_wakeup_to_parent(), since these
+ * flags belong to the same group of bit fields and they should not be
+ * updated at the same time without synchronization.
+ */
+ list_for_each_entry_reverse(dev, &dpm_suspended_list, power.entry)
+ dpm_clear_async_state(dev);
+
+ /*
* Start processing "async" leaf devices upfront so they don't need to
* wait for the "sync" devices they don't depend on.
*/
list_for_each_entry_reverse(dev, &dpm_suspended_list, power.entry) {
- dpm_clear_async_state(dev);
if (dpm_leaf_device(dev))
dpm_async_with_cleanup(dev, async_suspend_late);
}
@@ -2023,11 +2041,20 @@ int dpm_suspend(pm_message_t state)
mutex_lock(&dpm_list_mtx);
/*
+ * Clear the async state for all devices upfront to prevent the
+ * power.work_in_progress updates from racing with power.wakeup_path
+ * updates carried out by dpm_propagate_wakeup_to_parent(), since these
+ * flags belong to the same group of bit fields and they should not be
+ * updated at the same time without synchronization.
+ */
+ list_for_each_entry_reverse(dev, &dpm_prepared_list, power.entry)
+ dpm_clear_async_state(dev);
+
+ /*
* Start processing "async" leaf devices upfront so they don't need to
* wait for the "sync" devices they don't depend on.
*/
list_for_each_entry_reverse(dev, &dpm_prepared_list, power.entry) {
- dpm_clear_async_state(dev);
if (dpm_leaf_device(dev))
dpm_async_with_cleanup(dev, async_suspend);
}
Powered by blists - more mailing lists