1*0f9e9ec2Sjsg /* $OpenBSD: acpitz.c,v 1.60 2024/05/13 01:15:50 jsg Exp $ */
2588ea222Scanacar /*
3588ea222Scanacar * Copyright (c) 2006 Can Erkin Acar <canacar@openbsd.org>
4588ea222Scanacar * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
5588ea222Scanacar *
6588ea222Scanacar * Permission to use, copy, modify, and distribute this software for any
7588ea222Scanacar * purpose with or without fee is hereby granted, provided that the above
8588ea222Scanacar * copyright notice and this permission notice appear in all copies.
9588ea222Scanacar *
10588ea222Scanacar * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11588ea222Scanacar * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12588ea222Scanacar * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13588ea222Scanacar * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14588ea222Scanacar * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15588ea222Scanacar * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16588ea222Scanacar * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17588ea222Scanacar */
18588ea222Scanacar
19588ea222Scanacar #include <sys/param.h>
20588ea222Scanacar #include <sys/proc.h>
21588ea222Scanacar #include <sys/signalvar.h>
22588ea222Scanacar #include <sys/systm.h>
23588ea222Scanacar #include <sys/device.h>
24588ea222Scanacar #include <sys/malloc.h>
2563c8bcf8Smarco #include <sys/kernel.h>
26262397e4Smarco #include <sys/kthread.h>
27588ea222Scanacar
28588ea222Scanacar #include <machine/bus.h>
29588ea222Scanacar
30588ea222Scanacar #include <dev/acpi/acpivar.h>
31588ea222Scanacar #include <dev/acpi/acpidev.h>
32588ea222Scanacar #include <dev/acpi/amltypes.h>
33588ea222Scanacar #include <dev/acpi/dsdt.h>
34588ea222Scanacar
35588ea222Scanacar #include <sys/sensors.h>
36588ea222Scanacar
3763c8bcf8Smarco #define KTOC(k) ((k - 2732) / 10)
3863c8bcf8Smarco #define ACPITZ_MAX_AC (10)
3963c8bcf8Smarco #define ACPITZ_TMP_RETRY (3)
40576e0c08Ssemarie #define ACPITZ_UNKNOWN (-1)
41854d2903Smarco
42588ea222Scanacar struct acpitz_softc {
43588ea222Scanacar struct device sc_dev;
44588ea222Scanacar
45588ea222Scanacar struct acpi_softc *sc_acpi;
46588ea222Scanacar struct aml_node *sc_devnode;
47588ea222Scanacar
48854d2903Smarco int sc_tmp;
49854d2903Smarco int sc_crt;
50854d2903Smarco int sc_hot;
51854d2903Smarco int sc_ac[ACPITZ_MAX_AC];
52854d2903Smarco int sc_ac_stat[ACPITZ_MAX_AC];
53854d2903Smarco int sc_pse;
54854d2903Smarco int sc_psv;
55854d2903Smarco int sc_tc1;
56854d2903Smarco int sc_tc2;
57854d2903Smarco int sc_lasttmp;
585bdf07b2Sjordan
59275cbf62Sderaadt struct ksensor sc_sens;
60275cbf62Sderaadt struct ksensordev sc_sensdev;
615bdf07b2Sjordan
625bdf07b2Sjordan struct acpi_devlist_head sc_psl;
635bdf07b2Sjordan struct acpi_devlist_head sc_alx[ACPITZ_MAX_AC];
64588ea222Scanacar };
65588ea222Scanacar
66588ea222Scanacar int acpitz_match(struct device *, void *, void *);
67588ea222Scanacar void acpitz_attach(struct device *, struct device *, void *);
6834e64ca6Sderaadt int acpitz_activate(struct device *, int);
69588ea222Scanacar
70471aeecfSnaddy const struct cfattach acpitz_ca = {
7134e64ca6Sderaadt sizeof(struct acpitz_softc), acpitz_match, acpitz_attach,
7234e64ca6Sderaadt NULL, acpitz_activate
73588ea222Scanacar };
74588ea222Scanacar
75588ea222Scanacar struct cfdriver acpitz_cd = {
76588ea222Scanacar NULL, "acpitz", DV_DULL
77588ea222Scanacar };
78588ea222Scanacar
79262397e4Smarco void acpitz_init_perf(void *);
80262397e4Smarco void acpitz_setperf(int);
81588ea222Scanacar void acpitz_refresh(void *);
82588ea222Scanacar int acpitz_notify(struct aml_node *, int, void *);
8363c8bcf8Smarco int acpitz_gettempreading(struct acpitz_softc *, char *);
84911b45c8Smarco int acpitz_getreading(struct acpitz_softc *, char *);
85854d2903Smarco int acpitz_setfan(struct acpitz_softc *, int, char *);
865bdf07b2Sjordan void acpitz_init(struct acpitz_softc *, int);
87588ea222Scanacar
88262397e4Smarco void (*acpitz_cpu_setperf)(int);
89262397e4Smarco int acpitz_perflevel = -1;
905bdf07b2Sjordan extern void (*cpu_setperf)(int);
915bdf07b2Sjordan extern int perflevel;
925bdf07b2Sjordan #define PERFSTEP 10
935bdf07b2Sjordan
945bdf07b2Sjordan #define ACPITZ_TRIPS (1L << 0)
955bdf07b2Sjordan #define ACPITZ_DEVLIST (1L << 1)
965774468cSjsg #define ACPITZ_INIT (ACPITZ_TRIPS|ACPITZ_DEVLIST)
975bdf07b2Sjordan
985bdf07b2Sjordan void
acpitz_init_perf(void * arg)99262397e4Smarco acpitz_init_perf(void *arg)
100262397e4Smarco {
101262397e4Smarco if (acpitz_perflevel == -1)
102262397e4Smarco acpitz_perflevel = perflevel;
103262397e4Smarco
104262397e4Smarco if (cpu_setperf != acpitz_setperf) {
105262397e4Smarco acpitz_cpu_setperf = cpu_setperf;
106262397e4Smarco cpu_setperf = acpitz_setperf;
107262397e4Smarco }
108262397e4Smarco }
109262397e4Smarco
110262397e4Smarco void
acpitz_setperf(int level)111262397e4Smarco acpitz_setperf(int level)
112262397e4Smarco {
113262397e4Smarco extern struct acpi_softc *acpi_softc;
114262397e4Smarco
115262397e4Smarco if (level < 0 || level > 100)
116262397e4Smarco return;
117262397e4Smarco
118262397e4Smarco if (acpi_softc == NULL)
119262397e4Smarco return;
120262397e4Smarco if (acpi_softc->sc_pse && level > acpitz_perflevel)
121262397e4Smarco return;
122262397e4Smarco
123262397e4Smarco if (acpitz_cpu_setperf)
124262397e4Smarco acpitz_cpu_setperf(level);
125262397e4Smarco }
126262397e4Smarco
127262397e4Smarco void
acpitz_init(struct acpitz_softc * sc,int flag)1285bdf07b2Sjordan acpitz_init(struct acpitz_softc *sc, int flag)
1295bdf07b2Sjordan {
1305bdf07b2Sjordan int i;
1315bdf07b2Sjordan char name[5];
1325bdf07b2Sjordan struct aml_value res;
1335bdf07b2Sjordan
1345bdf07b2Sjordan /* Read trip points */
1355bdf07b2Sjordan if (flag & ACPITZ_TRIPS) {
1365bdf07b2Sjordan sc->sc_psv = acpitz_getreading(sc, "_PSV");
1375bdf07b2Sjordan for (i = 0; i < ACPITZ_MAX_AC; i++) {
1385bdf07b2Sjordan snprintf(name, sizeof(name), "_AC%d", i);
1395bdf07b2Sjordan sc->sc_ac[i] = acpitz_getreading(sc, name);
1405bdf07b2Sjordan }
1415bdf07b2Sjordan }
1425bdf07b2Sjordan
1435bdf07b2Sjordan /* Read device lists */
1445bdf07b2Sjordan if (flag & ACPITZ_DEVLIST) {
1455bdf07b2Sjordan if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSL",
1465bdf07b2Sjordan 0, NULL, &res)) {
1475bdf07b2Sjordan acpi_freedevlist(&sc->sc_psl);
1485bdf07b2Sjordan acpi_getdevlist(&sc->sc_psl, sc->sc_devnode, &res, 0);
1495bdf07b2Sjordan aml_freevalue(&res);
1505bdf07b2Sjordan }
1515bdf07b2Sjordan for (i = 0; i < ACPITZ_MAX_AC; i++) {
1525bdf07b2Sjordan snprintf(name, sizeof(name), "_AL%d", i);
1535bdf07b2Sjordan if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, name,
1545bdf07b2Sjordan 0, NULL, &res)) {
1555bdf07b2Sjordan acpi_freedevlist(&sc->sc_alx[i]);
1565bdf07b2Sjordan acpi_getdevlist(&sc->sc_alx[i],
1575bdf07b2Sjordan sc->sc_devnode, &res, 0);
1585bdf07b2Sjordan aml_freevalue(&res);
1595bdf07b2Sjordan }
160576e0c08Ssemarie /* initialize current state to unknown */
161576e0c08Ssemarie sc->sc_ac_stat[i] = ACPITZ_UNKNOWN;
1625bdf07b2Sjordan }
1635bdf07b2Sjordan }
1645bdf07b2Sjordan }
1655bdf07b2Sjordan
166588ea222Scanacar int
acpitz_match(struct device * parent,void * match,void * aux)167588ea222Scanacar acpitz_match(struct device *parent, void *match, void *aux)
168588ea222Scanacar {
169588ea222Scanacar struct acpi_attach_args *aa = aux;
170588ea222Scanacar struct cfdata *cf = match;
171588ea222Scanacar
172588ea222Scanacar /* sanity */
173588ea222Scanacar if (aa->aaa_name == NULL ||
174588ea222Scanacar strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
175588ea222Scanacar aa->aaa_table != NULL)
176588ea222Scanacar return (0);
177588ea222Scanacar
1784e8c6959Sjordan if (aa->aaa_node->value->type != AML_OBJTYPE_THERMZONE)
179588ea222Scanacar return (0);
180588ea222Scanacar
181588ea222Scanacar return (1);
182588ea222Scanacar }
183588ea222Scanacar
184588ea222Scanacar void
acpitz_attach(struct device * parent,struct device * self,void * aux)185588ea222Scanacar acpitz_attach(struct device *parent, struct device *self, void *aux)
186588ea222Scanacar {
187588ea222Scanacar struct acpitz_softc *sc = (struct acpitz_softc *)self;
188588ea222Scanacar struct acpi_attach_args *aa = aux;
189854d2903Smarco int i;
1904c216af8Smlarkin char name[5];
191588ea222Scanacar
192588ea222Scanacar sc->sc_acpi = (struct acpi_softc *)parent;
1933b455a03Smarco sc->sc_devnode = aa->aaa_node;
194588ea222Scanacar
1955bdf07b2Sjordan TAILQ_INIT(&sc->sc_psl);
1965bdf07b2Sjordan for (i = 0; i < ACPITZ_MAX_AC; i++)
1975bdf07b2Sjordan TAILQ_INIT(&sc->sc_alx[i]);
1985bdf07b2Sjordan
1994c216af8Smlarkin /*
2004c216af8Smlarkin * Preread the trip points (discard/ignore values read here as we will
2014c216af8Smlarkin * re-read them later)
2024c216af8Smlarkin */
2034c216af8Smlarkin acpitz_gettempreading(sc, "_CRT");
2044c216af8Smlarkin acpitz_gettempreading(sc, "_HOT");
2054c216af8Smlarkin acpitz_gettempreading(sc, "_PSV");
2064c216af8Smlarkin for (i = 0; i < ACPITZ_MAX_AC; i++) {
2074c216af8Smlarkin snprintf(name, sizeof(name), "_AC%d", i);
2084c216af8Smlarkin acpitz_getreading(sc, name);
2094c216af8Smlarkin }
2104c216af8Smlarkin acpitz_gettempreading(sc, "_TMP");
2114c216af8Smlarkin
212854d2903Smarco sc->sc_lasttmp = -1;
21363c8bcf8Smarco if ((sc->sc_tmp = acpitz_gettempreading(sc, "_TMP")) == -1) {
21401947b10Sdv dnprintf(10, ": failed to read _TMP");
21501947b10Sdv printf("\n");
216588ea222Scanacar return;
217588ea222Scanacar }
218588ea222Scanacar
21963c8bcf8Smarco if ((sc->sc_crt = acpitz_gettempreading(sc, "_CRT")) == -1)
2207c54c5b5Sderaadt printf(": no critical temperature defined\n");
22163c8bcf8Smarco else
222935b954fSmarco printf(": critical temperature is %d degC\n", KTOC(sc->sc_crt));
223854d2903Smarco
22463c8bcf8Smarco sc->sc_hot = acpitz_gettempreading(sc, "_HOT");
225854d2903Smarco sc->sc_tc1 = acpitz_getreading(sc, "_TC1");
226854d2903Smarco sc->sc_tc2 = acpitz_getreading(sc, "_TC2");
2275bdf07b2Sjordan
2285bdf07b2Sjordan /* get _PSL, _ALx */
2295bdf07b2Sjordan acpitz_init(sc, ACPITZ_INIT);
2305bdf07b2Sjordan
23163c8bcf8Smarco dnprintf(10, "%s: _HOT: %d _TC1: %d _TC2: %d _PSV: %d _TMP: %d "
23263c8bcf8Smarco "_CRT: %d\n", DEVNAME(sc), sc->sc_hot, sc->sc_tc1, sc->sc_tc2,
23363c8bcf8Smarco sc->sc_psv, sc->sc_tmp, sc->sc_crt);
23463c8bcf8Smarco
23527515a6bSderaadt strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
23627515a6bSderaadt sizeof(sc->sc_sensdev.xname));
237588ea222Scanacar strlcpy(sc->sc_sens.desc, "zone temperature",
238588ea222Scanacar sizeof(sc->sc_sens.desc));
239588ea222Scanacar sc->sc_sens.type = SENSOR_TEMP;
24027515a6bSderaadt sensor_attach(&sc->sc_sensdev, &sc->sc_sens);
24127515a6bSderaadt sensordev_install(&sc->sc_sensdev);
24225ae5cf1Smarco
2433b455a03Smarco aml_register_notify(sc->sc_devnode, NULL,
24425ae5cf1Smarco acpitz_notify, sc, ACPIDEV_POLL);
245588ea222Scanacar
246262397e4Smarco /*
247262397e4Smarco * XXX use kthread_create_deferred to ensure we are the very last
248262397e4Smarco * piece of code that touches this pointer after all CPUs have been
249262397e4Smarco * fully attached
250262397e4Smarco */
251262397e4Smarco kthread_create_deferred(acpitz_init_perf, sc);
252854d2903Smarco }
253854d2903Smarco
254854d2903Smarco int
acpitz_activate(struct device * self,int act)25534e64ca6Sderaadt acpitz_activate(struct device *self, int act)
25634e64ca6Sderaadt {
25734e64ca6Sderaadt struct acpitz_softc *sc = (struct acpitz_softc *)self;
25834e64ca6Sderaadt
25934e64ca6Sderaadt switch (act) {
26034e64ca6Sderaadt case DVACT_WAKEUP:
26134e64ca6Sderaadt acpitz_init(sc, ACPITZ_INIT);
26234e64ca6Sderaadt break;
26334e64ca6Sderaadt }
26434e64ca6Sderaadt return 0;
26534e64ca6Sderaadt }
26634e64ca6Sderaadt
26734e64ca6Sderaadt int
acpitz_setfan(struct acpitz_softc * sc,int i,char * method)268854d2903Smarco acpitz_setfan(struct acpitz_softc *sc, int i, char *method)
269854d2903Smarco {
2709e221bbbSmiod struct aml_node *node;
2715bdf07b2Sjordan struct aml_value res1, *ref;
272854d2903Smarco char name[8];
2731ec8e3cbSmarco int rv = 1, x, y;
27413627354Sjordan int64_t sta;
2755bdf07b2Sjordan struct acpi_devlist *dl;
276854d2903Smarco
27743ae3879Smarco dnprintf(20, "%s: acpitz_setfan(%d, %s)\n", DEVNAME(sc), i, method);
278854d2903Smarco
2797283f83eSjordan x = 0;
2807283f83eSjordan snprintf(name, sizeof(name), "_AL%d", i);
2815bdf07b2Sjordan TAILQ_FOREACH(dl, &sc->sc_alx[i], dev_link) {
2825bdf07b2Sjordan if (aml_evalname(sc->sc_acpi, dl->dev_node, "_PR0",0 , NULL,
283854d2903Smarco &res1)) {
284854d2903Smarco printf("%s: %s[%d] _PR0 failed\n", DEVNAME(sc),
2851ec8e3cbSmarco name, x);
286854d2903Smarco aml_freevalue(&res1);
2877283f83eSjordan x++;
288eae1dbd3Ssemarie
289eae1dbd3Ssemarie /*
290eae1dbd3Ssemarie * This fan lacks the right method to operate:
291eae1dbd3Ssemarie * disabling active cooling trip points.
292eae1dbd3Ssemarie */
293eae1dbd3Ssemarie sc->sc_ac[i] = -1;
294854d2903Smarco continue;
295854d2903Smarco }
296854d2903Smarco if (res1.type != AML_OBJTYPE_PACKAGE) {
297854d2903Smarco printf("%s: %s[%d] _PR0 not a package\n", DEVNAME(sc),
2981ec8e3cbSmarco name, x);
299854d2903Smarco aml_freevalue(&res1);
3007283f83eSjordan x++;
301854d2903Smarco continue;
302854d2903Smarco }
303854d2903Smarco for (y = 0; y < res1.length; y++) {
3049e221bbbSmiod ref = res1.v_package[y];
305d90a88ceSkettenis if (ref->type == AML_OBJTYPE_NAMEREF) {
3069e221bbbSmiod node = aml_searchrel(sc->sc_devnode,
307abe2aaccSpatrick aml_getname(ref->v_nameref));
3089e221bbbSmiod if (node == NULL) {
309f27190e5Smlarkin printf("%s: %s[%d.%d] _PR0"
3109e221bbbSmiod " not a valid device\n",
3111ec8e3cbSmarco DEVNAME(sc), name, x, y);
312854d2903Smarco continue;
313854d2903Smarco }
3149e221bbbSmiod ref = node->value;
3159e221bbbSmiod }
3169e221bbbSmiod if (ref->type == AML_OBJTYPE_OBJREF) {
3179e221bbbSmiod ref = ref->v_objref.ref;
3189e221bbbSmiod }
3195622a274Smiod if (ref->type != AML_OBJTYPE_DEVICE &&
3205622a274Smiod ref->type != AML_OBJTYPE_POWERRSRC) {
321f27190e5Smlarkin printf("%s: %s[%d.%d] _PR0 not a package\n",
3221ec8e3cbSmarco DEVNAME(sc), name, x, y);
3239e221bbbSmiod continue;
3249e221bbbSmiod }
325854d2903Smarco if (aml_evalname(sc->sc_acpi, ref->node, method, 0,
326854d2903Smarco NULL, NULL))
327854d2903Smarco printf("%s: %s[%d.%d] %s fails\n",
3281ec8e3cbSmarco DEVNAME(sc), name, x, y, method);
329854d2903Smarco
330854d2903Smarco /* save off status of fan */
33113627354Sjordan if (aml_evalinteger(sc->sc_acpi, ref->node, "_STA", 0,
33213627354Sjordan NULL, &sta))
333854d2903Smarco printf("%s: %s[%d.%d] _STA fails\n",
3341ec8e3cbSmarco DEVNAME(sc), name, x, y);
335087e5b15Smarco else {
33613627354Sjordan sc->sc_ac_stat[i] = sta;
337087e5b15Smarco }
338854d2903Smarco }
339854d2903Smarco aml_freevalue(&res1);
3407283f83eSjordan x++;
341854d2903Smarco }
342854d2903Smarco rv = 0;
343854d2903Smarco return (rv);
344854d2903Smarco }
345854d2903Smarco
346588ea222Scanacar void
acpitz_refresh(void * arg)347588ea222Scanacar acpitz_refresh(void *arg)
348588ea222Scanacar {
349588ea222Scanacar struct acpitz_softc *sc = arg;
3505bdf07b2Sjordan int i, trend, nperf;
351588ea222Scanacar
352588ea222Scanacar dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc),
3533b455a03Smarco sc->sc_devnode->name);
354588ea222Scanacar
35563c8bcf8Smarco /* get _TMP and debounce the value */
356dbe1d7a8Sderaadt if ((sc->sc_tmp = acpitz_gettempreading(sc, "_TMP")) == -1) {
35763c8bcf8Smarco printf("%s: %s: failed to read temp\n", DEVNAME(sc),
3583b455a03Smarco sc->sc_devnode->name);
35963c8bcf8Smarco return;
360588ea222Scanacar }
36163c8bcf8Smarco /* critical trip points */
362854d2903Smarco if (sc->sc_crt != -1 && sc->sc_crt <= sc->sc_tmp) {
36363c8bcf8Smarco /* do critical shutdown */
3642758dbf1Sderaadt printf("%s: critical temperature exceeded %dC, shutting "
3652758dbf1Sderaadt "down\n", DEVNAME(sc), KTOC(sc->sc_tmp));
366de4108eaSguenther prsignal(initprocess, SIGUSR2);
367588ea222Scanacar }
36863c8bcf8Smarco if (sc->sc_hot != -1 && sc->sc_hot <= sc->sc_tmp) {
369854d2903Smarco printf("%s: _HOT temperature\n", DEVNAME(sc));
37063c8bcf8Smarco /* XXX go to S4, until then cool as hard as we can */
37163c8bcf8Smarco }
372139c6cc2Sderaadt
37363c8bcf8Smarco /* passive cooling */
374139c6cc2Sderaadt if (sc->sc_lasttmp != -1 && sc->sc_tc1 != -1 && sc->sc_tc2 != -1 &&
375139c6cc2Sderaadt sc->sc_psv != -1) {
37663c8bcf8Smarco dnprintf(30, "%s: passive cooling: lasttmp: %d tc1: %d "
37763c8bcf8Smarco "tc2: %d psv: %d\n", DEVNAME(sc), sc->sc_lasttmp,
37863c8bcf8Smarco sc->sc_tc1, sc->sc_tc2, sc->sc_psv);
3795bdf07b2Sjordan
380262397e4Smarco nperf = acpitz_perflevel;
381854d2903Smarco if (sc->sc_psv <= sc->sc_tmp) {
3825bdf07b2Sjordan /* Passive cooling enabled */
3835bdf07b2Sjordan dnprintf(1, "%s: enabling passive %d %d\n",
3845bdf07b2Sjordan DEVNAME(sc), sc->sc_tmp, sc->sc_psv);
3855bdf07b2Sjordan if (!sc->sc_pse)
3865bdf07b2Sjordan sc->sc_acpi->sc_pse++;
387854d2903Smarco sc->sc_pse = 1;
3885bdf07b2Sjordan
3895bdf07b2Sjordan trend = sc->sc_tc1 * (sc->sc_tmp - sc->sc_lasttmp) +
390854d2903Smarco sc->sc_tc2 * (sc->sc_tmp - sc->sc_psv);
3915bdf07b2Sjordan
3925bdf07b2Sjordan /* Depending on trend, slow down/speed up */
3935bdf07b2Sjordan if (trend > 0)
3945bdf07b2Sjordan nperf -= PERFSTEP;
3955bdf07b2Sjordan else
3965bdf07b2Sjordan nperf += PERFSTEP;
3975bdf07b2Sjordan }
3985bdf07b2Sjordan else {
3995bdf07b2Sjordan /* Passive cooling disabled, increase % */
4005bdf07b2Sjordan dnprintf(1, "%s: disabling passive %d %d\n",
4015bdf07b2Sjordan DEVNAME(sc), sc->sc_tmp, sc->sc_psv);
4025bdf07b2Sjordan if (sc->sc_pse)
4035bdf07b2Sjordan sc->sc_acpi->sc_pse--;
404854d2903Smarco sc->sc_pse = 0;
4055bdf07b2Sjordan nperf += PERFSTEP;
4065bdf07b2Sjordan }
4075bdf07b2Sjordan if (nperf < 0)
4085bdf07b2Sjordan nperf = 0;
4095bdf07b2Sjordan else if (nperf > 100)
4105bdf07b2Sjordan nperf = 100;
4115bdf07b2Sjordan
412262397e4Smarco /* clamp passive cooling request */
413262397e4Smarco if (nperf > perflevel)
414262397e4Smarco nperf = perflevel;
415262397e4Smarco
4165bdf07b2Sjordan /* Perform CPU setperf */
417262397e4Smarco if (acpitz_cpu_setperf && nperf != acpitz_perflevel) {
418262397e4Smarco acpitz_perflevel = nperf;
419262397e4Smarco acpitz_cpu_setperf(nperf);
4205bdf07b2Sjordan }
421854d2903Smarco }
422854d2903Smarco sc->sc_lasttmp = sc->sc_tmp;
423854d2903Smarco
42463c8bcf8Smarco /* active cooling */
425854d2903Smarco for (i = 0; i < ACPITZ_MAX_AC; i++) {
426854d2903Smarco if (sc->sc_ac[i] != -1 && sc->sc_ac[i] <= sc->sc_tmp) {
427854d2903Smarco /* turn on fan i */
428139c6cc2Sderaadt if (sc->sc_ac_stat[i] <= 0)
429854d2903Smarco acpitz_setfan(sc, i, "_ON_");
430854d2903Smarco } else if (sc->sc_ac[i] != -1) {
431854d2903Smarco /* turn off fan i */
432576e0c08Ssemarie if ((sc->sc_ac_stat[i] == ACPITZ_UNKNOWN) ||
433576e0c08Ssemarie (sc->sc_ac_stat[i] > 0))
434854d2903Smarco acpitz_setfan(sc, i, "_OFF");
435854d2903Smarco }
436854d2903Smarco }
437e7c83a59Scnst sc->sc_sens.value = sc->sc_tmp * 100000 - 50000;
438588ea222Scanacar }
439588ea222Scanacar
440588ea222Scanacar int
acpitz_getreading(struct acpitz_softc * sc,char * name)441911b45c8Smarco acpitz_getreading(struct acpitz_softc *sc, char *name)
442588ea222Scanacar {
443d2eaebe9Skettenis uint64_t val;
444588ea222Scanacar
445409e6d04Smarco if (!aml_evalinteger(sc->sc_acpi, sc->sc_devnode, name, 0, NULL, &val))
446409e6d04Smarco return (val);
447409e6d04Smarco
448409e6d04Smarco return (-1);
449588ea222Scanacar }
450588ea222Scanacar
451588ea222Scanacar int
acpitz_gettempreading(struct acpitz_softc * sc,char * name)45263c8bcf8Smarco acpitz_gettempreading(struct acpitz_softc *sc, char *name)
45363c8bcf8Smarco {
45463c8bcf8Smarco int rv = -1, tmp = -1, i;
45563c8bcf8Smarco
45663c8bcf8Smarco for (i = 0; i < ACPITZ_TMP_RETRY; i++) {
45763c8bcf8Smarco tmp = acpitz_getreading(sc, name);
45863c8bcf8Smarco if (tmp == -1)
45963c8bcf8Smarco goto out;
4604c216af8Smlarkin if (KTOC(tmp) >= 0) {
46163c8bcf8Smarco rv = tmp;
46263c8bcf8Smarco break;
46363c8bcf8Smarco } else {
46463c8bcf8Smarco dnprintf(20, "%s: %d invalid reading on %s, "
46563c8bcf8Smarco "debouncing\n", DEVNAME(sc), tmp, name);
46663c8bcf8Smarco }
46763c8bcf8Smarco
46878ac519aSderaadt acpi_sleep(1000, "acpitz"); /* debounce: 1000 msec */
46963c8bcf8Smarco }
47063c8bcf8Smarco if (i >= ACPITZ_TMP_RETRY) {
47163c8bcf8Smarco printf("%s: %s: failed to read %s\n", DEVNAME(sc),
4723b455a03Smarco sc->sc_devnode->name, name);
47363c8bcf8Smarco goto out;
47463c8bcf8Smarco }
47563c8bcf8Smarco out:
4762758dbf1Sderaadt dnprintf(30, "%s: name: %s tmp: %d => %dC, rv: %d\n", DEVNAME(sc),
47763c8bcf8Smarco name, tmp, KTOC(tmp), rv);
47863c8bcf8Smarco return (rv);
47963c8bcf8Smarco }
48063c8bcf8Smarco
48163c8bcf8Smarco int
acpitz_notify(struct aml_node * node,int notify_type,void * arg)482588ea222Scanacar acpitz_notify(struct aml_node *node, int notify_type, void *arg)
483588ea222Scanacar {
484588ea222Scanacar struct acpitz_softc *sc = arg;
485588ea222Scanacar
486588ea222Scanacar dnprintf(10, "%s notify: %.2x %s\n", DEVNAME(sc), notify_type,
4873b455a03Smarco sc->sc_devnode->name);
488588ea222Scanacar
489588ea222Scanacar switch (notify_type) {
49063c8bcf8Smarco case 0x80: /* hardware notifications */
49163c8bcf8Smarco break;
49263c8bcf8Smarco case 0x81: /* operating Points changed */
4935bdf07b2Sjordan acpitz_init(sc, ACPITZ_TRIPS);
49463c8bcf8Smarco break;
49563c8bcf8Smarco case 0x82: /* re-evaluate thermal device list */
4965bdf07b2Sjordan acpitz_init(sc, ACPITZ_DEVLIST);
497588ea222Scanacar break;
498588ea222Scanacar default:
499588ea222Scanacar break;
500588ea222Scanacar }
50163c8bcf8Smarco
502588ea222Scanacar acpitz_refresh(sc);
503588ea222Scanacar return (0);
504588ea222Scanacar }
505