From: minyard@acm.org To: Guenter Roeck <linux@roeck-us.net>, Wim Van Sebroeck <wim@linux-watchdog.org> Cc: linux-watchdog@vger.kernel.org, Gabriele Paoloni <gabriele.paoloni@intel.com>, Corey Minyard <cminyard@mvista.com> Subject: [PATCH 2/6] watchdog: Add ioctls for millisecond timeout handling Date: Sat, 20 Jun 2020 12:33:47 -0500 Message-ID: <20200620173351.18752-3-minyard@acm.org> (raw) In-Reply-To: <20200620173351.18752-1-minyard@acm.org> From: Corey Minyard <cminyard@mvista.com> Add millisecond ioctls for the five timeout ioctls in the watchdog. If the driver being used doesn't support milliseconds, the appropriate conversions are done. Signed-off-by: Corey Minyard <cminyard@mvista.com> --- drivers/watchdog/watchdog_core.c | 5 +- drivers/watchdog/watchdog_core.h | 2 + drivers/watchdog/watchdog_dev.c | 123 ++++++++++++++++++++++--------- include/uapi/linux/watchdog.h | 5 ++ 4 files changed, 98 insertions(+), 37 deletions(-) diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index b54451a9a336..9c531ae05c46 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c @@ -138,9 +138,8 @@ int watchdog_init_timeout(struct watchdog_device *wdd, &timeout_parm) == 0) { if (timeout_parm && !watchdog_timeout_invalid(wdd, timeout_parm)) { - if (!(wdd->info->options & WDIOF_MSECTIMER)) - /* Convert to msecs if not already so. */ - timeout_parm *= 1000; + timeout_parm = watchdog_timeout_tointernal(wdd, false, + timeout_parm); goto set_timeout; } diff --git a/drivers/watchdog/watchdog_core.h b/drivers/watchdog/watchdog_core.h index a5062e8e0d13..151806073d58 100644 --- a/drivers/watchdog/watchdog_core.h +++ b/drivers/watchdog/watchdog_core.h @@ -31,3 +31,5 @@ extern int watchdog_dev_register(struct watchdog_device *); extern void watchdog_dev_unregister(struct watchdog_device *); extern int __init watchdog_dev_init(void); extern void __exit watchdog_dev_exit(void); +extern unsigned int watchdog_timeout_tointernal(struct watchdog_device *, + bool, unsigned int); diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 480460b89c16..eca13ce1dc91 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -371,6 +371,56 @@ static unsigned int watchdog_get_status(struct watchdog_device *wdd) return status; } +/* + * watchdog_timeout_tointernal: Convert to internal time representation + * @wdd: the watchdog device + * @in_msecs: false - timeout in seconds, true - timeout in milliseconds + * @timeout: timeout to convert + * + * Convert from an external representation of the timeout in + * seconds (or milliseconds if in_msecs is true) to the internal + * timeout in seconds or milliseconds, depending on + * WDIOF_MSECTIMER. + */ +unsigned int watchdog_timeout_tointernal(struct watchdog_device *wdd, + bool in_msecs, + unsigned int timeout) +{ + if (wdd->info->options & WDIOF_MSECTIMER) { + if (!in_msecs) + timeout *= 1000; + } else if (in_msecs) { + /* Truncate up. */ + timeout = (timeout + 999) / 1000; + } + return timeout; +} + +/* + * watchdog_timeout_toexternal: Convert to external time representation + * @wdd: the watchdog device + * @in_msecs: false - returns seconds, true - returns milliseconds + * @timeout: timeout in seconds (or milliseconds if WDIOF_MSECTIMER is set) + * + * Convert from an internal representation of the timeout in + * seconds (or milliseconds if WDIOF_MSECTIMER is set) to the + * external timeout in seconds or milliseconds, depending on + * in_msecs. + */ +static unsigned int watchdog_timeout_toexternal(struct watchdog_device *wdd, + bool in_msecs, + unsigned int timeout) +{ + if (wdd->info->options & WDIOF_MSECTIMER) { + if (!in_msecs) + timeout /= 1000; + } else if (in_msecs) { + timeout *= 1000; + } + + return timeout; +} + /* * watchdog_set_timeout: set the watchdog timer timeout * @wdd: the watchdog device to set the timeout for @@ -379,7 +429,7 @@ static unsigned int watchdog_get_status(struct watchdog_device *wdd) * The caller must hold wd_data->lock. */ -static int watchdog_set_timeout(struct watchdog_device *wdd, +static int watchdog_set_timeout(struct watchdog_device *wdd, bool in_msecs, unsigned int timeout) { int err = 0; @@ -387,11 +437,13 @@ static int watchdog_set_timeout(struct watchdog_device *wdd, if (!(wdd->info->options & WDIOF_SETTIMEOUT)) return -EOPNOTSUPP; - if (watchdog_timeout_invalid(wdd, timeout)) + if (in_msecs) { + if (_watchdog_timeout_invalid(wdd, timeout)) + return -EINVAL; + } else if (watchdog_timeout_invalid(wdd, timeout)) return -EINVAL; - if (wdd->info->options & WDIOF_MSECTIMER) - timeout *= 1000; + timeout = watchdog_timeout_tointernal(wdd, in_msecs, timeout); if (wdd->ops->set_timeout) { err = wdd->ops->set_timeout(wdd, timeout); } else { @@ -413,6 +465,7 @@ static int watchdog_set_timeout(struct watchdog_device *wdd, */ static int watchdog_set_pretimeout(struct watchdog_device *wdd, + bool in_msecs, unsigned int timeout) { int err = 0; @@ -423,8 +476,7 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd, if (watchdog_pretimeout_invalid(wdd, timeout)) return -EINVAL; - if (wdd->info->options & WDIOF_MSECTIMER) - timeout *= 1000; + timeout = watchdog_timeout_tointernal(wdd, in_msecs, timeout); if (wdd->ops->set_pretimeout) err = wdd->ops->set_pretimeout(wdd, timeout); else @@ -443,7 +495,7 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd, * Get the time before a watchdog will reboot (if not pinged). */ -static int watchdog_get_timeleft(struct watchdog_device *wdd, +static int watchdog_get_timeleft(struct watchdog_device *wdd, bool in_msecs, unsigned int *timeleft) { *timeleft = 0; @@ -452,8 +504,7 @@ static int watchdog_get_timeleft(struct watchdog_device *wdd, return -EOPNOTSUPP; *timeleft = wdd->ops->get_timeleft(wdd); - if (wdd->info->options & WDIOF_MSECTIMER) - *timeleft /= 1000; + *timeleft = watchdog_timeout_toexternal(wdd, in_msecs, *timeleft); return 0; } @@ -520,13 +571,11 @@ static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr, unsigned int val; mutex_lock(&wd_data->lock); - status = watchdog_get_timeleft(wdd, &val); + status = watchdog_get_timeleft(wdd, false, &val); mutex_unlock(&wd_data->lock); - if (!status) { - if (wdd->info->options & WDIOF_MSECTIMER) - val /= 1000; - status = sprintf(buf, "%u\n", val); - } + if (!status) + status = sprintf(buf, "%u\n", + watchdog_timeout_toexternal(wdd, false, val)); return status; } @@ -536,12 +585,9 @@ static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct watchdog_device *wdd = dev_get_drvdata(dev); - unsigned int t = wdd->timeout; - if (wdd->info->options & WDIOF_MSECTIMER) - t /= 1000; - - return sprintf(buf, "%u\n", t); + return sprintf(buf, "%u\n", + watchdog_timeout_toexternal(wdd, false, wdd->timeout)); } static DEVICE_ATTR_RO(timeout); @@ -549,12 +595,10 @@ static ssize_t pretimeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct watchdog_device *wdd = dev_get_drvdata(dev); - unsigned int t = wdd->pretimeout; - - if (wdd->info->options & WDIOF_MSECTIMER) - t /= 1000; - return sprintf(buf, "%u\n", t); + return sprintf(buf, "%u\n", + watchdog_timeout_toexternal(wdd, false, + wdd->pretimeout)); } static DEVICE_ATTR_RO(pretimeout); @@ -788,11 +832,13 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, err = watchdog_ping(wdd); break; case WDIOC_SETTIMEOUT: + case WDIOC_SETTIMEOUT_MS: if (get_user(val, p)) { err = -EFAULT; break; } - err = watchdog_set_timeout(wdd, val); + err = watchdog_set_timeout(wdd, cmd == WDIOC_SETTIMEOUT_MS, + val); if (err < 0) break; /* If the watchdog is active then we send a keepalive ping @@ -803,33 +849,42 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, break; /* fall through */ case WDIOC_GETTIMEOUT: + case WDIOC_GETTIMEOUT_MS: /* timeout == 0 means that we don't know the timeout */ if (wdd->timeout == 0) { err = -EOPNOTSUPP; break; } - val = wdd->timeout; - if (wdd->info->options & WDIOF_MSECTIMER) - val /= 1000; + val = watchdog_timeout_toexternal(wdd, + (cmd == WDIOC_SETTIMEOUT_MS || + cmd == WDIOC_GETTIMEOUT_MS), + wdd->timeout); err = put_user(val, p); break; case WDIOC_GETTIMELEFT: - err = watchdog_get_timeleft(wdd, &val); + case WDIOC_GETTIMELEFT_MS: + err = watchdog_get_timeleft(wdd, cmd == WDIOC_GETTIMELEFT_MS, + &val); if (err < 0) break; err = put_user(val, p); break; case WDIOC_SETPRETIMEOUT: + case WDIOC_SETPRETIMEOUT_MS: if (get_user(val, p)) { err = -EFAULT; break; } - err = watchdog_set_pretimeout(wdd, val); + err = watchdog_set_pretimeout(wdd, + cmd == WDIOC_SETPRETIMEOUT_MS, + val); break; case WDIOC_GETPRETIMEOUT: - val = wdd->pretimeout; - if (wdd->info->options & WDIOF_MSECTIMER) - val /= 1000; + case WDIOC_GETPRETIMEOUT_MS: + val = watchdog_timeout_toexternal(wdd, + (cmd == WDIOC_SETPRETIMEOUT_MS || + cmd == WDIOC_GETPRETIMEOUT_MS), + wdd->pretimeout); err = put_user(val, p); break; default: diff --git a/include/uapi/linux/watchdog.h b/include/uapi/linux/watchdog.h index feb3bcc46993..3df7880c6fca 100644 --- a/include/uapi/linux/watchdog.h +++ b/include/uapi/linux/watchdog.h @@ -32,6 +32,11 @@ struct watchdog_info { #define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int) #define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int) #define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int) +#define WDIOC_SETTIMEOUT_MS _IOWR(WATCHDOG_IOCTL_BASE, 11, int) +#define WDIOC_GETTIMEOUT_MS _IOR(WATCHDOG_IOCTL_BASE, 12, int) +#define WDIOC_SETPRETIMEOUT_MS _IOWR(WATCHDOG_IOCTL_BASE, 13, int) +#define WDIOC_GETPRETIMEOUT_MS _IOR(WATCHDOG_IOCTL_BASE, 14, int) +#define WDIOC_GETTIMELEFT_MS _IOR(WATCHDOG_IOCTL_BASE, 15, int) #define WDIOF_UNKNOWN -1 /* Unknown flag error */ #define WDIOS_UNKNOWN -1 /* Unknown status error */ -- 2.17.1
next prev parent reply index Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-06-20 17:33 [PATCH 0/6] watchdog: Add millisecond-level capabilities minyard 2020-06-20 17:33 ` [PATCH 1/6] watchdog: Allow a driver to use milliseconds instead of seconds minyard 2020-06-26 23:10 ` Guenter Roeck 2020-06-27 2:18 ` Corey Minyard 2020-06-27 4:08 ` Guenter Roeck 2020-06-28 14:54 ` Guenter Roeck 2020-06-28 17:56 ` Corey Minyard 2020-12-01 22:54 ` Corey Minyard 2020-12-01 23:43 ` Guenter Roeck 2020-06-20 17:33 ` minyard [this message] 2020-06-20 17:33 ` [PATCH 3/6] watchdog: Add millisecond precision device attributes minyard 2020-06-20 17:33 ` [PATCH 4/6] watchdog: Add documentation for millisecond interfaces minyard 2020-06-20 17:33 ` [PATCH 5/6] watchdog:i6300: Convert to a millisecond watchdog device minyard 2020-06-20 17:33 ` [PATCH 6/6] watchdog:softdog: Convert to a millisecond watchdog minyard
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=20200620173351.18752-3-minyard@acm.org \ --to=minyard@acm.org \ --cc=cminyard@mvista.com \ --cc=gabriele.paoloni@intel.com \ --cc=linux-watchdog@vger.kernel.org \ --cc=linux@roeck-us.net \ --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
Linux-Watchdog Archive on lore.kernel.org Archives are clonable: git clone --mirror https://lore.kernel.org/linux-watchdog/0 linux-watchdog/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 linux-watchdog linux-watchdog/ https://lore.kernel.org/linux-watchdog \ linux-watchdog@vger.kernel.org public-inbox-index linux-watchdog Example config snippet for mirrors Newsgroup available over NNTP: nntp://nntp.lore.kernel.org/org.kernel.vger.linux-watchdog AGPL code for this site: git clone https://public-inbox.org/public-inbox.git