Linux Watchdog driver development
 help / color / mirror / Atom feed
* [PATCH] watchdog: npcm: fix clock prepare leak when setting timeout on a running watchdog
@ 2026-11-09  7:10 Zhao Feng
  2026-11-09  7:18 ` sashiko-bot
  2026-11-09 23:09 ` Guenter Roeck
  0 siblings, 2 replies; 3+ messages in thread
From: Zhao Feng @ 2026-11-09  7:10 UTC (permalink / raw)
  To: Wim Van Sebroeck, Guenter Roeck, linux-watchdog
  Cc: linux-kernel, Zhao Feng, stable

npcm_wdt_start() unconditionally prepares and enables the watchdog
clock, and npcm_wdt_stop() is the only place that disables it.
npcm_wdt_set_timeout() calls npcm_wdt_start() again whenever the
watchdog is already active, so every WDIOC_SETTIMEOUT ioctl issued
while the watchdog is running takes one extra clock prepare/enable
reference that is never dropped.

Split the register programming out of npcm_wdt_start() into a
__npcm_wdt_start() helper that assumes the clock is already running,
and call the helper from npcm_wdt_set_timeout() instead; only the
watchdog .start callback (and the restart path, which intentionally
keeps the clock) now acquires the clock.

Fixes: af084fdccfaf ("watchdog: npcm: Enable clock if provided")
Cc: stable@vger.kernel.org
Signed-off-by: Zhao Feng <zhaofeng2@cmss.chinamobile.com>
---
Verified against current upstream master.  Not runtime-tested (no
Nuvoton NPCM hardware).

Note: this overlaps textually with Triet Hoang's pending
error-propagation patch
(https://marc.info/?l=linux-kernel&m=178955112320092)
but fixes a different bug; whichever lands second will need a
trivial rebase.

 drivers/watchdog/npcm_wdt.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c
--- a/drivers/watchdog/npcm_wdt.c
+++ b/drivers/watchdog/npcm_wdt.c
@@ -148,10 +148,8 @@
-static int npcm_wdt_start(struct watchdog_device *wdd)
+static void __npcm_wdt_start(struct watchdog_device *wdd)
 {
 	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
 	u32 val;
 
-	clk_prepare_enable(wdt->clk);
-
 	if (wdd->timeout < 2)
 		val = 0x800;
 	else if (wdd->timeout < 3)
@@ -176,10 +174,19 @@
 	val |= NPCM_WTRE | NPCM_WTE | NPCM_WTR | NPCM_WTIE;
 
 	writel(val, wdt->reg);
-
-	return 0;
 }
 
+static int npcm_wdt_start(struct watchdog_device *wdd)
+{
+	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
+
+	clk_prepare_enable(wdt->clk);
+
+	__npcm_wdt_start(wdd);
+
+	return 0;
+}
+
 static int npcm_wdt_stop(struct watchdog_device *wdd)
 {
 	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
@@ -216,7 +223,7 @@
 		wdd->timeout = 2750;
 
 	if (watchdog_active(wdd))
-		npcm_wdt_start(wdd);
+		__npcm_wdt_start(wdd);
 
 	return 0;
 }
-- 
2.39.2




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] watchdog: npcm: fix clock prepare leak when setting timeout on a running watchdog
  2026-11-09  7:10 [PATCH] watchdog: npcm: fix clock prepare leak when setting timeout on a running watchdog Zhao Feng
@ 2026-11-09  7:18 ` sashiko-bot
  2026-11-09 23:09 ` Guenter Roeck
  1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-11-09  7:18 UTC (permalink / raw)
  To: Zhao Feng, linux-watchdog

Thank you for your contribution! Sashiko AI review found no new issues
in this patch, but noticed 1 related pre-existing issue it does not
introduce:
- [High] watchdog: npcm: sleep in atomic context in npcm_wdt_restart()
  [1]
--

commit 17842ca84b08ec6bbd438017f39f767a1910936b
Author: Zhao Feng <zhaofeng2@cmss.chinamobile.com>

watchdog: npcm: fix clock prepare leak when setting timeout on a running watchdog

This commit splits register programming out of npcm_wdt_start() into
__npcm_wdt_start() so that npcm_wdt_set_timeout() does not acquire an
extra clock reference when updating the timeout on an active watchdog.

> diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c
> index 51348969bf492..31253fd7bad5b 100644
> --- a/drivers/watchdog/npcm_wdt.c
> +++ b/drivers/watchdog/npcm_wdt.c
> @@ -145,13 +145,11 @@ static int npcm_wdt_ping(struct watchdog_device *wdd)
>  	return 0;
>  }
>  
> -static int npcm_wdt_start(struct watchdog_device *wdd)
> +static void __npcm_wdt_start(struct watchdog_device *wdd)
>  {
>  	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
>  	u32 val;
>  
> -	clk_prepare_enable(wdt->clk);
> -
>  	if (wdd->timeout < 2)
>  		val = 0x800;
>  	else if (wdd->timeout < 3)
> @@ -176,6 +174,15 @@ static int npcm_wdt_start(struct watchdog_device *wdd)
>  	val |= NPCM_WTRE | NPCM_WTE | NPCM_WTR | NPCM_WTIE;
>  
>  	writel(val, wdt->reg);
> +}
> +
> +static int npcm_wdt_start(struct watchdog_device *wdd)
> +{
> +	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
> +
> +	clk_prepare_enable(wdt->clk);
> +
> +	__npcm_wdt_start(wdd);
>  
>  	return 0;
>  }

