Module Name:    src
Committed By:   mlelstv
Date:           Sun Aug  1 08:16:14 UTC 2010

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

Log Message:
sc_cmd_mtx protects a command sequence, no longer abuse it for delays.

Initialize mutexes and condition variables in attach and not in the
asynchronously started kernel thread.

Increase BMC spin timeout from 5ms to 15ms, this is necessary to detect
the BMC in a HP ML110G4 reliably.

Implement non-linear sensors as defined in IPMIv2.0 with some crude
32.32 fixed point arithmetic. This adds some small errors as logarithm
and power functions are only approximated.

Fix sensor index mapping so that sensor limits are computed correctly.


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/x86/include/ipmivar.h
cvs rdiff -u -r1.47 -r1.48 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.10 src/sys/arch/x86/include/ipmivar.h:1.11
--- src/sys/arch/x86/include/ipmivar.h:1.10	Mon Jul 20 19:11:30 2009
+++ src/sys/arch/x86/include/ipmivar.h	Sun Aug  1 08:16:14 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: ipmivar.h,v 1.10 2009/07/20 19:11:30 dyoung Exp $ */
+/* $NetBSD: ipmivar.h,v 1.11 2010/08/01 08:16:14 mlelstv Exp $ */
 
 /*
  * Copyright (c) 2005 Jordan Hargrave
@@ -92,6 +92,7 @@
 	kcondvar_t		sc_poll_cv;
 
 	kmutex_t		sc_cmd_mtx;
+	kmutex_t		sc_sleep_mtx;
 	kcondvar_t		sc_cmd_sleep;
 
 	struct ipmi_bmc_args	*sc_iowait_args;
@@ -103,7 +104,6 @@
 	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;

Index: src/sys/arch/x86/x86/ipmi.c
diff -u src/sys/arch/x86/x86/ipmi.c:1.47 src/sys/arch/x86/x86/ipmi.c:1.48
--- src/sys/arch/x86/x86/ipmi.c:1.47	Sat Jul 17 21:34:39 2010
+++ src/sys/arch/x86/x86/ipmi.c	Sun Aug  1 08:16:14 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipmi.c,v 1.47 2010/07/17 21:34:39 pgoyette Exp $ */
+/*	$NetBSD: ipmi.c,v 1.48 2010/08/01 08:16:14 mlelstv Exp $ */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -52,7 +52,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipmi.c,v 1.47 2010/07/17 21:34:39 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipmi.c,v 1.48 2010/08/01 08:16:14 mlelstv Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -188,7 +188,6 @@
 void	ipmi_attach(device_t, device_t, void *);
 static int ipmi_detach(device_t, int);
 
-long	ipow(long, int);
 long	ipmi_convert(uint8_t, struct sdrtype1 *, long);
 void	ipmi_sensor_name(char *, int, uint8_t, uint8_t *);
 
@@ -304,7 +303,9 @@
 		v = bmc_read(sc, offset);
 		if ((v & mask) == value)
 			return v;
-		cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_cmd_mtx, 1);
+		mutex_enter(&sc->sc_sleep_mtx);
+		cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_sleep_mtx, 1);
+		mutex_exit(&sc->sc_sleep_mtx);
 	}
 	return -1;
 }
@@ -327,7 +328,7 @@
     uint8_t value)
 {
 	uint8_t	v;
-	int			count = cold ? 5000 : 500;
+	int			count = cold ? 15000 : 500;
 	/* ~us */
 
 	while (count--) {
@@ -1113,8 +1114,11 @@
 {
 	if (cold)
 		delay(ms * 1000);
-	else
-		cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_cmd_mtx, mstohz(ms));
+	else {
+		mutex_enter(&sc->sc_sleep_mtx);
+		cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_sleep_mtx, mstohz(ms));
+		mutex_exit(&sc->sc_sleep_mtx);
+	}
 }
 
 /* Read a partial SDR entry */
@@ -1271,39 +1275,168 @@
 	*name = 0;
 }
 
-/* Calculate val * 10^exp */
+/* Sign extend a n-bit value */
 long
