drivers/base/power/main.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-)
Extend the DPM watchdog to wrap device_suspend_late, device_suspend_noirq,
device_resume_early, and device_resume_noirq callbacks. If a driver hangs
during these transitions, the watchdog will fire and dump a stack trace
to help identify the offending driver.
To prevent false-positive timeouts, the watchdog is set only after
waiting for subordinate (during suspend) and superior (during resume)
devices.
Signed-off-by: Mayank Rungta <mrungta@google.com>
---
Testing:
- Tested on an ARM64 SoC (Pixel platform running a 6.18-based kernel with
DPM watchdog enabled; Android 6.18 kernel has latest DPM changes
backported).
drivers/base/power/main.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 184dc4b3b938..b6778700af28 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -802,6 +802,7 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy
const char *info = NULL;
bool skip_resume;
int error = 0;
+ DECLARE_DPM_WATCHDOG_ON_STACK(wd);
TRACE_DEVICE(dev);
TRACE_RESUME(0);
@@ -827,6 +828,7 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy
if (!dpm_wait_for_superior(dev, async))
goto Out;
+ dpm_watchdog_set(&wd, dev);
skip_resume = dev_pm_skip_resume(dev);
/*
* If the driver callback is skipped below or by the middle layer
@@ -871,6 +873,7 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy
error = dpm_run_callback(callback, dev, state, info);
Skip:
+ dpm_watchdog_clear(&wd);
dev->power.is_noirq_suspended = false;
Out:
@@ -971,6 +974,7 @@ static void device_resume_early(struct device *dev, pm_message_t state, bool asy
pm_callback_t callback = NULL;
const char *info = NULL;
int error = 0;
+ DECLARE_DPM_WATCHDOG_ON_STACK(wd);
TRACE_DEVICE(dev);
TRACE_RESUME(0);
@@ -987,6 +991,7 @@ static void device_resume_early(struct device *dev, pm_message_t state, bool asy
if (!dpm_wait_for_superior(dev, async))
goto Out;
+ dpm_watchdog_set(&wd, dev);
if (dev->pm_domain) {
info = "early power domain ";
callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -1004,7 +1009,7 @@ static void device_resume_early(struct device *dev, pm_message_t state, bool asy
goto Run;
if (dev_pm_skip_resume(dev))
- goto Skip;
+ goto End;
if (dev->driver && dev->driver->pm) {
info = "early driver ";
@@ -1014,6 +1019,9 @@ static void device_resume_early(struct device *dev, pm_message_t state, bool asy
Run:
error = dpm_run_callback(callback, dev, state, info);
+End:
+ dpm_watchdog_clear(&wd);
+
Skip:
dev->power.is_late_suspended = false;
pm_runtime_enable(dev);
@@ -1508,6 +1516,7 @@ static void device_suspend_noirq(struct device *dev, pm_message_t state, bool as
pm_callback_t callback = NULL;
const char *info = NULL;
int error = 0;
+ DECLARE_DPM_WATCHDOG_ON_STACK(wd);
TRACE_DEVICE(dev);
TRACE_SUSPEND(0);
@@ -1520,6 +1529,7 @@ static void device_suspend_noirq(struct device *dev, pm_message_t state, bool as
if (dev->power.syscore || dev->power.direct_complete)
goto Complete;
+ dpm_watchdog_set(&wd, dev);
if (dev->pm_domain) {
info = "noirq power domain ";
callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -1550,7 +1560,7 @@ static void device_suspend_noirq(struct device *dev, pm_message_t state, bool as
WRITE_ONCE(async_error, error);
dpm_save_failed_dev(dev_name(dev));
pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
- goto Complete;
+ goto End;
}
Skip:
@@ -1569,6 +1579,9 @@ static void device_suspend_noirq(struct device *dev, pm_message_t state, bool as
if (dev->power.must_resume)
dpm_superior_set_must_resume(dev);
+End:
+ dpm_watchdog_clear(&wd);
+
Complete:
complete_all(&dev->power.completion);
TRACE_SUSPEND(error);
@@ -1703,6 +1716,7 @@ static void device_suspend_late(struct device *dev, pm_message_t state, bool asy
pm_callback_t callback = NULL;
const char *info = NULL;
int error = 0;
+ DECLARE_DPM_WATCHDOG_ON_STACK(wd);
TRACE_DEVICE(dev);
TRACE_SUSPEND(0);
@@ -1720,6 +1734,8 @@ static void device_suspend_late(struct device *dev, pm_message_t state, bool asy
if (dev->power.direct_complete)
goto Complete;
+ dpm_watchdog_set(&wd, dev);
+
/*
* After this point, any runtime PM operations targeting the device
* will fail until the corresponding pm_runtime_enable() call in
@@ -1761,13 +1777,16 @@ static void device_suspend_late(struct device *dev, pm_message_t state, bool asy
dpm_save_failed_dev(dev_name(dev));
pm_dev_err(dev, state, async ? " async late" : " late", error);
pm_runtime_enable(dev);
- goto Complete;
+ goto End;
}
dpm_propagate_wakeup_to_parent(dev);
Skip:
dev->power.is_late_suspended = true;
+End:
+ dpm_watchdog_clear(&wd);
+
Complete:
TRACE_SUSPEND(error);
complete_all(&dev->power.completion);
base-commit: 77ae27fd98f3b548797c9f22c10ab5cf1c4ada53
--
2.55.0.766.g2966f0265a-goog
On Fri, Aug 21, 2026 at 10:06:48AM -0700, Mayank Rungta wrote: > Extend the DPM watchdog to wrap device_suspend_late, device_suspend_noirq, > device_resume_early, and device_resume_noirq callbacks. If a driver hangs > during these transitions, the watchdog will fire and dump a stack trace > to help identify the offending driver. > > To prevent false-positive timeouts, the watchdog is set only after > waiting for subordinate (during suspend) and superior (during resume) > devices. > > Signed-off-by: Mayank Rungta <mrungta@google.com> Reviewed-by: Tzung-Bi Shih <tzungbi@kernel.org>
Hi, On Fri, Aug 21, 2026 at 10:06 AM Mayank Rungta <mrungta@google.com> wrote: > > Extend the DPM watchdog to wrap device_suspend_late, device_suspend_noirq, > device_resume_early, and device_resume_noirq callbacks. If a driver hangs > during these transitions, the watchdog will fire and dump a stack trace > to help identify the offending driver. > > To prevent false-positive timeouts, the watchdog is set only after > waiting for subordinate (during suspend) and superior (during resume) > devices. > > Signed-off-by: Mayank Rungta <mrungta@google.com> > --- > Testing: > - Tested on an ARM64 SoC (Pixel platform running a 6.18-based kernel with > DPM watchdog enabled; Android 6.18 kernel has latest DPM changes > backported). > > drivers/base/power/main.c | 25 ++++++++++++++++++++++--- > 1 file changed, 22 insertions(+), 3 deletions(-) I reviewed this patch for Mayank before he sent it. It seems correct / useful to me, so I'm happy with: Reviewed-by: Douglas Anderson <dianders@chromium.org>
Hi, On Fri, Aug 21, 2026 at 3:37 PM Doug Anderson <dianders@chromium.org> wrote: > > Hi, > > On Fri, Aug 21, 2026 at 10:06 AM Mayank Rungta <mrungta@google.com> wrote: > > > > Extend the DPM watchdog to wrap device_suspend_late, device_suspend_noirq, > > device_resume_early, and device_resume_noirq callbacks. If a driver hangs > > during these transitions, the watchdog will fire and dump a stack trace > > to help identify the offending driver. > > > > To prevent false-positive timeouts, the watchdog is set only after > > waiting for subordinate (during suspend) and superior (during resume) > > devices. > > > > Signed-off-by: Mayank Rungta <mrungta@google.com> > > --- > > Testing: > > - Tested on an ARM64 SoC (Pixel platform running a 6.18-based kernel with > > DPM watchdog enabled; Android 6.18 kernel has latest DPM changes > > backported). > > > > drivers/base/power/main.c | 25 ++++++++++++++++++++++--- > > 1 file changed, 22 insertions(+), 3 deletions(-) > > I reviewed this patch for Mayank before he sent it. It seems correct / > useful to me, so I'm happy with: > > Reviewed-by: Douglas Anderson <dianders@chromium.org> Since I reviewed this patch, someone pointed out to me that we should probably also add the DPM watchdog to the "prepare" / "complete" stages too. I know those stages are used less-often, but it still seems like the DPM watchdog would be relevant there. Unless Rafael chimes in and says he disagrees or that he dislikes this patch in general, maybe you could post a v2 patch that adds that? Thanks! -Doug
On Wed, Sep 2, 2026 at 2:15 PM Doug Anderson <dianders@chromium.org> wrote: > > Hi, > > On Fri, Aug 21, 2026 at 3:37 PM Doug Anderson <dianders@chromium.org> wrote: > > > > Hi, > > > > On Fri, Aug 21, 2026 at 10:06 AM Mayank Rungta <mrungta@google.com> wrote: > > > > > > Extend the DPM watchdog to wrap device_suspend_late, device_suspend_noirq, > > > device_resume_early, and device_resume_noirq callbacks. If a driver hangs > > > during these transitions, the watchdog will fire and dump a stack trace > > > to help identify the offending driver. > > > > > > To prevent false-positive timeouts, the watchdog is set only after > > > waiting for subordinate (during suspend) and superior (during resume) > > > devices. > > > > > > Signed-off-by: Mayank Rungta <mrungta@google.com> > > > --- > > > Testing: > > > - Tested on an ARM64 SoC (Pixel platform running a 6.18-based kernel with > > > DPM watchdog enabled; Android 6.18 kernel has latest DPM changes > > > backported). > > > > > > drivers/base/power/main.c | 25 ++++++++++++++++++++++--- > > > 1 file changed, 22 insertions(+), 3 deletions(-) > > > > I reviewed this patch for Mayank before he sent it. It seems correct / > > useful to me, so I'm happy with: > > > > Reviewed-by: Douglas Anderson <dianders@chromium.org> > > Since I reviewed this patch, someone pointed out to me that we should > probably also add the DPM watchdog to the "prepare" / "complete" > stages too. I know those stages are used less-often, but it still > seems like the DPM watchdog would be relevant there. Unless Rafael > chimes in and says he disagrees or that he dislikes this patch in > general, maybe you could post a v2 patch that adds that? > > Thanks! > > -Doug Thanks Doug. I have posted v2 with prepare and complete support here: https://lore.kernel.org/r/20260909224818.2177311-1-mrungta@google.com
© 2016 - 2026 Red Hat, Inc.