Messages in this thread |  | | From | "Rafael J. Wysocki" <> | | Date | Tue, 26 May 2026 13:03:26 +0200 | | Subject | Re: [PATCH v3] PM: sleep: Use complete() in device_pm_sleep_init() and skip no_pm devices in dpm_wait() |
| |
On Sat, May 23, 2026 at 4:23 AM Jiakai Xu <xujiakai24@mails.ucas.ac.cn> wrote: > > Replace complete_all() with complete() in device_pm_sleep_init() to allow > it to be called in atomic contexts without triggering a false-positive > WARNING from lockdep_assert_RT_in_threaded_ctx() when > CONFIG_PROVE_RAW_LOCK_NESTING is enabled. > > device_pm_sleep_init() may be called during device initialization while > holding a raw_spinlock (e.g., from within device_initialize()), and > complete_all() is unsafe in atomic contexts on PREEMPT_RT kernels. > complete(), which is safe to call from any context, is sufficient here. > > complete_all() sets the completion count to UINT_MAX/2 (permanently > signaled), while complete() increments it by 1. Since no threads can be > waiting during device initialization, both are functionally equivalent. > The completion is always reinitialized via reinit_completion() in > dpm_clear_async_state() before each suspend/resume cycle. > > However, changing to complete() introduces a potential deadlock for > devices with no PM support (dev->power.no_pm = true). Such devices are > never added to the dpm_list and never go through dpm_clear_async_state(), > so their completion is never reinitialized. A parent device waiting on a > no_pm child across multiple suspend phases would consume the single-use > token in the first phase and block forever in the second. > > Fix this by adding an early return in dpm_wait() when dev->power.no_pm is > set, since no_pm devices do not participate in system suspend/resume. > > Fixes: 152e1d592071 ("PM: Prevent waiting forever on asynchronous resume after failing suspend") > Signed-off-by: Jiakai Xu <xujiakai24@mails.ucas.ac.cn> > --- > V1 -> V2: > - Updated dpm_wait() to skip devices with no PM support, > as suggested by Rafael J. Wysocki. > > V2 -> V3: > - Revised commit message to clarify that the lockdep warning originates > from device_pm_sleep_init() called in atomic context, not from > device_pm_remove(). No code changes relative to v2. > --- > drivers/base/power/main.c | 6 +++++- > 1 file changed, 5 insertions(+), 1 deletion(-) > > diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c > index e1b550664bab..ed48c292f575 100644 > --- a/drivers/base/power/main.c > +++ b/drivers/base/power/main.c > @@ -115,7 +115,7 @@ void device_pm_sleep_init(struct device *dev) > dev->power.is_noirq_suspended = false; > dev->power.is_late_suspended = false; > init_completion(&dev->power.completion); > - complete_all(&dev->power.completion); > + complete(&dev->power.completion); > dev->power.wakeup = NULL; > INIT_LIST_HEAD(&dev->power.entry); > } > @@ -252,6 +252,10 @@ static void dpm_wait(struct device *dev, bool async) > if (!dev) > return; > > + /* Devices with no PM support don't use the completion. */ > + if (dev->power.no_pm) > + return; > + > if (async || (pm_async_enabled && dev->power.async_suspend)) > wait_for_completion(&dev->power.completion); > } > --
Applied as 7.2 material, thanks!
|  |