summaryrefslogtreecommitdiff
path: root/sys/dev/ipmi.c
diff options
context:
space:
mode:
authorJordan Hargrave <jordan@cvs.openbsd.org>2005-11-28 23:47:43 +0000
committerJordan Hargrave <jordan@cvs.openbsd.org>2005-11-28 23:47:43 +0000
commit6c2af509b4f560e01a139814ee7f8737439659e8 (patch)
treee91e933ad61c5d07a08124cc8a1e66dd6ef4cf4e /sys/dev/ipmi.c
parentc18da06e7fa5cd4936a1837959785e2b56331a58 (diff)
Added ipmi watchdog code, based on esm watchdog code by dlg@
Added signextend function to cleanup conversion routine ok marco@
Diffstat (limited to 'sys/dev/ipmi.c')
-rw-r--r--sys/dev/ipmi.c85
1 files changed, 66 insertions, 19 deletions
diff --git a/sys/dev/ipmi.c b/sys/dev/ipmi.c
index 2d6c461e618..8d99875d569 100644
--- a/sys/dev/ipmi.c
+++ b/sys/dev/ipmi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipmi.c,v 1.19 2005/11/22 04:28:14 marco Exp $ */
+/* $OpenBSD: ipmi.c,v 1.20 2005/11/28 23:47:42 jordan Exp $ */
/*
* Copyright (c) 2005 Jordan Hargrave
@@ -128,6 +128,8 @@ int ipmi_poll = 1;
if (len && ipmi_dbg >= lvl) \
dumpb(msg, len, (const u_int8_t *)(buf));
+long signextend(unsigned long, int);
+
SLIST_HEAD(ipmi_sensors_head, ipmi_sensor);
struct ipmi_sensors_head ipmi_sensor_list =
SLIST_HEAD_INITIALIZER(&ipmi_sensor_list);
@@ -146,6 +148,8 @@ int get_sdr(struct ipmi_softc *, u_int16_t, u_int16_t *);
int ipmi_sendcmd(struct ipmi_softc *, int, int, int, int, int, const void*);
int ipmi_recvcmd(struct ipmi_softc *, int, int *, void *);
+int ipmi_watchdog(void *, int);
+
int ipmi_intr(void *);
int ipmi_match(struct device *, void *, void *);
void ipmi_attach(struct device *, struct device *, void *);
@@ -1206,6 +1210,15 @@ ipow(long val, int exp)
return (val);
}
+/* Sign extend a n-bit value */
+long
+signextend(unsigned long val, int bits)
+{
+ long msk = (1L << (bits-1))-1;
+
+ return (-(val & ~msk) | val);
+}
+
/* Convert IPMI reading from sensor factors */
long
ipmi_convert(u_int8_t v, sdrtype1 *s1, long adj)
@@ -1214,24 +1227,11 @@ ipmi_convert(u_int8_t v, sdrtype1 *s1, long adj)
char K1, K2;
long val;
- /* M is 10-bit value: check if negative */
- M = (((short)(s1->m_tolerance & 0xC0)) << 2) + s1->m;
- if (M & 0x200)
- M |= 0xFC00;
-
- /* B is 10-bit value; check if negative */
- B = (((short)(s1->b_accuracy & 0xC0)) << 2) + s1->b;
- if (B & 0x200)
- B |= 0xFC00;
-
- /* K1/K2 are 4-bit values; check if negative */
- K1 = s1->rbexp & 0xF;
- if (K1 & 0x8)
- K1 |= 0xF0;
-
- K2 = s1->rbexp >> 4;
- if (K2 & 0x8)
- K2 |= 0xF0;
+ /* Calculate linear reading variables */
+ M = signextend((((short)(s1->m_tolerance & 0xC0)) << 2) + s1->m, 10);
+ B = signextend((((short)(s1->b_accuracy & 0xC0)) << 2) + s1->b, 10);
+ K1 = signextend(s1->rbexp & 0xF, 4);
+ K2 = signextend(s1->rbexp >> 4, 4);
/* Calculate sensor reading:
* y = L((M * v + (B * 10^K1)) * 10^(K2+adj)
@@ -1661,4 +1661,51 @@ ipmi_attach(struct device *parent, struct device *self, void *aux)
if (ia->iaa_if_irq != -1)
printf(" irq %d", ia->iaa_if_irq);
printf("\n");
+
+ /* Setup Watchdog timer */
+ sc->sc_wdog_period = 0;
+ wdog_register(sc, ipmi_watchdog);
+}
+
+
+int
+ipmi_watchdog(void *arg, int period)
+{
+ struct ipmi_softc *sc = arg;
+ struct ipmi_watchdog wdog;
+ int s, rc, len;
+
+ if (sc->sc_wdog_period == period) {
+ if (period != 0) {
+ s = splsoftclock();
+ /* tickle the watchdog */
+ rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
+ APP_RESET_WATCHDOG, 0, NULL);
+ rc = ipmi_recvcmd(sc, 0, &len, NULL);
+ splx(s);
+ }
+ return (period);
+ }
+
+ if (period < 10 && period > 0)
+ period = 10;
+
+ s = splsoftclock();
+ rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
+ APP_GET_WATCHDOG_TIMER, 0, NULL);
+ rc = ipmi_recvcmd(sc, sizeof(wdog), &len, &wdog);
+
+ /* Period is 10ths/sec */
+ wdog.wdog_timeout = htole32(period * 10);
+ wdog.wdog_action &= ~IPMI_WDOG_MASK;
+ wdog.wdog_action |= (period == 0) ? IPMI_WDOG_DISABLED : IPMI_WDOG_REBOOT;
+
+ rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
+ APP_SET_WATCHDOG_TIMER, sizeof(wdog), &wdog);
+ rc = ipmi_recvcmd(sc, 0, &len, NULL);
+
+ splx(s);
+
+ sc->sc_wdog_period = period;
+ return (period);
}