watchdog fixes for v7.3-rc4

* da9062, da9063: Fix suspend/resume handling of HW_RUNNING watchdog
 
 * digicolor, rtd119x, and rzv2h: Avoid division by zero if clock rate is 0
 
 * msc313e: Fix premature reset during timeout update, and propagate error
   code in resume()
 
 * sp5100_tco: Fix pci_dev reference leak in sp5100_tco_init()
 
 * starfive-wdt: Fix runtime PM leak in starfive_wdt_pm_start()
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmqtZJEACgkQyx8mb86f
 mYGnwA/8C90wOrDbHonYx0SahuJaYniOmz6yHCuAR1AwtzKfXDua3WJ7ry4WfZXN
 WCACTcFCUp1CiLvstwpX7nDKGReYG47FOq6Rbou+JaJo43m9SGga5IGxKM28MBy7
 F4TH3CDMSOcomlgPYeXc5jx0oRkNXyDPMDHtbCOM5h+WwJb0Zxtfh+77l5q2LrQg
 D7nIGCkoztl7PDIgbvYESp9DYVdUgT6paeIRjJbs5BCwmNleU9LInDPDAtcXHnRp
 cyCa8FlfPrQMxhtbF1YQyaEdU04GlAwtHW4HE55tcxY3pTE/9qqA5SUzQBDXT2gO
 yCCG1qIFOmJY6QnlSfIYpHZtNxcpA75d8fQvqm14H+ACxkbaRF1d+sobtJTTckTD
 WBSr6RlrB5f/DAltqbV2OAsLddhBl4rQkW2RiljTW4C4pUiedPoSR8StTpnM6lC3
 VBpUdYp7tCIWihX/v/v+iRK1Y7JWVM+lhQnMpqBtpLtl3k7VLCLoFsmSbz0hHhu6
 kAJ1ZWeBy2xYgiGOM+D361iKhefjsZk9tdrC8IxriJ/gUwlcazELqqcsvU+I5ebN
 sutAYvE6Vdl5qwiLIRRHNpHvKm0wu9URIpPJrdwDtAIbaT3joSZIkV3TA7ZFBwGG
 tU4Z9ok0O4N4DDPv0CAg82lXBrMiWt3agYKKkhKTsmKROqqWVa8=
 =oqFf
 -----END PGP SIGNATURE-----

Merge tag 'watchdog-fixes-for-v7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull watchdog fixes from Guenter Roeck:

 - Fix suspend/resume handling of HW_RUNNING watchdog (da9062, da9063)

 - Avoid division by zero if clock rate is 0 (digicolor, rtd119x, and
   rzv2h)

 - Fix premature reset during timeout update, and propagate error code
   in msc313e resume()

 - Fix pci_dev reference leak in sp5100_tco_init()

 - Fix runtime PM leak in starfive_wdt_pm_start()

* tag 'watchdog-fixes-for-v7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  watchdog: da9063: fix suspend/resume handling of HW_RUNNING watchdog
  watchdog: starfive-wdt: Fix runtime PM leak in starfive_wdt_pm_start()
  watchdog: da9062: fix suspend/resume handling of HW_RUNNING watchdog
  watchdog: msc313e: Fix premature reset during timeout update
  watchdog: msc313e: Propagate error code in resume()
  watchdog: rzv2h: Avoid division by zero
  watchdog: rtd119x: Avoid division by zero
  watchdog: digicolor: Avoid division by zero
  watchdog: sp5100_tco: Fix pci_dev reference leak in sp5100_tco_init()
This commit is contained in:
Linus Torvalds 2026-09-18 10:18:32 -07:00
commit 928ba50514
8 changed files with 44 additions and 15 deletions

View File

@ -256,7 +256,7 @@ static int __maybe_unused da9062_wdt_suspend(struct device *dev)
if (!wdt->use_sw_pm)
return 0;
if (watchdog_active(wdd))
if (watchdog_active(wdd) || watchdog_hw_running(wdd))
return da9062_wdt_stop(wdd);
return 0;
@ -270,7 +270,7 @@ static int __maybe_unused da9062_wdt_resume(struct device *dev)
if (!wdt->use_sw_pm)
return 0;
if (watchdog_active(wdd))
if (watchdog_active(wdd) || watchdog_hw_running(wdd))
return da9062_wdt_start(wdd);
return 0;

View File

@ -271,7 +271,7 @@ static int da9063_wdt_suspend(struct device *dev)
if (!da9063->use_sw_pm)
return 0;
if (watchdog_active(wdd))
if (watchdog_active(wdd) || watchdog_hw_running(wdd))
return da9063_wdt_stop(wdd);
return 0;
@ -285,7 +285,7 @@ static int da9063_wdt_resume(struct device *dev)
if (!da9063->use_sw_pm)
return 0;
if (watchdog_active(wdd))
if (watchdog_active(wdd) || watchdog_hw_running(wdd))
return da9063_wdt_start(wdd);
return 0;

View File

@ -25,6 +25,7 @@ struct dc_wdt {
void __iomem *base;
struct clk *clk;
spinlock_t lock;
unsigned long rate;
};
static unsigned timeout;
@ -61,7 +62,7 @@ static int dc_wdt_start(struct watchdog_device *wdog)
{
struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
dc_wdt_set(wdt, wdog->timeout * clk_get_rate(wdt->clk));
dc_wdt_set(wdt, wdog->timeout * wdt->rate);
return 0;
}
@ -79,7 +80,7 @@ static int dc_wdt_set_timeout(struct watchdog_device *wdog, unsigned int t)
{
struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
dc_wdt_set(wdt, t * clk_get_rate(wdt->clk));
dc_wdt_set(wdt, t * wdt->rate);
wdog->timeout = t;
return 0;
@ -90,7 +91,7 @@ static unsigned int dc_wdt_get_timeleft(struct watchdog_device *wdog)
struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
uint32_t count = readl_relaxed(wdt->base + TIMER_A_COUNT);
return count / clk_get_rate(wdt->clk);
return count / wdt->rate;
}
static const struct watchdog_ops dc_wdt_ops = {
@ -130,7 +131,11 @@ static int dc_wdt_probe(struct platform_device *pdev)
wdt->clk = devm_clk_get(dev, NULL);
if (IS_ERR(wdt->clk))
return PTR_ERR(wdt->clk);
dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk);
wdt->rate = clk_get_rate(wdt->clk);
if (!wdt->rate)
return -EINVAL;
dc_wdt_wdd.max_timeout = U32_MAX / wdt->rate;
dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout;
dc_wdt_wdd.parent = dev;

