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