xref: /freebsd/sys/dev/acpica/acpi_thermal.c (revision 4091481652fcca6cbaaf63af10619cd410f2f5e7)
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  *	$FreeBSD$
28  */
29 
30 #include "opt_acpi.h"
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/reboot.h>
35 #include <sys/sysctl.h>
36 
37 #include "acpi.h"
38 
39 #include <dev/acpica/acpivar.h>
40 
41 /*
42  * Hooks for the ACPI CA debugging infrastructure
43  */
44 #define _COMPONENT	ACPI_THERMAL
45 MODULE_NAME("THERMAL")
46 
47 #define TZ_ZEROC	2732
48 #define TZ_KELVTOC(x)	(((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10)
49 
50 #define TZ_DPRINT(dev, x...) do {					\
51 	if (acpi_get_verbose(acpi_device_get_parent_softc(dev)))	\
52 		device_printf(dev, x);					\
53 } while (0)
54 
55 #define TZ_NOTIFY_TEMPERATURE	0x80
56 #define TZ_NOTIFY_DEVICES	0x81
57 #define TZ_NOTIFY_LEVELS	0x82
58 
59 #define TZ_POLLRATE	(hz * 10)	/* every ten seconds */
60 
61 #define TZ_NUMLEVELS	10		/* defined by ACPI spec */
62 struct acpi_tz_zone {
63     int		ac[TZ_NUMLEVELS];
64     ACPI_BUFFER	al[TZ_NUMLEVELS];
65     int		crt;
66     int		hot;
67     ACPI_BUFFER	psl;
68     int		psv;
69     int		tc1;
70     int		tc2;
71     int		tsp;
72     int		tzp;
73 };
74 
75 
76 struct acpi_tz_softc {
77     device_t			tz_dev;			/* device handle */
78     ACPI_HANDLE			tz_handle;		/* thermal zone handle */
79     struct callout_handle	tz_timeout;		/* poll routine handle */
80     int				tz_temperature;		/* current temperature */
81     int				tz_active;		/* current active cooling */
82 #define TZ_ACTIVE_NONE		-1
83     int				tz_requested;		/* user-requested minimum active cooling */
84     int				tz_thflags;		/* current temperature-related flags */
85 #define TZ_THFLAG_NONE		0
86 #define TZ_THFLAG_PSV		(1<<0)
87 #define TZ_THFLAG_HOT		(1<<2)
88 #define TZ_THFLAG_CRT		(1<<3)
89     int				tz_flags;
90 #define TZ_FLAG_NO_SCP		(1<<0)			/* no _SCP method */
91 #define TZ_FLAG_GETPROFILE	(1<<1)			/* fetch powerprofile in timeout */
92     struct timespec		tz_cooling_started;	/* current cooling starting time */
93 
94     struct sysctl_ctx_list	tz_sysctl_ctx;		/* sysctl tree */
95     struct sysctl_oid		*tz_sysctl_tree;
96 
97     struct acpi_tz_zone 	tz_zone;		/* thermal zone parameters */
98 };
99 
100 static int	acpi_tz_probe(device_t dev);
101 static int	acpi_tz_attach(device_t dev);
102 static int	acpi_tz_establish(struct acpi_tz_softc *sc);
103 static void	acpi_tz_monitor(struct acpi_tz_softc *sc);
104 static void	acpi_tz_all_off(struct acpi_tz_softc *sc);
105 static void	acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg);
106 static void	acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg);
107 static void	acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data);
108 static void	acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what);
109 static int	acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS);
110 static void	acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context);
111 static void	acpi_tz_timeout(void *arg);
112 static void	acpi_tz_powerprofile(void *arg);
113 
114 static device_method_t acpi_tz_methods[] = {
115     /* Device interface */
116     DEVMETHOD(device_probe,	acpi_tz_probe),
117     DEVMETHOD(device_attach,	acpi_tz_attach),
118 
119     {0, 0}
120 };
121 
122 static driver_t acpi_tz_driver = {
123     "acpi_tz",
124     acpi_tz_methods,
125     sizeof(struct acpi_tz_softc),
126 };
127 
128 devclass_t acpi_tz_devclass;
129 DRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0);
130 
131 static struct sysctl_ctx_list	acpi_tz_sysctl_ctx;
132 static struct sysctl_oid	*acpi_tz_sysctl_tree;
133 
134 static int			acpi_tz_min_runtime = 0;/* minimum cooling run time */
135 
136 /*
137  * Match an ACPI thermal zone.
138  */
139 static int
140 acpi_tz_probe(device_t dev)
141 {
142     int		result;
143 
144     ACPI_LOCK;
145 
146     /* no FUNCTION_TRACE - too noisy */
147 
148     if ((acpi_get_type(dev) == ACPI_TYPE_THERMAL) &&
149 	!acpi_disabled("thermal")) {
150 	device_set_desc(dev, "thermal zone");
151 	result = -10;
152     } else {
153 	result = ENXIO;
154     }
155     ACPI_UNLOCK;
156     return(result);
157 }
158 
159 /*
160  * Attach to an ACPI thermal zone.
161  */
162 static int
163 acpi_tz_attach(device_t dev)
164 {
165     struct acpi_tz_softc	*sc;
166     struct acpi_softc		*acpi_sc;
167     int				error;
168     char			oidname[8];
169     int				i;
170 
171     FUNCTION_TRACE(__func__);
172 
173     ACPI_LOCK;
174 
175     sc = device_get_softc(dev);
176     sc->tz_dev = dev;
177     sc->tz_handle = acpi_get_handle(dev);
178     sc->tz_requested = TZ_ACTIVE_NONE;
179 
180     /*
181      * Parse the current state of the thermal zone and build control
182      * structures.
183      */
184     if ((error = acpi_tz_establish(sc)) != 0)
185 	goto out;
186 
187     /*
188      * Register for any Notify events sent to this zone.
189      */
190     AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY,
191 			     acpi_tz_notify_handler, sc);
192 
193     /*
194      * Create our sysctl nodes.
195      *
196      * XXX we need a mechanism for adding nodes under ACPI.
197      */
198     if (device_get_unit(dev) == 0) {
199 	acpi_sc = acpi_device_get_parent_softc(dev);
200 	sysctl_ctx_init(&acpi_tz_sysctl_ctx);
201 	acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx,
202 					      SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
203 					      OID_AUTO, "thermal", CTLFLAG_RD, 0, "");
204 	SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
205 		       SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
206 		       OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW,
207 		       &acpi_tz_min_runtime, 0, "minimum cooling run time in sec");
208     }
209     sysctl_ctx_init(&sc->tz_sysctl_ctx);
210     sprintf(oidname, "tz%d", device_get_unit(dev));
211     sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx,
212 					 SYSCTL_CHILDREN(acpi_tz_sysctl_tree), OID_AUTO,
213 					 oidname, CTLFLAG_RD, 0, "");
214     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
215 		   OID_AUTO, "temperature", CTLFLAG_RD,
216 		   &sc->tz_temperature, 0, "current thermal zone temperature");
217     SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
218 		    OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW,
219 		    sc, 0, acpi_tz_active_sysctl, "I", "");
220 
221     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
222 		   OID_AUTO, "thermal_flags", CTLFLAG_RD,
223 		   &sc->tz_thflags, 0, "thermal zone flags");
224     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
225 		   OID_AUTO, "_PSV", CTLFLAG_RD,
226 		   &sc->tz_zone.psv, 0, "");
227     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
228 		   OID_AUTO, "_HOT", CTLFLAG_RD,
229 		   &sc->tz_zone.hot, 0, "");
230     SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
231 		   OID_AUTO, "_CRT", CTLFLAG_RD,
232 		   &sc->tz_zone.crt, 0, "");
233     for (i = 0; i < TZ_NUMLEVELS; i++) {
234 	sprintf(oidname, "_AC%d", i);
235 	SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
236 		       OID_AUTO, oidname, CTLFLAG_RD,
237 		       &sc->tz_zone.ac[i], 0, "");
238     }
239 
240     /*
241      * Register our power profile event handler, and flag it for a manual
242      * invocation by our timeout.  We defer it like this so that the rest
243      * of the subsystem has time to come up.
244      */
245     EVENTHANDLER_REGISTER(powerprofile_change, acpi_tz_powerprofile, sc, 0);
246     sc->tz_flags |= TZ_FLAG_GETPROFILE;
247 
248     /*
249      * Don't bother evaluating/printing the temperature at this point;
250      * on many systems it'll be bogus until the EC is running.
251      */
252 
253  out:
254     ACPI_UNLOCK;
255 
256     /*
257      * Start the timeout routine, with enough delay for the rest of the
258      * subsystem to come up.
259      */
260     sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE);
261 
262     return_VALUE(error);
263 }
264 
265 /*
266  * Parse the current state of this thermal zone and set up to use it.
267  *
268  * Note that we may have previous state, which will have to be discarded.
269  */
270 static int
271 acpi_tz_establish(struct acpi_tz_softc *sc)
272 {
273     ACPI_OBJECT	*obj;
274     int		i;
275     char	nbuf[8];
276 
277     FUNCTION_TRACE(__func__);
278 
279     ACPI_ASSERTLOCK;
280 
281     /*
282      * Power everything off and erase any existing state.
283      */
284     acpi_tz_all_off(sc);
285     for (i = 0; i < TZ_NUMLEVELS; i++)
286 	if (sc->tz_zone.al[i].Pointer != NULL)
287 	    AcpiOsFree(sc->tz_zone.al[i].Pointer);
288     if (sc->tz_zone.psl.Pointer != NULL)
289 	AcpiOsFree(sc->tz_zone.psl.Pointer);
290     bzero(&sc->tz_zone, sizeof(sc->tz_zone));
291 
292     /*
293      * Evaluate thermal zone parameters.
294      */
295     for (i = 0; i < TZ_NUMLEVELS; i++) {
296 	sprintf(nbuf, "_AC%d", i);
297 	acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]);
298 	sprintf(nbuf, "_AL%d", i);
299 	acpi_EvaluateIntoBuffer(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]);
300 	obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer;
301 	if (obj != NULL) {
302 	    /* should be a package containing a list of power objects */
303 	    if (obj->Type != ACPI_TYPE_PACKAGE) {
304 		device_printf(sc->tz_dev, "%s has unknown object type %d, rejecting\n",
305 			      nbuf, obj->Type);
306 		return_VALUE(ENXIO);
307 	    }
308 	}
309     }
310     acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt);
311     acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot);
312     acpi_EvaluateIntoBuffer(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl);
313     acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv);
314     acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1);
315     acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2);
316     acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp);
317     acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp);
318 
319     /*
320      * Sanity-check the values we've been given.
321      *
322      * XXX what do we do about systems that give us the same value for
323      *     more than one of these setpoints?
324      */
325     acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT");
326     acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT");
327     acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV");
328     for (i = 0; i < TZ_NUMLEVELS; i++)
329 	acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx");
330 
331     /*
332      * Power off everything that we've just been given.
333      */
334     acpi_tz_all_off(sc);
335 
336     return_VALUE(0);
337 }
338 
339 static char	*aclevel_string[] =	{
340 	"NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4",
341 	"_AC5", "_AC6", "_AC7", "_AC8", "_AC9" };
342 
343 static __inline const char *
344 acpi_tz_aclevel_string(int active)
345 {
346 	if (active < -1 || active >= TZ_NUMLEVELS) {
347 		return (aclevel_string[0]);
348 	}
349 
350 	return (aclevel_string[active+1]);
351 }
352 
353 /*
354  * Evaluate the condition of a thermal zone, take appropriate actions.
355  */
356 static void
357 acpi_tz_monitor(struct acpi_tz_softc *sc)
358 {
359     int		temp;
360     int		i;
361     int		newactive, newflags;
362     struct	timespec curtime;
363 
364     FUNCTION_TRACE(__func__);
365 
366     ACPI_ASSERTLOCK;
367 
368     /*
369      * Get the current temperature.
370      */
371     if ((acpi_EvaluateInteger(sc->tz_handle, "_TMP", &temp)) != AE_OK) {
372 	device_printf(sc->tz_dev, "error fetching current temperature\n");
373 	/* XXX disable zone? go to max cooling? */
374 	return_VOID;
375     }
376     ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp)));
377     sc->tz_temperature = temp;
378 
379     /*
380      * Work out what we ought to be doing right now.
381      *
382      * Note that the _ACx levels sort from hot to cold.
383      */
384     newactive = TZ_ACTIVE_NONE;
385     for (i = TZ_NUMLEVELS - 1; i >= 0; i--) {
386 	if ((sc->tz_zone.ac[i] != -1) && (temp >= sc->tz_zone.ac[i])) {
387 	    newactive = i;
388 	    if (sc->tz_active != newactive) {
389 		TZ_DPRINT(sc->tz_dev,
390 			  "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i,
391 			  TZ_KELVTOC(temp), TZ_KELVTOC(sc->tz_zone.ac[i]));
392 		getnanotime(&sc->tz_cooling_started);
393 	    }
394 	}
395     }
396 
397     /*
398      * We are going to get _ACx level down (colder side), but give a guaranteed
399      * minimum cooling run time if requested.
400      */
401     if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE &&
402 	(newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) {
403 	getnanotime(&curtime);
404 	timespecsub(&curtime, &sc->tz_cooling_started);
405 	if (curtime.tv_sec < acpi_tz_min_runtime) {
406 	    newactive = sc->tz_active;
407 	}
408     }
409 
410     /* handle user override of active mode */
411     if (sc->tz_requested > newactive)
412 	newactive = sc->tz_requested;
413 
414     /* update temperature-related flags */
415     newflags = TZ_THFLAG_NONE;
416     if ((sc->tz_zone.psv != -1) && (temp >= sc->tz_zone.psv))
417 	newflags |= TZ_THFLAG_PSV;
418     if ((sc->tz_zone.hot != -1) && (temp >= sc->tz_zone.hot))
419 	newflags |= TZ_THFLAG_HOT;
420     if ((sc->tz_zone.crt != -1) && (temp >= sc->tz_zone.crt))
421 	newflags |= TZ_THFLAG_CRT;
422 
423     /*
424      * If the active cooling state has changed, we have to switch things.
425      */
426     if (newactive != sc->tz_active) {
427 
428 	/* turn off the cooling devices that are on, if any are */
429 	if (sc->tz_active != TZ_ACTIVE_NONE)
430 	    acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[sc->tz_active].Pointer,
431 				      acpi_tz_switch_cooler_off, sc);
432 
433 	/* turn on cooling devices that are required, if any are */
434 	if (newactive != TZ_ACTIVE_NONE)
435 	    acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[newactive].Pointer,
436 				      acpi_tz_switch_cooler_on, sc);
437 	TZ_DPRINT(sc->tz_dev, "switched from %s to %s: %d.%dC\n",
438 		  acpi_tz_aclevel_string(sc->tz_active),
439 		  acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp));
440 	sc->tz_active = newactive;
441     }
442 
443     /*
444      * XXX (de)activate any passive cooling that may be required.
445      */
446 
447     /*
448      * If we have just become _HOT or _CRT, warn the user.
449      *
450      * We should actually shut down at this point, but it's not clear
451      * that some systems don't actually map _CRT to the same value as _AC0.
452      */
453     if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) &&
454 	!(sc->tz_thflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT))) {
455 	device_printf(sc->tz_dev, "WARNING - current temperature (%d.%dC) exceeds system limits\n",
456 		      TZ_KELVTOC(sc->tz_temperature), sc->tz_temperature);
457 	/* shutdown_nice(RB_POWEROFF);*/
458     }
459     sc->tz_thflags = newflags;
460 
461     return_VOID;
462 }
463 
464 /*
465  * Turn off all the cooling devices.
466  */
467 static void
468 acpi_tz_all_off(struct acpi_tz_softc *sc)
469 {
470     int		i;
471 
472     FUNCTION_TRACE(__func__);
473 
474     ACPI_ASSERTLOCK;
475 
476     /*
477      * Scan all the _ALx objects, and turn them all off.
478      */
479     for (i = 0; i < TZ_NUMLEVELS; i++) {
480 	if (sc->tz_zone.al[i].Pointer == NULL)
481 	    continue;
482 	acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_zone.al[i].Pointer,
483 				  acpi_tz_switch_cooler_off, sc);
484     }
485 
486     /*
487      * XXX revert any passive-cooling options.
488      */
489 
490     sc->tz_active = TZ_ACTIVE_NONE;
491     sc->tz_thflags = TZ_THFLAG_NONE;
492     return_VOID;
493 }
494 
495 /*
496  * Given an object, verify that it's a reference to a device of some sort,
497  * and try to switch it off.
498  */
499 static void
500 acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg)
501 {
502     ACPI_HANDLE		cooler;
503 
504     FUNCTION_TRACE(__func__);
505 
506     ACPI_ASSERTLOCK;
507 
508     switch(obj->Type) {
509     case ACPI_TYPE_STRING:
510 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n", obj->String.Pointer));
511 
512 	/*
513 	 * Find the handle for the device and turn it off.
514 	 * The String object here seems to contain a fully-qualified path, so we
515 	 * don't have to search for it in our parents.
516 	 *
517 	 * XXX This may not always be the case.
518 	 */
519 	if (AcpiGetHandle(NULL, obj->String.Pointer, &cooler) == AE_OK)
520 	    acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3);
521 	break;
522 
523     default:
524 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to handle unsupported object type %d\n",
525 			  obj->Type));
526 	break;
527     }
528     return_VOID;
529 }
530 
531 /*
532  * Given an object, verify that it's a reference to a device of some sort,
533  * and try to switch it on.
534  *
535  * XXX replication of off/on function code is bad, mmmkay?
536  */
537 static void
538 acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg)
539 {
540     struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)arg;
541     ACPI_HANDLE			cooler;
542     ACPI_STATUS			status;
543 
544     FUNCTION_TRACE(__func__);
545 
546     ACPI_ASSERTLOCK;
547 
548     switch(obj->Type) {
549     case ACPI_TYPE_STRING:
550 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n", obj->String.Pointer));
551 
552 	/*
553 	 * Find the handle for the device and turn it off.
554 	 * The String object here seems to contain a fully-qualified path, so we
555 	 * don't have to search for it in our parents.
556 	 *
557 	 * XXX This may not always be the case.
558 	 */
559 	if (AcpiGetHandle(NULL, obj->String.Pointer, &cooler) == AE_OK) {
560 	    if (ACPI_FAILURE(status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0))) {
561 		device_printf(sc->tz_dev, "failed to activate %s - %s\n",
562 			      obj->String.Pointer, AcpiFormatException(status));
563 	    }
564 	} else {
565 	    device_printf(sc->tz_dev, "couldn't find %s\n", obj->String.Pointer);
566 	}
567 	break;
568 
569     default:
570 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to handle unsupported object type %d\n",
571 			  obj->Type));
572 	break;
573     }
574 	return_VOID;
575 }
576 
577 /*
578  * Read/debug-print a parameter, default it to -1.
579  */
580 static void
581 acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data)
582 {
583 
584     FUNCTION_TRACE(__func__);
585 
586     ACPI_ASSERTLOCK;
587 
588     if (acpi_EvaluateInteger(sc->tz_handle, node, data) != AE_OK) {
589 	*data = -1;
590     } else {
591 	ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n", acpi_name(sc->tz_handle),
592 			  node, *data));
593     }
594     return_VOID;
595 }
596 
597 /*
598  * Sanity-check a temperature value.  Assume that setpoints
599  * should be between 0C and 150C.
600  */
601 static void
602 acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what)
603 {
604     if ((*val != -1) && ((*val < TZ_ZEROC) || (*val > (TZ_ZEROC + 1500)))) {
605 	device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n",
606 		      what, TZ_KELVTOC(*val));
607 	*val = -1;
608     }
609 }
610 
611 /*
612  * Respond to a sysctl on the active state node.
613  */
614 static int
615 acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS)
616 {
617     struct acpi_tz_softc	*sc;
618     int				active;
619     int		 		error;
620 
621     ACPI_LOCK;
622 
623     sc = (struct acpi_tz_softc *)oidp->oid_arg1;
624     active = sc->tz_active;
625     error = sysctl_handle_int(oidp, &active, 0, req);
626 
627     /* error or no new value */
628     if ((error != 0) || (req->newptr == NULL))
629 	goto out;
630 
631     /* range check */
632     if ((active < -1) || (active >= TZ_NUMLEVELS)) {
633 	error = EINVAL;
634 	goto out;
635     }
636 
637     /* set new preferred level and re-switch */
638     sc->tz_requested = active;
639     acpi_tz_monitor(sc);
640 
641  out:
642     ACPI_UNLOCK;
643     return(error);
644 }
645 
646 /*
647  * Respond to a Notify event sent to the zone.
648  */
649 static void
650 acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
651 {
652     struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)context;
653 
654     FUNCTION_TRACE(__func__);
655 
656     ACPI_ASSERTLOCK;
657 
658     switch(notify) {
659     case TZ_NOTIFY_TEMPERATURE:
660 	/* temperature change occurred */
661 	AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_monitor, sc);
662 	break;
663     case TZ_NOTIFY_DEVICES:
664     case TZ_NOTIFY_LEVELS:
665 	/* zone devices/setpoints changed */
666 	AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc);
667 	break;
668     default:
669 	device_printf(sc->tz_dev, "unknown Notify event 0x%x\n", notify);
670 	break;
671     }
672     return_VOID;
673 }
674 
675 /*
676  * Poll the thermal zone.
677  */
678 static void
679 acpi_tz_timeout(void *arg)
680 {
681     struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)arg;
682 
683     /* do we need to get the power profile settings? */
684     if (sc->tz_flags & TZ_FLAG_GETPROFILE) {
685 	acpi_tz_powerprofile(arg);
686 	sc->tz_flags &= ~TZ_FLAG_GETPROFILE;
687     }
688 
689     ACPI_LOCK;
690 
691     /* check temperature, take action */
692     AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_monitor, sc);
693 
694     /* XXX passive cooling actions? */
695 
696     /* re-register ourself */
697     sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE);
698 
699     ACPI_UNLOCK;
700 }
701 
702 /*
703  * System power profile may have changed; fetch and notify the
704  * thermal zone accordingly.
705  *
706  * Since this can be called from an arbitrary eventhandler, it needs
707  * to get the ACPI lock itself.
708  */
709 static void
710 acpi_tz_powerprofile(void *arg)
711 {
712     ACPI_OBJECT_LIST		args;
713     ACPI_OBJECT			obj;
714     ACPI_STATUS			status;
715     struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)arg;
716 
717     ACPI_LOCK;
718 
719     /* check that we haven't decided there's no _SCP method */
720     if (!(sc->tz_flags & TZ_FLAG_NO_SCP)) {
721 
722 	/* call _SCP to set the new profile */
723 	obj.Type = ACPI_TYPE_INTEGER;
724 	obj.Integer.Value = (powerprofile_get_state() == POWERPROFILE_PERFORMANCE) ? 0 : 1;
725 	args.Count = 1;
726 	args.Pointer = &obj;
727 	if (ACPI_FAILURE(status = AcpiEvaluateObject(sc->tz_handle, "_SCP", &args, NULL))) {
728 	    if (status != AE_NOT_FOUND)
729 		device_printf(sc->tz_dev, "can't evaluate %s._SCP - %s\n", acpi_name(sc->tz_handle),
730 			      AcpiFormatException(status));
731 	    sc->tz_flags |= TZ_FLAG_NO_SCP;
732 	} else {
733 	    /* we have to re-evaluate the entire zone now */
734 	    AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, (OSD_EXECUTION_CALLBACK)acpi_tz_establish, sc);
735 	}
736     }
737     ACPI_UNLOCK;
738 }
739 
740