diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2006-01-05 07:39:31 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2006-01-05 07:39:31 +0000 |
commit | c561b5e78ceab3f681a200f320da9a93164411ca (patch) | |
tree | 6aa4b2f694e9795c9e5af8544fb3f22f83361b9b | |
parent | ce0e39feed1c1997221d24d6f8d3ca69dd8d41bf (diff) |
interacting with the watchdog while we're in the middle of updating sensors
is bad(tm). if updates are happening then make esm_refresh to do
esm_watchdogs work after its own.
-rw-r--r-- | sys/arch/i386/i386/esm.c | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/sys/arch/i386/i386/esm.c b/sys/arch/i386/i386/esm.c index 8ce91142201..3ca30d0d09f 100644 --- a/sys/arch/i386/i386/esm.c +++ b/sys/arch/i386/i386/esm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: esm.c,v 1.31 2006/01/04 21:58:21 dlg Exp $ */ +/* $OpenBSD: esm.c,v 1.32 2006/01/05 07:39:30 dlg Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -23,6 +23,7 @@ #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/timeout.h> +#include <sys/proc.h> #include <sys/queue.h> #include <sys/sensors.h> @@ -115,10 +116,11 @@ struct esm_softc { TAILQ_HEAD(, esm_sensor) sc_sensors; struct esm_sensor *sc_nextsensor; int sc_retries; - int sc_step; + volatile int sc_step; struct timeout sc_timeout; int sc_wdog_period; + volatile int sc_wdog_tickle; }; struct cfattach esm_ca = { @@ -280,13 +282,20 @@ esm_watchdog(void *arg, int period) if (sc->sc_wdog_period == period) { if (period != 0) { s = splsoftclock(); - /* tickle the watchdog */ - EWRITE(sc, ESM2_CTRL_REG, ESM2_TC_HBDB); + if (sc->sc_step != 0) { + /* defer tickling to the sensor refresh */ + sc->sc_wdog_tickle = 1; + } else { + /* tickle the watchdog */ + EWRITE(sc, ESM2_CTRL_REG, ESM2_TC_HBDB); + } splx(s); } return (period); } + /* we're changing the watchdog period */ + memset(&prop, 0, sizeof(prop)); memset(&state, 0, sizeof(state)); @@ -300,9 +309,21 @@ esm_watchdog(void *arg, int period) prop.action = (period == 0) ? ESM_WDOG_DISABLE : ESM_WDOG_RESET; prop.time = period; + /* + * if we're doing a refresh, we need to wait till the hardware is + * available again. since period changes only happen via sysctl we + * should have a process context we can sleep in. + */ + while (sc->sc_step != 0) { + if (tsleep(sc, PUSER | PCATCH, "esm", 0) == EINTR) { + splx(s); + return (sc->sc_wdog_period); + } + } + if (esm_cmd(sc, &prop, sizeof(prop), NULL, 0, 1, 0) != 0) { splx(s); - return (0); + return (sc->sc_wdog_period); } state.cmd = ESM2_CMD_HWDC; @@ -420,6 +441,16 @@ esm_refresh(void *arg) sc->sc_retries = 0; sc->sc_step = 0; + if (sc->sc_wdog_tickle) { + /* + * the controller was busy in a refresh when the watchdog + * needed a tickle, so do it now. + */ + EWRITE(sc, ESM2_CTRL_REG, ESM2_TC_HBDB); + sc->sc_wdog_tickle = 0; + } + wakeup(sc); + if (sc->sc_nextsensor == NULL) { sc->sc_nextsensor = TAILQ_FIRST(&sc->sc_sensors); timeout_add(&sc->sc_timeout, hz * 10); |