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 [thread overview]
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 other threads:[~2020-06-20 17:35 UTC|newest]
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
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.