Skip to contentSkip to conversation

watchdog: msc313e: Fix issues Sashiko reported

PATCH Applied Tzung-Bi Shih 3 participants 9 messages Aug 27 – Aug 28

Subsystems (2)

v1 of 2 Applied Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover watchdog: msc313e: Fix issues Sashiko reported

The series fixes the two issues reported by Sashiko in [1].

[1] https://lore.kernel.org/all/[email protected]/

Tzung-Bi Shih (2):
watchdog: msc313e: Fix NULL pointer dereference in PM callbacks
watchdog: msc313e: Enable clock before accessing hardware registers

 drivers/watchdog/msc313e_wdt.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)
Signature · 1 line
2.55.0.887.g758fc8c411-goog
#1 lore raw

PATCH 1/2 watchdog: msc313e: Fix NULL pointer dereference in PM callbacks

msc313e_wdt_probe() doesn't set the driver data for the platform device. As a result, dev_get_drvdata() in msc313e_wdt_suspend() and msc313e_wdt_resume() will return NULL, leading to a NULL pointer dereference afterward.

Set the platform device driver data in msc313e_wdt_probe().

Fixes e9800b799464 ("watchdog: Add Mstar MSC313e WDT driver")
---
 drivers/watchdog/msc313e_wdt.c | 1 +
 1 file changed, 1 insertion(+)
drivers/watchdog/msc313e_wdt.c +1 -0
index d962589e2c55..f69d66971c41 100644
@@ -124,6 +124,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
 		set_bit(WDOG_HW_RUNNING, &priv->wdev.status);
 
 	watchdog_set_drvdata(&priv->wdev, priv);
+	platform_set_drvdata(pdev, priv);
 
 	watchdog_init_timeout(&priv->wdev, timeout, dev);
 	watchdog_stop_on_reboot(&priv->wdev);
Signature · 1 line
2.55.0.887.g758fc8c411-goog
#2 lore raw

Re: [PATCH 1/2] watchdog: msc313e: Fix NULL pointer dereference in PM callbacks

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

Pre-existing issues:
- [High] Hardware watchdog is not properly stopped during system suspend if it was started by the bootloader but not opened by userspace.
- [High] The resume callback ignores the return value of msc313e_wdt_start().
- [High] Potential division by zero during max_timeout calculation.
- [High] Clock reference count leak and unintended hardware activation in msc313e_wdt_settimeout.
- [Low] Struct initialization uses commas instead of semicolons.
--

commit c2fa09163e4f9bd75f052d03568c2d22f22158f0
Author: Tzung-Bi Shih <[email protected]>

watchdog: msc313e: Fix NULL pointer dereference in PM callbacks

The commit fixes a NULL pointer dereference in the power management callbacks of the msc313e watchdog driver. It ensures that the driver data is properly set for the platform device in the probe function so it can be retrieved during suspend and resume.

drivers/watchdog/msc313e_wdt.c static int msc313e_wdt_probe(struct platform_device *pdev) · line 131

Quoted 12 lines
drivers/watchdog/msc313e_wdt.c +1 -0
index 90171431fc594..3b62650375628 100644
@@ -125,6 +125,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
 		set_bit(WDOG_HW_RUNNING, &priv->wdev.status);
 
 	watchdog_set_drvdata(&priv->wdev, priv);
+	platform_set_drvdata(pdev, priv);
 
 	watchdog_init_timeout(&priv->wdev, timeout, dev);
 	watchdog_stop_on_reboot(&priv->wdev);

While reviewing this code, I noticed a few pre-existing issues in the driver:

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_suspend()

    if (watchdog_active(&priv->wdev))
        msc313e_wdt_stop(&priv->wdev);

[Severity: High]
This is a pre-existing issue, but does this bypass stopping the hardware watchdog if userspace hasn't opened the device?

If the hardware was started by the bootloader but not yet opened by userspace, the ping worker is frozen during suspend. Since watchdog_active() checks if userspace has opened it, will the active hardware timer continue running and trigger a spurious system reset during system suspend?

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_resume()

    if (watchdog_active(&priv->wdev))
        msc313e_wdt_start(&priv->wdev);

[Severity: High]
This is a pre-existing issue, but is it safe to ignore the return value of msc313e_wdt_start()?

