From: sashiko-bot@kernel.org
To: "Artur Kowalski" <arturkow2000@gmail.com>
Cc: linux-watchdog@vger.kernel.org
Subject: Re: [PATCH 6/6] watchdog: tegra_wdt: Stop on Tegra20 VDE power off
Date: Tue, 10 Nov 2026 12:56:40 +0000 [thread overview]
Message-ID: <sashiko-outbox-207056@kernel.org> (raw)
In-Reply-To: <20261110-t20-for-upstream-v1-6-5923449951fe@gmail.com>
Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [Medium] watchdog: tegra_wdt: refcount leak in
tegra20_wdt_powergate_notify()
- [Medium] watchdog: tegra_wdt: stale WDOG_ACTIVE after
tegra20_wdt_powergate_notify()
- [Medium] watchdog: tegra_wdt: race on WDOG_HW_RUNNING in
tegra20_wdt_powergate_notify()
--
commit 7bc831b226455fa0dc8d2f0743ce747806275870
Author: Artur Kowalski <arturkow2000@gmail.com>
watchdog: tegra_wdt: Stop on Tegra20 VDE power off
This commit registers a Tegra PMC powergate notifier on Tegra20 to stop the
watchdog before the VDE partition is powered off and prevent it from being
started afterwards.
> diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
> index 7c2c21f90de52..d36310c50f782 100644
> --- a/drivers/watchdog/tegra_wdt.c
> +++ b/drivers/watchdog/tegra_wdt.c
[ ... ]
> @@ -256,6 +276,35 @@ static int tegra20_wdt_stop(struct watchdog_device *wdd)
> writel(0, wdt->tmr_regs + TIMER_PTV);
> writel(TIMER_PCR_INTR_CLR, wdt->tmr_regs + TIMER_PCR);
> +}
> +
> +static int tegra20_wdt_start(struct watchdog_device *wdd)
> +{
> + struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
> + int ret = 0;
> +
> + mutex_lock(&wdt->lock);
> +
> + if (wdt->vde_off) {
> + dev_warn(wdd->parent,
> + "not starting, a reset would hang with VDE powered off\n");
> + ret = -EBUSY;
> + } else {
> + __tegra20_wdt_start(wdt);
> + }
> +
> + mutex_unlock(&wdt->lock);
> +
> + return ret;
> +}
[Severity: Medium]
Can tegra20_wdt_powergate_notify() race with watchdog_open() ->
watchdog_start() on WDOG_HW_RUNNING and WDOG_ACTIVE?
tegra20_wdt_powergate_notify() serializes on wdt->lock, whereas
watchdog_open() and watchdog_start() inspect and update wdd->status under
wd_data->lock:
CPU0 CPU1
watchdog_open()
watchdog_start()
tegra20_wdt_start()
mutex_lock(&wdt->lock)
__tegra20_wdt_start(wdt)
mutex_unlock(&wdt->lock)
tegra20_wdt_powergate_notify()
mutex_lock(&wdt->lock)
wdt->vde_off = true
__tegra20_wdt_stop(wdt)
clear_bit(WDOG_HW_RUNNING, ...)
mutex_unlock(&wdt->lock)
set_bit(WDOG_ACTIVE, ...)
set_bit(WDOG_HW_RUNNING, ...) <-- set after watchdog was stopped
This leaves WDOG_ACTIVE and WDOG_HW_RUNNING set and allows open() to
succeed after the VDE partition was powered off and the hardware timer was
stopped.
If WDOG_HW_RUNNING was already set at boot, a similar race in
watchdog_open() either calls __watchdog_ping() -> tegra20_wdt_ping() (which
does not check wdt->vde_off and returns 0) or sees WDOG_HW_RUNNING cleared
before watchdog_start() and calls module_put() at out_mod without a
matching try_module_get() in watchdog_open().
> @@ -296,6 +350,45 @@ static const struct watchdog_ops tegra20_wdt_ops = {
> .set_timeout = tegra20_wdt_set_timeout,
> };
>
> +static int tegra20_wdt_powergate_notify(struct notifier_block *nb,
> + unsigned long event, void *data)
> +{
> + struct tegra_wdt *wdt = container_of(nb, struct tegra_wdt,
> + powergate_nb);
> + unsigned int id = *(unsigned int *)data;
> +
> + if (event != TEGRA_PMC_POWERGATE_POWER_OFF ||
> + id != TEGRA_POWERGATE_VDEC)
> + return NOTIFY_DONE;
> +
> + mutex_lock(&wdt->lock);
> +
> + if (!wdt->vde_off) {
> + wdt->vde_off = true;
> + __tegra20_wdt_stop(wdt);
> +
> + /*
> + * Stop the core's pings. If user space has the device open,
> + * its pings don't restart the watchdog either.
> + */
> + clear_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
[Severity: Medium]
Does clearing only WDOG_HW_RUNNING here leave WDOG_ACTIVE set when
/dev/watchdog is already open?
If user space later closes /dev/watchdog without the magic close character
(or with nowayout enabled), watchdog_release() leaves WDOG_ACTIVE set while
dropping the module and device references because WDOG_HW_RUNNING is false:
drivers/watchdog/watchdog_dev.c:watchdog_release() {
...
done:
running = wdd && watchdog_hw_running(wdd);
mutex_unlock(&wd_data->lock);
if (!running) {
module_put(wd_data->cdev.owner);
put_device(&wd_data->dev);
}
return 0;
}
On a subsequent open(/dev/watchdog), watchdog_start() sees
watchdog_active(wdd) == true and returns 0 immediately without calling
tegra20_wdt_start(), so opening the stopped watchdog succeeds instead of
failing with -EBUSY. While the file remains open, WDIOC_SETTIMEOUT also
sees watchdog_active(wdd) in tegra20_wdt_set_timeout(), updates
wdd->timeout, and then fails with -EBUSY in tegra20_wdt_start().
> +
> + dev_info(wdt->wdd.parent,
> + "VDE powered off, watchdog stopped\n");
> + }
> +
> + mutex_unlock(&wdt->lock);
> +
> + return NOTIFY_OK;
> +}
[ ... ]
> @@ -326,18 +419,46 @@ static int tegra20_wdt_init(struct platform_device *pdev, struct tegra_wdt *wdt,
> /*
> * The bootloader may leave the watchdog running. Take it over with
> * our own timeout and timer 1, and let the core ping it until user
> * space opens the device.
> */
> - if (readl(wdt->rst_source) & T20_RST_SOURCE_WDT_EN) {
> + mutex_lock(&wdt->lock);
> +
> + if (!wdt->vde_off &&
> + (readl(wdt->rst_source) & T20_RST_SOURCE_WDT_EN)) {
> dev_info(dev, "watchdog left running by the bootloader, taking it over (timeout %u sec)\n",
> wdt->wdd.timeout);
> - tegra20_wdt_start(&wdt->wdd);
> + __tegra20_wdt_start(wdt);
> set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
> }
[Severity: Medium]
Does clearing WDOG_HW_RUNNING in tegra20_wdt_powergate_notify() leak the
module and wd_data->dev references acquired for a boot-enabled watchdog?
When WDOG_HW_RUNNING is set here before devm_watchdog_register_device(),
watchdog_cdev_register() takes a module reference and a device reference:
drivers/watchdog/watchdog_dev.c:watchdog_cdev_register() {
...
if (watchdog_hw_running(wdd)) {
__module_get(wdd->ops->owner);
get_device(&wd_data->dev);
...
}
The watchdog core only drops those references after user space opens the
device while WDOG_HW_RUNNING is still set and later closes it with
WDOG_HW_RUNNING cleared. If the VDE partition powers off before
/dev/watchdog is opened, tegra20_wdt_powergate_notify() clears
WDOG_HW_RUNNING and sets wdt->vde_off = true, so any later watchdog_open()
fails with -EBUSY in tegra20_wdt_start() and those references are never
released, preventing the module from being unloaded.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261110-t20-for-upstream-v1-0-5923449951fe@gmail.com?part=6
prev parent reply other threads:[~2026-11-10 12:56 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 12:39 [PATCH 0/6] watchdog: tegra_wdt: Add Tegra20 support Artur Kowalski
2026-11-10 12:39 ` [PATCH 1/6] clocksource/drivers/timer-tegra: Keep Tegra20's watchdog timers free Artur Kowalski
2026-11-10 12:48 ` sashiko-bot
2026-11-10 12:39 ` [PATCH 2/6] watchdog: tegra_wdt: Move SoC specific parts into match data Artur Kowalski
2026-11-10 12:39 ` [PATCH 3/6] watchdog: tegra_wdt: Support Tegra20 Artur Kowalski
2026-11-10 16:21 ` Krzysztof Kozlowski
2026-11-10 12:39 ` [PATCH 4/6] soc/tegra: pmc: Add an option to keep the VDE partition on Artur Kowalski
2026-11-10 12:39 ` [PATCH 5/6] soc/tegra: pmc: Add a partition power off notifier Artur Kowalski
2026-11-10 12:39 ` [PATCH 6/6] watchdog: tegra_wdt: Stop on Tegra20 VDE power off Artur Kowalski
2026-11-10 12:56 ` 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=sashiko-outbox-207056@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=arturkow2000@gmail.com \
--cc=linux-watchdog@vger.kernel.org \
--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.