Module Name:    src
Committed By:   dyoung
Date:           Mon Jul 20 19:11:30 UTC 2009

Modified Files:
        src/sys/arch/x86/include: ipmivar.h
        src/sys/arch/x86/x86: ipmi.c

Log Message:
Overhaul synchronization in ipmi(4): synchronize all access to
device registers with a mutex.  Convert tsleep/wakeup calls to
cv_wait/cv_signal.

Do not repeatedly malloc/free tiny buffers for sending/receiving
commands, but reserve a command buffer in the softc.

Tickle the watchdog in the sensors-refreshing thread.

I am fairly certain that after the device is attached, every register
access happens in the sensors-refreshing thread.  Moreover, no
software interrupt touches any register, now.  So I may get rid of
the mutex that protects register accesses, sc_cmd_mtx.


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/x86/include/ipmivar.h
cvs rdiff -u -r1.38 -r1.39 src/sys/arch/x86/x86/ipmi.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/include/ipmivar.h
diff -u src/sys/arch/x86/include/ipmivar.h:1.9 src/sys/arch/x86/include/ipmivar.h:1.10
--- src/sys/arch/x86/include/ipmivar.h:1.9	Mon Nov  3 12:25:53 2008
+++ src/sys/arch/x86/include/ipmivar.h	Mon Jul 20 19:11:30 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: ipmivar.h,v 1.9 2008/11/03 12:25:53 cegger Exp $ */
+/* $NetBSD: ipmivar.h,v 1.10 2009/07/20 19:11:30 dyoung Exp $ */
 
 /*
  * Copyright (c) 2005 Jordan Hargrave
@@ -28,6 +28,7 @@
  */
 
 #include <sys/mutex.h>
+#include <sys/condvar.h>
 
 #include <dev/sysmon/sysmonvar.h>
 
@@ -45,13 +46,6 @@
 struct ipmi_thread;
 struct ipmi_softc;
 
-struct ipmi_bmc_args{
-	int			offset;
-	uint8_t		mask;
-	uint8_t		value;
-	volatile uint8_t	*v;
-};
-
 struct ipmi_attach_args {
 	bus_space_tag_t	iaa_iot;
 	bus_space_tag_t	iaa_memt;
@@ -92,22 +86,27 @@
 
 	struct lwp		*sc_kthread;
 
-	struct callout		sc_callout;
 	int			sc_max_retries;
-	int			sc_retries;
-	int			sc_wakeup;
 
-	kmutex_t		sc_lock;
+	kmutex_t		sc_poll_mtx;
+	kcondvar_t		sc_poll_cv;
+
+	kmutex_t		sc_cmd_mtx;
+	kcondvar_t		sc_cmd_sleep;
 
 	struct ipmi_bmc_args	*sc_iowait_args;
 
 	struct ipmi_sensor	*current_sensor;
-	volatile int		sc_thread_running;
+	volatile bool		sc_thread_running;
+	volatile bool		sc_tickle_due;
 	struct sysmon_wdog	sc_wdog;
 	struct sysmon_envsys	*sc_envsys;
 	envsys_data_t		*sc_sensor;
 	int 		sc_nsensors; /* total number of sensors */
 	int		sc_nsensors_typ[ENVSYS_NSENSORS]; /* number per type */
+
+	char		sc_buf[64];
+	bool		sc_buf_rsvd;
 };
 
 struct ipmi_thread {
@@ -115,26 +114,37 @@
 	volatile int	    running;
 };
 