If the clock enable fails inside msc313e_wdt_start(), the function will silently discard the error. Will subsequent register operations in the watchdog then access unclocked memory and cause a system crash?

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_probe()

    priv->wdev.info = &msc313e_wdt_ident,
    priv->wdev.ops = &msc313e_wdt_ops,
    priv->wdev.parent = dev;

[Severity: Low]
This isn't a bug introduced by this patch, but are these assignments using comma operators intentionally instead of semicolons?

While syntactically valid, this violates standard kernel coding style and could cause unintended behavior during refactoring.

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_probe()

    priv->wdev.min_timeout = MSC313E_WDT_MIN_TIMEOUT;
    priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk);
    priv->wdev.timeout = MSC313E_WDT_DEFAULT_TIMEOUT;

[Severity: High]
This is a pre-existing issue, but could this calculation result in a division by zero panic?

If clk_get_rate() returns 0 for an uninitialized clock, using it directly as a denominator here will trigger a division by zero exception during probe.

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_settimeout()

    wdev->timeout = new_time;

    return msc313e_wdt_start(wdev);

[Severity: High]
This is a pre-existing issue, but does unconditionally calling msc313e_wdt_start() here cause a clock reference leak or unintended hardware activation?

If the watchdog is already active, this would increment the clock reference count redundantly. If it is stopped, it inadvertently starts the hardware timer without the watchdog core tracking it, which could cause an unexpected system reset.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#3 lore raw

Re: [PATCH 1/2] watchdog: msc313e: Fix NULL pointer dereference in PM callbacks

Quoted 8 lines · On Thu, Aug 27, 2026 at 04:57:46AM +0000, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

Pre-existing issues:
- [High] Hardware watchdog is not properly stopped during system suspend if it was started by the bootloader but not opened by userspace.
- [High] The resume callback ignores the return value of msc313e_wdt_start().
- [High] Potential division by zero during max_timeout calculation.
- [High] Clock reference count leak and unintended hardware activation in msc313e_wdt_settimeout.
- [Low] Struct initialization uses commas instead of semicolons.

Proposed fixes for them in the series [1].

[1] https://lore.kernel.org/all/[email protected]

Quoted 4 lines

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_suspend()

    if (watchdog_active(&priv->wdev))
        msc313e_wdt_stop(&priv->wdev);
Quoted 8 lines

[Severity: High]
This is a pre-existing issue, but does this bypass stopping the hardware watchdog if userspace hasn't opened the device?

If the hardware was started by the bootloader but not yet opened by userspace, the ping worker is frozen during suspend. Since watchdog_active() checks if userspace has opened it, will the active hardware timer continue running and trigger a spurious system reset during system suspend?

https://lore.kernel.org/all/[email protected]

Quoted 11 lines

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_resume()

    if (watchdog_active(&priv->wdev))
        msc313e_wdt_start(&priv->wdev);

[Severity: High]
This is a pre-existing issue, but is it safe to ignore the return value of msc313e_wdt_start()?

If the clock enable fails inside msc313e_wdt_start(), the function will silently discard the error. Will subsequent register operations in the watchdog then access unclocked memory and cause a system crash?

https://lore.kernel.org/all/[email protected]

Quoted 11 lines

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_probe()

    priv->wdev.info = &msc313e_wdt_ident,
    priv->wdev.ops = &msc313e_wdt_ops,
    priv->wdev.parent = dev;

[Severity: Low]
This isn't a bug introduced by this patch, but are these assignments using comma operators intentionally instead of semicolons?

While syntactically valid, this violates standard kernel coding style and could cause unintended behavior during refactoring.

https://lore.kernel.org/all/[email protected]

Quoted 11 lines

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_probe()

    priv->wdev.min_timeout = MSC313E_WDT_MIN_TIMEOUT;
    priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk);
    priv->wdev.timeout = MSC313E_WDT_DEFAULT_TIMEOUT;

[Severity: High]
This is a pre-existing issue, but could this calculation result in a division by zero panic?

If clk_get_rate() returns 0 for an uninitialized clock, using it directly as a denominator here will trigger a division by zero exception during probe.

https://lore.kernel.org/all/[email protected]

Quoted 10 lines

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_settimeout()

    wdev->timeout = new_time;

    return msc313e_wdt_start(wdev);

[Severity: High]
This is a pre-existing issue, but does unconditionally calling msc313e_wdt_start() here cause a clock reference leak or unintended hardware activation?

Quoted 4 lines

If the watchdog is already active, this would increment the clock reference count redundantly. If it is stopped, it inadvertently starts the hardware timer without the watchdog core tracking it, which could cause an unexpected system reset.

