diff options
author | ru <ru@FreeBSD.org> | 2009-12-18 12:10:42 +0000 |
---|---|---|
committer | ru <ru@FreeBSD.org> | 2009-12-18 12:10:42 +0000 |
commit | 0c4b4a5c2b4a37b1dacf179368080f353b911872 (patch) | |
tree | 279d7010fedb1467434338c52016d198013d479f /sys/dev/ipmi | |
parent | 36f082ff8ff98f121ca93b7f9e4fa7a381b4806b (diff) | |
download | FreeBSD-src-0c4b4a5c2b4a37b1dacf179368080f353b911872.zip FreeBSD-src-0c4b4a5c2b4a37b1dacf179368080f353b911872.tar.gz |
- Fixed incorrect watchdog timeout setting: MSB of a 2-byte
value is obtained by dividing it by 256, not by 2550; also,
one second is 10^9 nanoseconds, not 1800000000 nanoseconds.
- Due to rounding error, setting watchdog to a really small
timeout (<1 sec) was turning the watchdog off. It should
set the watchdog to a small timeout instead.
- Implemented error checking in ipmi_wd_event(), as required
by watchdog(9).
PR: kern/130512
Submitted by: Dmitrij Tejblum
- Additionally, check that the timeout value is within the
supported range, and if it's too large, act as required by
watchdog(9).
MFC after: 3 days
Diffstat (limited to 'sys/dev/ipmi')
-rw-r--r-- | sys/dev/ipmi/ipmi.c | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c index 8e53d01..da024fc 100644 --- a/sys/dev/ipmi/ipmi.c +++ b/sys/dev/ipmi/ipmi.c @@ -588,12 +588,15 @@ ipmi_polled_enqueue_request(struct ipmi_softc *sc, struct ipmi_request *req) * Watchdog event handler. */ -static void -ipmi_set_watchdog(struct ipmi_softc *sc, int sec) +static int +ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec) { struct ipmi_request *req; int error; + if (sec > 0xffff / 10) + return (EINVAL); + req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_SET_WDOG, 6, 0); @@ -604,7 +607,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc, int sec) req->ir_request[2] = 0; req->ir_request[3] = 0; /* Timer use */ req->ir_request[4] = (sec * 10) & 0xff; - req->ir_request[5] = (sec * 10) / 2550; + req->ir_request[5] = (sec * 10) >> 8; } else { req->ir_request[0] = IPMI_SET_WD_TIMER_SMS_OS; req->ir_request[1] = 0; @@ -617,8 +620,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc, int sec) error = ipmi_submit_driver_request(sc, req, 0); if (error) device_printf(sc->ipmi_dev, "Failed to set watchdog\n"); - - if (error == 0 && sec) { + else if (sec) { ipmi_free_request(req); req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), @@ -631,6 +633,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc, int sec) } ipmi_free_request(req); + return (error); /* dump_watchdog(sc); */ @@ -641,14 +644,22 @@ ipmi_wd_event(void *arg, unsigned int cmd, int *error) { struct ipmi_softc *sc = arg; unsigned int timeout; + int e; cmd &= WD_INTERVAL; if (cmd > 0 && cmd <= 63) { - timeout = ((uint64_t)1 << cmd) / 1800000000; - ipmi_set_watchdog(sc, timeout); - *error = 0; + timeout = ((uint64_t)1 << cmd) / 1000000000; + if (timeout == 0) + timeout = 1; + e = ipmi_set_watchdog(sc, timeout); + if (e == 0) + *error = 0; + else + (void)ipmi_set_watchdog(sc, 0); } else { - ipmi_set_watchdog(sc, 0); + e = ipmi_set_watchdog(sc, 0); + if (e != 0 && cmd == 0) + *error = EOPNOTSUPP; } } |