svn commit: r200666 - head/sys/dev/ipmi
Ruslan Ermilov
ru at FreeBSD.org
Fri Dec 18 12:10:43 UTC 2009
Author: ru
Date: Fri Dec 18 12:10:42 2009
New Revision: 200666
URL: http://svn.freebsd.org/changeset/base/200666
Log:
- 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
Modified:
head/sys/dev/ipmi/ipmi.c
Modified: head/sys/dev/ipmi/ipmi.c
==============================================================================
--- head/sys/dev/ipmi/ipmi.c Fri Dec 18 12:09:44 2009 (r200665)
+++ head/sys/dev/ipmi/ipmi.c Fri Dec 18 12:10:42 2009 (r200666)
@@ -588,12 +588,15 @@ ipmi_polled_enqueue_request(struct ipmi_
* 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,
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,
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,
}
ipmi_free_request(req);
+ return (error);
/*
dump_watchdog(sc);
*/
@@ -641,14 +644,22 @@ ipmi_wd_event(void *arg, unsigned int cm
{
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;
}
}
More information about the svn-src-head
mailing list