-#define IPMI_WDOG_USE_NLOG		0x80
-#define IPMI_WDOG_USE_NSTOP		0x40
-#define IPMI_WDOG_USE_USE_MASK		0x07
-#define IPMI_WDOG_USE_USE_FRB2		0x01
-#define IPMI_WDOG_USE_USE_POST		0x02
-#define IPMI_WDOG_USE_USE_OSLOAD	0x03
-#define IPMI_WDOG_USE_USE_OS		0x04
-#define IPMI_WDOG_USE_USE_EOM		0x05
-
-#define IPMI_WDOG_ACT_MASK		0x07
-#define IPMI_WDOG_ACT_DISABLED		0x00
-#define IPMI_WDOG_ACT_RESET		0x01
-#define IPMI_WDOG_ACT_PWROFF		0x02
-#define IPMI_WDOG_ACT_PWRCYCLE		0x03
-
-#define IPMI_WDOG_ACT_PRE_MASK		0x70
-#define IPMI_WDOG_ACT_PRE_DISABLED	0x00
-#define IPMI_WDOG_ACT_PRE_SMI		0x10
-#define IPMI_WDOG_ACT_PRE_NMI		0x20
-#define IPMI_WDOG_ACT_PRE_INTERRUPT	0x30
+#define IPMI_WDOG_USE_NOLOG		__BIT(7)
+#define IPMI_WDOG_USE_NOSTOP		__BIT(6)
+#define IPMI_WDOG_USE_RSVD1		__BITS(5, 3)
+#define IPMI_WDOG_USE_USE_MASK		__BITS(2, 0)
+#define IPMI_WDOG_USE_USE_RSVD		__SHIFTIN(0, IPMI_WDOG_USE_USE_MASK);
+#define IPMI_WDOG_USE_USE_FRB2		__SHIFTIN(1, IPMI_WDOG_USE_USE_MASK);
+#define IPMI_WDOG_USE_USE_POST		__SHIFTIN(2, IPMI_WDOG_USE_USE_MASK);
+#define IPMI_WDOG_USE_USE_OSLOAD	__SHIFTIN(3, IPMI_WDOG_USE_USE_MASK);
+#define IPMI_WDOG_USE_USE_OS		__SHIFTIN(4, IPMI_WDOG_USE_USE_MASK);
+#define IPMI_WDOG_USE_USE_OEM		__SHIFTIN(5, IPMI_WDOG_USE_USE_MASK);
+
+#define IPMI_WDOG_ACT_PRE_RSVD1		__BIT(7)
+#define IPMI_WDOG_ACT_PRE_MASK		__BITS(6, 4)
+#define IPMI_WDOG_ACT_PRE_DISABLED	__SHIFTIN(0, IPMI_WDOG_ACT_MASK)
+#define IPMI_WDOG_ACT_PRE_SMI		__SHIFTIN(1, IPMI_WDOG_ACT_MASK)
+#define IPMI_WDOG_ACT_PRE_NMI		__SHIFTIN(2, IPMI_WDOG_ACT_MASK)
+#define IPMI_WDOG_ACT_PRE_INTERRUPT	__SHIFTIN(3, IPMI_WDOG_ACT_MASK)
+#define IPMI_WDOG_ACT_PRE_RSVD0		__BIT(3)
+#define IPMI_WDOG_ACT_MASK		__BITS(2, 0)
+#define IPMI_WDOG_ACT_DISABLED		__SHIFTIN(0, IPMI_WDOG_ACT_MASK)
+#define IPMI_WDOG_ACT_RESET		__SHIFTIN(1, IPMI_WDOG_ACT_MASK)
+#define IPMI_WDOG_ACT_PWROFF		__SHIFTIN(2, IPMI_WDOG_ACT_MASK)
+#define IPMI_WDOG_ACT_PWRCYCLE		__SHIFTIN(3, IPMI_WDOG_ACT_MASK)
+
+#define IPMI_WDOG_FLAGS_RSVD1		__BITS(7, 6)
+#define IPMI_WDOG_FLAGS_OEM		__BIT(5)
+#define IPMI_WDOG_FLAGS_OS		__BIT(4)
+#define IPMI_WDOG_FLAGS_OSLOAD		__BIT(3)
+#define IPMI_WDOG_FLAGS_POST		__BIT(2)
+#define IPMI_WDOG_FLAGS_FRB2		__BIT(1)
+#define IPMI_WDOG_FLAGS_RSVD0		__BIT(0)
 
 struct ipmi_set_watchdog {
 	uint8_t		wdog_use;

Index: src/sys/arch/x86/x86/ipmi.c
diff -u src/sys/arch/x86/x86/ipmi.c:1.38 src/sys/arch/x86/x86/ipmi.c:1.39
--- src/sys/arch/x86/x86/ipmi.c:1.38	Sat Jul 11 05:03:11 2009
+++ src/sys/arch/x86/x86/ipmi.c	Mon Jul 20 19:11:30 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipmi.c,v 1.38 2009/07/11 05:03:11 pgoyette Exp $ */
+/*	$NetBSD: ipmi.c,v 1.39 2009/07/20 19:11:30 dyoung Exp $ */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -57,7 +57,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipmi.c,v 1.38 2009/07/11 05:03:11 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipmi.c,v 1.39 2009/07/20 19:11:30 dyoung Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -95,7 +95,6 @@
 
 int	ipmi_nintr;
 int	ipmi_dbg = 0;
-int	ipmi_poll = 1;
 int	ipmi_enabled = 0;
 
 #define SENSOR_REFRESH_RATE (5 * hz)
@@ -178,12 +177,15 @@
 	    uint8_t, uint8_t, void *, uint16_t *);
 int	get_sdr(struct ipmi_softc *, uint16_t, uint16_t *);
 
