git: 69f7d6912a24 - main - watchdog: Add a new "Control" ioctl

From: Justin Hibbits <jhibbits_at_FreeBSD.org>
Date: Thu, 14 Aug 2025 19:03:08 UTC
The branch main has been updated by jhibbits:

URL: https://cgit.FreeBSD.org/src/commit/?id=69f7d6912a24d3caab4957a33e07529275cf4d09

commit 69f7d6912a24d3caab4957a33e07529275cf4d09
Author:     Justin Hibbits <jhibbits@FreeBSD.org>
AuthorDate: 2025-02-26 20:17:24 +0000
Commit:     Justin Hibbits <jhibbits@FreeBSD.org>
CommitDate: 2025-08-14 19:02:46 +0000

    watchdog: Add a new "Control" ioctl
    
    Summary:
    In preparation for a new watchdog timeout interface using sbintime_t,
    add a new control ioctl to arm, pat, and disarm the watchdog.
    
    Reviewed by:    jhb, phk
    Sponsored by:   Juniper Networks, Inc.
    Differential Revision: https://reviews.freebsd.org/D49182
---
 sys/dev/watchdog/watchdog.c    | 20 ++++++++++++++++++++
 sys/sys/watchdog.h             |  8 ++++++++
 usr.sbin/watchdogd/watchdogd.c | 13 +++++++++++--
 3 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/sys/dev/watchdog/watchdog.c b/sys/dev/watchdog/watchdog.c
index e6b6dc1eac70..c0babef1b29b 100644
--- a/sys/dev/watchdog/watchdog.c
+++ b/sys/dev/watchdog/watchdog.c
@@ -117,6 +117,23 @@ seconds_to_pow2ns(int seconds)
 	return (power);
 }
 
+int
+wdog_control(int ctrl)
+{
+	/* Disable takes precedence */
+	if (ctrl == WD_CTRL_DISABLE) {
+		wdog_kern_pat(0);
+	}
+
+	if ((ctrl & WD_CTRL_RESET) != 0) {
+		wdog_kern_pat(WD_ACTIVE | WD_LASTVAL);
+	} else if ((ctrl & WD_CTRL_ENABLE) != 0) {
+		wdog_kern_pat(WD_ACTIVE | WD_LASTVAL);
+	}
+
+	return (0);
+}
+
 int
 wdog_kern_pat(u_int utim)
 {
@@ -374,6 +391,9 @@ wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
 	case WDIOCPATPAT:
 		error = wd_ioctl_patpat(data);
 		break;
+	case WDIOC_CONTROL:
+		wdog_control(*(int *)data);
+		break;
 	default:
 		error = ENOIOCTL;
 		break;
diff --git a/sys/sys/watchdog.h b/sys/sys/watchdog.h
index 4a16b18509f5..3c9d31eb577b 100644
--- a/sys/sys/watchdog.h
+++ b/sys/sys/watchdog.h
@@ -48,6 +48,8 @@
 #define WDIOC_SETSOFT	_IOW('W', 49, int)
 #define WDIOC_SETSOFTTIMEOUTACT	_IOW('W', 50, int)
 
+#define	WDIOC_CONTROL		_IOW('W', 51, int)	/* configure watchdog */
+
 #define WD_ACTIVE	0x8000000
 	/* 
 	 * Watchdog reset, timeout set to value in WD_INTERVAL field.
@@ -93,6 +95,11 @@
 #define WD_TO_64SEC	36
 #define WD_TO_128SEC	37
 
+/* Control options for WDIOC_CONTROL */
+#define	WD_CTRL_DISABLE	0x00000000
+#define	WD_CTRL_ENABLE	0x00000001
+#define	WD_CTRL_RESET	0x00000002
+
 /* action on pre-timeout trigger */
 #define	WD_SOFT_PANIC	0x01	/* panic */
 #define	WD_SOFT_DDB	0x02	/* enter debugger */
@@ -110,6 +117,7 @@ EVENTHANDLER_DECLARE(watchdog_list, watchdog_fn);
 
 u_int	wdog_kern_last_timeout(void);
 int	wdog_kern_pat(u_int utim);
+int		wdog_control(int ctrl);
 
 /*
  * The following function pointer is used to attach a software watchdog
diff --git a/usr.sbin/watchdogd/watchdogd.c b/usr.sbin/watchdogd/watchdogd.c
index 88b467486da1..228438955006 100644
--- a/usr.sbin/watchdogd/watchdogd.c
+++ b/usr.sbin/watchdogd/watchdogd.c
@@ -396,6 +396,15 @@ watchdog_patpat(u_int t)
 	return ioctl(fd, WDIOCPATPAT, &t);
 }
 
+static int
+watchdog_control(u_int control)
+{
+	if (is_dry_run)
+		return (0);
+
+	return ioctl(fd, WDIOC_CONTROL, &control);
+}
+
 /*
  * Toggle the kernel's watchdog. This routine is used to enable and
  * disable the watchdog.
@@ -454,10 +463,10 @@ watchdog_onoff(int onoff)
 		/* pat one more time for good measure */
 		return watchdog_patpat((timeout|WD_ACTIVE));
 	 } else {
-		return watchdog_patpat(exit_timeout);
+		return watchdog_control(WD_CTRL_DISABLE);
 	 }
 failsafe:
-	watchdog_patpat(exit_timeout);
+	watchdog_control(WD_CTRL_DISABLE);
 	return (error);
 }