-ipow(long val, int exp)
+signextend(unsigned long val, int bits)
+{
+	long msk = (1L << (bits-1))-1;
+
+	return (-(val & ~msk) | val);
+}
+
+
+/* fixpoint arithmetic */
+#define FIX2INT(x)   ((int64_t)((x) >> 32))
+#define INT2FIX(x)   ((int64_t)((int64_t)(x) << 32))
+
+#define FIX2            0x0000000200000000ll /* 2.0 */
+#define FIX3            0x0000000300000000ll /* 3.0 */
+#define FIXE            0x00000002b7e15163ll /* 2.71828182845904523536 */
+#define FIX10           0x0000000a00000000ll /* 10.0 */
+#define FIXMONE         0xffffffff00000000ll /* -1.0 */
+#define FIXHALF         0x0000000080000000ll /* 0.5 */
+#define FIXTHIRD        0x0000000055555555ll /* 0.33333333333333333333 */
+
+#define FIX1LOG2        0x0000000171547653ll /* 1.0/log(2) */
+#define FIX1LOGE        0x0000000100000000ll /* 1.0/log(2.71828182845904523536) */
+#define FIX1LOG10       0x000000006F2DEC55ll /* 1.0/log(10) */
+
+#define FIX1E           0x000000005E2D58D9ll /* 1.0/2.71828182845904523536 */
+
+static int64_t fixlog_a[] = {
+	0x0000000100000000ll /* 1.0/1.0 */,
+	0xffffffff80000000ll /* -1.0/2.0 */,
+	0x0000000055555555ll /* 1.0/3.0 */,
+	0xffffffffc0000000ll /* -1.0/4.0 */,
+	0x0000000033333333ll /* 1.0/5.0 */,
+	0x000000002aaaaaabll /* -1.0/6.0 */,
+	0x0000000024924925ll /* 1.0/7.0 */,
+	0x0000000020000000ll /* -1.0/8.0 */,
+	0x000000001c71c71cll /* 1.0/9.0 */
+}; 
+
+static int64_t fixexp_a[] = {
+	0x0000000100000000ll /* 1.0/1.0 */,
+	0x0000000100000000ll /* 1.0/1.0 */,
+	0x0000000080000000ll /* 1.0/2.0 */,
+	0x000000002aaaaaabll /* 1.0/6.0 */,
+	0x000000000aaaaaabll /* 1.0/24.0 */,
+	0x0000000002222222ll /* 1.0/120.0 */, 
+	0x00000000005b05b0ll /* 1.0/720.0 */,
+	0x00000000000d00d0ll /* 1.0/5040.0 */,
+	0x000000000001a01all /* 1.0/40320.0 */
+};      
+
+static int64_t
+fixmul(int64_t x, int64_t y)
+{
+	int64_t z;
+	int64_t a,b,c,d; 
+	int neg;
+
+	neg = 0;
+	if (x < 0) {
+		x = -x;
+		neg = !neg;
+	}
+	if (y < 0) { 
+		y = -y;
+		neg = !neg;
+	}
+
+	a = FIX2INT(x);
+	b = x - INT2FIX(a);
+	c = FIX2INT(y);
+	d = y - INT2FIX(c);
+
+	z = INT2FIX(a*c) + a * d + b * c + (b/2 * d/2 >> 30);
+
+	return neg ? -z : z;
+}
+
+static int64_t
+poly(int64_t x0, int64_t x, int64_t a[], int n)
 {
-	while (exp > 0) {
-		val *= 10;
-		exp--;
+	int64_t z;
+	int i;
+
+	z  = fixmul(x0, a[0]);
+	for (i=1; i<n; ++i) {
+		x0 = fixmul(x0, x);
+		z  = fixmul(x0, a[i]) + z;
+	}
+	return z;
+}
+
+static int64_t
+logx(int64_t x, int64_t y)
+{
+	int64_t z; 
+
+	if (x <= INT2FIX(0)) {
+		z = INT2FIX(-99999);
+		goto done;
 	}
 
-	while (exp < 0) {
-		val /= 10;
-		exp++;
+	z = INT2FIX(0);
+	while (x >= FIXE) {
+		x = fixmul(x, FIX1E);
+		z += INT2FIX(1);
+	}
+	while (x < INT2FIX(1)) {
+		x = fixmul(x, FIXE);
+		z -= INT2FIX(1);
 	}
 
-	return (val);
+	x -= INT2FIX(1);
+	z += poly(x, x, fixlog_a, sizeof(fixlog_a)/sizeof(fixlog_a[0]));
+	z  = fixmul(z, y);
+
+done:
+	return z;
 }
 
-/* Sign extend a n-bit value */
-long
-signextend(unsigned long val, int bits)
+static int64_t
+powx(int64_t x, int64_t y)
 {
-	long msk = (1L << (bits-1))-1;
+	int64_t k;
 
-	return (-(val & ~msk) | val);
+	if (x == INT2FIX(0))
+		goto done;
+
+	x = logx(x,y);
+
+	if (x < INT2FIX(0)) {
+		x = INT2FIX(0) - x;
+		k = -FIX2INT(x);
+		x = INT2FIX(-k) - x;
+	} else {
+		k = FIX2INT(x);
+		x = x - INT2FIX(k);
+	}
+
+	x = poly(INT2FIX(1), x, fixexp_a, sizeof(fixexp_a)/sizeof(fixexp_a[0]));
+
+	while (k < 0) {
+		x = fixmul(x, FIX1E);
+		++k;
+	}
+	while (k > 0) {
+		x = fixmul(x, FIXE);
+		--k;
+	}
+
+done:
+	return x;
 }
 
 /* Convert IPMI reading from sensor factors */
 long
 ipmi_convert(uint8_t v, struct sdrtype1 *s1, long adj)
 {
-	short	M, B;
+	int64_t	M, B;
 	char	K1, K2;
-	long	val;
+	int64_t	val, v1, v2;
 
 	/* Calculate linear reading variables */
 	M  = signextend((((short)(s1->m_tolerance & 0xC0)) << 2) + s1->m, 10);
@@ -1316,13 +1449,30 @@
 	 *
 	 * This commutes out to:
 	 *  y = L(M*v * 10^(K2+adj) + B * 10^(K1+K2+adj)); */
-	val = ipow(M * v, K2 + adj) + ipow(B, K1 + K2 + adj);
+	v1 = powx(FIX10, INT2FIX(K2 + adj));
+	v2 = powx(FIX10, INT2FIX(K1 + K2 + adj));
+	val = M * v * v1 + B * v2;
 
 	/* Linearization function: y = f(x) 0 : y = x 1 : y = ln(x) 2 : y =
 	 * log10(x) 3 : y = log2(x) 4 : y = e^x 5 : y = 10^x 6 : y = 2^x 7 : y
 	 * = 1/x 8 : y = x^2 9 : y = x^3 10 : y = square root(x) 11 : y = cube
 	 * root(x) */
-	return (val);
+	switch (s1->linear & 0x7f) {
+	case 0: break;
+	case 1: val = logx(val,FIX1LOGE); break;
+	case 2: val = logx(val,FIX1LOG10); break;
+	case 3: val = logx(val,FIX1LOG2); break;
+	case 4: val = powx(FIXE,val); break;
+	case 5: val = powx(FIX10,val); break;
+	case 6: val = powx(FIX2,val); break;
+	case 7: val = powx(val,FIXMONE); break;
+	case 8: val = powx(val,FIX2); break;
+	case 9: val = powx(val,FIX3); break;
+	case 10: val = powx(val,FIXHALF); break;
+	case 11: val = powx(val,FIXTHIRD); break;
+	}
+
+	return FIX2INT(val);
 }
 
 int32_t
@@ -1406,7 +1556,7 @@
 	int	rxlen;
 	uint8_t	data[32];
 
-	*props = 0;
+	*props &= ~(PROP_CRITMIN | PROP_CRITMAX | PROP_WARNMIN | PROP_WARNMAX);
 	data[0] = psensor->i_num;
 	mutex_enter(&sc->sc_cmd_mtx);
 	failure =
@@ -1527,6 +1677,8 @@
 		goto err;
 	mutex_exit(&sc->sc_cmd_mtx);
 
+	dbg_printf(10, "m=%u, m_tolerance=%u, b=%u, b_accuracy=%u, rbexp=%u, linear=%d\n",
+	    s1->m, s1->m_tolerance, s1->b, s1->b_accuracy, s1->rbexp, s1->linear);
 	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) {
@@ -1627,7 +1779,6 @@
 	}
 	dupcnt = 0;
 	sc->sc_nsensors += count;
-	sc->sc_nsensors_typ[typ] += count;
 	for (idx = 0; idx < count; idx++) {
 		psensor = malloc(sizeof(struct ipmi_sensor), M_DEVBUF,
 		    M_WAITOK|M_CANFAIL);
@@ -1836,17 +1987,9 @@
 	uint16_t		rec;
 	struct ipmi_sensor *ipmi_s;
 	int i;
-	int current_index_typ[ENVSYS_NSENSORS];
 
 	sc->sc_thread_running = true;
 
-	/* lock around read_sensor so that no one messes with the bmc regs */
-	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_max_retries = hz * 90; /* 90 seconds max */
 
@@ -1858,14 +2001,6 @@
 		if (get_sdr(sc, rec, &rec))
 			break;
 
-	/* fill in sensor infos: */
-	/* get indexes for each unit, and number of units */
-	current_index_typ[0] = 0;
-	for (i = 1; i < ENVSYS_NSENSORS; i++) {
-		current_index_typ[i] =
-		    current_index_typ[i-1] + sc->sc_nsensors_typ[i - 1];
-	}
-
 	/* allocate and fill sensor arrays */
 	sc->sc_sensor =
 	    malloc(sizeof(envsys_data_t) * sc->sc_nsensors,
@@ -1880,11 +2015,10 @@
 	sc->sc_envsys->sme_get_limits = ipmi_get_limits;
 	sc->sc_envsys->sme_set_limits = ipmi_set_limits;
 
+	i = 0;
 	SLIST_FOREACH(ipmi_s, &ipmi_sensor_list, i_list) {
-		i = current_index_typ[ipmi_s->i_envtype];
-		current_index_typ[ipmi_s->i_envtype]++;
-		ipmi_s->i_envnum = i;
 		ipmi_s->i_props = 0;
+		ipmi_s->i_envnum = -1;
 		sc->sc_sensor[i].units = ipmi_s->i_envtype;
 		sc->sc_sensor[i].state = ENVSYS_SINVALID;
 		/*
@@ -1901,9 +2035,14 @@
 		}
 		(void)strlcpy(sc->sc_sensor[i].desc, ipmi_s->i_envdesc,
 		    sizeof(sc->sc_sensor[i].desc));
+		++i;
+
 		if (sysmon_envsys_sensor_attach(sc->sc_envsys,
-						&sc->sc_sensor[i]))
+						&sc->sc_sensor[i-1]))
 			continue;
+
+		/* get reference number from envsys */
+		ipmi_s->i_envnum = sc->sc_sensor[i-1].sensor;
 	}
 
 	sc->sc_envsys->sme_name = device_xname(sc->sc_dev);
@@ -1963,6 +2102,14 @@
 	sc->sc_dev = self;
 	aprint_normal("\n");
 
+	/* lock around read_sensor so that no one messes with the bmc regs */
+	mutex_init(&sc->sc_cmd_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
+	mutex_init(&sc->sc_sleep_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");
+
 	if (kthread_create(PRI_NONE, 0, NULL, ipmi_thread, self,
 	    &sc->sc_kthread, "ipmi") != 0) {
 		aprint_error("ipmi: unable to create thread, disabled\n");
@@ -2018,6 +2165,7 @@
 	cv_destroy(&sc->sc_poll_cv);
 	mutex_destroy(&sc->sc_poll_mtx);
 	cv_destroy(&sc->sc_cmd_sleep);
+	mutex_destroy(&sc->sc_sleep_mtx);
 	mutex_destroy(&sc->sc_cmd_mtx);
 
 	return 0;

Reply via email to