Re: [PATCH v2 2/3] watchdog: Add Nuvoton MA35D1 watchdog driver support
[email protected] Fri, 24 Jul 2026 09:24:54 +0000
| Newsgroups | org.kernel.vger.linux-watchdog,org.kernel.vger.linux-devicetree |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 6 potential issue(= s) to consider: - [High] Writes to REG_WDT_CTL are missing required hardware synchronizatio= n waits (SYNC bit), risking dropped writes and hardware state corruption. - [High] The watchdog timer is not paused during system suspend if it was r= unning from the bootloader but not yet opened by userspace, leading to unin= tended system resets. - [High] Driver fails to synchronize the hardware timeout with the software= configuration when inheriting a running watchdog during probe. - [High] Read-modify-write operations on REG_WDT_CTL inadvertently clear W1= C (Write-1-to-Clear) status flags, leading to lost interrupts and wakeup ev= ents. - [Medium] In ma35d1_wdt_resume(), the driver writes to REG_WDT_RSTCNT befo= re ensuring the control register changes have synchronized. - [Low] Spelling mistake in Kconfig help text. -- --- Patch [2]: [PATCH v2 2/3] watchdog: Add Nuvoton MA35D1 watchdog driver = support --- commit 31ed5d4971c74d4f75935b7f98c40e226cdc3521 Author: Zi-Yu Chen <[email protected]> watchdog: Add Nuvoton MA35D1 watchdog driver support =20 This commit adds a new watchdog driver for the Nuvoton MA35D1 SoC. It provi= des support for timeout configuration, ping, and system reset functionality via the standard watchdog framework. > diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig > index 08cb8612d41fe..972740fd36a69 100644 > --- a/drivers/watchdog/Kconfig > +++ b/drivers/watchdog/Kconfig > @@ -720,6 +720,16 @@ config STMP3XXX_RTC_WATCHDOG > To compile this driver as a module, choose M here: the > module will be called stmp3xxx_rtc_wdt. > =20 > +config MA35D1_WDT > + tristate "Nuvoton MA35D1 Watchdog Timer" > + depends on ARCH_MA35 || COMPILE_TEST > + select WATCHDOG_CORE > + help > + Say Y here to include support for the watchdog timer > + for the Nuvoton MA35D1 series microprosser. [Severity: Low] Is "microprosser" a typo here? Did you mean "microprocessor"? > diff --git a/drivers/watchdog/ma35d1_wdt.c b/drivers/watchdog/ma35d1_wdt.c > new file mode 100644 > index 0000000000000..e5247e55dfee4 > --- /dev/null > +++ b/drivers/watchdog/ma35d1_wdt.c [ ... ] > +static int ma35d1_wdt_stop(struct watchdog_device *wdt_dev) > +{ > + struct ma35d1_wdt_dev *ma35d1_wdt =3D watchdog_get_drvdata(wdt_dev); > + unsigned int val; > + int ret; > + > + guard(spinlock_irqsave)(&ma35d1_wdt->lock); > + val =3D readl_relaxed(ma35d1_wdt->wdt_base + REG_WDT_CTL); > + val &=3D ~WDTEN; > + writel_relaxed(val, ma35d1_wdt->wdt_base + REG_WDT_CTL); [Severity: High] Will this read-modify-write inadvertently clear Write-1-to-Clear (W1C) flags like IF, WKF, or RSTF?=20 Looking at ma35d1_wdt_isr(), it appears that reading a 1 and writing it back clears the flag. Should these W1C flags be explicitly masked out when doing read-modify-write operations on REG_WDT_CTL here, and similarly in other functions like ma35d1_wdt_set_timeout(), ma35d1_wdt_start(), and ma35d1_wdt_suspend()? [ ... ] > +static int ma35d1_wdt_set_timeout(struct watchdog_device *wdt_dev, > + unsigned int timeout) > +{ > + struct ma35d1_wdt_dev *ma35d1_wdt =3D watchdog_get_drvdata(wdt_dev); > + unsigned long target_ticks; > + unsigned int val, i; [ ... ] > + guard(spinlock_irqsave)(&ma35d1_wdt->lock); > + val =3D readl_relaxed(ma35d1_wdt->wdt_base + REG_WDT_CTL); > + val &=3D ~TOUTSEL; > + val |=3D FIELD_PREP(TOUTSEL, i); > + writel_relaxed(val, ma35d1_wdt->wdt_base + REG_WDT_CTL); > + > + ma35d1_wdt_ping(wdt_dev); > + return 0; > +} [Severity: High] Does this writel_relaxed() require a call to ma35d1_wdt_wait_sync() before proceeding?=20 Without waiting for the SYNC bit, could the immediate ping command be ignor= ed by the hardware or cause hardware state corruption? > +static int ma35d1_wdt_start(struct watchdog_device *wdt_dev) > +{ > + struct ma35d1_wdt_dev *ma35d1_wdt =3D watchdog_get_drvdata(wdt_dev); > + void __iomem *wdt_base =3D ma35d1_wdt->wdt_base; > + unsigned int val; > + int ret; > + > + ret =3D ma35d1_wdt_set_timeout(wdt_dev, wdt_dev->timeout); > + if (ret < 0) > + return ret; > + > + guard(spinlock_irqsave)(&ma35d1_wdt->lock); > + val =3D readl_relaxed(wdt_base + REG_WDT_CTL); > + val |=3D (WDTEN | RSTEN); > + > + writel_relaxed(val, wdt_base + REG_WDT_CTL); [Severity: High] Because ma35d1_wdt_set_timeout() writes to REG_WDT_CTL without waiting for sync, and then ma35d1_wdt_start() immediately performs another read-modify-= write on the same register, could this back-to-back unsynchronized access cause dropped writes and prevent the watchdog from starting properly? [ ... ] > +static int ma35d1_wdt_probe(struct platform_device *pdev) > +{ > + struct device *dev =3D &pdev->dev; > + struct ma35d1_wdt_dev *ma35d1_wdt; [ ... ] > + val =3D readl_relaxed(ma35d1_wdt->wdt_base + REG_WDT_CTL); > + if (val & RSTF) { > + ma35d1_wdt->wdt_dev.bootstatus =3D WDIOF_CARDRESET; > + writel_relaxed(val, ma35d1_wdt->wdt_base + REG_WDT_CTL); > + } [Severity: High] Should there be a wait for hardware synchronization after this write clears the RSTF bit? > + > + if (val & WDTEN) > + set_bit(WDOG_HW_RUNNING, &ma35d1_wdt->wdt_dev.status); [Severity: High] If the bootloader left the watchdog running with a very short timeout, could the system reset before the core's ping worker can keep it alive? Should this also call ma35d1_wdt_set_timeout() to ensure the hardware's timeout matches the software configuration when taking over a running watch= dog? [ ... ] > +static int ma35d1_wdt_suspend(struct device *dev) > +{ > + struct ma35d1_wdt_dev *ma35d1_wdt =3D dev_get_drvdata(dev); > + > + if (watchdog_active(&ma35d1_wdt->wdt_dev)) { [Severity: High] Does this need to check watchdog_hw_running() as well? If the bootloader started the watchdog (WDOG_HW_RUNNING is set) but userspa= ce hasn't opened the device yet (WDOG_ACTIVE is false), this check will skip pausing the hardware. Could the timer then expire and unexpectedly reset the system during sleep? [ ... ] > +static int ma35d1_wdt_resume(struct device *dev) > +{ > + struct ma35d1_wdt_dev *ma35d1_wdt =3D dev_get_drvdata(dev); > + > + if (watchdog_active(&ma35d1_wdt->wdt_dev)) { [Severity: High] Similar to suspend, should this also check watchdog_hw_running() to ensure a hardware-running watchdog is properly resumed? > + u32 val; > + int ret; > + > + guard(spinlock_irqsave)(&ma35d1_wdt->lock); > + val =3D readl_relaxed(ma35d1_wdt->wdt_base + REG_WDT_CTL); > + > + if (device_may_wakeup(dev)) { > + val |=3D RSTEN; > + val &=3D ~(INTEN | WKEN); > + } else { > + val |=3D (WDTEN | RSTEN); > + } > + writel_relaxed(val, ma35d1_wdt->wdt_base + REG_WDT_CTL); > + writel_relaxed(RESET_COUNTER, > + ma35d1_wdt->wdt_base + REG_WDT_RSTCNT); > + ret =3D ma35d1_wdt_wait_sync(ma35d1_wdt); [Severity: Medium] Is it safe to issue the ping command (writing to REG_WDT_RSTCNT) before waiting for the control register changes to synchronize? In ma35d1_wdt_start(), the ping happens after ma35d1_wdt_wait_sync(). Could doing it before sync here cause the ping to be ignored by the hardware? --=20 Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260724091427.1689= [email protected]?part=3D2