https://lore.kernel.org/all/[email protected]

maintainer Applied
#4 lore raw

Re: [PATCH 1/2] watchdog: msc313e: Fix NULL pointer dereference in PM callbacks

In reply to Tzung-Bi Shih
Quoted 9 lines · Tzung-Bi Shih

msc313e_wdt_probe() doesn't set the driver data for the platform device. As a result, dev_get_drvdata() in msc313e_wdt_suspend() and msc313e_wdt_resume() will return NULL, leading to a NULL pointer dereference afterward.

Set the platform device driver data in msc313e_wdt_probe().

Fixes e9800b799464 ("watchdog: Add Mstar MSC313e WDT driver")

Applied.

Thanks,
Guenter

Quoted 16 lines
---
 drivers/watchdog/msc313e_wdt.c | 1 +
 1 file changed, 1 insertion(+)
drivers/watchdog/msc313e_wdt.c +1 -0
index d962589e2c55..f69d66971c41 100644
@@ -124,6 +124,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
 		set_bit(WDOG_HW_RUNNING, &priv->wdev.status);
 
 	watchdog_set_drvdata(&priv->wdev, priv);
+	platform_set_drvdata(pdev, priv);
 
 	watchdog_init_timeout(&priv->wdev, timeout, dev);
 	watchdog_stop_on_reboot(&priv->wdev);
#5 lore raw

PATCH 2/2 watchdog: msc313e: Enable clock before accessing hardware registers

In reply to Tzung-Bi Shih

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 ffd264bd152c ("watchdog: msc313e: Check if the WDT was running at boot")
---
 drivers/watchdog/msc313e_wdt.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
drivers/watchdog/msc313e_wdt.c +14 -1
index f69d66971c41..b279ef645430 100644
@@ -97,6 +97,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct msc313e_wdt_priv *priv;
+	int ret;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -119,9 +120,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
 	priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk);
 	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);
Signature · 1 line
2.55.0.887.g758fc8c411-goog
#6 lore raw

Re: [PATCH 2/2] watchdog: msc313e: Enable clock before accessing hardware registers

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [Medium] Clock reference count is leaked on the probe error path if watchdog registration fails.

Pre-existing issues:
- [High] Repeatedly setting the watchdog timeout leaks clock prepare and enable references, potentially leading to refcount overflow.
- [High] System will unexpectedly reset during suspend if the hardware watchdog is running but was never opened by userspace.
- [High] Potential division by zero if clk_get_rate() returns 0.
--

commit 363d0038f19004fef94c7716c644171a89070cb1
Author: Tzung-Bi Shih <[email protected]>
Subject: watchdog: msc313e: Enable clock before accessing hardware registers

msc313e_wdt_probe() reads from hardware registers without ensuring the required clock is enabled. This patch calls clk_prepare_enable() before reading WDT registers and leaves the clock enabled if the WDT is running.

Quoted 12 lines
drivers/watchdog/msc313e_wdt.c +1 -0
index 3b62650375628..b89b1cddaa5e8 100644
@@ -98,6 +98,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct msc313e_wdt_priv *priv;
+	int ret;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)

[ ... ]

drivers/watchdog/msc313e_wdt.c static int msc313e_wdt_probe(struct platform_device *pdev) · line 121

Quoted 2 lines
drivers/watchdog/msc313e_wdt.c +0 -0
@@ -120,9 +121,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
 	priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk);

[Severity: High]
This isn't a bug introduced by this patch, but does this code cause a division by zero panic during device probe if clk_get_rate() returns 0?

Quoted 11 lines
drivers/watchdog/msc313e_wdt.c +6 -1
 	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);