+char	*ipmi_buf_acquire(struct ipmi_softc *, size_t);
+void	ipmi_buf_release(struct ipmi_softc *, char *);
 int	ipmi_sendcmd(struct ipmi_softc *, int, int, int, int, int, const void*);
 int	ipmi_recvcmd(struct ipmi_softc *, int, int *, void *);
 void	ipmi_delay(struct ipmi_softc *, int);
 
 int	ipmi_watchdog_setmode(struct sysmon_wdog *);
 int	ipmi_watchdog_tickle(struct sysmon_wdog *);
+void	ipmi_dotickle(struct ipmi_softc *);
 
 int	ipmi_intr(void *);
 int	ipmi_match(device_t, cfdata_t, void *);
@@ -198,9 +200,8 @@
 uint8_t bmc_read(struct ipmi_softc *, int);
 void	bmc_write(struct ipmi_softc *, int, uint8_t);
 int	bmc_io_wait(struct ipmi_softc *, int, uint8_t, uint8_t, const char *);
-int	bmc_io_wait_spin(struct ipmi_softc *, int, uint8_t, uint8_t,
-    const char *);
-void	_bmc_io_wait(void *);
+int	bmc_io_wait_spin(struct ipmi_softc *, int, uint8_t, uint8_t);
+int	bmc_io_wait_sleep(struct ipmi_softc *, int, uint8_t, uint8_t);
 
 void	*bt_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *);
 void	*cmn_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *);
@@ -292,68 +293,42 @@
 	    offset * sc->sc_if_iospacing, val);
 }
 
-void
-_bmc_io_wait(void *arg)
+int
+bmc_io_wait_sleep(struct ipmi_softc *sc, int offset, uint8_t mask,
+    uint8_t value)
 {
-	struct ipmi_softc	*sc = arg;
-	struct ipmi_bmc_args	*a = sc->sc_iowait_args;
+	int retries;
+	uint8_t v;
 
-	*a->v = bmc_read(sc, a->offset);
-	if ((*a->v & a->mask) == a->value) {
-		sc->sc_wakeup = 0;
-		wakeup(sc);
-		return;
-	}
+	KASSERT(mutex_owned(&sc->sc_cmd_mtx));
 
-	if (++sc->sc_retries > sc->sc_max_retries) {
-		sc->sc_wakeup = 0;
-		wakeup(sc);
-		return;
+	for (retries = 0; retries < sc->sc_max_retries; retries++) {
+		v = bmc_read(sc, offset);
+		if ((v & mask) == value)
+			return v;
+		cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_cmd_mtx, 1);
 	}
-
-	callout_schedule(&sc->sc_callout, 1);
+	return -1;
 }
 
 int
 bmc_io_wait(struct ipmi_softc *sc, int offset, uint8_t mask, uint8_t value,
     const char *lbl)
 {
-	volatile uint8_t	v;
-	int			u;
-	struct ipmi_bmc_args	args;
-
-	u = bmc_io_wait_spin(sc, offset, mask, value, lbl);
-	if (cold || u != -1)
-		return u;
-
-	sc->sc_retries = 0;
-	sc->sc_wakeup = 1;
-
-	args.offset = offset;
-	args.mask = mask;
-	args.value = value;
-	args.v = &v;
-	sc->sc_iowait_args = &args;
-
-	_bmc_io_wait(sc);
-
-	while (sc->sc_wakeup)
-		tsleep(sc, PWAIT, lbl, 0);
-
-	if (sc->sc_retries > sc->sc_max_retries) {
-		dbg_printf(1, "ipmi: bmc_io_wait fails : v=%.2x m=%.2x "
-		    "b=%.2x %s\n", v, mask, value, lbl);
-		return (-1);
-	}
+	int v;
 
-	return (v);
+	v = bmc_io_wait_spin(sc, offset, mask, value);
+	if (cold || v != -1)
+		return v;
+
+	return bmc_io_wait_sleep(sc, offset, mask, value);
 }
 
 int
 bmc_io_wait_spin(struct ipmi_softc *sc, int offset, uint8_t mask,
-    uint8_t value, const char *lbl)
+    uint8_t value)
 {
-	volatile uint8_t	v;
+	uint8_t	v;
 	int			count = cold ? 5000 : 500;
 	/* ~us */
 
@@ -981,7 +956,7 @@
 
 	/* Block transfer needs 4 extra bytes: length/netfn/seq/cmd + data */
 	*txlen = len + 4;
-	buf = malloc(*txlen, M_DEVBUF, M_WAITOK|M_CANFAIL);
+	buf = ipmi_buf_acquire(sc, *txlen);
 	if (buf == NULL)
 		return (NULL);
 
@@ -1010,7 +985,7 @@
 
 	/* Common needs two extra bytes: nfLun/cmd + data */
 	*txlen = len + 2;
-	buf = malloc(*txlen, M_DEVBUF, M_WAITOK|M_CANFAIL);
+	buf = ipmi_buf_acquire(sc, *txlen);
 	if (buf == NULL)
 		return (NULL);
 
@@ -1022,7 +997,11 @@
 	return (buf);
 }
 
