From 01497b95ec59c17d92a095a59f12954e6e2eee17 Mon Sep 17 00:00:00 2001 From: pgoyette Date: Thu, 22 Jul 2010 14:10:14 +0000 Subject: [PATCH] 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. --- share/man/man4/swwdog.4 | 25 +++- sys/dev/sysmon/files.sysmon | 4 +- sys/dev/sysmon/swwdog.c | 142 ++++++++++++++++++----- sys/rump/dev/lib/libsysmon/Makefile | 3 +- sys/rump/dev/lib/libsysmon/SYSMON.ioconf | 8 ++ 5 files changed, 145 insertions(+), 37 deletions(-) create mode 100644 sys/rump/dev/lib/libsysmon/SYSMON.ioconf diff --git a/share/man/man4/swwdog.4 b/share/man/man4/swwdog.4 index 5eb9ecebfab5..eae8929d790a 100644 --- a/share/man/man4/swwdog.4 +++ b/share/man/man4/swwdog.4 @@ -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 diff --git a/sys/dev/sysmon/files.sysmon b/sys/dev/sysmon/files.sysmon index 1b3def06d2c2..2977811aac9f 100644 --- a/sys/dev/sysmon/files.sysmon +++ b/sys/dev/sysmon/files.sysmon @@ -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 diff --git a/sys/dev/sysmon/swwdog.c b/sys/dev/sysmon/swwdog.c index fc322773febc..b5e5e69104df 100644 --- a/sys/dev/sysmon/swwdog.c +++ b/sys/dev/sysmon/swwdog.c @@ -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 -__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 #include #include +#include #include #include +#include #include #include -#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); +} diff --git a/sys/rump/dev/lib/libsysmon/Makefile b/sys/rump/dev/lib/libsysmon/Makefile index 43325fb3a826..9a138444de35 100644 --- a/sys/rump/dev/lib/libsysmon/Makefile +++ b/sys/rump/dev/lib/libsysmon/Makefile @@ -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 \ diff --git a/sys/rump/dev/lib/libsysmon/SYSMON.ioconf b/sys/rump/dev/lib/libsysmon/SYSMON.ioconf new file mode 100644 index 000000000000..ca1978e45ff8 --- /dev/null +++ b/sys/rump/dev/lib/libsysmon/SYSMON.ioconf @@ -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