drivers/watchdog/watchdog_dev.c | 35 ++++++++++++++------------------- 1 file changed, 15 insertions(+), 20 deletions(-)
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
© 2016 - 2025 Red Hat, Inc.