From df044e02206230c7d79a9aef96a6c087476f5533 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 31 Aug 2016 14:52:41 +0300 Subject: watchdog: add pretimeout support to the core Since the watchdog framework centrializes the IOCTL interfaces of device drivers now, SETPRETIMEOUT and GETPRETIMEOUT need to be added in the common code. Signed-off-by: Robin Gong Signed-off-by: Wolfram Sang [vzapolskiy: added conditional pretimeout sysfs attribute visibility] Signed-off-by: Vladimir Zapolskiy Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/watchdog_dev.c | 56 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 040bf8382f46..4b381a6be2ff 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -335,16 +335,45 @@ static int watchdog_set_timeout(struct watchdog_device *wdd, if (watchdog_timeout_invalid(wdd, timeout)) return -EINVAL; - if (wdd->ops->set_timeout) + if (wdd->ops->set_timeout) { err = wdd->ops->set_timeout(wdd, timeout); - else + } else { wdd->timeout = timeout; + /* Disable pretimeout if it doesn't fit the new timeout */ + if (wdd->pretimeout >= wdd->timeout) + wdd->pretimeout = 0; + } watchdog_update_worker(wdd); return err; } +/* + * watchdog_set_pretimeout: set the watchdog timer pretimeout + * @wdd: the watchdog device to set the timeout for + * @timeout: pretimeout to set in seconds + */ + +static int watchdog_set_pretimeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + int err = 0; + + if (!(wdd->info->options & WDIOF_PRETIMEOUT)) + return -EOPNOTSUPP; + + if (watchdog_pretimeout_invalid(wdd, timeout)) + return -EINVAL; + + if (wdd->ops->set_pretimeout) + err = wdd->ops->set_pretimeout(wdd, timeout); + else + wdd->pretimeout = timeout; + + return err; +} + /* * watchdog_get_timeleft: wrapper to get the time left before a reboot * @wdd: the watchdog device to get the remaining time from @@ -429,6 +458,15 @@ static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(timeout); +static ssize_t pretimeout_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", wdd->pretimeout); +} +static DEVICE_ATTR_RO(pretimeout); + static ssize_t identity_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -459,6 +497,9 @@ static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr, if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft) mode = 0; + else if (attr == &dev_attr_pretimeout.attr && + !(wdd->info->options & WDIOF_PRETIMEOUT)) + mode = 0; return mode; } @@ -466,6 +507,7 @@ static struct attribute *wdt_attrs[] = { &dev_attr_state.attr, &dev_attr_identity.attr, &dev_attr_timeout.attr, + &dev_attr_pretimeout.attr, &dev_attr_timeleft.attr, &dev_attr_bootstatus.attr, &dev_attr_status.attr, @@ -646,6 +688,16 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, break; err = put_user(val, p); break; + case WDIOC_SETPRETIMEOUT: + if (get_user(val, p)) { + err = -EFAULT; + break; + } + err = watchdog_set_pretimeout(wdd, val); + break; + case WDIOC_GETPRETIMEOUT: + err = put_user(wdd->pretimeout, p); + break; default: err = -ENOTTY; break; -- cgit v1.2.3