xref: /openbsd-src/sys/dev/acpi/acpitz.c (revision 0f9e9ec23bb2b65cc62a3d17df12827a45dae80c)
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