Convert swwdog(4) from a simple defpseudo device to a defpseudodev so

that we can attach a power management handler.  The handler prevents
a suspend if the watchdog is active, to be consistent with other
watchdog drivers.

As discussed on tech-kern.
This commit is contained in:
pgoyette 2010-07-22 14:10:14 +00:00
parent 95c959ca44
commit 01497b95ec
5 changed files with 145 additions and 37 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: swwdog.4,v 1.4 2010/01/30 21:55:28 pooka Exp $
.\" $NetBSD: swwdog.4,v 1.5 2010/07/22 14:10:14 pgoyette Exp $
.\"
.\" Copyright (c) 2004, 2005 Steven M. Bellovin
.\" All rights reserved.
@ -31,7 +31,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd January 30, 2010
.Dd July 21, 2010
.\" Written by Steven M. Bellovin
.Dt SWWDOG 4
.Os
@ -45,14 +45,26 @@ The
.Nm
driver provides a software watchdog timer that works with
.Xr wdogctl 8 .
If the timer expires, the system reboots unless the variable
If the timer expires, the system reboots unless the boolean variable
.Va swwdog_panic
is non-zero; if it is, the system will panic instead.
is
.Dv true ;
if it is, the system will panic instead.
.Va swwdog_reboot
is accessible as a
.Xr sysctl 8
variable, machdep.swwdog0.reboot and defaults to
.Dv false .
.Pp
The default period of
.Nm
is 60 seconds.
.Pp
As with other watchdog timers, the
.Nm
driver prevents a system from suspending when the watchdog is armed.
.Sh SEE ALSO
.Xr sysctl 8
.Xr wdogctl 8
.Sh HISTORY
The
@ -61,7 +73,10 @@ driver was written by
.An Steven M. Bellovin .
.Sh BUGS
Only one watchdog timer can be active at any given time.
Arguably, this is a bug in the watchdog timer framework.
(Arguably, this is a bug in the watchdog timer framework.)
Therefore, only a single instance of the
.Nm
device can be created.
.Pp
Kernel tickle mode is useless with
.Nm

View File

@ -1,4 +1,4 @@
# $NetBSD: files.sysmon,v 1.11 2010/01/30 21:55:28 pooka Exp $
# $NetBSD: files.sysmon,v 1.12 2010/07/22 14:10:15 pgoyette Exp $
define sysmon_taskq
file dev/sysmon/sysmon_taskq.c sysmon_taskq needs-flag
@ -18,5 +18,5 @@ file dev/sysmon/sysmon_wdog.c sysmon_wdog needs-flag
file dev/sysmon/sysmon.c sysmon_envsys | sysmon_wdog |
sysmon_power
defpseudo swwdog: sysmon_wdog
defpseudodev swwdog: sysmon_wdog
file dev/sysmon/swwdog.c swwdog

View File

