drivers/watchdog/mtk_wdt.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-)
When the bootloader leaves the watchdog enabled, probe only marks it
running and sets the timeout, so WDT_MODE keeps whatever the bootloader
wrote. The Amazon Fire HD 10 (2017) bootloader leaves dual mode with the
bark IRQ enabled, and no pretimeout is configured, so each timeout only
raises the IRQ and restarts the count: with the 20 s timeout systemd
sets, a hung system was reset after 37.95-39.76 s, and after 18.25-20.92 s
once IRQ_EN was cleared by hand.
Program the mode as mtk_wdt_start() does, which also applies
mediatek,disable-extrst and mediatek,reset-by-toprgu to a running
watchdog; read those two properties first.
Fixes: bbece05c0d3a ("watchdog: mtk_wdt: Remove mtk_wdt_stop() in probe() to prevent the system freeze and it doesn't reboot by watchdog problem")
Assisted-by: LLM
Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
Found on an Amazon Fire HD 10 (2017), an MT8173 board that is not upstream
yet. Its watchdog node has no interrupt, so no pretimeout is set up. The
timings in the commit message were taken from the host side of the USB
link; with this patch a hung reboot resets after 18.35-18.45 s (n=3).
It is based on v7.3-rc4 but it also applies cleanly to watchdog-next,
where "watchdog: mediatek: acknowledge pretimeout interrupt" moves
spin_lock_init() ahead of mtk_wdt_init(), so calling mtk_wdt_start() from
there is safe on both.
---
drivers/watchdog/mtk_wdt.c | 43 ++++++++++++++++++++++++-------------------
1 file changed, 24 insertions(+), 19 deletions(-)
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index d9c30e4c80e3..b12ea113b63e 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -285,19 +285,6 @@ static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,
return 0;
}
-static void mtk_wdt_init(struct watchdog_device *wdt_dev)
-{
- struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
- void __iomem *wdt_base;
-
- wdt_base = mtk_wdt->wdt_base;
-
- if (readl(wdt_base + WDT_MODE) & WDT_MODE_EN) {
- set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
- mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
- }
-}
-
static int mtk_wdt_stop(struct watchdog_device *wdt_dev)
{
struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
@@ -338,6 +325,24 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
return 0;
}
+static void mtk_wdt_init(struct watchdog_device *wdt_dev)
+{
+ struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
+ void __iomem *wdt_base;
+
+ wdt_base = mtk_wdt->wdt_base;
+
+ /*
+ * The bootloader may have left it in dual mode, where a timeout only
+ * raises the bark IRQ and the reset comes one timeout later. Apply
+ * this driver's mode instead, as mtk_wdt_start() does.
+ */
+ if (readl(wdt_base + WDT_MODE) & WDT_MODE_EN) {
+ set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
+ mtk_wdt_start(wdt_dev);
+ }
+}
+
static int mtk_wdt_set_pretimeout(struct watchdog_device *wdd,
unsigned int timeout)
{
@@ -440,6 +445,12 @@ static int mtk_wdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt);
+ mtk_wdt->disable_wdt_extrst =
+ of_property_read_bool(dev->of_node, "mediatek,disable-extrst");
+
+ mtk_wdt->reset_by_toprgu =
+ of_property_read_bool(dev->of_node, "mediatek,reset-by-toprgu");
+
mtk_wdt_init(&mtk_wdt->wdt_dev);
watchdog_stop_on_reboot(&mtk_wdt->wdt_dev);
@@ -460,12 +471,6 @@ static int mtk_wdt_probe(struct platform_device *pdev)
mtk_wdt->has_swsysrst_en = wdt_data->has_swsysrst_en;
}
- mtk_wdt->disable_wdt_extrst =
- of_property_read_bool(dev->of_node, "mediatek,disable-extrst");
-
- mtk_wdt->reset_by_toprgu =
- of_property_read_bool(dev->of_node, "mediatek,reset-by-toprgu");
-
return 0;
}
---
base-commit: 93f51579e7df248780214094418f205253383cc5
change-id: 20260923-rbrue-suez-upstreaming-mtk-wdt-dual-mode-6758e7b879f9
Best regards,
--
Ryan Brue <ryanbrue.dev@gmail.com>
© 2016 - 2026 Red Hat, Inc.