[PATCH v2 4/6] watchdog: starfive: guard system suspend/resume hardware access
From: William Theesfeld
Date: Fri Jun 05 2026 - 09:15:52 EST
starfive_wdt_suspend() reads from STARFIVE_WDT_VALUE and writes to
WDOGCONTROL via starfive_wdt_get_count() and starfive_wdt_stop()
before calling pm_runtime_force_suspend(). If the device was already
runtime-suspended when system suspend began, the apb and core clocks
are gated and those register accesses produce a synchronous external
abort.
starfive_wdt_resume() has the mirror problem: it unconditionally
restores the WDOGLOAD value after pm_runtime_force_resume() returns,
but pm_runtime_force_resume() leaves the device in whichever runtime
PM state it was in pre-suspend. If the device stays suspended, the
restore writes race with gated clocks.
Gate both halves with pm_runtime_status_suspended() so the hardware
is only touched when it is actually active. When the watchdog was
suspended at runtime PM level there is no state to save or restore.
Signed-off-by: William Theesfeld <william@xxxxxxxxxxxxx>
---
drivers/watchdog/starfive-wdt.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c
index 6539bf089..4926984bf 100644
--- a/drivers/watchdog/starfive-wdt.c
+++ b/drivers/watchdog/starfive-wdt.c
@@ -556,11 +556,16 @@ static int starfive_wdt_suspend(struct device *dev)
{
struct starfive_wdt *wdt = dev_get_drvdata(dev);
- /* Save watchdog state, and turn it off. */
- wdt->reload = starfive_wdt_get_count(wdt);
-
- /* Note that WTCNT doesn't need to be saved. */
- starfive_wdt_stop(wdt);
+ /*
+ * Only access the hardware while the device is runtime-resumed; if
+ * runtime PM has already suspended the device, its clocks are gated
+ * and a register read/write would trigger a synchronous external
+ * abort. WTCNT does not need to be saved.
+ */
+ if (!pm_runtime_status_suspended(dev)) {
+ wdt->reload = starfive_wdt_get_count(wdt);
+ starfive_wdt_stop(wdt);
+ }
return pm_runtime_force_suspend(dev);
}
@@ -574,8 +579,16 @@ static int starfive_wdt_resume(struct device *dev)
if (ret)
return ret;
+ /*
+ * pm_runtime_force_resume() leaves the device in whichever runtime
+ * PM state it was in before system suspend. Only restore hardware
+ * state when the device is actually resumed; otherwise the register
+ * writes below would race with gated clocks.
+ */
+ if (pm_runtime_status_suspended(dev))
+ return 0;
+
starfive_wdt_unlock(wdt);
- /* Restore watchdog state. */
starfive_wdt_set_reload_count(wdt, wdt->reload);
starfive_wdt_lock(wdt);
--
2.54.0