public inbox for linux-watchdog@vger.kernel.org
 help / color / mirror / Atom feed
From: Guenter Roeck <linux@roeck-us.net>
To: Wim Van Sebroeck <wim@linux-watchdog.org>
Cc: linux-watchdog@vger.kernel.org, linux-kernel@vger.kernel.org,
	Guenter Roeck <linux@roeck-us.net>
Subject: [PATCH] watchdog: Always return time left until watchdog times out
Date: Tue, 18 Nov 2025 13:04:07 -0800	[thread overview]
Message-ID: <20251118210407.2362338-1-linux@roeck-us.net> (raw)

The watchdog core knows when the most recent keepalive was sent. It also
knows the configured timeout. With that, it can always calculate and
return the time left until a watchdog times out, even if its driver does
not support it.

Convert watchdog_get_timeleft() into a void function. It never returns an
error after this patch is applied, so the error checks in the calling code
are now pointless and can be removed.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
Tested on system which supports reading the remaining time from the
hardware. Confirmed that the calculated remaining time is never more
than 1 second different than the time reported by the hardware.

 drivers/watchdog/watchdog_dev.c | 35 ++++++++++++++-------------------
 1 file changed, 15 insertions(+), 20 deletions(-)

diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 8369fd94fc1a..9a5e544b886b 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -424,20 +424,22 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd,
  *
  * Get the time before a watchdog will reboot (if not pinged).
  * The caller must hold wd_data->lock.
- *
- * Return: 0 if successful, error otherwise.
  */
-static int watchdog_get_timeleft(struct watchdog_device *wdd,
-							unsigned int *timeleft)
+static void watchdog_get_timeleft(struct watchdog_device *wdd,
+				  unsigned int *timeleft)
 {
 	*timeleft = 0;
 
-	if (!wdd->ops->get_timeleft)
-		return -EOPNOTSUPP;
+	if (wdd->ops->get_timeleft) {
+		*timeleft = wdd->ops->get_timeleft(wdd);
+	} else {
+		struct watchdog_core_data *wd_data = wdd->wd_data;
+		s64 last_keepalive_ms = ktime_ms_delta(ktime_get(), wd_data->last_keepalive);
+		s64 last_keepalive = DIV_ROUND_UP_ULL(last_keepalive_ms, 1000);
 
-	*timeleft = wdd->ops->get_timeleft(wdd);
-
-	return 0;
+		if (wdd->timeout > last_keepalive)
+			*timeleft = wdd->timeout - last_keepalive;
+	}
 }
 
 #ifdef CONFIG_WATCHDOG_SYSFS
@@ -499,16 +501,13 @@ static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr,
 {
 	struct watchdog_device *wdd = dev_get_drvdata(dev);
 	struct watchdog_core_data *wd_data = wdd->wd_data;
-	ssize_t status;
 	unsigned int val;
 
 	mutex_lock(&wd_data->lock);
-	status = watchdog_get_timeleft(wdd, &val);
+	watchdog_get_timeleft(wdd, &val);
 	mutex_unlock(&wd_data->lock);
-	if (!status)
-		status = sysfs_emit(buf, "%u\n", val);
 
-	return status;
+	return sysfs_emit(buf, "%u\n", val);
 }
 static DEVICE_ATTR_RO(timeleft);
 
@@ -624,9 +623,7 @@ static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr,
 	struct watchdog_device *wdd = dev_get_drvdata(dev);
 	umode_t mode = attr->mode;
 
-	if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft)
-		mode = 0;
-	else if (attr == &dev_attr_pretimeout.attr && !watchdog_have_pretimeout(wdd))
+	if (attr == &dev_attr_pretimeout.attr && !watchdog_have_pretimeout(wdd))
 		mode = 0;
 	else if ((attr == &dev_attr_pretimeout_governor.attr ||
 		  attr == &dev_attr_pretimeout_available_governors.attr) &&
@@ -825,9 +822,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
 		err = put_user(wdd->timeout, p);
 		break;
 	case WDIOC_GETTIMELEFT:
-		err = watchdog_get_timeleft(wdd, &val);
-		if (err < 0)
-			break;
+		watchdog_get_timeleft(wdd, &val);
 		err = put_user(val, p);
 		break;
 	case WDIOC_SETPRETIMEOUT:
-- 
2.45.2


                 reply	other threads:[~2025-11-18 21:04 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20251118210407.2362338-1-linux@roeck-us.net \
    --to=linux@roeck-us.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-watchdog@vger.kernel.org \
    --cc=wim@linux-watchdog.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox