The WOR register is 32 bits, so any tick count exceeding U32_MAX is truncated by writel(). A large requested timeout can wrap to a small value causing the watchdog to fire sooner than requested.
Clamp the calculated value to U32_MAX prior to writing the register so over-large requests will be set to the maximum timeout value. Found by code review. Signed-off-by: Juuso Rinta <[email protected]> --- drivers/watchdog/sbsa_gwdt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index 807884c5bc7..3a924cb2b9a 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -50,6 +50,7 @@ static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) { struct sbsa_gwdt_priv *priv = dev_get_priv(dev); u32 clk; + u64 tout_wdog; /* * it work in the single stage mode in u-boot, @@ -58,8 +59,13 @@ static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) * to half value of timeout. */ clk = get_tbclk(); - writel(clk / (2 * 1000) * timeout, - priv->reg_control + SBSA_GWDT_WOR); + + /* if requested timeout overflows, clamp it to u32_max */ + tout_wdog = ((u64)clk * timeout) / (2 * 1000); + if (tout_wdog > U32_MAX) + tout_wdog = U32_MAX; + + writel(tout_wdog, priv->reg_control + SBSA_GWDT_WOR); /* writing WCS will cause an explicit watchdog refresh */ writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS); --- base-commit: 4433253ecf2041f9362a763bb6cb79960921ac7e change-id: 20260428-fix-sbsa-timeout-overflow-20cf84fa8a6b Best regards, -- Juuso Rinta <[email protected]> -- Juuso Rinta <[email protected]>

