* [PATCH v2] watchdog: sunxi_wdt: preserve boot-enabled watchdog
@ 2026-08-28 4:42 James Hilliard
2026-08-28 14:40 ` Guenter Roeck
0 siblings, 1 reply; 2+ messages in thread
From: James Hilliard @ 2026-08-28 4:42 UTC (permalink / raw)
To: Wim Van Sebroeck, Guenter Roeck, Chen-Yu Tsai, Jernej Skrabec,
Samuel Holland, Carlo Caione, Maxime Ripard
Cc: Wim Van Sebroeck, linux-watchdog, linux-arm-kernel, linux-sunxi,
linux-kernel, stable, James Hilliard
sunxi_wdt_probe() unconditionally stops the watchdog even when firmware
left it running. This opens an unprotected interval during boot and
prevents CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED from taking over the active
watchdog.
Detect an enabled watchdog and decode its programmed interval. Preserve
representable timeouts, and round the 0.5-second interval up to the
minimum representable one-second timeout. Use the configured timeout for
reserved interval encodings. Set the Linux reset mode and ping the
watchdog without clearing its enable bit, then mark it hardware-running
before registration so the watchdog core services it until userspace
takes control. Leave disabled watchdogs untouched.
Fixes: d00680ed0026 ("watchdog: sunxi: New watchdog driver for Allwinner A10/A13")
Cc: stable@vger.kernel.org
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
Changes v1 -> v2:
- Use one second for the boot-enabled 0.5-second interval instead of
falling back to the configured timeout. (suggested by Guenter Roeck)
- Leave an already-disabled watchdog untouched. (suggested by Guenter Roeck)
---
drivers/watchdog/sunxi_wdt.c | 45 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
index b6c761acc3de..3db34524ed13 100644
--- a/drivers/watchdog/sunxi_wdt.c
+++ b/drivers/watchdog/sunxi_wdt.c
@@ -128,6 +128,38 @@ static int sunxi_wdt_ping(struct watchdog_device *wdt_dev)
return 0;
}
+static bool sunxi_wdt_is_running(struct watchdog_device *wdt_dev)
+{
+ struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
+ const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs;
+
+ return readl(sunxi_wdt->wdt_base + regs->wdt_mode) & WDT_MODE_EN;
+}
+
+static unsigned int sunxi_wdt_get_timeout(struct watchdog_device *wdt_dev)
+{
+ struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
+ const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs;
+ unsigned int timeout;
+ u32 interval;
+
+ interval = readl(sunxi_wdt->wdt_base + regs->wdt_mode);
+ interval >>= regs->wdt_timeout_shift;
+ interval &= WDT_TIMEOUT_MASK;
+ /* Round the 0.5-second interval up to the minimum representable timeout. */
+ if (!interval)
+ return WDT_MIN_TIMEOUT;
+
+ for (timeout = WDT_MIN_TIMEOUT;
+ timeout < ARRAY_SIZE(wdt_timeout_map); timeout++) {
+ if (wdt_timeout_map[timeout] == interval)
+ return timeout;
+ }
+
+ /* Reserved interval encoding. */
+ return 0;
+}
+
static int sunxi_wdt_set_timeout(struct watchdog_device *wdt_dev,
unsigned int timeout)
{
@@ -259,6 +291,7 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sunxi_wdt_dev *sunxi_wdt;
+ unsigned int running_timeout;
int err;
sunxi_wdt = devm_kzalloc(dev, sizeof(*sunxi_wdt), GFP_KERNEL);
@@ -286,7 +319,17 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(&sunxi_wdt->wdt_dev, sunxi_wdt);
- sunxi_wdt_stop(&sunxi_wdt->wdt_dev);
+ if (sunxi_wdt_is_running(&sunxi_wdt->wdt_dev)) {
+ running_timeout = sunxi_wdt_get_timeout(&sunxi_wdt->wdt_dev);
+ if (running_timeout)
+ sunxi_wdt->wdt_dev.timeout = running_timeout;
+
+ err = sunxi_wdt_start(&sunxi_wdt->wdt_dev);
+ if (err)
+ return err;
+
+ set_bit(WDOG_HW_RUNNING, &sunxi_wdt->wdt_dev.status);
+ }
watchdog_stop_on_reboot(&sunxi_wdt->wdt_dev);
err = devm_watchdog_register_device(dev, &sunxi_wdt->wdt_dev);
---
base-commit: 1b78070aaef63512688aebfbc82365ef9d6660f1
change-id: 20260827-submit-sunxi-wdt-boot-enabled-v1-94cd6be885d2
Best regards,
--
James Hilliard <james.hilliard1@gmail.com>
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v2] watchdog: sunxi_wdt: preserve boot-enabled watchdog
2026-08-28 4:42 [PATCH v2] watchdog: sunxi_wdt: preserve boot-enabled watchdog James Hilliard
@ 2026-08-28 14:40 ` Guenter Roeck
0 siblings, 0 replies; 2+ messages in thread
From: Guenter Roeck @ 2026-08-28 14:40 UTC (permalink / raw)
To: James Hilliard
Cc: Wim Van Sebroeck, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
Carlo Caione, Maxime Ripard, Wim Van Sebroeck, linux-watchdog,
linux-arm-kernel, linux-sunxi, linux-kernel, stable
On Thu, Aug 27, 2026 at 10:42:31PM -0600, James Hilliard wrote:
> sunxi_wdt_probe() unconditionally stops the watchdog even when firmware
> left it running. This opens an unprotected interval during boot and
> prevents CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED from taking over the active
> watchdog.
>
> Detect an enabled watchdog and decode its programmed interval. Preserve
> representable timeouts, and round the 0.5-second interval up to the
> minimum representable one-second timeout. Use the configured timeout for
> reserved interval encodings. Set the Linux reset mode and ping the
> watchdog without clearing its enable bit, then mark it hardware-running
> before registration so the watchdog core services it until userspace
> takes control. Leave disabled watchdogs untouched.
>
> Fixes: d00680ed0026 ("watchdog: sunxi: New watchdog driver for Allwinner A10/A13")
> Cc: stable@vger.kernel.org
> Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Applied.
Thanks,
Guenter
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-28 14:41 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-28 4:42 [PATCH v2] watchdog: sunxi_wdt: preserve boot-enabled watchdog James Hilliard
2026-08-28 14:40 ` Guenter Roeck
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox