As we all know, some Thinkpads have problems with their EC fan control.
EC is not spinning up the fans to maximum speed, let alone blast mode.
They also do not offer ACPI methods to spin the fan up.

Previous diffs doing manual fan control were always rejected because
hooking into the sensors framework with fixed temp limits is crude and
there are concerns with slowing the fan down and frying the hardware.

This is an attempt to solve the problem slightly differently.
- Hook into acpitz and only speed the fan up when it is requesting active
  cooling
- Never set the fan to a mode that would endanger the hardware should we
  crash

PS: It would be nice if there was a function to add cooling methods to
acpitz eg: acpitz_add(void (*fn)(struct acpitz_softc *, void *), void *arg)
I tried but getting struct acpitz_softc into a header is a bit messy.

Index: acpithinkpad.c
===================================================================
RCS file: /home/vcs/cvs/openbsd/src/sys/dev/acpi/acpithinkpad.c,v
retrieving revision 1.44
diff -u -p -r1.44 acpithinkpad.c
--- acpithinkpad.c      24 Apr 2015 14:44:17 -0000      1.44
+++ acpithinkpad.c      14 Jul 2015 23:52:14 -0000
@@ -104,6 +104,11 @@
 #define THINKPAD_ECOFFSET_FANLO                0x84
 #define THINKPAD_ECOFFSET_FANHI                0x85
 
+#define THINKPAD_ECOFFSET_FANLEVEL     0x2f
+#define THINKPAD_ECFANLEVEL_MAX                7
+#define THINKPAD_ECFANLEVEL_BLAST      (1<<6)
+#define THINKPAD_ECFANLEVEL_AUTO       (1<<7)
+
 #define        THINKPAD_ADAPTIVE_MODE_HOME     1
 #define        THINKPAD_ADAPTIVE_MODE_FUNCTION 3
 
@@ -119,6 +124,7 @@ struct acpithinkpad_softc {
 };
 
 extern void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
+extern void (*acpitz_activecool)(int, int);
 
 int    thinkpad_match(struct device *, void *, void *);
 void   thinkpad_attach(struct device *, struct device *, void *);
@@ -134,6 +140,7 @@ int thinkpad_brightness_up(struct acpith
 int    thinkpad_brightness_down(struct acpithinkpad_softc *);
 int    thinkpad_adaptive_change(struct acpithinkpad_softc *);
 int    thinkpad_activate(struct device *, int);
+void    thinkpad_activecool(int, int);
 
 void    thinkpad_sensor_attach(struct acpithinkpad_softc *sc);
 void    thinkpad_sensor_refresh(void *);
@@ -228,6 +235,7 @@ thinkpad_attach(struct device *parent, s
 {
        struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self;
        struct acpi_attach_args *aa = aux;
+       u_int8_t level;
 
        sc->sc_acpi = (struct acpi_softc *)parent;
        sc->sc_devnode = aa->aaa_node;
@@ -241,6 +249,11 @@ thinkpad_attach(struct device *parent, s
        /* Run thinkpad_hotkey on button presses */
        aml_register_notify(sc->sc_devnode, aa->aaa_dev,
            thinkpad_hotkey, sc, ACPIDEV_POLL);
+
+       /* Make sure fan is in auto mode, otherwise we're not sure of support */
+       acpiec_read(acpi_softc->sc_ec, THINKPAD_ECOFFSET_FANLEVEL, 1, &level);
+       if (level == THINKPAD_ECFANLEVEL_AUTO)
+               acpitz_activecool = thinkpad_activecool;
 }
 
 int
@@ -546,4 +559,30 @@ thinkpad_activate(struct device *self, i
                break;
        }
        return (0);
+}
+
+void
+thinkpad_activecool(int tmp, int psv)
+{
+       static uint8_t level = THINKPAD_ECFANLEVEL_AUTO;
+       uint8_t nlevel;
+
+       if (tmp < 0 || psv < 0)
+               return;
+
+       if (tmp > psv)
+               nlevel = THINKPAD_ECFANLEVEL_BLAST;
+       else if (tmp > psv-50)
+               /* EC firmware fan control is too slow in some models. When
+                * we're getting within 5C of active cooling mode, turn the
+                * fan to MAX. Helps with oscillation between blast and auto */
+               nlevel = THINKPAD_ECFANLEVEL_MAX;
+       else
+               nlevel = THINKPAD_ECFANLEVEL_AUTO;
+
+       if (nlevel != level) {
+               acpiec_write(acpi_softc->sc_ec, THINKPAD_ECOFFSET_FANLEVEL, 1,
+                   &nlevel);
+               level = nlevel;
+       }
 }
Index: acpitz.c
===================================================================
RCS file: /home/vcs/cvs/openbsd/src/sys/dev/acpi/acpitz.c,v
retrieving revision 1.49
diff -u -p -r1.49 acpitz.c
--- acpitz.c    6 May 2015 01:41:55 -0000       1.49
+++ acpitz.c    14 Jul 2015 23:52:14 -0000
@@ -86,6 +86,7 @@ int   acpitz_setfan(struct acpitz_softc *,
 void   acpitz_init(struct acpitz_softc *, int);
 
 void           (*acpitz_cpu_setperf)(int);
+void            (*acpitz_activecool)(int, int) = NULL;
 int            acpitz_perflevel = -1;
 extern void    (*cpu_setperf)(int);
 extern int     perflevel;
@@ -427,6 +428,11 @@ acpitz_refresh(void *arg)
                                acpitz_setfan(sc, i, "_OFF");
                }
        }
+
+       /* active cooling hook */
+       if (acpitz_activecool)
+               acpitz_activecool(sc->sc_tmp, sc->sc_psv);
+
        sc->sc_sens.value = sc->sc_tmp * 100000 - 50000;
 }
 

Reply via email to