+		/*

drivers/watchdog/msc313e_wdt.c static int msc313e_wdt_probe(struct platform_device *pdev) · line 140

Quoted 10 lines
drivers/watchdog/msc313e_wdt.c +7 -0
+		 * 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);

[Severity: Medium]
If the hardware watchdog is already running at boot, the driver intentionally leaves the clock enabled here. However, if devm_watchdog_register_device() subsequently fails:

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_probe() {
    ...
	return devm_watchdog_register_device(dev, &priv->wdev);
}

Does this regression leak the clock reference count on the error path if device registration fails, since the prepared clock is never disabled?

[Severity: High]
This is a pre-existing issue, but repeatedly setting the watchdog timeout leaks clock prepare and enable references, potentially leading to refcount overflow.

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_settimeout() {
    ...
	return msc313e_wdt_start(wdev);
}
drivers/watchdog/msc313e_wdt.c:msc313e_wdt_start() {
    ...
	err = clk_prepare_enable(priv->clk);
    ...
}

Since the set_timeout callback directly wraps msc313e_wdt_start(), does this sequence unconditionally increment the clock refcount every time the timeout is updated, without a corresponding decrement?

[Severity: High]
This isn't a bug introduced by this patch, but will the system unexpectedly reset during suspend if the hardware watchdog is running but was never opened by userspace?

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_suspend() {
    ...
	if (watchdog_active(&priv->wdev))
		msc313e_wdt_stop(&priv->wdev);
    ...
}

If the watchdog was left running by the bootloader (WDOG_HW_RUNNING is set) but never opened by userspace, watchdog_active() is false and the driver skips stopping it. Meanwhile, the watchdog core suspends its background ping worker.

Since the hardware timer continues counting down without being pinged, will it expire and reset the suspended system?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
maintainer
#7 lore raw

Re: [PATCH 2/2] watchdog: msc313e: Enable clock before accessing hardware registers

Quoted 5 lines · On 8/26/26 22:01, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [Medium] Clock reference count is leaked on the probe error path if watchdog registration fails.

That seems real.

Quoted 63 lines

Pre-existing issues:
- [High] Repeatedly setting the watchdog timeout leaks clock prepare and enable references, potentially leading to refcount overflow.
- [High] System will unexpectedly reset during suspend if the hardware watchdog is running but was never opened by userspace.
- [High] Potential division by zero if clk_get_rate() returns 0.
--

commit 363d0038f19004fef94c7716c644171a89070cb1
Author: Tzung-Bi Shih <[email protected]>
Subject: watchdog: msc313e: Enable clock before accessing hardware registers

msc313e_wdt_probe() reads from hardware registers without ensuring the required clock is enabled. This patch calls clk_prepare_enable() before reading WDT registers and leaves the clock enabled if the WDT is running.

Quoted 12 lines
drivers/watchdog/msc313e_wdt.c +1 -0
index 3b62650375628..b89b1cddaa5e8 100644
@@ -98,6 +98,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
  {
  	struct device *dev = &pdev->dev;
  	struct msc313e_wdt_priv *priv;
+	int ret;
 
  	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  	if (!priv)

[ ... ]

drivers/watchdog/msc313e_wdt.c static int msc313e_wdt_probe(struct platform_device *pdev) · line 121

Quoted 2 lines
drivers/watchdog/msc313e_wdt.c +0 -0
@@ -120,9 +121,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
  	priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk);

[Severity: High]
This isn't a bug introduced by this patch, but does this code cause a division by zero panic during device probe if clk_get_rate() returns 0?

Quoted 11 lines
drivers/watchdog/msc313e_wdt.c +6 -1
  	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);
+		/*

drivers/watchdog/msc313e_wdt.c static int msc313e_wdt_probe(struct platform_device *pdev) · line 140

Quoted 10 lines
drivers/watchdog/msc313e_wdt.c +7 -0
+		 * 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);

[Severity: Medium]
If the hardware watchdog is already running at boot, the driver intentionally leaves the clock enabled here. However, if devm_watchdog_register_device() subsequently fails:

Quoted 8 lines
drivers/watchdog/msc313e_wdt.c:msc313e_wdt_probe() {
     ...
	return devm_watchdog_register_device(dev, &priv->wdev);
}

Does this regression leak the clock reference count on the error path if device registration fails, since the prepared clock is never disabled?

Yes, that will need to be fixed.

Quoted 17 lines

[Severity: High]
This is a pre-existing issue, but repeatedly setting the watchdog timeout leaks clock prepare and enable references, potentially leading to refcount overflow.

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_settimeout() {
     ...
	return msc313e_wdt_start(wdev);
}
drivers/watchdog/msc313e_wdt.c:msc313e_wdt_start() {
     ...
	err = clk_prepare_enable(priv->clk);
     ...
}
Quoted 4 lines

Since the set_timeout callback directly wraps msc313e_wdt_start(), does this sequence unconditionally increment the clock refcount every time the timeout is updated, without a corresponding decrement?

Worse, it starts the watchdog even if it isn't running. Separate problem, though.

Quoted 21 lines

[Severity: High]
This isn't a bug introduced by this patch, but will the system unexpectedly reset during suspend if the hardware watchdog is running but was never opened by userspace?

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_suspend() {
     ...
	if (watchdog_active(&priv->wdev))
		msc313e_wdt_stop(&priv->wdev);
     ...
}

If the watchdog was left running by the bootloader (WDOG_HW_RUNNING is set) but never opened by userspace, watchdog_active() is false and the driver skips stopping it. Meanwhile, the watchdog core suspends its background ping worker.

Since the hardware timer continues counting down without being pinged, will it expire and reset the suspended system?

#8 lore raw

Re: [PATCH 2/2] watchdog: msc313e: Enable clock before accessing hardware registers

Quoted 8 lines · Guenter Roeck
Quoted 5 lines · On 8/26/26 22:01, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [Medium] Clock reference count is leaked on the probe error path if watchdog registration fails.

That seems real.

Fixed it in v2.

https://lore.kernel.org/all/[email protected]

Quoted 5 lines
Quoted 5 lines

Pre-existing issues:
- [High] Repeatedly setting the watchdog timeout leaks clock prepare and enable references, potentially leading to refcount overflow.
- [High] System will unexpectedly reset during suspend if the hardware watchdog is running but was never opened by userspace.
- [High] Potential division by zero if clk_get_rate() returns 0.

Proposed fixes for them in the series [1].

[1] https://lore.kernel.org/all/[email protected]

Quoted 6 lines
Quoted 6 lines

drivers/watchdog/msc313e_wdt.c static int msc313e_wdt_probe(struct platform_device *pdev) · line 121

Quoted 2 lines
drivers/watchdog/msc313e_wdt.c +0 -0
@@ -120,9 +121,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev)
  	priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk);

[Severity: High]
This isn't a bug introduced by this patch, but does this code cause a division by zero panic during device probe if clk_get_rate() returns 0?

https://lore.kernel.org/all/[email protected]

Quoted 31 lines
Quoted 31 lines
Quoted 10 lines
drivers/watchdog/msc313e_wdt.c +5 -1
  	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);

drivers/watchdog/msc313e_wdt.c static int msc313e_wdt_probe(struct platform_device *pdev) · line 140

Quoted 10 lines
drivers/watchdog/msc313e_wdt.c +8 -0
+		/*
+		 * 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);

[Severity: Medium]
If the hardware watchdog is already running at boot, the driver intentionally leaves the clock enabled here. However, if devm_watchdog_register_device() subsequently fails:

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_probe() {
     ...
	return devm_watchdog_register_device(dev, &priv->wdev);
}
Quoted 4 lines
Quoted 3 lines

Does this regression leak the clock reference count on the error path if device registration fails, since the prepared clock is never disabled?

Yes, that will need to be fixed.

https://lore.kernel.org/all/[email protected]

Quoted 16 lines
Quoted 16 lines

[Severity: High]
This is a pre-existing issue, but repeatedly setting the watchdog timeout leaks clock prepare and enable references, potentially leading to refcount overflow.

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_settimeout() {
     ...
	return msc313e_wdt_start(wdev);
}
drivers/watchdog/msc313e_wdt.c:msc313e_wdt_start() {
     ...
	err = clk_prepare_enable(priv->clk);
     ...
}
Quoted 6 lines
Quoted 4 lines

Since the set_timeout callback directly wraps msc313e_wdt_start(), does this sequence unconditionally increment the clock refcount every time the timeout is updated, without a corresponding decrement?

Worse, it starts the watchdog even if it isn't running. Separate problem, though.

https://lore.kernel.org/all/[email protected]

Quoted 12 lines
Quoted 12 lines

[Severity: High]
This isn't a bug introduced by this patch, but will the system unexpectedly reset during suspend if the hardware watchdog is running but was never opened by userspace?

drivers/watchdog/msc313e_wdt.c:msc313e_wdt_suspend() {
     ...
	if (watchdog_active(&priv->wdev))
		msc313e_wdt_stop(&priv->wdev);
     ...
}
Quoted 7 lines
Quoted 7 lines

If the watchdog was left running by the bootloader (WDOG_HW_RUNNING is set) but never opened by userspace, watchdog_active() is false and the driver skips stopping it. Meanwhile, the watchdog core suspends its background ping worker.

Since the hardware timer continues counting down without being pinged, will it expire and reset the suspended system?

https://lore.kernel.org/all/[email protected]