@ -1,4 +1,4 @@
/* $NetBSD: swwdog.c,v 1.9 2010/01/31 02:54:56 pooka Exp $ */
/* $NetBSD: swwdog.c,v 1.10 2010/07/22 14:10:15 pgoyette Exp $ */
/*
* Copyright (c) 2004, 2005 Steven M. Bellovin
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: swwdog.c,v 1.9 2010/01/31 02:54:56 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: swwdog.c,v 1.10 2010/07/22 14:10:15 pgoyette Exp $");
/*
*
@ -44,20 +44,28 @@ __KERNEL_RCSID(0, "$NetBSD: swwdog.c,v 1.9 2010/01/31 02:54:56 pooka Exp $");
#include <sys/callout.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/reboot.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/wdog.h>
#include <dev/sysmon/sysmonvar.h>
#define NSWWDOG 1
#include "ioconf.h"
struct swwdog_softc {
device_t sc_dev;
struct sysmon_wdog sc_smw;
struct callout sc_c;
char sc_name[20];
int sc_wdog_armed;
} sc_wdog[NSWWDOG];
};
void swwdogattach(int);
void swwdogattach(int);
static int swwdog_match(device_t, cfdata_t, void *);
static void swwdog_attach(device_t, device_t, void *);
static int swwdog_detach(device_t, int);
static bool swwdog_suspend(device_t, const pmf_qual_t *);
static int swwdog_setmode(struct sysmon_wdog *);
static int swwdog_tickle(struct sysmon_wdog *);
@ -67,34 +75,87 @@ static int swwdog_disarm(struct swwdog_softc *);
static void swwdog_panic(void *);
int swwdog_reboot = 0; /* set for panic instead of reboot */
bool swwdog_reboot = false; /* set for panic instead of reboot */
#define SWDOG_DEFAULT 60 /* 60-second default period */
CFATTACH_DECL_NEW(swwdog, sizeof(struct swwdog_softc),
swwdog_match, swwdog_attach, swwdog_detach, NULL);
void
swwdogattach(int count __unused)
swwdogattach(int n __unused)
{
int i;
int err;
static struct cfdata cf;
for (i = 0; i < NSWWDOG; i++) {
struct swwdog_softc *sc = &sc_wdog[i];
snprintf(sc->sc_name, sizeof sc->sc_name, "swwdog%d", i);
printf("%s: ", sc->sc_name);
sc->sc_smw.smw_name = sc->sc_name;
sc->sc_smw.smw_cookie = sc;
sc->sc_smw.smw_setmode = swwdog_setmode;
sc->sc_smw.smw_tickle = swwdog_tickle;
sc->sc_smw.smw_period = SWDOG_DEFAULT;
callout_init(&sc->sc_c, 0);
callout_setfunc(&sc->sc_c, swwdog_panic, sc);
if (sysmon_wdog_register(&sc->sc_smw) == 0)
printf("software watchdog initialized\n");
else
printf("unable to register software watchdog "
"with sysmon\n");
err = config_cfattach_attach(swwdog_cd.cd_name, &swwdog_ca);
if (err) {
aprint_error("%s: couldn't register cfattach: %d\n",
swwdog_cd.cd_name, err);
config_cfdriver_detach(&swwdog_cd);
return;
}
cf.cf_name = swwdog_cd.cd_name;
cf.cf_atname = swwdog_cd.cd_name;
cf.cf_unit = 0;
cf.cf_fstate = FSTATE_STAR;
(void)config_attach_pseudo(&cf);
return;
}
static int
swwdog_match(device_t parent, cfdata_t data, void *aux)
{
return 1;
}
static void
swwdog_attach(device_t parent, device_t self, void *aux)
{
struct swwdog_softc *sc = device_private(self);
sc->sc_dev = self;
sc->sc_smw.smw_name = device_xname(self);
sc->sc_smw.smw_cookie = sc;
sc->sc_smw.smw_setmode = swwdog_setmode;
sc->sc_smw.smw_tickle = swwdog_tickle;
sc->sc_smw.smw_period = SWDOG_DEFAULT;
callout_init(&sc->sc_c, 0);
callout_setfunc(&sc->sc_c, swwdog_panic, sc);
if (sysmon_wdog_register(&sc->sc_smw) == 0)
aprint_normal_dev(self, "software watchdog initialized\n");
else
aprint_error_dev(self, "unable to register software "
"watchdog with sysmon\n");
if (!pmf_device_register(self, swwdog_suspend, NULL))
aprint_error_dev(self, "couldn't establish power handler\n");
}
static int
swwdog_detach(device_t self, int flags)
{
struct swwdog_softc *sc = device_private(self);
swwdog_disarm(sc);
callout_destroy(&sc->sc_c);
return 1;
}
static bool
swwdog_suspend(device_t dev, const pmf_qual_t *qual)
{
struct swwdog_softc *sc = device_private(dev);
/* Don't allow suspend if watchdog is armed */
if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) != WDOG_MODE_DISARMED)
return false;
return true;
}
static int
@ -144,13 +205,13 @@ static void
swwdog_panic(void *vsc)
{
struct swwdog_softc *sc = vsc;
int do_panic;
bool do_panic;
do_panic = swwdog_reboot;
swwdog_reboot = 1;
callout_schedule(&sc->sc_c, 60 * hz); /* deliberate double-panic */
printf("%s: %d second timer expired\n", sc->sc_name,
printf("%s: %d second timer expired\n", device_xname(sc->sc_dev),
sc->sc_smw.smw_period);
if (do_panic)
@ -158,3 +219,26 @@ swwdog_panic(void *vsc)
else
cpu_reboot(0, NULL);
}
SYSCTL_SETUP(sysctl_swwdog, "swwdog subtree setup")
{
int err;
const struct sysctlnode *me;
err = sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_PERMANENT,
CTLTYPE_NODE, "machdep", NULL,
NULL, 0, NULL, 0,
CTL_HW, CTL_EOL);
if (err == 0)
err = sysctl_createv(NULL, 0, NULL, &me, CTLFLAG_READWRITE,
CTLTYPE_NODE, "swwdog", NULL,
NULL, 0, NULL, 0,
CTL_HW, CTL_CREATE, CTL_EOL);
if (err == 0)
err = sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_READWRITE,
CTLTYPE_BOOL, "reboot", "reboot if timer expires",
NULL, 0, &swwdog_reboot, sizeof(bool),
CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
}

View File

@ -1,9 +1,10 @@
# $NetBSD: Makefile,v 1.2 2010/02/16 20:42:45 pooka Exp $
# $NetBSD: Makefile,v 1.3 2010/07/22 14:10:14 pgoyette Exp $
#
.PATH: ${.CURDIR}/../../../../dev/sysmon
LIB= rumpdev_sysmon
IOCONF= SYSMON.ioconf
SRCS= sysmon_taskq.c sysmon_power.c sysmon_envsys.c sysmon_envsys_events.c \
sysmon_envsys_tables.c sysmon_envsys_util.c sysmon_wdog.c sysmon.c \

View File

@ -0,0 +1,8 @@
# $NetBSD: SYSMON.ioconf,v 1.1 2010/07/22 14:10:14 pgoyette Exp $
#
ioconf swwdog
include "conf/files"
pseudo-device swwdog