mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
watchdog: msc313e: Enable clock before accessing hardware registers
msc313e_wdt_probe() reads from hardware registers without ensuring the
required clock is enabled. Furthermore, if the bootloader leaves the
watchdog running, msc313e_wdt_probe() sets WDOG_HW_RUNNING without
increasing the clock's reference count.
While the clock is currently supplied as a fixed clock by the device
tree (`xtal_div2` in arch/arm/boot/dts/sigmastar/mstar-v7.dtsi) which
masks the physical issue, this still violates the API usage.
Call clk_prepare_enable() before reading WDT registers. If the WDT is
running, leave the clock enabled so the CCF reference counter is
balanced.
Fixes: ffd264bd15 ("watchdog: msc313e: Check if the WDT was running at boot")
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
Link: https://patch.msgid.link/20260828161348.13212-5-tzungbi@kernel.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
parent
3db30f3159
commit
3db2df24e7
|
|
@ -108,6 +108,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct msc313e_wdt_priv *priv;
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
|
|
@ -133,9 +134,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
|
|||
priv->wdev.max_timeout = U32_MAX / rate;
|
||||
priv->wdev.timeout = MSC313E_WDT_DEFAULT_TIMEOUT;
|
||||
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* If the period is non-zero the WDT is running */
|
||||
if (readw(priv->base + REG_WDT_MAX_PRD_L) | (readw(priv->base + REG_WDT_MAX_PRD_H) << 16))
|
||||
if (readw(priv->base + REG_WDT_MAX_PRD_L) | (readw(priv->base + REG_WDT_MAX_PRD_H) << 16)) {
|
||||
set_bit(WDOG_HW_RUNNING, &priv->wdev.status);
|
||||
/*
|
||||
* Keep the clock enabled. The watchdog core will skip the next
|
||||
* start() and a future stop() will balance the CCF reference
|
||||
* count.
|
||||
*/
|
||||
} else {
|
||||
clk_disable_unprepare(priv->clk);
|
||||
}
|
||||
|
||||
watchdog_set_drvdata(&priv->wdev, priv);
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
|
@ -144,7 +157,13 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
|
|||
watchdog_stop_on_reboot(&priv->wdev);
|
||||
watchdog_stop_on_unregister(&priv->wdev);
|
||||
|
||||
return devm_watchdog_register_device(dev, &priv->wdev);
|
||||
ret = devm_watchdog_register_device(dev, &priv->wdev);
|
||||
|
||||
/* If the WDT is running and anything goes wrong, disable the clock. */
|
||||
if (ret && test_bit(WDOG_HW_RUNNING, &priv->wdev.status))
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused msc313e_wdt_suspend(struct device *dev)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user