On Tue, 29 Jan 2013, David Coppa wrote:
> On Tue, Jan 29, 2013 at 11:17 AM, Andriy Samsonyuk
> <[email protected]> wrote:
> > Hi,
> >
> > is apm/apmd the only wat to change the fan speen?
> >
> > The fan speen never goes above:
> > hw.sensors.acpithinkpad0.fan0=4527 RPM
> > +- few RPMs
> >
> > if i set apmd -C or -A the laptop powers off after a while
> > without any warnings.
> >
> > with apm -L or -H its running, but getting hotter.
> >
> > Any suggestions/ideas?
>
> Try this patch by zhuk@:
>
> http://marc.info/?l=openbsd-tech&m=135645173413550
Attached to this mail, at your convenience...
Ciao,
David
Index: acpithinkpad.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpithinkpad.c,v
retrieving revision 1.28
diff -u -p -r1.28 acpithinkpad.c
--- acpithinkpad.c 6 Jun 2011 06:13:46 -0000 1.28
+++ acpithinkpad.c 25 Dec 2012 15:19:25 -0000
@@ -76,11 +76,25 @@
#define THINKPAD_POWER_CHANGED 0x6030
#define THINKPAD_SWITCH_WIRELESS 0x7000
-#define THINKPAD_NSENSORS 9
-#define THINKPAD_NTEMPSENSORS 8
+#define THINKPAD_NSENSORS 10
+#define THINKPAD_NTEMPSENSORS 8
+
+#define THINKPAD_SENSOR_FANRPM (THINKPAD_NTEMPSENSORS + 0)
+#define THINKPAD_SENSOR_FANMODE (THINKPAD_NTEMPSENSORS + 1)
#define THINKPAD_ECOFFSET_FANLO 0x84
#define THINKPAD_ECOFFSET_FANHI 0x85
+#define THINKPAD_ECOFFSET_FANMODE 0x2f
+
+/* not used: #define THINKPAD_FANMODE_MIN 0x00 */
+#define THINKPAD_FANMODE_MAX 0x07
+#define THINKPAD_FANMODE_AUTO 0x80
+#define THINKPAD_FANMODE_DISENGAGED 0x40
+#define THINKPAD_FANMODE_FORCEMAX (THINKPAD_FANMODE_MAX |
THINKPAD_FANMODE_DISENGAGED)
+
+/* critical temperature marks, in Celsius */
+#define THINKPAD_TEMP_OUCH_HMARK 80
+#define THINKPAD_TEMP_OUCH_LMARK 70
struct acpithinkpad_softc {
struct device sc_dev;
@@ -90,7 +104,10 @@ struct acpithinkpad_softc {
struct aml_node *sc_devnode;
struct ksensor sc_sens[THINKPAD_NSENSORS];
+#define sc_sensfanmode sc_sens[THINKPAD_SENSOR_FANMODE]
struct ksensordev sc_sensdev;
+
+ u_int8_t sc_fanmodeinit;
};
extern void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
@@ -108,7 +125,7 @@ int thinkpad_volume_mute(struct acpithin
int thinkpad_brightness_up(struct acpithinkpad_softc *);
int thinkpad_brightness_down(struct acpithinkpad_softc *);
-void thinkpad_sensor_attach(struct acpithinkpad_softc *sc);
+void thinkpad_sensor_attach(struct acpithinkpad_softc *);
void thinkpad_sensor_refresh(void *);
#if NAUDIO > 0 && NWSKBD > 0
@@ -165,8 +182,14 @@ thinkpad_sensor_attach(struct acpithinkp
}
/* Add fan probe */
- sc->sc_sens[i].type = SENSOR_FANRPM;
- sensor_attach(&sc->sc_sensdev, &sc->sc_sens[i]);
+ sc->sc_sens[THINKPAD_SENSOR_FANRPM].type = SENSOR_FANRPM;
+ sensor_attach(&sc->sc_sensdev, &sc->sc_sens[THINKPAD_SENSOR_FANRPM]);
+
+ /* Add fan mode indicator */
+ sc->sc_sens[THINKPAD_SENSOR_FANMODE].type = SENSOR_INTEGER;
+ sensor_attach(&sc->sc_sensdev, &sc->sc_sens[THINKPAD_SENSOR_FANMODE]);
+ acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANMODE, 1,
+ &sc->sc_fanmodeinit);
sensordev_install(&sc->sc_sensdev);
}
@@ -176,8 +199,10 @@ thinkpad_sensor_refresh(void *arg)
{
struct acpithinkpad_softc *sc = arg;
u_int8_t lo, hi, i;
- int64_t tmp;
+ int64_t tmp, maxtmp = -127; /* minimal correct value, see below */
+ int updatemode = 0; /* should we bother BIOS? */
char sname[5];
+ const char *desc;
/* Refresh sensor readings */
for (i=0; i<THINKPAD_NTEMPSENSORS; i++) {
@@ -185,14 +210,60 @@ thinkpad_sensor_refresh(void *arg)
aml_evalinteger(sc->sc_acpi, sc->sc_ec->sc_devnode,
sname, 0, 0, &tmp);
sc->sc_sens[i].value = (tmp * 1000000) + 273150000;
- if (tmp > 127 || tmp < -127)
+ if (tmp > 127 || tmp < -127) {
sc->sc_sens[i].flags = SENSOR_FINVALID;
+ sc->sc_sens[i].status = SENSOR_S_UNKNOWN;
+ }
+ if ((sc->sc_sens[i].flags & SENSOR_FINVALID) == SENSOR_FINVALID)
+ continue;
+ if (tmp > maxtmp)
+ maxtmp = tmp;
+ if (tmp > THINKPAD_TEMP_OUCH_HMARK)
+ sc->sc_sens[i].status = SENSOR_S_CRIT;
+ else if (tmp > THINKPAD_TEMP_OUCH_LMARK)
+ sc->sc_sens[i].status = SENSOR_S_WARN;
+ else
+ sc->sc_sens[i].status = SENSOR_S_OK;
}
/* Read fan RPM */
acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANLO, 1, &lo);
acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANHI, 1, &hi);
- sc->sc_sens[i].value = ((hi << 8L) + lo);
+ sc->sc_sens[THINKPAD_SENSOR_FANRPM].value = ((hi << 8L) + lo);
+
+ /*
+ * Update fan mode based on max temperature seen.
+ * If temperature is between THINKPAD_TEMP_OUCH_LMARK and
+ * THINKPAD_TEMP_OUCH_HMARK, we try to avoid setting fan mode
+ * to avoid extra spinning.
+ */
+
+ if (maxtmp > THINKPAD_TEMP_OUCH_HMARK) {
+ sc->sc_sensfanmode.value = THINKPAD_FANMODE_FORCEMAX;
+ sc->sc_sensfanmode.status = SENSOR_S_CRIT;
+ desc = "disengaged";
+ updatemode = 1;
+ } else if (maxtmp <= THINKPAD_TEMP_OUCH_LMARK) {
+ sc->sc_sensfanmode.value = sc->sc_fanmodeinit;
+ sc->sc_sensfanmode.status = SENSOR_S_OK;
+ desc = "auto";
+ updatemode = 1;
+ } else {
+ if (sc->sc_sensfanmode.status == SENSOR_S_UNSPEC) {
+ /* Better safe than sorry */
+ sc->sc_sensfanmode.value = THINKPAD_FANMODE_FORCEMAX;
+ desc = "disengaged";
+ updatemode = 1;
+ }
+ sc->sc_sensfanmode.status = SENSOR_S_WARN;
+ }
+
+ if (updatemode) {
+ snprintf(sc->sc_sensfanmode.desc,
+ sizeof(sc->sc_sensfanmode.desc), "fan mode: %s", desc);
+ acpiec_write(sc->sc_ec, THINKPAD_ECOFFSET_FANMODE, 1,
+ (u_int8_t*)&sc->sc_sensfanmode.value);
+ }
}
void