diff mbox series

[10/12] watchdog: Add a way to set the governor through the ioctl

Message ID 20190819203711.32599-11-minyard@acm.org (mailing list archive)
State Changes Requested
Headers show
Series [01/12] watchdog: NULL the default governor if it is unregistered | expand

Commit Message

Corey Minyard Aug. 19, 2019, 8:37 p.m. UTC
From: Corey Minyard <cminyard@mvista.com>

The watchdog governor could only be set through the systfs interface
before, make that function available through the ioctl, too.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 Documentation/watchdog/watchdog-api.rst | 31 +++++++++++++++++++++++++
 drivers/watchdog/watchdog_dev.c         | 14 +++++++++++
 drivers/watchdog/watchdog_pretimeout.h  |  2 +-
 include/uapi/linux/watchdog.h           |  8 +++++++
 4 files changed, 54 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/Documentation/watchdog/watchdog-api.rst b/Documentation/watchdog/watchdog-api.rst
index 927be9e56b5d..a2a3057e2b5d 100644
--- a/Documentation/watchdog/watchdog-api.rst
+++ b/Documentation/watchdog/watchdog-api.rst
@@ -177,6 +177,37 @@  and queried::
 Note that the pretimeout governor that reads data is not compatible with
 the NMI preaction.  The NMI preaction can only do nothing or panic.
 
+Pretimeout Governors
+====================
+
+When a pretimeout occurs and the pretimeout framework is compiled in
+to the kernel, the pretimeout framework will generally be called.
+(The exception is that NMI pretimeouts do not call the pretimeout
+framework because they need special handling.)  Several pretimeout
+governers can be registered::
+
+    noop - Don't do anything on a pretimeout
+    panic - Issue a panic when a pretimeout occurs.  This is generally the
+            default
+    read_data - Provide one byte of data on the read interface to the
+                watchdog timer.  This way a userland program can handle
+		the pretimeout.
+
+If the CONFING_WATCHDOG_SYSFS is enabled, the pretimeout governor can
+be set by writing the value to the
+/sys/class/watchdog/watchdog<n>/pretimeout_governor sysfs file.
+
+The pretimeout governor can also be set through the ioctl interface with::
+
+    char governor[WATCHDOG_GOV_NAME_MAXLEN] = "panic";
+    ioctl(fd, WDIOC_SETPREGOV, gov);
+
+and can be queried with::
+
+    char governor[WATCHDOG_GOV_NAME_MAXLEN];
+    ioctl(fd, WDIOC_GETPREGOV, gov);
+    printf("The governor is %s\n", gov);
+
 Get the number of seconds before reboot
 =======================================
 
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 0e70f510a491..7e1ad6e303d0 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -762,6 +762,7 @@  static long watchdog_ioctl(struct file *file, unsigned int cmd,
 	int __user *p = argp;
 	unsigned int val;
 	int err;
+	char gov[WATCHDOG_GOV_NAME_MAXLEN];
 
 	mutex_lock(&wd_data->lock);
 
@@ -866,6 +867,19 @@  static long watchdog_ioctl(struct file *file, unsigned int cmd,
 	case WDIOC_GETPREACTION:
 		err = put_user(wdd->preaction, p);
 		break;
+	case WDIOC_SETPREGOV:
+		err = strncpy_from_user(gov, argp, sizeof(gov));
+		if (err >= 0)
+			err = watchdog_pretimeout_governor_set(wdd, gov);
+		break;
+	case WDIOC_GETPREGOV:
+		err = 0;
+		val = watchdog_pretimeout_governor_get(wdd, gov);
+		if (val == 0)
+			err = -ENOENT;
+		if (copy_to_user(argp, gov, val + 1))
+			err = -EFAULT;
+		break;
 	default:
 		err = -ENOTTY;
 		break;
diff --git a/drivers/watchdog/watchdog_pretimeout.h b/drivers/watchdog/watchdog_pretimeout.h
index 819517ed0138..e6e191b787bb 100644
--- a/drivers/watchdog/watchdog_pretimeout.h
+++ b/drivers/watchdog/watchdog_pretimeout.h
@@ -2,7 +2,7 @@ 
 #ifndef __WATCHDOG_PRETIMEOUT_H
 #define __WATCHDOG_PRETIMEOUT_H
 
-#define WATCHDOG_GOV_NAME_MAXLEN	20
+#include <uapi/linux/watchdog.h>
 
 struct watchdog_device;
 
diff --git a/include/uapi/linux/watchdog.h b/include/uapi/linux/watchdog.h
index bf13cf25f9e0..2acbfff6db8c 100644
--- a/include/uapi/linux/watchdog.h
+++ b/include/uapi/linux/watchdog.h
@@ -36,10 +36,18 @@  struct watchdog_info {
 #define	WDIOC_GETACTION		_IOR(WATCHDOG_IOCTL_BASE, 12, int)
 #define	WDIOC_SETPREACTION	_IOWR(WATCHDOG_IOCTL_BASE, 13, int)
 #define	WDIOC_GETPREACTION	_IOR(WATCHDOG_IOCTL_BASE, 14, int)
+#define	WDIOC_SETPREGOV		_IOWR(WATCHDOG_IOCTL_BASE, 15, char)
+#define	WDIOC_GETPREGOV		_IOR(WATCHDOG_IOCTL_BASE, 16, char)
 
 #define	WDIOF_UNKNOWN		-1	/* Unknown flag error */
 #define	WDIOS_UNKNOWN		-1	/* Unknown status error */
 
+/*
+ * Buffer for WDIOC_GETPREGOV must be at least this big.  WDIOC_SETPRGOV
+ * will take at max this many bytes - 1, excess will be ignored.
+ */
+#define WATCHDOG_GOV_NAME_MAXLEN	20
+
 #define	WDIOF_OVERHEAT		0x0001	/* Reset due to CPU overheat */
 #define	WDIOF_FANFAULT		0x0002	/* Fan failed */
 #define	WDIOF_EXTERN1		0x0004	/* External relay 1 */