-/* Send an IPMI command */
+/*
+ * ipmi_sendcmd: caller must hold sc_cmd_mtx.
+ *
+ * Send an IPMI command
+ */
 int
 ipmi_sendcmd(struct ipmi_softc *sc, int rssa, int rslun, int netfn, int cmd,
     int txlen, const void *data)
@@ -1062,7 +1041,7 @@
 		goto done;
 	}
 	rc = sc->sc_if->sendmsg(sc, txlen, buf);
-	free(buf, M_DEVBUF);
+	ipmi_buf_release(sc, buf);
 
 	ipmi_delay(sc, 50); /* give bmc chance to digest command */
 
@@ -1070,6 +1049,28 @@
 	return (rc);
 }
 
+void
+ipmi_buf_release(struct ipmi_softc *sc, char *buf)
+{
+	KASSERT(sc->sc_buf_rsvd);
+	KASSERT(sc->sc_buf == buf);
+	sc->sc_buf_rsvd = false;
+}
+
+char *
+ipmi_buf_acquire(struct ipmi_softc *sc, size_t len)
+{
+	KASSERT(len <= sizeof(sc->sc_buf));
+
+	if (sc->sc_buf_rsvd || len > sizeof(sc->sc_buf))
+		return NULL;
+	sc->sc_buf_rsvd = true;
+	return sc->sc_buf;
+}
+
+/*
+ * ipmi_recvcmd: caller must hold sc_cmd_mtx.
+ */
 int
 ipmi_recvcmd(struct ipmi_softc *sc, int maxlen, int *rxlen, void *data)
 {
@@ -1077,7 +1078,7 @@
 	int		rawlen;
 
 	/* Need three extra bytes: netfn/cmd/ccode + data */
-	buf = malloc(maxlen + 3, M_DEVBUF, M_WAITOK|M_CANFAIL);
+	buf = ipmi_buf_acquire(sc, maxlen + 3);
 	if (buf == NULL) {
 		printf("ipmi: ipmi_recvcmd: malloc fails\n");
 		return (-1);
@@ -1099,18 +1100,21 @@
 	    *rxlen);
 	dbg_dump(10, " recv", *rxlen, data);
 
-	free(buf, M_DEVBUF);
+	ipmi_buf_release(sc, buf);
 
 	return (rc);
 }
 
+/*
+ * ipmi_delay: caller must hold sc_cmd_mtx.
+ */
 void
 ipmi_delay(struct ipmi_softc *sc, int ms)
 {
 	if (cold)
 		delay(ms * 1000);
 	else
-		while (tsleep(sc, PWAIT, "ipmicmd", mstohz(ms)) != EWOULDBLOCK);
+		cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_cmd_mtx, mstohz(ms));
 }
 
 /* Read a partial SDR entry */
