Fix the dbcool_{get,set}_limits() routines to properly deal with min/max

values on temp limits.  The actual ranges for temp limits varies if the
chip is running in "extended temperature" mode, so we need to handle this
difference, too.

Verified on my home machine which runs in extended-temp mode and by
njoly@ on a machine which does runs in the older 2s-complement mode.
This commit is contained in:
pgoyette 2010-03-20 02:42:19 +00:00
parent 2ff643e1f6
commit 9a70d7bce8

View File

@ -1,4 +1,4 @@
/* $NetBSD: dbcool.c,v 1.18 2010/03/01 03:14:49 pgoyette Exp $ */
/* $NetBSD: dbcool.c,v 1.19 2010/03/20 02:42:19 pgoyette Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@ -49,7 +49,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: dbcool.c,v 1.18 2010/03/01 03:14:49 pgoyette Exp $");
__KERNEL_RCSID(0, "$NetBSD: dbcool.c,v 1.19 2010/03/20 02:42:19 pgoyette Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -1377,6 +1377,11 @@ dbcool_setup(device_t self)
else
sc->sc_root_sysctl_num = 0;
aprint_debug_dev(self, "Supply voltage %ld.%06ldV, %s temp range\n",
sc->sc_supply_voltage / 1000000,
sc->sc_supply_voltage % 1000000,
sc->sc_temp_offset ? "extended" : "normal");
/* Create the sensors for this device */
sc->sc_sme = sysmon_envsys_create();
if (dbcool_setup_sensors(sc))
@ -1722,6 +1727,7 @@ dbcool_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
int index = edata->sensor;
struct dbcool_softc *sc = sme->sme_cookie;
*props &= ~(PROP_CRITMIN | PROP_CRITMAX);
switch (edata->units) {
case ENVSYS_STEMP:
dbcool_get_temp_limits(sc, index, limits, props);
@ -1737,6 +1743,12 @@ dbcool_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
break;
}
*props &= ~PROP_DRIVER_LIMITS;
/* If both limits provided, make sure they're sane */
if ((*props & PROP_CRITMIN) &&
(*props & PROP_CRITMAX) &&
(limits->sel_critmin >= limits->sel_critmax))
*props &= ~(PROP_CRITMIN | PROP_CRITMAX);
}
static void
@ -1744,37 +1756,37 @@ dbcool_get_temp_limits(struct dbcool_softc *sc, int idx,
sysmon_envsys_lim_t *lims, uint32_t *props)
{
struct reg_list *reg = sc->sc_regs[idx];
int32_t limit;
uint8_t lo_lim, hi_lim;
lo_lim = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->lo_lim_reg);
hi_lim = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->hi_lim_reg);
if (sc->sc_temp_offset) {
limit = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->lo_lim_reg);
limit -= sc->sc_temp_offset;
} else
limit = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc,
reg->lo_lim_reg);
if (limit) {
limit *= 1000000;
limit += 273150000;
lims->sel_critmin = limit;
if (lo_lim > 0x01) {
lims->sel_critmin = lo_lim - sc->sc_temp_offset;
*props |= PROP_CRITMIN;
} else
*props &= ~PROP_CRITMIN;
if (sc->sc_temp_offset) {
limit = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->hi_lim_reg);
limit -= sc->sc_temp_offset;
} else
limit = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc,
reg->hi_lim_reg);
if (limit) {
limit *= 1000000;
limit += 273150000;
lims->sel_critmax = limit;
}
if (hi_lim != 0xff) {
lims->sel_critmax = hi_lim - sc->sc_temp_offset;
*props |= PROP_CRITMAX;
} else
*props &= ~PROP_CRITMAX;
}
} else {
if (lo_lim != 0x80 && lo_lim != 0x81) {
lims->sel_critmin = (int8_t)lo_lim;
*props |= PROP_CRITMIN;
}
if (hi_lim != 0x7f) {
lims->sel_critmax = (int8_t)hi_lim;
*props |= PROP_CRITMAX;
}
}
/* Convert temp limits to microKelvin */
lims->sel_critmin *= 1000000;
lims->sel_critmin += 273150000;
lims->sel_critmax *= 1000000;
lims->sel_critmax += 273150000;
}
static void
@ -1791,18 +1803,14 @@ dbcool_get_volt_limits(struct dbcool_softc *sc, int idx,
nom *= 1000000; /* scale for microvolts */
limit = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->lo_lim_reg);
if (limit == 0x00 || limit == 0xff)
*props &= ~PROP_CRITMIN;
else {
if (limit != 0x00 && limit != 0xff) {
limit *= nom;
limit /= 0xc0;
lims->sel_critmin = limit;
*props |= PROP_CRITMIN;
}
limit = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->hi_lim_reg);
if (limit == 0x00 || limit == 0xff)
*props &= ~PROP_CRITMAX;
else {
if (limit != 0x00 && limit != 0xff) {
limit *= nom;
limit /= 0xc0;
lims->sel_critmax = limit;
@ -1821,8 +1829,7 @@ dbcool_get_fan_limits(struct dbcool_softc *sc, int idx,
if (limit) {
lims->sel_critmin = limit;
*props |= PROP_CRITMIN;
} else
*props &= ~PROP_CRITMIN;
}
}
/*
@ -1862,25 +1869,45 @@ dbcool_set_temp_limits(struct dbcool_softc *sc, int idx,
if (*props & PROP_CRITMIN) {
limit = lims->sel_critmin - 273150000;
limit /= 1000000;
if (sc->sc_temp_offset) {
limit += sc->sc_temp_offset;
if (limit < 0)
limit = 0;
else if (limit > 0xff)
limit = 0xff;
else if (limit > 255)
limit = 255;
} else {
if (limit < -127)
limit = -127;
else if (limit > 127)
limit = 127;
}
} else
limit = 0;
if (sc->sc_temp_offset)
limit = 0x00;
else
limit = 0x80;
sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg, (uint8_t)limit);
if (*props & PROP_CRITMAX) {
limit = lims->sel_critmax - 273150000;
limit /= 1000000;
if (sc->sc_temp_offset) {
limit += sc->sc_temp_offset;
if (limit < 0)
limit = 0;
else if (limit > 0xff)
limit = 0xff;
else if (limit > 255)
limit = 255;
} else {
if (limit < -127)
limit = -127;
else if (limit > 127)
limit = 127;
}
} else
if (sc->sc_temp_offset)
limit = 0xff;
else
limit = 0x7f;
sc->sc_dc.dc_writereg(&sc->sc_dc, reg->hi_lim_reg, (uint8_t)limit);
}