View File

@ -46,6 +46,9 @@ static void msc313e_wdt_set_hw_timeout(struct msc313e_wdt_priv *priv,
{
u32 t = timeout * clk_get_rate(priv->clk);
/* Clear before to prevent premature reset during non-atomic updates. */
writew(1, priv->base + REG_WDT_CLR);
writew(t & 0xffff, priv->base + REG_WDT_MAX_PRD_L);
writew((t >> 16) & 0xffff, priv->base + REG_WDT_MAX_PRD_H);
writew(1, priv->base + REG_WDT_CLR);
@ -76,6 +79,9 @@ static int msc313e_wdt_stop(struct watchdog_device *wdev)
{
struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
/* Clear before to prevent premature reset during non-atomic updates. */
writew(1, priv->base + REG_WDT_CLR);
writew(0, priv->base + REG_WDT_MAX_PRD_L);
writew(0, priv->base + REG_WDT_MAX_PRD_H);
writew(0, priv->base + REG_WDT_CLR);
@ -191,11 +197,15 @@ static int __maybe_unused msc313e_wdt_suspend(struct device *dev)
static int __maybe_unused msc313e_wdt_resume(struct device *dev)
{
struct msc313e_wdt_priv *priv = dev_get_drvdata(dev);
int ret = 0;
if (watchdog_active(&priv->wdev) || watchdog_hw_running(&priv->wdev))
msc313e_wdt_start(&priv->wdev);
if (watchdog_active(&priv->wdev) || watchdog_hw_running(&priv->wdev)) {
ret = msc313e_wdt_start(&priv->wdev);
if (ret)
dev_err(dev, "Failed to restart watchdog (err=%d)\n", ret);
}
return 0;
return ret;
}
static SIMPLE_DEV_PM_OPS(msc313e_wdt_pm_ops, msc313e_wdt_suspend, msc313e_wdt_resume);

View File

@ -98,6 +98,7 @@ static int rtd119x_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rtd119x_watchdog_device *data;
unsigned long rate;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@ -111,10 +112,14 @@ static int rtd119x_wdt_probe(struct platform_device *pdev)
if (IS_ERR(data->clk))
return PTR_ERR(data->clk);
rate = clk_get_rate(data->clk);
if (!rate)
return -EINVAL;
data->wdt_dev.info = &rtd119x_wdt_info;
data->wdt_dev.ops = &rtd119x_wdt_ops;
data->wdt_dev.timeout = 120;
data->wdt_dev.max_timeout = 0xffffffff / clk_get_rate(data->clk);
data->wdt_dev.max_timeout = 0xffffffff / rate;
data->wdt_dev.min_timeout = 1;
data->wdt_dev.parent = dev;

View File

@ -278,6 +278,7 @@ static int rzv2h_wdt_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rzv2h_wdt_priv *priv;
struct clk *count_clk;
unsigned long rate;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@ -314,8 +315,12 @@ static int rzv2h_wdt_probe(struct platform_device *pdev)
return dev_err_probe(dev, -EINVAL, "Invalid count source\n");
}
rate = clk_get_rate(count_clk);
if (!rate)
return dev_err_probe(dev, -EINVAL, "Invalid clock rate\n");
priv->wdev.max_hw_heartbeat_ms = (MILLI * priv->of_data->timeout_cycles *
priv->of_data->cks_div) / clk_get_rate(count_clk);
priv->of_data->cks_div) / rate;
dev_dbg(dev, "max hw timeout of %dms\n", priv->wdev.max_hw_heartbeat_ms);
ret = devm_pm_runtime_enable(dev);

View File

@ -605,8 +605,10 @@ static int __init sp5100_tco_init(void)
pr_info("SP5100/SB800 TCO WatchDog Timer Driver\n");
err = platform_driver_register(&sp5100_tco_driver);
if (err)
if (err) {
pci_dev_put(sp5100_tco_pci);
return err;
}
sp5100_tco_platform_device =
platform_device_register_simple(TCO_DRIVER_NAME, -1, NULL, 0);
@ -619,6 +621,7 @@ static int __init sp5100_tco_init(void)
unreg_platform_driver:
platform_driver_unregister(&sp5100_tco_driver);
pci_dev_put(sp5100_tco_pci);
return err;
}
@ -626,6 +629,7 @@ static void __exit sp5100_tco_exit(void)
{
platform_device_unregister(sp5100_tco_platform_device);
platform_driver_unregister(&sp5100_tco_driver);
pci_dev_put(sp5100_tco_pci);
}
module_init(sp5100_tco_init);

View File

@ -371,7 +371,7 @@ static void starfive_wdt_stop(struct starfive_wdt *wdt)
static int starfive_wdt_pm_start(struct watchdog_device *wdd)
{
struct starfive_wdt *wdt = watchdog_get_drvdata(wdd);
int ret = pm_runtime_get_sync(wdd->parent);
int ret = pm_runtime_resume_and_get(wdd->parent);
if (ret < 0)
return ret;