@@ -1125,15 +1129,19 @@
 	((uint16_t *) cmd)[1] = recordId;
 	cmd[4] = offset;
 	cmd[5] = length;
+	mutex_enter(&sc->sc_cmd_mtx);
 	if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_GET_SDR, 6,
 	    cmd)) {
+		mutex_exit(&sc->sc_cmd_mtx);
 		printf("ipmi: sendcmd fails\n");
 		return (-1);
 	}
 	if (ipmi_recvcmd(sc, 8 + length, &len, cmd)) {
+		mutex_exit(&sc->sc_cmd_mtx);
 		printf("ipmi: getSdrPartial: recvcmd fails\n");
 		return (-1);
 	}
+	mutex_exit(&sc->sc_cmd_mtx);
 	if (nxtRecordId)
 		*nxtRecordId = *(uint16_t *) cmd;
 	memcpy(buffer, cmd + 2, len - 2);
@@ -1152,16 +1160,20 @@
 	uint8_t	*psdr;
 	struct sdrhdr	shdr;
 
+	mutex_enter(&sc->sc_cmd_mtx);
 	/* Reserve SDR */
 	if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_RESERVE_SDR,
 	    0, NULL)) {
+		mutex_exit(&sc->sc_cmd_mtx);
 		printf("ipmi: reserve send fails\n");
 		return (-1);
 	}
 	if (ipmi_recvcmd(sc, sizeof(resid), &len, &resid)) {
+		mutex_exit(&sc->sc_cmd_mtx);
 		printf("ipmi: reserve recv fails\n");
 		return (-1);
 	}
+	mutex_exit(&sc->sc_cmd_mtx);
 	/* Get SDR Header */
 	if (get_sdr_partial(sc, recid, resid, 0, sizeof shdr, &shdr, nxtrec)) {
 		printf("ipmi: get header fails\n");
@@ -1380,14 +1392,19 @@
 		       sysmon_envsys_lim_t *limits)
 {
 	struct sdrtype1	*s1 = (struct sdrtype1 *)psensor->i_sdr;
+	bool failure;
 	int	rxlen;
 	uint8_t	data[32];
 
 	limits->sel_flags = 0;
 	data[0] = psensor->i_num;
-	if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun,
+	mutex_enter(&sc->sc_cmd_mtx);
+	failure =
+	    ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun,
 			 SE_NETFN, SE_GET_SENSOR_THRESHOLD, 1, data) ||
-	    ipmi_recvcmd(sc, sizeof(data), &rxlen, data))
+	    ipmi_recvcmd(sc, sizeof(data), &rxlen, data);
+	mutex_exit(&sc->sc_cmd_mtx);
+	if (failure)
 		return;
 
 	dbg_printf(25, "recvdata: %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
@@ -1485,18 +1502,21 @@
 {
 	struct sdrtype1	*s1 = (struct sdrtype1 *) psensor->i_sdr;
 	uint8_t	data[8];
-	int		rxlen, rv = -1;
+	int		rxlen;
 	envsys_data_t *edata = &sc->sc_sensor[psensor->i_envnum];
 
-	mutex_enter(&sc->sc_lock);
 	memset(data, 0, sizeof(data));
 	data[0] = psensor->i_num;
+
+	mutex_enter(&sc->sc_cmd_mtx);
 	if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun, SE_NETFN,
 	    SE_GET_SENSOR_READING, 1, data))
-		goto done;
+		goto err;
 
 	if (ipmi_recvcmd(sc, sizeof(data), &rxlen, data))
-		goto done;
+		goto err;
+	mutex_exit(&sc->sc_cmd_mtx);
+
 	dbg_printf(10, "values=%.2x %.2x %.2x %.2x %s\n",
 	    data[0],data[1],data[2],data[3], edata->desc);
 	if (data[1] & IPMI_INVALID_SENSOR) {
@@ -1505,10 +1525,10 @@
 	} else {
 		edata->state = ipmi_sensor_status(sc, psensor, edata, data);
 	}