[Severity: High]
This problem wasn't introduced by this patch, but can npcm_wdt_restart()
sleep in atomic context when calling clk_prepare_enable(wdt->clk)
[1]?

drivers/watchdog/npcm_wdt.c:npcm_wdt_restart() {
	struct npcm_wdt *wdt = to_npcm_wdt(wdd);

	/* For reset, we start the WDT clock and leave it running. */
	clk_prepare_enable(wdt->clk);
    ...
}

do_kernel_restart() invokes restart handlers via
atomic_notifier_call_chain() under an RCU read lock, whereas
clk_prepare_enable() calls clk_prepare() and takes the sleeping
prepare_lock mutex.  This triggers a scheduling-while-atomic bug and can
deadlock during reboot or panic recovery.

[1] https://sashiko.dev/#/bug/linux-d877d7dc-83e2-4c44-b88a-c3f7ea954cd4

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261109071004.1506-1-zhaofeng2@cmss.chinamobile.com?part=1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] watchdog: npcm: fix clock prepare leak when setting timeout on a running watchdog
  2026-11-09  7:10 [PATCH] watchdog: npcm: fix clock prepare leak when setting timeout on a running watchdog Zhao Feng
  2026-11-09  7:18 ` sashiko-bot
@ 2026-11-09 23:09 ` Guenter Roeck
  1 sibling, 0 replies; 3+ messages in thread
From: Guenter Roeck @ 2026-11-09 23:09 UTC (permalink / raw)
  To: Zhao Feng; +Cc: Wim Van Sebroeck, linux-watchdog, linux-kernel, stable

On Mon, Nov 09, 2026 at 03:10:03PM +0800, Zhao Feng wrote:
> npcm_wdt_start() unconditionally prepares and enables the watchdog
> clock, and npcm_wdt_stop() is the only place that disables it.
> npcm_wdt_set_timeout() calls npcm_wdt_start() again whenever the
> watchdog is already active, so every WDIOC_SETTIMEOUT ioctl issued
> while the watchdog is running takes one extra clock prepare/enable
> reference that is never dropped.
> 
> Split the register programming out of npcm_wdt_start() into a
> __npcm_wdt_start() helper that assumes the clock is already running,
> and call the helper from npcm_wdt_set_timeout() instead; only the
> watchdog .start callback (and the restart path, which intentionally
> keeps the clock) now acquires the clock.
> 
> Fixes: af084fdccfaf ("watchdog: npcm: Enable clock if provided")
> Cc: stable@vger.kernel.org
> Signed-off-by: Zhao Feng <zhaofeng2@cmss.chinamobile.com>

Applied.

Couple of notes:

The problem reported by Sashiko seems real, but I have any idea how to fix
it, and it is unrelated to this patch.

The error propagation patch has a number of issues (as reported by Sashiko)
and will have to be resubmitted anyway. When thet is done it will have
to be rebased to this patch.

Thanks,
Guenter

> ---
> Verified against current upstream master.  Not runtime-tested (no
> Nuvoton NPCM hardware).
> 
> Note: this overlaps textually with Triet Hoang's pending
> error-propagation patch
> (https://marc.info/?l=linux-kernel&m=178955112320092)
> but fixes a different bug; whichever lands second will need a
> trivial rebase.
> 
>  drivers/watchdog/npcm_wdt.c | 17 +++++++++++++----
>  1 file changed, 13 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c
> --- a/drivers/watchdog/npcm_wdt.c
> +++ b/drivers/watchdog/npcm_wdt.c
> @@ -148,10 +148,8 @@
> -static int npcm_wdt_start(struct watchdog_device *wdd)
> +static void __npcm_wdt_start(struct watchdog_device *wdd)
>  {
>  	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
>  	u32 val;
>  
> -	clk_prepare_enable(wdt->clk);
> -
>  	if (wdd->timeout < 2)
>  		val = 0x800;
>  	else if (wdd->timeout < 3)
> @@ -176,10 +174,19 @@
>  	val |= NPCM_WTRE | NPCM_WTE | NPCM_WTR | NPCM_WTIE;
>  
>  	writel(val, wdt->reg);
> -
> -	return 0;
>  }
>  
> +static int npcm_wdt_start(struct watchdog_device *wdd)
> +{
> +	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
> +
> +	clk_prepare_enable(wdt->clk);
> +
> +	__npcm_wdt_start(wdd);
> +
> +	return 0;
> +}
> +
>  static int npcm_wdt_stop(struct watchdog_device *wdd)
>  {
>  	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
> @@ -216,7 +223,7 @@
>  		wdd->timeout = 2750;
>  
>  	if (watchdog_active(wdd))
> -		npcm_wdt_start(wdd);
> +		__npcm_wdt_start(wdd);
>  
>  	return 0;
>  }

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-11-09 23:10 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-09  7:10 [PATCH] watchdog: npcm: fix clock prepare leak when setting timeout on a running watchdog Zhao Feng
2026-11-09  7:18 ` sashiko-bot
2026-11-09 23:09 ` Guenter Roeck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox