diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/ddb/db_command.c | 8 | ||||
-rw-r--r-- | sys/dev/watchdog/watchdog.c | 64 | ||||
-rw-r--r-- | sys/sys/watchdog.h | 9 |
3 files changed, 60 insertions, 21 deletions
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c index d8c8cb0..21cb7c5 100644 --- a/sys/ddb/db_command.c +++ b/sys/ddb/db_command.c @@ -724,14 +724,6 @@ db_watchdog(dummy1, dummy2, dummy3, dummy4) } else if ((tout & WD_INTERVAL) == WD_TO_NEVER) { db_error("Out of range watchdog interval\n"); return; - } else { - - /* - * XXX: Right now we only support WD_ACTIVE, in the future we - * may be possibly needing a more convoluted function for - * dealing with different cases. - */ - tout |= WD_ACTIVE; } EVENTHANDLER_INVOKE(watchdog_list, tout, &i); } diff --git a/sys/dev/watchdog/watchdog.c b/sys/dev/watchdog/watchdog.c index 06498c9..e7edf31 100644 --- a/sys/dev/watchdog/watchdog.c +++ b/sys/dev/watchdog/watchdog.c @@ -40,35 +40,73 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> static struct cdev *wd_dev; +static volatile u_int wd_last_u; + +static int +kern_do_pat(u_int utim) +{ + int error; + + if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0) + return (EINVAL); + + if ((utim & WD_LASTVAL) != 0) { + MPASS((wd_last_u & ~WD_INTERVAL) == 0); + utim &= ~WD_LASTVAL; + utim |= wd_last_u; + } else + wd_last_u = (utim & WD_INTERVAL); + if ((utim & WD_INTERVAL) == WD_TO_NEVER) { + utim = 0; + + /* Assume all is well; watchdog signals failure. */ + error = 0; + } else { + /* Assume no watchdog available; watchdog flags success */ + error = EOPNOTSUPP; + } + EVENTHANDLER_INVOKE(watchdog_list, utim, &error); + return (error); +} static int wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags __unused, struct thread *td) { - int error; u_int u; if (cmd != WDIOCPATPAT) return (ENOIOCTL); u = *(u_int *)data; - if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_INTERVAL)) + if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_LASTVAL | WD_INTERVAL)) return (EINVAL); if ((u & (WD_ACTIVE | WD_PASSIVE)) == (WD_ACTIVE | WD_PASSIVE)) return (EINVAL); - if ((u & (WD_ACTIVE | WD_PASSIVE)) == 0 && (u & WD_INTERVAL) > 0) + if ((u & (WD_ACTIVE | WD_PASSIVE)) == 0 && ((u & WD_INTERVAL) > 0 || + (u & WD_LASTVAL) != 0)) return (EINVAL); if (u & WD_PASSIVE) return (ENOSYS); /* XXX Not implemented yet */ - if ((u & WD_INTERVAL) == WD_TO_NEVER) { - u = 0; - /* Assume all is well; watchdog signals failure. */ - error = 0; - } else { - /* Assume no watchdog available; watchdog flags success */ - error = EOPNOTSUPP; - } - EVENTHANDLER_INVOKE(watchdog_list, u, &error); - return (error); + u &= ~(WD_ACTIVE | WD_PASSIVE); + + return (kern_do_pat(u)); +} + +u_int +wdog_kern_last_timeout(void) +{ + + return (wd_last_u); +} + +int +wdog_kern_pat(u_int utim) +{ + + if (utim & ~(WD_LASTVAL | WD_INTERVAL)) + return (EINVAL); + + return (kern_do_pat(utim)); } static struct cdevsw wd_cdevsw = { diff --git a/sys/sys/watchdog.h b/sys/sys/watchdog.h index 9410775..ba58a7c 100644 --- a/sys/sys/watchdog.h +++ b/sys/sys/watchdog.h @@ -50,6 +50,12 @@ * right to the kernel. */ +#define WD_LASTVAL 0x0200000 + /* + * Use the already last used timeout value. + * The kernel will use as timeout the last valid timeout provided. + */ + #define WD_INTERVAL 0x00000ff /* * Mask for duration bits. @@ -78,6 +84,9 @@ typedef void (*watchdog_fn)(void *, u_int, int *); EVENTHANDLER_DECLARE(watchdog_list, watchdog_fn); + +u_int wdog_kern_last_timeout(void); +int wdog_kern_pat(u_int utim); #endif #endif /* _SYS_WATCHDOG_H */ |