From: sashiko-bot@kernel.org
To: "Prajwal N" <prajwal.n@oss.qualcomm.com>
Cc: linux-watchdog@vger.kernel.org
Subject: Re: [RFC PATCH 2/2] drivers/watchdog: Add RISC-V SBI watchdog driver
Date: Sat, 03 Oct 2026 01:33:18 +0000 [thread overview]
Message-ID: <20261003013318.E74021F0089A@smtp.kernel.org> (raw)
In-Reply-To: <20261002163758.2919372-3-prajwal.n@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [High] watchdog: riscv_sbi_wdt: Probe returns success on MSI virtual IRQ failure
- [High] watchdog: riscv_sbi_wdt: Silent u32 overflow in timeout conversion allows premature resets
- [High] watchdog: riscv_sbi_wdt: MSI interrupts leak and Use-After-Free on unbind
- [Medium] watchdog: riscv_sbi_wdt: Missing wdt->dev and parent initializations
- [Medium] watchdog: riscv_sbi_wdt: WDIOF_PRETIMEOUT exposed without hardware support
- [Medium] watchdog: riscv_sbi_wdt: set_timeout fails to adjust pretimeout
- [Low] watchdog: riscv_sbi_wdt: Build failure due to non-existent fwnode member
- [Low] watchdog: riscv_sbi_wdt: Missing module_exit() prevents unloading
- [Low] watchdog: riscv_sbi_wdt: Build failure on configs missing GENERIC_MSI_IRQ
--
commit 5a455815a87582fc7be391ea2d8512e1bd8d0b90
Author: Prajwal N <prajwal.n@oss.qualcomm.com>
drivers/watchdog: Add RISC-V SBI watchdog driver
This commit adds support for the RISC-V SBI watchdog extension, integrating
with the Linux watchdog framework. It configures and controls the watchdog
via standard SBI calls and optionally supports pretimeout MSIs.
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
[ ... ]
> +config RISCV_SBI_WATCHDOG
> + tristate "RISC-V SBI based Watchdog support"
> + depends on RISCV_SBI
[Severity: Low]
Does this configuration need a dependency on CONFIG_GENERIC_MSI_IRQ?
Without it, the unconditional call to
platform_device_msi_init_and_alloc_irqs() in probe will cause a build
failure when that config is disabled.
> diff --git a/drivers/watchdog/riscv_sbi_wdt.c b/drivers/watchdog/riscv_sbi_wdt.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/watchdog/riscv_sbi_wdt.c
[ ... ]
> +/* Convert second to microsecond */
> +static inline u32 sec_to_usec(unsigned int sec)
> +{
> + return (u32)(sec * 1000000ULL);
> +}
[Severity: High]
Can this silently overflow if a user with privileges configures a large
timeout?
For example, setting a timeout greater than 4294 seconds overflows the u32
calculation, causing the hardware to receive an extremely short timeout
instead, potentially triggering an unexpected system reset.
[ ... ]
> +/* Set the watchdog timeout value */
> +static int sbiwdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
> +{
> + struct sbiwdt *wdt = watchdog_get_drvdata(wdd);
> + u32 period_usec;
> + int ret;
> +
> + period_usec = sec_to_usec(timeout);
> +
> + ret = sbiwdt_write_attribute(SBI_WDT_PERIOD, period_usec);
> + if (ret)
> + return ret;
> +
> + wdt->attrs.wdt_period = period_usec;
> + wdt->wdd.timeout = timeout;
> +
> + return 0;
> +}
[Severity: Medium]
Does this function need to adjust or validate against wdd->pretimeout?
If a user sets a new timeout that is smaller than the current pretimeout,
the hardware could be left in an invalid state where the notification time
is greater than the period time.
[ ... ]
> +/* Get the watchdog timeleft before expiry */
> +static unsigned int sbiwdt_get_timeleft(struct watchdog_device *wdd)
> +{
> + struct sbiwdt *wdt = watchdog_get_drvdata(wdd);
> + unsigned int time_left_usec;
> + int ret;
> +
> + ret = sbiwdt_read_attribute(SBI_WDT_TIME_LEFT, &time_left_usec);
> + if (ret) {
> + dev_err(wdt->dev, "Failed to read watchdog time left: %d\n", ret);
[Severity: Medium]
Will this dereference an uninitialized wdt->dev pointer?
It appears wdt->dev is never assigned during probe, which would lead to
obscured error logs displaying "(NULL device *)".
> + return 0;
> + }
> +
> + return usec_to_sec(time_left_usec);
> +}
> +
> +static const struct watchdog_info sbiwdt_info = {
> + .options = WDIOF_SETTIMEOUT |
> + WDIOF_KEEPALIVEPING |
> + WDIOF_PRETIMEOUT |
> + WDIOF_MAGICCLOSE,
[Severity: Medium]
Should WDIOF_PRETIMEOUT only be advertised if the firmware actually
supports MSI capabilities?
Statically advertising it means userspace could configure a pretimeout that
will silently never trigger on platforms without MSI support.
[ ... ]
> +/* Initialize the watchdog attributes */
> +static int sbiwdt_init_attributes(struct sbiwdt *wdt)
> +{
[ ... ]
> + /* Initialize the watchdog timeout to default value */
> + timeout_usec = sec_to_usec(SBI_WDT_DEFAULT_TIMEOUT);
> + ret = sbiwdt_write_attribute(SBI_WDT_PERIOD, timeout_usec);
> + if (ret)
> + return ret;
> +
> + wdt->attrs.wdt_period = timeout_usec;
> + wdt->wdd.timeout = SBI_WDT_DEFAULT_TIMEOUT;
[Severity: High]
Should wdt->wdd.max_timeout be explicitly initialized here?
Without an upper bound set by the driver, the watchdog core defaults to no
hardware limit, allowing large timeouts to be passed to sec_to_usec()
which then truncates them via integer overflow.
[ ... ]
> +static int sbiwdt_probe(struct platform_device *pdev)
> +{
> + struct sbiwdt *wdt;
> + struct imsic_global_config *imsic_global;
> + struct irq_domain *msi_domain;
> + struct device *dev = &pdev->dev;
> + int rc;
> +
> + /* Allocate memory for the global watchdog structure */
> + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
> + if (!wdt)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, wdt);
> + watchdog_set_drvdata(&wdt->wdd, wdt);
[Severity: Medium]
Are we missing assignments for wdt->dev and wdt->wdd.parent here?
Failing to set wdt->wdd.parent = dev breaks the sysfs hierarchy for the
watchdog device, and missing wdt->dev = dev leads to the uninitialized
pointer use observed in sbiwdt_get_timeleft().
[ ... ]
> + /* Setup MSI if the capability is available */
> + if (wdt->attrs.wdt_capability & SBI_WDT_CAP_MSI_SUPPORT_MASK) {
> + imsic_global = imsic_get_global_config();
> + if (!imsic_global) {
> + dev_err(dev, "IMSIC firmware node is unavailable\n");
> + return -ENODEV;
> + }
> +
> + msi_domain = irq_find_matching_fwnode(imsic_global->fwnode,
> + DOMAIN_BUS_PLATFORM_MSI);
[Severity: Low]
Does struct imsic_global_config actually have an fwnode member?
It appears this member does not exist in the upstream struct definition,
which will cause an immediate build failure.
> + if (!msi_domain) {
> + dev_err(dev, "IMSIC platform MSI domain is unavailable\n");
> + return -ENODEV;
> + }
> +
> + dev_set_msi_domain(&pdev->dev, msi_domain);
> +
> + /* MSI setup*/
> + rc = platform_device_msi_init_and_alloc_irqs(dev, 1, sbiwdt_msi_write);
[Severity: High]
Are these MSI allocations ever cleaned up if subsequent probe steps fail?
Since this is not a device-managed function, error paths that return early
will leak these interrupts.
> + if (rc) {
> + dev_err(dev, "Failed to allocate MSIs\n");
> + return rc;
> + }
> +
> + wdt->virq = msi_get_virq(dev, 0);
> + if (!wdt->virq) {
> + dev_err(dev, "Failed to get MSI virtual IRQ: %d\n", wdt->virq);
> + return wdt->virq;
> + }
[Severity: High]
Will this return 0 (success) when it intends to return a failure?
msi_get_virq() returns 0 on failure. Returning wdt->virq here falsely
signals a successful probe to the driver core, leaving the system silently
unprotected since the watchdog never fully registers.
[ ... ]
> +static struct platform_driver sbiwdt_driver = {
> + .probe = sbiwdt_probe,
> + .driver = {
> + .name = DRV_NAME,
> + },
> +};
[Severity: High]
Does this driver need a .remove callback to properly free the MSIs?
Without one, unbinding the driver permanently leaks the interrupts. If a
leaked MSI triggers later, it could execute sbiwdt_msi_write() causing a
use-after-free on the released driver data.
> +
> +static int __init sbiwdt_init(void)
> +{
> + int ret;
> + struct platform_device *pdev;
> +
> + /* Probe for SBI WDT extension */
> + if (sbi_spec_version < sbi_mk_version(3, 0) ||
> + sbi_probe_extension(SBI_EXT_WDT) <= 0) {
> + return -ENODEV;
> + }
> +
> + ret = platform_driver_register(&sbiwdt_driver);
> + if (ret)
> + return ret;
> +
> + pdev = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
> + if (IS_ERR(pdev)) {
> + platform_driver_unregister(&sbiwdt_driver);
> + return PTR_ERR(pdev);
> + }
> +
> + return 0;
> +}
> +late_initcall(sbiwdt_init);
[Severity: Low]
Should a symmetric module_exit() routine be provided here?
Since the driver is configured as tristate, omitting an exit function
prevents it from ever being unloaded via rmmod.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261002163758.2919372-1-prajwal.n@oss.qualcomm.com?part=2
prev parent reply other threads:[~2026-10-03 1:33 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-02 16:37 [RFC PATCH 0/2] Add RISC-V SBI watchdog driver Prajwal N
2026-10-02 16:37 ` Prajwal N
2026-10-02 16:37 ` [RFC PATCH 1/2] include: sbi_ecall_interface: Add defines for the RISC-V SBI watchdog extension Prajwal N
2026-10-02 16:37 ` Prajwal N
2026-10-03 1:33 ` sashiko-bot
2026-10-02 16:37 ` [RFC PATCH 2/2] drivers/watchdog: Add RISC-V SBI watchdog driver Prajwal N
2026-10-02 16:37 ` Prajwal N
2026-10-03 1:33 ` sashiko-bot [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261003013318.E74021F0089A@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-watchdog@vger.kernel.org \
--cc=prajwal.n@oss.qualcomm.com \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.