svn commit: r245833 - in user/alfred/ewatchdog/sys: dev/watchdog sys
Alfred Perlstein
alfred at FreeBSD.org
Wed Jan 23 02:29:06 UTC 2013
Author: alfred
Date: Wed Jan 23 02:29:05 2013
New Revision: 245833
URL: http://svnweb.freebsd.org/changeset/base/245833
Log:
Implement part of Linux's watchdog API.
ioctls added:
WDIOC_GETTIMELEFT - seconds until watchdog goes off
WDIOC_SETTIMEOUT - set the timeout (nearly the same as WDIOCPATPAT)
WDIOC_GETTIMEOUT - get the timeout/interval
This will allow us to craft a utility to bark when
the timeout is about to expire and otherwise gather
information about pending watchdogs.
Modified:
user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c
user/alfred/ewatchdog/sys/sys/watchdog.h
Modified: user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c
==============================================================================
--- user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c Wed Jan 23 02:06:20 2013 (r245832)
+++ user/alfred/ewatchdog/sys/dev/watchdog/watchdog.c Wed Jan 23 02:29:05 2013 (r245833)
@@ -39,8 +39,13 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <machine/bus.h>
+#include <sys/syscallsubr.h> /* kern_clock_gettime() */
+
static struct cdev *wd_dev;
-static volatile u_int wd_last_u;
+static volatile u_int wd_last_u; /* last timeout value set by kern_do_pat */
+
+static int wd_lastpat_valid = 0;
+static time_t wd_lastpat = 0; /* when the watchdog was last patted */
static int
kern_do_pat(u_int utim)
@@ -51,11 +56,20 @@ kern_do_pat(u_int utim)
return (EINVAL);
if ((utim & WD_LASTVAL) != 0) {
+ /*
+ * if WD_LASTVAL is set, fill in the bits for timeout
+ * from the saved value in wd_last_u.
+ */
MPASS((wd_last_u & ~WD_INTERVAL) == 0);
utim &= ~WD_LASTVAL;
utim |= wd_last_u;
- } else
+ } else {
+ /*
+ * Otherwise save the new interval.
+ * This can be zero (to disable the watchdog)
+ */
wd_last_u = (utim & WD_INTERVAL);
+ }
if ((utim & WD_INTERVAL) == WD_TO_NEVER) {
utim = 0;
@@ -66,17 +80,28 @@ kern_do_pat(u_int utim)
error = EOPNOTSUPP;
}
EVENTHANDLER_INVOKE(watchdog_list, utim, &error);
+ /*
+ * If we were able to arm/strobe the watchdog, then
+ * update the last time it was strobed for WDIOC_GETTIMELEFT
+ */
+ if (!error) {
+ struct timespec ts;
+
+ error = kern_clock_gettime(curthread /* XXX */,
+ CLOCK_MONOTONIC_FAST, &ts);
+ if (!error) {
+ wd_lastpat = ts.tv_sec;
+ wd_lastpat_valid = 1;
+ }
+ }
return (error);
}
static int
-wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
- int flags __unused, struct thread *td)
+wd_ioctl_patpat(caddr_t data)
{
u_int u;
- if (cmd != WDIOCPATPAT)
- return (ENOIOCTL);
u = *(u_int *)data;
if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_LASTVAL | WD_INTERVAL))
return (EINVAL);
@@ -92,6 +117,57 @@ wd_ioctl(struct cdev *dev __unused, u_lo
return (kern_do_pat(u));
}
+static int
+wd_get_time_left(struct thread *td, time_t *remainp)
+{
+ struct timespec ts;
+ int error;
+
+ error = kern_clock_gettime(td, CLOCK_MONOTONIC_FAST, &ts);
+ if (error)
+ return (error);
+ if (!wd_lastpat_valid)
+ return (ENOENT);
+ *remainp = ts.tv_sec - wd_lastpat;
+ return (0);
+}
+
+static int
+wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
+ int flags __unused, struct thread *td)
+{
+ u_int u;
+ time_t timeleft;
+ int error;
+
+ error = 0;
+
+ switch (cmd) {
+ case WDIOC_GETTIMELEFT:
+ error = wd_get_time_left(td, &timeleft);
+ if (error)
+ break;
+ *(int *)data = (int)timeleft;
+ break;
+ case WDIOC_SETTIMEOUT:
+ u = *(u_int *)data;
+ error = wdog_kern_pat(u);
+ break;
+ case WDIOC_GETTIMEOUT:
+ u = wdog_kern_last_timeout();
+ *(u_int *)data = u;
+ break;
+ case WDIOCPATPAT:
+ error = wd_ioctl_patpat(data);
+ break;
+ default:
+ error = ENOIOCTL;
+ break;
+ }
+ return (error);
+}
+
+
u_int
wdog_kern_last_timeout(void)
{
Modified: user/alfred/ewatchdog/sys/sys/watchdog.h
==============================================================================
--- user/alfred/ewatchdog/sys/sys/watchdog.h Wed Jan 23 02:06:20 2013 (r245832)
+++ user/alfred/ewatchdog/sys/sys/watchdog.h Wed Jan 23 02:29:05 2013 (r245833)
@@ -33,6 +33,9 @@
#define _PATH_WATCHDOG "fido"
#define WDIOCPATPAT _IOW('W', 42, u_int)
+#define WDIOC_SETTIMEOUT _IOW('W', 43, int)
+#define WDIOC_GETTIMEOUT _IOR('W', 44, int)
+#define WDIOC_GETTIMELEFT _IOR('W', 45, int)
#define WD_ACTIVE 0x8000000
/*
More information about the svn-src-user
mailing list