[PATCH 1/2] PM: sleep: publish pm_transition with release semantics

From: Jaidev Shastri via B4 Relay

Date: Mon Sep 21 2026 - 21:28:19 EST


From: Jaidev Shastri <jaidevshastri@xxxxxx>

Each dpm_*() phase function stores the current transition to
pm_transition with a plain store before it schedules the asynchronous
device callbacks. dev_pm_skip_resume() and pm_hibernate_is_recovering()
read pm_transition.event from those callbacks, on other CPUs, with plain
loads.

Store the event with smp_store_release() and read it with
smp_load_acquire().

Found with MBCheck, a static herd7-based memory consistency checker.

Signed-off-by: Jaidev Shastri <jaidevshastri@xxxxxx>
---
drivers/base/power/main.c | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index e130da428..bf4b4fd1b 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -78,7 +78,8 @@ static int async_error;
*/
bool pm_hibernate_is_recovering(void)
{
- return pm_transition.event == PM_EVENT_RECOVER;
+ /* Pairs with the smp_store_release() in the dpm_*() phase functions. */
+ return smp_load_acquire(&pm_transition.event) == PM_EVENT_RECOVER;
}
EXPORT_SYMBOL_GPL(pm_hibernate_is_recovering);

@@ -682,10 +683,13 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
*/
bool dev_pm_skip_resume(struct device *dev)
{
- if (pm_transition.event == PM_EVENT_RESTORE)
+ /* Pairs with the smp_store_release() in the dpm_*() phase functions. */
+ int event = smp_load_acquire(&pm_transition.event);
+
+ if (event == PM_EVENT_RESTORE)
return false;

- if (pm_transition.event == PM_EVENT_THAW)
+ if (event == PM_EVENT_THAW)
return dev_pm_skip_suspend(dev);

return !dev->power.must_resume;
@@ -902,7 +906,8 @@ static void dpm_noirq_resume_devices(pm_message_t state)
trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, true);

async_error = 0;
- pm_transition = state;
+ /* Pairs with the smp_load_acquire() in dev_pm_skip_resume(). */
+ smp_store_release(&pm_transition.event, state.event);

mutex_lock(&dpm_list_mtx);

@@ -1052,7 +1057,8 @@ void dpm_resume_early(pm_message_t state)
trace_suspend_resume(TPS("dpm_resume_early"), state.event, true);

async_error = 0;
- pm_transition = state;
+ /* Pairs with the smp_load_acquire() in dev_pm_skip_resume(). */
+ smp_store_release(&pm_transition.event, state.event);

mutex_lock(&dpm_list_mtx);

@@ -1230,7 +1236,8 @@ void dpm_resume(pm_message_t state)

trace_suspend_resume(TPS("dpm_resume"), state.event, true);

- pm_transition = state;
+ /* Pairs with the smp_load_acquire() in dev_pm_skip_resume(). */
+ smp_store_release(&pm_transition.event, state.event);
async_error = 0;

mutex_lock(&dpm_list_mtx);
@@ -1595,7 +1602,8 @@ static int dpm_noirq_suspend_devices(pm_message_t state)

trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);

- pm_transition = state;
+ /* Pairs with the smp_load_acquire() in dev_pm_skip_resume(). */
+ smp_store_release(&pm_transition.event, state.event);
async_error = 0;

mutex_lock(&dpm_list_mtx);
@@ -1798,7 +1806,8 @@ int dpm_suspend_late(pm_message_t state)

trace_suspend_resume(TPS("dpm_suspend_late"), state.event, true);

- pm_transition = state;
+ /* Pairs with the smp_load_acquire() in dev_pm_skip_resume(). */
+ smp_store_release(&pm_transition.event, state.event);
async_error = 0;

wake_up_all_idle_cpus();
@@ -2091,7 +2100,8 @@ int dpm_suspend(pm_message_t state)
devfreq_suspend();
cpufreq_suspend();

- pm_transition = state;
+ /* Pairs with the smp_load_acquire() in dev_pm_skip_resume(). */
+ smp_store_release(&pm_transition.event, state.event);
async_error = 0;

mutex_lock(&dpm_list_mtx);

--
2.43.0