Align the interfaces for the various watchdogs and make the interface
behave as expected. Also: - Return an error if WD_PASSIVE is passed in to the ioctl as only WD_ACTIVE is implemented at the moment. See sys/watchdog.h for an explanation of the difference between WD_ACTIVE and WD_PASSIVE. - Remove the I_HAVE_TOTALLY_LOST_MY_SENSE_OF_HUMOR define. If you've lost your sense of humor, than don't add a define. Specific changes: i80321_wdog.c Don't roll your own passive watchdog tickle as this would defeat the purpose of an active (userland) watchdog tickle. ichwd.c / ipmi.c: WD_ACTIVE means active patting of the watchdog by a userland process, not whether the watchdog is active. See sys/watchdog.h. kern_clock.c: (software watchdog) Remove a check for WD_ACTIVE as this does not make sense here. This reverts r1.181.
This commit is contained in:
parent
2cd19db26a
commit
9079fff550
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=165260
@ -516,6 +516,7 @@ MLINKS+=wb.4 if_wb.4
|
||||
MLINKS+=wi.4 if_wi.4
|
||||
MLINKS+=xe.4 if_xe.4
|
||||
MLINKS+=xl.4 if_xl.4
|
||||
MLINKS+=watchdog.4 SW_WATCHDOG.4
|
||||
|
||||
.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386"
|
||||
_acpi_dock.4= acpi_dock.4
|
||||
|
@ -32,54 +32,95 @@
|
||||
.Nm watchdog
|
||||
.Nd "hardware and software watchdog"
|
||||
.Sh SYNOPSIS
|
||||
.Cd "options CPU_ELAN"
|
||||
.Cd "options CPU_GEODE"
|
||||
.Cd "options SW_WATCHDOG"
|
||||
.Pp
|
||||
.In sys/watchdog.h
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
facility is used for controlling hardware and software watchdogs.
|
||||
.Pp
|
||||
The interface is through a device
|
||||
.Pa /dev/fido
|
||||
which responds to a single
|
||||
responds to a single
|
||||
.Xr ioctl 2
|
||||
call,
|
||||
.Dv WDIOCPATPAT .
|
||||
It takes a single argument which represents a timeout value specified as a
|
||||
power of two nanoseconds, or-ed with a flag selecting active or passive control
|
||||
of the watchdog.
|
||||
.Pp
|
||||
The call takes a single argument which represents a timeout value
|
||||
specified as an integer power of two nanoseconds.
|
||||
.Pp
|
||||
The
|
||||
.Dv WD_ACTIVE
|
||||
flag signals that the
|
||||
indicates that the
|
||||
.Nm
|
||||
will be kept from
|
||||
timing out from userland, for instance by the
|
||||
will be kept from timing out from userland, for instance by the
|
||||
.Xr watchdogd 8
|
||||
daemon.
|
||||
.Pp
|
||||
To disable the watchdogs, an argument of zero should be used.
|
||||
.Dv WD_PASSIVE
|
||||
indicates that the
|
||||
.Nm
|
||||
will be kept from timing out from the kernel.
|
||||
.Pp
|
||||
The
|
||||
.Xr ioctl 2
|
||||
call will return success if just one of the available
|
||||
.Xr watchdog 9
|
||||
implementations support the request.
|
||||
If the call fails, for instance if none of
|
||||
implementations supports setting the timeout to the specified timeout. This
|
||||
means that at least one watchdog is armed. If the call fails, for instance if
|
||||
none of
|
||||
.Xr watchdog 9
|
||||
implementations support the timeout
|
||||
length, all watchdogs are disabled and must be explicitly re-enabled.
|
||||
implementations support the timeout length, all watchdogs are disabled and must
|
||||
be explicitly re-enabled.
|
||||
.Pp
|
||||
To disable the watchdogs pass
|
||||
.Dv WD_TO_NEVER .
|
||||
If disarming the watchdog(s) failed an error is returned. The watchdog might
|
||||
still be armed!
|
||||
.Sh RETURN VALUES
|
||||
The ioctl returns zero on success and non-zero on failure.
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EOPNOTSUPP
|
||||
No watchdog present in the kernel (timeout value other than 0).
|
||||
.It Bq Er EOPNOTSUPP
|
||||
Watchdog could not be disabled (timeout value of 0).
|
||||
.It Bq Er EINVALID
|
||||
Invalid flag combination passed.
|
||||
.It Bq Er EINVALID
|
||||
None of the watchdogs supports the requested timeout value.
|
||||
.Sh EXAMPLES
|
||||
.\" XXX insert some descriptive text here
|
||||
.Bd -literal -offset indent
|
||||
u_int u = WD_ACTIVE | WD_TO_8SEC;
|
||||
int fd = open("/dev/fido", O_RDWR);
|
||||
#include <paths.h>
|
||||
#include <sys/watchdog.h>
|
||||
|
||||
ioctl(fd, WDIOCPATPAT, &u);
|
||||
#define WDPATH "/dev/" _PATH_WATCHDOG
|
||||
int wdfd = -1;
|
||||
|
||||
static void
|
||||
wd_init(void)
|
||||
{
|
||||
wdfd = open(WDPATH, O_RDWR);
|
||||
if (wdfd == -1)
|
||||
err(1, WDPATH);
|
||||
}
|
||||
static void
|
||||
wd_reset(u_int timeout)
|
||||
{
|
||||
if (ioctl(wdfd, WDIOCPATPAT, &timeout) == -1)
|
||||
err(1, "WDIOCPATPAT");
|
||||
}
|
||||
|
||||
/* in main() */
|
||||
wd_init();
|
||||
wd_reset(WD_ACTIVE|WD_TO_8SEC);
|
||||
/* potential freeze point */
|
||||
wd_reset(WD_TO_NEVER);
|
||||
.Ed
|
||||
.Pp
|
||||
Enables a watchdog to recover from a potentially freezing piece of code.
|
||||
.Pp
|
||||
.Bd -literal -offset indent
|
||||
options SW_WATCHDOG
|
||||
.Ed
|
||||
.Pp
|
||||
in your kernel config adds a software watchdog in the kernel, dropping to KDB
|
||||
or panic-ing when firing.
|
||||
.Sh SEE ALSO
|
||||
.Xr watchdogd 8 ,
|
||||
.Xr watchdog 9
|
||||
@ -88,14 +129,17 @@ The
|
||||
.Nm
|
||||
code first appeared in
|
||||
.Fx 5.1 .
|
||||
.Sh BUGS
|
||||
The
|
||||
.Dv WD_PASSIVE
|
||||
option has not yet been implemented.
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm
|
||||
facility was written by
|
||||
.An Poul-Henning Kamp Aq phk@FreeBSD.org .
|
||||
The software watchdog code
|
||||
and this manual page were written by
|
||||
The software watchdog code and this manual page were written by
|
||||
.An Sean Kelly Aq smkelly@FreeBSD.org .
|
||||
Some contributions were made by
|
||||
.An Jeff Roberson Aq jeff@FreeBSD.org .
|
||||
|
@ -35,6 +35,7 @@
|
||||
.Ft void
|
||||
.Fn watchdog_fn "void *private" "u_int cmd" "int *error"
|
||||
.Fn EVENTHANDLER_REGISTER watchdog_list watchdog_fn private 0
|
||||
.Fn EVENTHANDLER_DEREGISTER watchdog_list eventhandler_tag
|
||||
.Sh DESCRIPTION
|
||||
To implement a watchdog in software or hardware, only a single
|
||||
function needs to be written and registered on the global
|
||||
@ -60,7 +61,12 @@ argument be set to zero.
|
||||
If the watchdog cannot be configured to the proposed timeout, it
|
||||
must be disabled and the
|
||||
.Fa error
|
||||
argument left untouched.
|
||||
argument set to
|
||||
.Dv EINVAL .
|
||||
If the watchdog cannot be disabled, the
|
||||
.Fa error
|
||||
argument must be set to
|
||||
.Dv EOPNOTSUPP .
|
||||
.Pp
|
||||
There is no specification of what the watchdog should do when it
|
||||
times out, but a hardware reset or similar
|
||||
|
@ -170,10 +170,15 @@ at91st_watchdog(void *argp, u_int cmd, int *error)
|
||||
uint32_t wdog;
|
||||
int t;
|
||||
|
||||
wdog = 0;
|
||||
t = cmd & WD_INTERVAL;
|
||||
if (cmd != 0 && t >= 22 && t <= 37)
|
||||
if (cmd > 0 && t >= 22 && t <= 37) {
|
||||
wdog = (1 << (t - 22)) | ST_WDMR_RSTEN;
|
||||
*error = 0;
|
||||
} else {
|
||||
wdog = 0;
|
||||
if (cmd > 0)
|
||||
*error = EINVAL;
|
||||
}
|
||||
WR4(ST_WDMR, wdog);
|
||||
WR4(ST_CR, ST_CR_WDRST);
|
||||
}
|
||||
|
@ -62,7 +62,6 @@ struct iopwdog_softc {
|
||||
device_t dev;
|
||||
int armed;
|
||||
int wdog_period;
|
||||
struct callout_handle wdog_callout;
|
||||
};
|
||||
|
||||
static __inline void
|
||||
@ -83,8 +82,6 @@ iopwdog_tickle(void *arg)
|
||||
return;
|
||||
wdtcr_write(WDTCR_ENABLE1);
|
||||
wdtcr_write(WDTCR_ENABLE2);
|
||||
sc->wdog_callout = timeout(iopwdog_tickle, sc,
|
||||
hz * (sc->wdog_period - 1));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -112,14 +109,21 @@ iopwdog_watchdog_fn(void *private, u_int cmd, int *error)
|
||||
{
|
||||
struct iopwdog_softc *sc = private;
|
||||
|
||||
if (cmd == 0)
|
||||
return;
|
||||
if ((((uint64_t)1 << (cmd & WD_INTERVAL))) >
|
||||
(uint64_t)sc->wdog_period * 1000000000)
|
||||
return;
|
||||
sc->armed = 1;
|
||||
iopwdog_tickle(sc);
|
||||
*error = 0;
|
||||
cmd &= WD_INTERVAL;
|
||||
if (cmd > 0 && cmd <= 63
|
||||
&& (uint64_t)1 << (cmd & WD_INTERVAL) <=
|
||||
(uint64_t)sc->wdog_period * 1000000000) {
|
||||
/* Valid value -> Enable watchdog */
|
||||
iopwdog_tickle(sc);
|
||||
sc->armed = 1;
|
||||
*error = 0;
|
||||
} else {
|
||||
/* XXX Can't disable this watchdog? */
|
||||
if (sc->armed)
|
||||
*error = EOPNOTSUPP;
|
||||
else if (cmd > 0)
|
||||
*error = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -178,38 +178,22 @@ ichwd_event(void *arg, unsigned int cmd, int *error)
|
||||
struct ichwd_softc *sc = arg;
|
||||
unsigned int timeout;
|
||||
|
||||
/* convert from power-of-two-ns to WDT ticks */
|
||||
cmd &= WD_INTERVAL;
|
||||
timeout = ((uint64_t)1 << cmd) / ICHWD_TICK;
|
||||
if (cmd > 0 && cmd <= 63
|
||||
&& timeout >= ICHWD_MIN_TIMEOUT && timeout <= ICHWD_MAX_TIMEOUT) {
|
||||
if (timeout != sc->timeout)
|
||||
ichwd_tmr_set(sc, timeout);
|
||||
|
||||
/* disable / enable */
|
||||
if (!(cmd & WD_ACTIVE)) {
|
||||
ichwd_tmr_reload(sc);
|
||||
*error = 0;
|
||||
} else {
|
||||
if (sc->active)
|
||||
ichwd_tmr_disable(sc);
|
||||
*error = 0;
|
||||
return;
|
||||
if (cmd > 0)
|
||||
*error = EINVAL;
|
||||
}
|
||||
if (!sc->active)
|
||||
ichwd_tmr_enable(sc);
|
||||
|
||||
cmd &= WD_INTERVAL;
|
||||
/* convert from power-of-to-ns to WDT ticks */
|
||||
if (cmd >= 64) {
|
||||
*error = EINVAL;
|
||||
return;
|
||||
}
|
||||
timeout = ((uint64_t)1 << cmd) / ICHWD_TICK;
|
||||
if (timeout < ICHWD_MIN_TIMEOUT || timeout > ICHWD_MAX_TIMEOUT) {
|
||||
*error = EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* set new initial value */
|
||||
if (timeout != sc->timeout)
|
||||
ichwd_tmr_set(sc, timeout);
|
||||
|
||||
/* reload */
|
||||
ichwd_tmr_reload(sc);
|
||||
|
||||
*error = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static unsigned int pmbase = 0;
|
||||
@ -332,8 +316,6 @@ ichwd_detach(device_t dev)
|
||||
{
|
||||
struct ichwd_softc *sc;
|
||||
|
||||
device_printf(dev, "detaching\n");
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
/* halt the watchdog timer */
|
||||
|
@ -649,25 +649,16 @@ ipmi_wd_event(void *arg, unsigned int cmd, int *error)
|
||||
struct ipmi_softc *sc = arg;
|
||||
unsigned int timeout;
|
||||
|
||||
/* disable / enable */
|
||||
if (!(cmd & WD_ACTIVE)) {
|
||||
ipmi_set_watchdog(sc, 0);
|
||||
*error = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
cmd &= WD_INTERVAL;
|
||||
/* convert from power-of-to-ns to WDT ticks */
|
||||
if (cmd >= 64) {
|
||||
*error = EINVAL;
|
||||
return;
|
||||
if (cmd > 0 && cmd <= 63) {
|
||||
timeout = ((uint64_t)1 << cmd) / 1800000000;
|
||||
ipmi_set_watchdog(sc, timeout);
|
||||
*error = 0;
|
||||
} else {
|
||||
ipmi_set_watchdog(sc, 0);
|
||||
if (cmd > 0)
|
||||
*error = 0;
|
||||
}
|
||||
timeout = ((uint64_t)1 << cmd) / 1800000000;
|
||||
|
||||
/* reload */
|
||||
ipmi_set_watchdog(sc, timeout);
|
||||
|
||||
*error = 0;
|
||||
}
|
||||
|
||||
#ifdef CLONING
|
||||
|
@ -297,7 +297,7 @@ mk48txx_watchdog(void *arg, u_int cmd, int *error)
|
||||
|
||||
wdog = 0;
|
||||
t = cmd & WD_INTERVAL;
|
||||
if (cmd != 0 && t >= 26 && t <= 37) {
|
||||
if (cmd > 0 && t >= 26 && t <= 37) {
|
||||
if (t <= WD_TO_2SEC) {
|
||||
wdog |= MK48TXX_WDOG_RB_1_16;
|
||||
t -= 26;
|
||||
@ -317,6 +317,8 @@ mk48txx_watchdog(void *arg, u_int cmd, int *error)
|
||||
if (sc->sc_flag & MK48TXX_WDOG_ENABLE_WDS)
|
||||
wdog |= MK48TXX_WDOG_WDS;
|
||||
*error = 0;
|
||||
} else if (cmd > 0) {
|
||||
*error = EINVAL;
|
||||
}
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
(*sc->sc_nvwr)(dev, sc->sc_clkoffset + MK48TXX_WDOG, wdog);
|
||||
|
@ -55,11 +55,14 @@ wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
|
||||
return (EINVAL);
|
||||
if ((u & (WD_ACTIVE | WD_PASSIVE)) == (WD_ACTIVE | WD_PASSIVE))
|
||||
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);
|
||||
|
@ -367,11 +367,11 @@ init_AMD_Elan_sc520(void)
|
||||
static void
|
||||
elan_watchdog(void *foo __unused, u_int spec, int *error)
|
||||
{
|
||||
u_int u, v;
|
||||
u_int u, v, w;
|
||||
static u_int cur;
|
||||
|
||||
u = spec & WD_INTERVAL;
|
||||
if (spec && u <= 35) {
|
||||
if (u > 0 && u <= 35) {
|
||||
u = imax(u - 5, 24);
|
||||
v = 2 << (u - 24);
|
||||
v |= 0xc000;
|
||||
@ -383,7 +383,7 @@ elan_watchdog(void *foo __unused, u_int spec, int *error)
|
||||
* for other reasons. Save and restore the GP echo mode
|
||||
* around our hardware tom-foolery.
|
||||
*/
|
||||
u = elan_mmcr->GPECHO;
|
||||
w = elan_mmcr->GPECHO;
|
||||
elan_mmcr->GPECHO = 0;
|
||||
if (v != cur) {
|
||||
/* Clear the ENB bit */
|
||||
@ -401,19 +401,19 @@ elan_watchdog(void *foo __unused, u_int spec, int *error)
|
||||
elan_mmcr->WDTMRCTL = 0xaaaa;
|
||||
elan_mmcr->WDTMRCTL = 0x5555;
|
||||
}
|
||||
elan_mmcr->GPECHO = u;
|
||||
elan_mmcr->GPECHO = w;
|
||||
*error = 0;
|
||||
return;
|
||||
} else {
|
||||
u = elan_mmcr->GPECHO;
|
||||
w = elan_mmcr->GPECHO;
|
||||
elan_mmcr->GPECHO = 0;
|
||||
elan_mmcr->WDTMRCTL = 0x3333;
|
||||
elan_mmcr->WDTMRCTL = 0xcccc;
|
||||
elan_mmcr->WDTMRCTL = 0x4080;
|
||||
elan_mmcr->WDTMRCTL = u;
|
||||
elan_mmcr->GPECHO = u;
|
||||
elan_mmcr->WDTMRCTL = w; /* XXX What does this statement do? */
|
||||
elan_mmcr->GPECHO = w;
|
||||
cur = 0;
|
||||
return;
|
||||
if (u > 0)
|
||||
*error = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -536,15 +536,15 @@ SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD,
|
||||
#ifdef SW_WATCHDOG
|
||||
|
||||
static void
|
||||
watchdog_config(void *unused __unused, u_int cmd, int *err)
|
||||
watchdog_config(void *unused __unused, u_int cmd, int *error)
|
||||
{
|
||||
u_int u;
|
||||
|
||||
u = cmd & WD_INTERVAL;
|
||||
if ((cmd & WD_ACTIVE) && u >= WD_TO_1SEC) {
|
||||
if (u >= WD_TO_1SEC) {
|
||||
watchdog_ticks = (1 << (u - WD_TO_1SEC)) * hz;
|
||||
watchdog_enabled = 1;
|
||||
*err = 0;
|
||||
*error = 0;
|
||||
} else {
|
||||
watchdog_enabled = 0;
|
||||
}
|
||||
|
@ -30,11 +30,7 @@
|
||||
|
||||
#include <sys/ioccom.h>
|
||||
|
||||
#ifdef I_HAVE_TOTALLY_LOST_MY_SENSE_OF_HUMOUR
|
||||
#define _PATH_WATCHDOG "watchdog"
|
||||
#else
|
||||
#define _PATH_WATCHDOG "fido"
|
||||
#endif
|
||||
|
||||
#define WDIOCPATPAT _IOW('W', 42, u_int)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user