xref: /freebsd/sys/dev/acpica/acpi_thermal.c (revision 6fd05b64b5b65dd4ba9b86482a0634a5f0b96c29)
1 /*-
2  * Copyright (c) 2000, 2001 Michael Smith
3  * Copyright (c) 2000 BSDi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include "opt_acpi.h"
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/kthread.h>
35 #include <sys/module.h>
36 #include <sys/bus.h>
37 #include <sys/proc.h>
38 #include <sys/reboot.h>
39 #include <sys/sysctl.h>
40 #include <sys/unistd.h>
41 #include <sys/power.h>
42 
43 #include "acpi.h"
44 #include <dev/acpica/acpivar.h>
45 
46 /* Hooks for the ACPI CA debugging infrastructure */
47 #define _COMPONENT	ACPI_THERMAL
48 ACPI_MODULE_NAME("THERMAL")
49 
50 #define TZ_ZEROC	2732
51 #define TZ_KELVTOC(x)	(((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10)
52 
53 #define TZ_NOTIFY_TEMPERATURE	0x80 /* Temperature changed. */
54 #define TZ_NOTIFY_LEVELS	0x81 /* Cooling levels changed. */
55 #define TZ_NOTIFY_DEVICES	0x82 /* Device lists changed. */
56 #define TZ_NOTIFY_CRITICAL	0xcc /* Fake notify that _CRT/_HOT reached. */
57 
58 /* Check for temperature changes every 10 seconds by default */
59 #define TZ_POLLRATE	10
60 
61 /* Make sure the reported temperature is valid for this number of polls. */
62 #define TZ_VALIDCHECKS	3
63 
64 /* Notify the user we will be shutting down in one more poll cycle. */
65 #define TZ_NOTIFYCOUNT	(TZ_VALIDCHECKS - 1)
66 
67 /* ACPI spec defines this */
68 #define TZ_NUMLEVELS	10
69 struct acpi_tz_zone {
70     int		ac[TZ_NUMLEVELS];
71     ACPI_BUFFER	al[TZ_NUMLEVELS];
72     int		crt;
73     int		hot;
74     ACPI_BUFFER	psl;
75     int		psv;
76     int		tc1;
77     int		tc2;
78     int		tsp;
79     int		tzp;
80 };
81 
82 struct acpi_tz_softc {
83     device_t			tz_dev;
84     ACPI_HANDLE			tz_handle;	/*Thermal zone handle*/
85     int				tz_temperature;	/*Current temperature*/
86     int				tz_active;	/*Current active cooling*/
87 #define TZ_ACTIVE_NONE		-1
88     int				tz_requested;	/*Minimum active cooling*/
89     int				tz_thflags;	/*Current temp-related flags*/
90 #define TZ_THFLAG_NONE		0
91 #define TZ_THFLAG_PSV		(1<<0)
92 #define TZ_THFLAG_HOT		(1<<2)
93 #define TZ_THFLAG_CRT		(1<<3)
94     int				tz_flags;
95 #define TZ_FLAG_NO_SCP		(1<<0)		/*No _SCP method*/
96 #define TZ_FLAG_GETPROFILE	(1<<1)		/*Get power_profile in timeout*/
97     struct timespec		tz_cooling_started;
98 					/*Current cooling starting time*/
99 
100     struct sysctl_ctx_list	tz_sysctl_ctx;
101     struct sysctl_oid		*tz_sysctl_tree;
102 
103     struct acpi_tz_zone 	tz_zone;	/*Thermal zone parameters*/
104     int				tz_tmp_updating;
105     int				tz_validchecks;
106 };
107 
108 static int	acpi_tz_probe(device_t dev);
109 static int	acpi_tz_attach(device_t dev);
110 static int	acpi_tz_establish(struct acpi_tz_softc *sc);
111 static void	acpi_tz_monitor(void *Context);
112 static void	acpi_tz_all_off(struct acpi_tz_softc *sc);
113 static void	acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg);
114 static void	acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg);
115 static void	acpi_tz_getparam(struct acpi_tz_softc *sc, char *node,
116 				 int *data);
117 static void	acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what);
118 static int	acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS);
119 static void	acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify,
120 				       void *context);
121 static void	acpi_tz_timeout(struct acpi_tz_softc *sc);
122 static void	acpi_tz_power_profile(void *arg);
123 static void	acpi_tz_thread(void *arg);
124 
125 static device_method_t acpi_tz_methods[] = {
126     /* Device interface */
127     DEVMETHOD(device_probe,	acpi_tz_probe),
128     DEVMETHOD(device_attach,	acpi_tz_attach),
129 
130     {0, 0}
131 };
132 
133 static driver_t acpi_tz_driver = {
134     "acpi_tz",
135     acpi_tz_methods,
136     sizeof(struct acpi_tz_softc),
137 };
138 
139 static devclass_t acpi_tz_devclass;
140 DRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0);
141 MODULE_DEPEND(acpi_tz, acpi, 1, 1, 1);
142 
143 static struct sysctl_ctx_list	acpi_tz_sysctl_ctx;
144 static struct sysctl_oid	*acpi_tz_sysctl_tree;
145 
146 /* Minimum cooling run time */
147 static int			acpi_tz_min_runtime = 0;
148 static int			acpi_tz_polling_rate = TZ_POLLRATE;
149 
150 /* Timezone polling thread */
151 static struct proc		*acpi_tz_proc;
152 
153 /*
154  * Match an ACPI thermal zone.
155  */
156 static int
157 acpi_tz_probe(device_t dev)
158 {
159     int		result;
160     ACPI_LOCK_DECL;
161 
162     ACPI_LOCK;
163 
164     /* No FUNCTION_TRACE - too noisy */
165 
166     if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) {
167 	device_set_desc(dev, "Thermal Zone");
168 	result = -10;
169     } else {
170 	result = ENXIO;
171     }
172     ACPI_UNLOCK;
173     return (result);
174 }
175 
176 /*
177  * Attach to an ACPI thermal zone.
178  */
179 static int
180 acpi_tz_attach(device_t dev)
181 {
182     struct acpi_tz_softc	*sc;
183     struct acpi_softc		*acpi_sc;
184     int				error;
185     char			oidname[8];
186     ACPI_LOCK_DECL;
187 
188     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
189 
190     ACPI_LOCK;
191 
192     sc = device_get_softc(dev);
193     sc->tz_dev = dev;
194     sc->tz_handle = acpi_get_handle(dev);
195     sc->tz_requested = TZ_ACTIVE_NONE;
196     sc->tz_tmp_updating = 0;
197 
198     /*
199      * Parse the current state of the thermal zone and build control
200      * structures.
201      */
202     if ((error = acpi_tz_establish(sc)) != 0)
203 	goto out;
204 
205     /*
206      * Register for any Notify events sent to this zone.
207      */
208     AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY,
209 			     acpi_tz_notify_handler, sc);
210 
211     /*
212      * Create our sysctl nodes.
213      *
214      * XXX we need a mechanism for adding nodes under ACPI.
215      */
216     if (device_get_unit(dev) == 0) {
217 	acpi_sc = acpi_device_get_parent_softc(dev);
218 	sysctl_ctx_init(&acpi_tz_sysctl_ctx);
219 	acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx,
220 			      SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
221 			      OID_AUTO, "thermal", CTLFLAG_RD, 0, "");
222 	SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
223 		       SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
224 		       OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW,
225 		       &acpi_tz_min_runtime, 0,
226 		       "minimum cooling run time in sec");
227 	SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
228 		       SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
229 		       OID_AUTO, "polling_rate", CTLFLAG_RD | CTLFLAG_RW,
230 		       &acpi_tz_polling_rate, 0, "monitor polling rate");
231     }
232     sysctl_ctx_init(&sc->tz_sysctl_ctx);
233     sprintf(oidname, "tz%d", device_get_unit(dev));
234     sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx,
235 					 SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
236 					 OID_AUTO, oidname, CTLFLAG_RD, 0, "");
237     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
238 		   OID_AUTO, "temperature", CTLFLAG_RD,
239 		   &sc->tz_temperature, 0, "current thermal zone temperature");
240     SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
241 		    OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW,
242 		    sc, 0, acpi_tz_active_sysctl, "I", "");
243 
244     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
245 		   OID_AUTO, "thermal_flags", CTLFLAG_RD,
246 		   &sc->tz_thflags, 0, "thermal zone flags");
247     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
248 		   OID_AUTO, "_PSV", CTLFLAG_RD,
249 		   &sc->tz_zone.psv, 0, "");
250     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
251 		   OID_AUTO, "_HOT", CTLFLAG_RD,
252 		   &sc->tz_zone.hot, 0, "");
253     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
254 		   OID_AUTO, "_CRT", CTLFLAG_RD,
255 		   &sc->tz_zone.crt, 0, "");
256     SYSCTL_ADD_OPAQUE(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
257 		      OID_AUTO, "_ACx", CTLFLAG_RD, &sc->tz_zone.ac,
258 		      sizeof(sc->tz_zone.ac), "I", "");
259 
260     /*
261      * Register our power profile event handler, and flag it for a manual
262      * invocation by our timeout.  We defer it like this so that the rest
263      * of the subsystem has time to come up.
264      */
265     EVENTHANDLER_REGISTER(power_profile_change, acpi_tz_power_profile, sc, 0);
266     sc->tz_flags |= TZ_FLAG_GETPROFILE;
267 
268     /*
269      * Don't bother evaluating/printing the temperature at this point;
270      * on many systems it'll be bogus until the EC is running.
271      */
272 
273     /*
274      * Create our thread; we only need one, it will service all of the
275      * thermal zones.
276      */
277     if (acpi_tz_proc == NULL) {
278 	    error = kthread_create(acpi_tz_thread, NULL, &acpi_tz_proc,
279 				   RFHIGHPID, 0, "acpi_thermal");
280 	    if (error != 0) {
281 		    device_printf(sc->tz_dev, "could not create thread - %d",
282 				  error);
283 		    goto out;
284 	    }
285     }
286 
287  out:
288     ACPI_UNLOCK;
289 
290     return_VALUE (error);
291 }
292 
293 /*
294  * Parse the current state of this thermal zone and set up to use it.
295  *
296  * Note that we may have previous state, which will have to be discarded.
297  */
298 static int
299 acpi_tz_establish(struct acpi_tz_softc *sc)
300 {
301     ACPI_OBJECT	*obj;
302     int		i;
303     char	nbuf[8];
304 
305     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
306 
307     ACPI_ASSERTLOCK;
308 
309     /* Power everything off and erase any existing state. */
310     acpi_tz_all_off(sc);
311     for (i = 0; i < TZ_NUMLEVELS; i++)
312 	if (sc->tz_zone.al[i].Pointer != NULL)
313 	    AcpiOsFree(sc->tz_zone.al[i].Pointer);
314     if (sc->tz_zone.psl.Pointer != NULL)
315 	AcpiOsFree(sc->tz_zone.psl.Pointer);
316     bzero(&sc->tz_zone, sizeof(sc->tz_zone));
317 
318     /* Evaluate thermal zone parameters. */
319     for (i = 0; i < TZ_NUMLEVELS; i++) {
320 	sprintf(nbuf, "_AC%d", i);
321 	acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]);
322 	sprintf(nbuf, "_AL%d", i);
323 	sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER;
324 	sc->tz_zone.al[i].Pointer = NULL;
325 	AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]);
326 	obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer;
327 	if (obj != NULL) {
328 	    /* Should be a package containing a list of power objects */
329 	    if (obj->Type != ACPI_TYPE_PACKAGE) {
330 		device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n",
331 			      nbuf, obj->Type);
332 		return_VALUE (ENXIO);
333 	    }
334 	}
335     }
336     acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt);
337     acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot);
338     sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER;
339     sc->tz_zone.psl.Pointer = NULL;
340     AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl);
341     acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv);
342     acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1);
343     acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2);
344     acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp);
345     acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp);
346 
347     /*
348      * Sanity-check the values we've been given.
349      *
350      * XXX what do we do about systems that give us the same value for
351      *     more than one of these setpoints?
352      */
353     acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT");
354     acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT");
355     acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV");
356     for (i = 0; i < TZ_NUMLEVELS; i++)
357 	acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx");
358 
359     /*
360      * Power off everything that we've just been given.
361      */
362     acpi_tz_all_off(sc);
363 
364     return_VALUE (0);
365 }
366 
367 static char	*aclevel_string[] =	{
368 	"NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4",
369 	"_AC5", "_AC6", "_AC7", "_AC8", "_AC9" };
370 
371 static __inline const char *
372 acpi_tz_aclevel_string(int active)
373 {
374 	if (active < -1 || active >= TZ_NUMLEVELS)
375 		return (aclevel_string[0]);
376 
377 	return (aclevel_string[active+1]);
378 }
379 
380 /*
381  * Evaluate the condition of a thermal zone, take appropriate actions.
382  */
383 static void
384 acpi_tz_monitor(void *Context)
385 {
386     struct acpi_tz_softc *sc;
387     struct	timespec curtime;
388     int		temp;
389     int		i;
390     int		newactive, newflags;
391     ACPI_STATUS	status;
392 
393     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
394 
395     ACPI_ASSERTLOCK;
396 
397     sc = (struct acpi_tz_softc *)Context;
398     if (sc->tz_tmp_updating)
399 	goto out;
400     sc->tz_tmp_updating = 1;
401 
402     /* Get the current temperature. */
403     status = acpi_GetInteger(sc->tz_handle, "_TMP", &temp);
404     if (ACPI_FAILURE(status)) {
405 	ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
406 	    "error fetching current temperature -- %s\n",
407 	     AcpiFormatException(status));
408 	/* XXX disable zone? go to max cooling? */
409 	goto out;
410     }
411 
412     ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp)));
413     sc->tz_temperature = temp;
414 
415     /*
416      * Work out what we ought to be doing right now.
417      *
418      * Note that the _ACx levels sort from hot to cold.
419      */
420     newactive = TZ_ACTIVE_NONE;
421     for (i = TZ_NUMLEVELS - 1; i >= 0; i--) {
422 	if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) {
423 	    newactive = i;
424 	    if (sc->tz_active != newactive) {
425 		ACPI_VPRINT(sc->tz_dev,
426 			    acpi_device_get_parent_softc(sc->tz_dev),
427 			    "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i,
428 			    TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i]));
429 		getnanotime(&sc->tz_cooling_started);
430 	    }
431 	}
432     }
433 
434     /*
435      * We are going to get _ACx level down (colder side), but give a guaranteed
436      * minimum cooling run time if requested.
437      */
438     if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE &&
439 	(newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) {
440 
441 	getnanotime(&curtime);
442 	timespecsub(&curtime, &sc->tz_cooling_started);
443 	if (curtime.tv_sec < acpi_tz_min_runtime)
444 	    newactive = sc->tz_active;
445     }
446 
447     /* Handle user override of active mode */
448     if (sc->tz_requested != TZ_ACTIVE_NONE && sc->tz_requested < newactive)
449 	newactive = sc->tz_requested;
450 
451     /* update temperature-related flags */
452     newflags = TZ_THFLAG_NONE;
453     if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv)
454 	newflags |= TZ_THFLAG_PSV;
455     if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot)
456 	newflags |= TZ_THFLAG_HOT;
457     if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt)
458 	newflags |= TZ_THFLAG_CRT;
459 
460     /* If the active cooling state has changed, we have to switch things. */
461     if (newactive != sc->tz_active) {
462 	/* Turn off the cooling devices that are on, if any are */
463 	if (sc->tz_active != TZ_ACTIVE_NONE)
464 	    acpi_ForeachPackageObject(
465 		(ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer,
466 		acpi_tz_switch_cooler_off, sc);
467 
468 	/* Turn on cooling devices that are required, if any are */
469 	if (newactive != TZ_ACTIVE_NONE) {
470 	    acpi_ForeachPackageObject(
471 		(ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer,
472 		acpi_tz_switch_cooler_on, sc);
473 	}
474 	ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
475 		    "switched from %s to %s: %d.%dC\n",
476 		    acpi_tz_aclevel_string(sc->tz_active),
477 		    acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp));
478 	sc->tz_active = newactive;
479     }
480 
481     /* XXX (de)activate any passive cooling that may be required. */
482 
483     /*
484      * If the temperature is at _HOT or _CRT, increment our event count.
485      * If it has occurred enough times, shutdown the system.  This is
486      * needed because some systems will report an invalid high temperature
487      * for one poll cycle.  It is suspected this is due to the embedded
488      * controller timing out.  A typical value is 138C for one cycle on
489      * a system that is otherwise 65C.
490      *
491      * If we're almost at that threshold, notify the user through devd(8).
492      */
493     if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) {
494 	sc->tz_validchecks++;
495 	if (sc->tz_validchecks == TZ_VALIDCHECKS) {
496 	    device_printf(sc->tz_dev,
497 		"WARNING - current temperature (%d.%dC) exceeds safe limits\n",
498 		TZ_KELVTOC(sc->tz_temperature));
499 	    shutdown_nice(RB_POWEROFF);
500 	} else if (sc->tz_validchecks == TZ_NOTIFYCOUNT)
501 	    acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL);
502     } else {
503 	sc->tz_validchecks = 0;
504     }
505     sc->tz_thflags = newflags;
506 
507 out:
508     sc->tz_tmp_updating = 0;
509     return_VOID;
510 }
511 
512 /*
513  * Turn off all the cooling devices.
514  */
515 static void
516 acpi_tz_all_off(struct acpi_tz_softc *sc)
517 {
518     int		i;
519 
520     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
521 
522     ACPI_ASSERTLOCK;
523 
524     /* Scan all the _ALx objects and turn them all off. */
525     for (i = 0; i < TZ_NUMLEVELS; i++) {
526 	if (sc->tz_zone.al[i].Pointer == NULL)
527 	    continue;
528 	acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[i].Pointer,
529 				  acpi_tz_switch_cooler_off, sc);
530     }
531 
532     /*
533      * XXX revert any passive-cooling options.
534      */
535 
536     sc->tz_active = TZ_ACTIVE_NONE;
537     sc->tz_thflags = TZ_THFLAG_NONE;
538 
539     return_VOID;
540 }
541 
542 /*
543  * Given an object, verify that it's a reference to a device of some sort,
544  * and try to switch it off.
545  */
546 static void
547 acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg)
548 {
549     ACPI_HANDLE			cooler;
550 
551     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
552 
553     ACPI_ASSERTLOCK;
554 
555     cooler = acpi_GetReference(NULL, obj);
556     if (cooler == NULL) {
557 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n"));
558 	return_VOID;
559     }
560 
561     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n",
562 		     acpi_name(cooler)));
563     acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3);
564 
565     return_VOID;
566 }
567 
568 /*
569  * Given an object, verify that it's a reference to a device of some sort,
570  * and try to switch it on.
571  *
572  * XXX replication of off/on function code is bad.
573  */
574 static void
575 acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg)
576 {
577     struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)arg;
578     ACPI_HANDLE			cooler;
579     ACPI_STATUS			status;
580 
581     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
582 
583     ACPI_ASSERTLOCK;
584 
585     cooler = acpi_GetReference(NULL, obj);
586     if (cooler == NULL) {
587 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n"));
588 	return_VOID;
589     }
590 
591     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n",
592 		     acpi_name(cooler)));
593     status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0);
594     if (ACPI_FAILURE(status)) {
595 	ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
596 		    "failed to activate %s - %s\n", acpi_name(cooler),
597 		    AcpiFormatException(status));
598     }
599 
600     return_VOID;
601 }
602 
603 /*
604  * Read/debug-print a parameter, default it to -1.
605  */
606 static void
607 acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data)
608 {
609 
610     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
611 
612     ACPI_ASSERTLOCK;
613 
614     if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) {
615 	*data = -1;
616     } else {
617 	ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n",
618 			 acpi_name(sc->tz_handle), node, *data));
619     }
620 
621     return_VOID;
622 }
623 
624 /*
625  * Sanity-check a temperature value.  Assume that setpoints
626  * should be between 0C and 150C.
627  */
628 static void
629 acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what)
630 {
631     if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 1500)) {
632 	device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n",
633 		      what, TZ_KELVTOC(*val));
634 	*val = -1;
635     }
636 }
637 
638 /*
639  * Respond to a sysctl on the active state node.
640  */
641 static int
642 acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS)
643 {
644     struct acpi_tz_softc	*sc;
645     int				active;
646     int		 		error;
647     ACPI_LOCK_DECL;
648 
649     ACPI_LOCK;
650 
651     sc = (struct acpi_tz_softc *)oidp->oid_arg1;
652     active = sc->tz_active;
653     error = sysctl_handle_int(oidp, &active, 0, req);
654 
655     /* Error or no new value */
656     if (error != 0 || req->newptr == NULL)
657 	goto out;
658     if (active < -1 || active >= TZ_NUMLEVELS) {
659 	error = EINVAL;
660 	goto out;
661     }
662 
663     /* Set new preferred level and re-switch */
664     sc->tz_requested = active;
665     acpi_tz_monitor(sc);
666 
667  out:
668     ACPI_UNLOCK;
669     return (error);
670 }
671 
672 /*
673  * Respond to a Notify event sent to the zone.
674  */
675 static void
676 acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
677 {
678     struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)context;
679 
680     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
681 
682     ACPI_ASSERTLOCK;
683 
684     switch(notify) {
685     case TZ_NOTIFY_TEMPERATURE:
686 	/* Temperature change occurred */
687 	AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, acpi_tz_monitor, sc);
688 	break;
689     case TZ_NOTIFY_DEVICES:
690     case TZ_NOTIFY_LEVELS:
691 	/* Zone devices/setpoints changed */
692 	AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
693 				(OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc);
694 	break;
695     default:
696 	ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
697 		    "unknown Notify event 0x%x\n", notify);
698 	break;
699     }
700 
701     acpi_UserNotify("Thermal", h, notify);
702 
703     return_VOID;
704 }
705 
706 /*
707  * Poll the thermal zone.
708  */
709 static void
710 acpi_tz_timeout(struct acpi_tz_softc *sc)
711 {
712     /* Do we need to get the power profile settings? */
713     if (sc->tz_flags & TZ_FLAG_GETPROFILE) {
714 	acpi_tz_power_profile((void *)sc);
715 	sc->tz_flags &= ~TZ_FLAG_GETPROFILE;
716     }
717 
718     ACPI_ASSERTLOCK;
719 
720     /* Check the current temperature and take action based on it */
721     acpi_tz_monitor(sc);
722 
723     /* XXX passive cooling actions? */
724 }
725 
726 /*
727  * System power profile may have changed; fetch and notify the
728  * thermal zone accordingly.
729  *
730  * Since this can be called from an arbitrary eventhandler, it needs
731  * to get the ACPI lock itself.
732  */
733 static void
734 acpi_tz_power_profile(void *arg)
735 {
736     ACPI_STATUS			status;
737     struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)arg;
738     int				state;
739     ACPI_LOCK_DECL;
740 
741     state = power_profile_get_state();
742     if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY)
743 	return;
744 
745     ACPI_LOCK;
746 
747     /* check that we haven't decided there's no _SCP method */
748     if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) {
749 
750 	/* Call _SCP to set the new profile */
751 	status = acpi_SetInteger(sc->tz_handle, "_SCP",
752 	    (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1);
753 	if (ACPI_FAILURE(status)) {
754 	    if (status != AE_NOT_FOUND)
755 		ACPI_VPRINT(sc->tz_dev,
756 			    acpi_device_get_parent_softc(sc->tz_dev),
757 			    "can't evaluate %s._SCP - %s\n",
758 			    acpi_name(sc->tz_handle),
759 			    AcpiFormatException(status));
760 	    sc->tz_flags |= TZ_FLAG_NO_SCP;
761 	} else {
762 	    /* We have to re-evaluate the entire zone now */
763 	    AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
764 				    (OSD_EXECUTION_CALLBACK)acpi_tz_establish,
765 				    sc);
766 	}
767     }
768 
769     ACPI_UNLOCK;
770 }
771 
772 /*
773  * Thermal zone monitor thread.
774  */
775 static void
776 acpi_tz_thread(void *arg)
777 {
778     device_t	*devs;
779     int		devcount, i;
780     ACPI_LOCK_DECL;
781 
782     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
783 
784     devs = NULL;
785     devcount = 0;
786 
787     for (;;) {
788 	tsleep(&acpi_tz_proc, PZERO, "tzpoll", hz * acpi_tz_polling_rate);
789 
790 #if __FreeBSD_version >= 500000
791 	mtx_lock(&Giant);
792 #endif
793 
794 	if (devcount == 0)
795 	    devclass_get_devices(acpi_tz_devclass, &devs, &devcount);
796 
797 	ACPI_LOCK;
798 	for (i = 0; i < devcount; i++)
799 	    acpi_tz_timeout(device_get_softc(devs[i]));
800 	ACPI_UNLOCK;
801 
802 #if __FreeBSD_version >= 500000
803 	mtx_unlock(&Giant);
804 #endif
805     }
806 }
807