-	rv = 0;
-done:
-	mutex_exit(&sc->sc_lock);
-	return (rv);
+	return 0;
+err:
+	mutex_exit(&sc->sc_cmd_mtx);
+	return -1;
 }
 
 int
@@ -1675,9 +1695,6 @@
 ipmi_refresh_sensors(struct ipmi_softc *sc)
 {
 
-	if (!ipmi_poll)
-		return;
-
 	if (SLIST_EMPTY(&ipmi_sensor_list))
 		return;
 
@@ -1764,27 +1781,35 @@
 	int			len;
 	int			rv = 0;
 
+	memset(&sc, 0, sizeof(sc));
+
 	/* Map registers */
 	if (ipmi_map_regs(&sc, ia) != 0)
 		return 0;
 
 	sc.sc_if->probe(&sc);
 
+	mutex_init(&sc.sc_cmd_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
+	mutex_enter(&sc.sc_cmd_mtx);
 	/* Identify BMC device early to detect lying bios */
 	if (ipmi_sendcmd(&sc, BMC_SA, 0, APP_NETFN, APP_GET_DEVICE_ID,
 	    0, NULL)) {
+		mutex_exit(&sc.sc_cmd_mtx);
 		dbg_printf(1, ": unable to send get device id "
 		    "command\n");
 		goto unmap;
 	}
 	if (ipmi_recvcmd(&sc, sizeof(cmd), &len, cmd)) {
+		mutex_exit(&sc.sc_cmd_mtx);
 		dbg_printf(1, ": unable to retrieve device id\n");
 		goto unmap;
 	}
+	mutex_exit(&sc.sc_cmd_mtx);
 
 	dbg_dump(1, "bmc data", len, cmd);
 	rv = 1; /* GETID worked, we got IPMI */
 unmap:
+	mutex_destroy(&sc.sc_cmd_mtx);
 	ipmi_unmap_regs(&sc);
 
 	return rv;
@@ -1801,17 +1826,17 @@
 	int i;
 	int current_index_typ[ENVSYS_NSENSORS];
 
-	sc->sc_thread_running = 1;
+	sc->sc_thread_running = true;
 
 	/* lock around read_sensor so that no one messes with the bmc regs */
-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->sc_cmd_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
+	cv_init(&sc->sc_cmd_sleep, "ipmicmd");
+
+	mutex_init(&sc->sc_poll_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
+	cv_init(&sc->sc_poll_cv, "ipmi_poll");
 
 	/* setup ticker */
-	sc->sc_retries = 0;
-	sc->sc_wakeup = 0;
 	sc->sc_max_retries = hz * 90; /* 90 seconds max */
-	callout_init(&sc->sc_callout, 0);
-	callout_setfunc(&sc->sc_callout, _bmc_io_wait, sc);
 
 	/* Map registers */
 	ipmi_map_regs(sc, ia);
@@ -1900,11 +1925,17 @@
 	sc->sc_wdog.smw_tickle = ipmi_watchdog_tickle;
 	sysmon_wdog_register(&sc->sc_wdog);
 
+	mutex_enter(&sc->sc_poll_mtx);
 	while (sc->sc_thread_running) {
 		ipmi_refresh_sensors(sc);
-		tsleep(&sc->sc_thread_running, PWAIT, "ipmi_poll",
+		cv_timedwait(&sc->sc_poll_cv, &sc->sc_poll_mtx,
 		    SENSOR_REFRESH_RATE);
+		if (sc->sc_tickle_due) {
+			ipmi_dotickle(sc);
+			sc->sc_tickle_due = false;
+		}
 	}
+	mutex_exit(&sc->sc_poll_mtx);
 	kthread_exit(0);
 }
 
@@ -1930,8 +1961,10 @@
 	int rc;
 	struct ipmi_softc *sc = device_private(self);
 
-	sc->sc_thread_running = 0;
-	wakeup(&sc->sc_thread_running);
+	mutex_enter(&sc->sc_poll_mtx);
+	sc->sc_thread_running = false;
+	cv_signal(&sc->sc_poll_cv);
+	mutex_exit(&sc->sc_poll_mtx);
 
 	if ((rc = sysmon_wdog_unregister(&sc->sc_wdog)) != 0) {
 		if (rc == ERESTART)
@@ -1967,8 +2000,10 @@
 
 	ipmi_unmap_regs(sc);
 
-	callout_destroy(&sc->sc_callout);
-	mutex_destroy(&sc->sc_lock);
+	cv_destroy(&sc->sc_poll_cv);
+	mutex_destroy(&sc->sc_poll_mtx);
+	cv_destroy(&sc->sc_cmd_sleep);
+	mutex_destroy(&sc->sc_cmd_mtx);
 
 	return 0;
 }
@@ -1979,7 +2014,7 @@
 	struct ipmi_softc	*sc = smwdog->smw_cookie;
 	struct ipmi_get_watchdog gwdog;
 	struct ipmi_set_watchdog swdog;
-	int			s, rc, len;
+	int			rc, len;
 
 	if (smwdog->smw_period < 10)
 		return EINVAL;
@@ -1988,32 +2023,31 @@
 	else
 		sc->sc_wdog.smw_period = smwdog->smw_period;
 
-	s = splsoftclock();
+	mutex_enter(&sc->sc_cmd_mtx);
 	/* see if we can properly task to the watchdog */
 	rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
 	    APP_GET_WATCHDOG_TIMER, 0, NULL);
 	rc = ipmi_recvcmd(sc, sizeof(gwdog), &len, &gwdog);
+	mutex_exit(&sc->sc_cmd_mtx);
 	if (rc) {
 		printf("ipmi: APP_GET_WATCHDOG_TIMER returned 0x%x\n", rc);
-		splx(s);
 		return EIO;
 	}
 
 	memset(&swdog, 0, sizeof(swdog));
 	/* Period is 10ths/sec */
-	swdog.wdog_timeout = htole32(sc->sc_wdog.smw_period * 10);
-	swdog.wdog_action = 0;
-	if ((smwdog->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
-		swdog.wdog_action |= IPMI_WDOG_ACT_DISABLED;
-	} else {
-		swdog.wdog_action |= IPMI_WDOG_ACT_RESET;
-	}
+	swdog.wdog_timeout = htole16(sc->sc_wdog.smw_period * 10);
+	if ((smwdog->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED)
+		swdog.wdog_action = IPMI_WDOG_ACT_DISABLED;
+	else
+		swdog.wdog_action = IPMI_WDOG_ACT_RESET;
 	swdog.wdog_use = IPMI_WDOG_USE_USE_OS;
 
-	rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
-	    APP_SET_WATCHDOG_TIMER, sizeof(swdog), &swdog);
-	rc = ipmi_recvcmd(sc, 0, &len, NULL);
-	splx(s);
+	mutex_enter(&sc->sc_cmd_mtx);
+	if ((rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
+	    APP_SET_WATCHDOG_TIMER, sizeof(swdog), &swdog)) == 0)
+		rc = ipmi_recvcmd(sc, 0, &len, NULL);
+	mutex_exit(&sc->sc_cmd_mtx);
 	if (rc) {
 		printf("ipmi: APP_SET_WATCHDOG_TIMER returned 0x%x\n", rc);
 		return EIO;
@@ -2026,17 +2060,27 @@
 ipmi_watchdog_tickle(struct sysmon_wdog *smwdog)
 {
 	struct ipmi_softc	*sc = smwdog->smw_cookie;
-	int			s, rc, len;
 
-	s = splsoftclock();
+	mutex_enter(&sc->sc_poll_mtx);
+	sc->sc_tickle_due = true;
+	cv_signal(&sc->sc_poll_cv);
+	mutex_exit(&sc->sc_poll_mtx);
+	return 0;
+}
+
+void
+ipmi_dotickle(struct ipmi_softc *sc)
+{
+	int			rc, len;
+
+	mutex_enter(&sc->sc_cmd_mtx);
 	/* 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);
-	if (rc) {
-		printf("ipmi: watchdog tickle returned 0x%x\n", rc);
-		return EIO;
+	if ((rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
+	    APP_RESET_WATCHDOG, 0, NULL)) == 0)
+		rc = ipmi_recvcmd(sc, 0, &len, NULL);
+	mutex_exit(&sc->sc_cmd_mtx);
+	if (rc != 0) {
+		printf("%s: watchdog tickle returned 0x%x\n",
+		    device_xname(sc->sc_dev), rc);
 	}
-	return (0);
 }

Reply via email to