On Sun, Dec 19, 2010 at 04:12:02PM +0100, Christopher Zimmermann wrote:
> Hi,
> 
> I've finally found some time to work on the fan control support for my
> thinkpad.
> But I'm having problems calling to acpiec_write() from sysctl or
> timeout_set(9) context. (Assertion failure in acpiec_gpehandler()).
> According to dev/acpi/acpiec.c:229 this function is meant to be called
> only from "acpi thread context".
> Now how am I supposed to talk to the acpi controller?

You are not supposed to talk directly to the ec device.

Jordan has a diff floating around for acpi tasklets.  This really should
be the way to get this done.  I'll forward the diff to tech with the
caveat that it isn't finalized yet.

I would prefer for this fan stuff to be automatic instead of by hand
based on the apm heuristics.

> One solution would be to use the aml_register_notify(..., ACPIDEV_POLL)
> callback mechanism already in use by the acpithinkpad(4) driver to
> somehow get into acpi thread context. The problem is that this callback
> mechanism is hardcoded to 10s intervals. But I need intervals <1s to
> implement a workaround described on
> http://www.thinkwiki.org/wiki/How_to_control_fan_speed#Disengaged_.28full-speed.29_mode
> 
> any help is appreciated. I'm stuck here.
> 
> Christopher
> 
> 
> 
> this is what I've got so far:
> 
> Index: arch/i386/i386/machdep.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/i386/i386/machdep.c,v
> retrieving revision 1.485
> diff -u -p -r1.485 machdep.c
> --- arch/i386/i386/machdep.c  2 Oct 2010 23:31:34 -0000       1.485
> +++ arch/i386/i386/machdep.c  19 Dec 2010 15:11:09 -0000
> @@ -243,6 +243,7 @@ void      via_update_sensor(void *args);
>  #endif
>  int kbd_reset;
>  int lid_suspend;
> +int fan_control;
> 
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
> @@ -3416,6 +3417,8 @@ cpu_sysctl(int *name, u_int namelen, voi
>               return (sysctl_rdint(oldp, oldlenp, newp, i386_has_xcrypt));
>       case CPU_LIDSUSPEND:
>               return (sysctl_int(oldp, oldlenp, newp, newlen, &lid_suspend));
> +     case CPU_FANCONTROL:
> +             return (sysctl_int(oldp, oldlenp, newp, newlen, &fan_control));
>       default:
>               return (EOPNOTSUPP);
>       }
> Index: arch/i386/include/cpu.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/i386/include/cpu.h,v
> retrieving revision 1.117
> diff -u -p -r1.117 cpu.h
> --- arch/i386/include/cpu.h   2 Oct 2010 23:13:28 -0000       1.117
> +++ arch/i386/include/cpu.h   19 Dec 2010 15:11:09 -0000
> @@ -461,7 +461,8 @@ void      vm86_gpfault(struct proc *, int);
>  #define CPU_SSE2             15      /* supports SSE2 */
>  #define CPU_XCRYPT           16      /* supports VIA xcrypt in userland */
>  #define CPU_LIDSUSPEND               17      /* lid close causes a suspend */
> -#define CPU_MAXID            18      /* number of valid machdep ids */
> +#define CPU_FANCONTROL               18      /* lid close causes a suspend */
> +#define CPU_MAXID            19      /* number of valid machdep ids */
> 
>  #define      CTL_MACHDEP_NAMES { \
>       { 0, 0 }, \
> @@ -482,6 +483,7 @@ void      vm86_gpfault(struct proc *, int);
>       { "sse2", CTLTYPE_INT }, \
>       { "xcrypt", CTLTYPE_INT }, \
>       { "lidsuspend", CTLTYPE_INT }, \
> +     { "fancontrol", CTLTYPE_INT }, \
>  }
> 
>  /*
> Index: dev/acpi/acpithinkpad.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/acpithinkpad.c,v
> retrieving revision 1.24
> diff -u -p -r1.24 acpithinkpad.c
> --- dev/acpi/acpithinkpad.c   7 Aug 2010 16:21:20 -0000       1.24
> +++ dev/acpi/acpithinkpad.c   19 Dec 2010 15:11:17 -0000
> @@ -77,6 +77,16 @@
>  #define THINKPAD_ECOFFSET_FANLO              0x84
>  #define THINKPAD_ECOFFSET_FANHI              0x85
> 
> +#define THINKPAD_ECOFFSET_FANCTL     0x2f
> +#define THINKPAD_FAN_REGVAL          0xff
> +/* Most thinkpads only support only speed steps 1-7 */
> +#define THINKPAD_FAN_MANUAL          0x3f
> +#define THINKPAD_FAN_DISENGAGE               0x40
> +#define THINKPAD_FAN_AUTO            0x80
> +/* AntiPulse */
> +#define THINKPAD_FAN_AP                      0x100
> +#define THINKPAD_FAN_AP_DISENGAGE    0x200
> +
>  struct acpithinkpad_softc {
>       struct device            sc_dev;
> 
> @@ -86,8 +96,13 @@ struct acpithinkpad_softc {
> 
>       struct ksensor           sc_sens[THINKPAD_NSENSORS];
>       struct ksensordev        sc_sensdev;
> +
> +     /* Fan control */
> +     struct timeout          sc_fan_timeout;
>  };
> 
> +extern int fan_control;
> +
>  extern void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
> 
>  int  thinkpad_match(struct device *, void *, void *);
> @@ -103,8 +118,9 @@ 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 *);
> +void    thinkpad_fancontrol(void *);
> 
>  struct cfattach acpithinkpad_ca = {
>       sizeof(struct acpithinkpad_softc), thinkpad_match, thinkpad_attach
> @@ -185,6 +201,46 @@ thinkpad_sensor_refresh(void *arg)
>  }
> 
>  void
> +thinkpad_fancontrol(void *arg)
> +{
> +     u_int8_t fanctl;
> +
> +     struct acpithinkpad_softc *sc = arg;
> +
> +     if (fan_control & THINKPAD_FAN_AP)
> +     {
> +             if (fan_control & THINKPAD_FAN_AP_DISENGAGE)
> +             {
> +                     fanctl = fan_control & 0xff;
> +                     fan_control &= ~THINKPAD_FAN_AP_DISENGAGE;
> +                     timeout_add_sec(&sc->sc_fan_timeout, 1);
> +             }
> +             else
> +             {
> +                     fanctl = 0x40;
> +                     fan_control |= THINKPAD_FAN_AP_DISENGAGE;
> +                     timeout_add_sec(&sc->sc_fan_timeout, 4);
> +             }
> +
> +     }
> +     else if ((fan_control & 0xff) != fanctl)
> +     {
> +             fanctl = fan_control & 0xff;
> +             timeout_add_sec(&sc->sc_fan_timeout, 5);
> +     }
> +     else
> +             return;
> +
> +     printf("thinkpad_fancontrol: setting to 0x%.2hhx",
> +                     fanctl);
> +     acpiec_write(sc->sc_acpi->sc_ec,
> +                     THINKPAD_ECOFFSET_FANCTL,
> +                     1,
> +                     &fanctl);
> +     printf(".\n");
> +}
> +
> +void
>  thinkpad_attach(struct device *parent, struct device *self, void *aux)
>  {
>       struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self;
> @@ -202,6 +258,13 @@ 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);
> +
> +     /* automatic fan control, AntiPulse disable by default*/
> +     fan_control = THINKPAD_FAN_AUTO;
> +
> +     /* Initialize and start fan timer */
> +     timeout_set(&sc->sc_fan_timeout, thinkpad_fancontrol, sc);
> +     timeout_add_sec(&sc->sc_fan_timeout, 1);
>  }
> 
>  int

  • acpi and sysctl Christopher Zimmermann
    • Re: acpi and sysctl Marco Peereboom

Reply via email to