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