[PATCH v5 1/8] watchdog: rzv2h: Drop enabling clocks in the restart handler

From: Prabhakar

Date: Fri Sep 11 2026 - 07:24:56 EST


From: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx>

The watchdog restart handler runs from do_kernel_restart() with
interrupts disabled and after smp_send_stop() has halted the other CPUs.
Calling clk_enable() from the !watchdog_active() path takes the clock
framework's global enable_lock. If a stopped CPU held this lock, the
CPU executing the restart handler can spin indefinitely and prevent the
watchdog from resetting the system.

Keep pclk and oscclk enabled for the lifetime of the watchdog device by
using devm_clk_get_enabled() and devm_clk_get_optional_enabled().
Remove the conditional clock enable/disable operations from the restart
handler so it does not acquire any clock framework locks.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx>
---
v4->v5:
- New patch
---
drivers/watchdog/rzv2h_wdt.c | 19 +++----------------
1 file changed, 3 insertions(+), 16 deletions(-)

diff --git a/drivers/watchdog/rzv2h_wdt.c b/drivers/watchdog/rzv2h_wdt.c
index 3b6abb66a1da..bd86da71b0eb 100644
--- a/drivers/watchdog/rzv2h_wdt.c
+++ b/drivers/watchdog/rzv2h_wdt.c
@@ -191,22 +191,9 @@ static int rzv2h_wdt_restart(struct watchdog_device *wdev,
int ret;

if (!watchdog_active(wdev)) {
- ret = clk_enable(priv->pclk);
- if (ret)
- return ret;
-
- ret = clk_enable(priv->oscclk);
- if (ret) {
- clk_disable(priv->pclk);
- return ret;
- }
-
ret = reset_control_deassert(priv->rstc);
- if (ret) {
- clk_disable(priv->oscclk);
- clk_disable(priv->pclk);
+ if (ret)
return ret;
- }
} else {
/*
* Writing to the WDT Control Register (WDTCR) or WDT Reset
@@ -290,11 +277,11 @@ static int rzv2h_wdt_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);

- priv->pclk = devm_clk_get_prepared(dev, "pclk");
+ priv->pclk = devm_clk_get_enabled(dev, "pclk");
if (IS_ERR(priv->pclk))
return dev_err_probe(dev, PTR_ERR(priv->pclk), "Failed to get pclk\n");

- priv->oscclk = devm_clk_get_optional_prepared(dev, "oscclk");
+ priv->oscclk = devm_clk_get_optional_enabled(dev, "oscclk");
if (IS_ERR(priv->oscclk))
return dev_err_probe(dev, PTR_ERR(priv->oscclk), "Failed to get oscclk\n");

--
2.55.0