2 * Copyright (c) 2000, 2001 Michael Smith
3 * Copyright (c) 2000 BSDi
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * $FreeBSD: src/sys/dev/acpica/acpi_thermal.c,v 1.47 2004/05/30 20:08:23 phk Exp $
28 * $DragonFly: src/sys/dev/acpica5/acpi_thermal.c,v 1.7 2007/01/17 18:31:19 y0netan1 Exp $
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/kthread.h>
35 #include <sys/module.h>
38 #include <sys/reboot.h>
39 #include <sys/sysctl.h>
40 #include <sys/unistd.h>
41 #include <sys/power.h>
42 #include <sys/thread2.h>
45 #include <dev/acpica5/acpivar.h>
47 /* Hooks for the ACPI CA debugging infrastructure */
48 #define _COMPONENT ACPI_THERMAL
49 ACPI_MODULE_NAME("THERMAL")
52 #define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10)
54 #define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */
55 #define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */
56 #define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */
57 #define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT reached. */
59 /* Check for temperature changes every 10 seconds by default */
60 #define TZ_POLLRATE 10
62 /* Make sure the reported temperature is valid for this number of polls. */
63 #define TZ_VALIDCHECKS 3
65 /* Notify the user we will be shutting down in one more poll cycle. */
66 #define TZ_NOTIFYCOUNT (TZ_VALIDCHECKS - 1)
68 /* ACPI spec defines this */
69 #define TZ_NUMLEVELS 10
72 ACPI_BUFFER al
[TZ_NUMLEVELS
];
83 struct acpi_tz_softc
{
85 ACPI_HANDLE tz_handle
; /*Thermal zone handle*/
86 int tz_temperature
; /*Current temperature*/
87 int tz_active
; /*Current active cooling*/
88 #define TZ_ACTIVE_NONE -1
89 int tz_requested
; /*Minimum active cooling*/
90 int tz_thflags
; /*Current temp-related flags*/
91 #define TZ_THFLAG_NONE 0
92 #define TZ_THFLAG_PSV (1<<0)
93 #define TZ_THFLAG_HOT (1<<2)
94 #define TZ_THFLAG_CRT (1<<3)
96 #define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/
97 #define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/
98 struct timespec tz_cooling_started
;
99 /*Current cooling starting time*/
101 struct sysctl_ctx_list tz_sysctl_ctx
;
102 struct sysctl_oid
*tz_sysctl_tree
;
104 struct acpi_tz_zone tz_zone
; /*Thermal zone parameters*/
109 static int acpi_tz_probe(device_t dev
);
110 static int acpi_tz_attach(device_t dev
);
111 static int acpi_tz_establish(struct acpi_tz_softc
*sc
);
112 static void acpi_tz_monitor(void *Context
);
113 static void acpi_tz_all_off(struct acpi_tz_softc
*sc
);
114 static void acpi_tz_switch_cooler_off(ACPI_OBJECT
*obj
, void *arg
);
115 static void acpi_tz_switch_cooler_on(ACPI_OBJECT
*obj
, void *arg
);
116 static void acpi_tz_getparam(struct acpi_tz_softc
*sc
, char *node
,
118 static void acpi_tz_sanity(struct acpi_tz_softc
*sc
, int *val
, char *what
);
119 static int acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS
);
120 static void acpi_tz_notify_handler(ACPI_HANDLE h
, UINT32 notify
,
122 static void acpi_tz_timeout(struct acpi_tz_softc
*sc
);
123 static void acpi_tz_power_profile(void *arg
);
124 static void acpi_tz_thread(void *arg
);
126 static device_method_t acpi_tz_methods
[] = {
127 /* Device interface */
128 DEVMETHOD(device_probe
, acpi_tz_probe
),
129 DEVMETHOD(device_attach
, acpi_tz_attach
),
134 static driver_t acpi_tz_driver
= {
137 sizeof(struct acpi_tz_softc
),
140 static devclass_t acpi_tz_devclass
;
141 DRIVER_MODULE(acpi_tz
, acpi
, acpi_tz_driver
, acpi_tz_devclass
, 0, 0);
142 MODULE_DEPEND(acpi_tz
, acpi
, 1, 1, 1);
144 static struct sysctl_ctx_list acpi_tz_sysctl_ctx
;
145 static struct sysctl_oid
*acpi_tz_sysctl_tree
;
147 /* Minimum cooling run time */
148 static int acpi_tz_min_runtime
= 0;
149 static int acpi_tz_polling_rate
= TZ_POLLRATE
;
151 /* Timezone polling thread */
152 static struct thread
*acpi_tz_td
;
155 * Match an ACPI thermal zone.
158 acpi_tz_probe(device_t dev
)
165 /* No FUNCTION_TRACE - too noisy */
167 if (acpi_get_type(dev
) == ACPI_TYPE_THERMAL
&& !acpi_disabled("thermal")) {
168 device_set_desc(dev
, "Thermal Zone");
178 * Attach to an ACPI thermal zone.
181 acpi_tz_attach(device_t dev
)
183 struct acpi_tz_softc
*sc
;
184 struct acpi_softc
*acpi_sc
;
189 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
193 sc
= device_get_softc(dev
);
195 sc
->tz_handle
= acpi_get_handle(dev
);
196 sc
->tz_requested
= TZ_ACTIVE_NONE
;
197 sc
->tz_tmp_updating
= 0;
200 * Parse the current state of the thermal zone and build control
203 if ((error
= acpi_tz_establish(sc
)) != 0)
207 * Register for any Notify events sent to this zone.
209 AcpiInstallNotifyHandler(sc
->tz_handle
, ACPI_DEVICE_NOTIFY
,
210 acpi_tz_notify_handler
, sc
);
213 * Create our sysctl nodes.
215 * XXX we need a mechanism for adding nodes under ACPI.
217 if (device_get_unit(dev
) == 0) {
218 acpi_sc
= acpi_device_get_parent_softc(dev
);
219 sysctl_ctx_init(&acpi_tz_sysctl_ctx
);
220 acpi_tz_sysctl_tree
= SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx
,
221 SYSCTL_CHILDREN(acpi_sc
->acpi_sysctl_tree
),
222 OID_AUTO
, "thermal", CTLFLAG_RD
, 0, "");
223 SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx
,
224 SYSCTL_CHILDREN(acpi_tz_sysctl_tree
),
225 OID_AUTO
, "min_runtime", CTLFLAG_RD
| CTLFLAG_RW
,
226 &acpi_tz_min_runtime
, 0,
227 "minimum cooling run time in sec");
228 SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx
,
229 SYSCTL_CHILDREN(acpi_tz_sysctl_tree
),
230 OID_AUTO
, "polling_rate", CTLFLAG_RD
| CTLFLAG_RW
,
231 &acpi_tz_polling_rate
, 0, "monitor polling rate");
233 sysctl_ctx_init(&sc
->tz_sysctl_ctx
);
234 ksprintf(oidname
, "tz%d", device_get_unit(dev
));
235 sc
->tz_sysctl_tree
= SYSCTL_ADD_NODE(&sc
->tz_sysctl_ctx
,
236 SYSCTL_CHILDREN(acpi_tz_sysctl_tree
),
237 OID_AUTO
, oidname
, CTLFLAG_RD
, 0, "");
238 SYSCTL_ADD_INT(&sc
->tz_sysctl_ctx
, SYSCTL_CHILDREN(sc
->tz_sysctl_tree
),
239 OID_AUTO
, "temperature", CTLFLAG_RD
,
240 &sc
->tz_temperature
, 0, "current thermal zone temperature");
241 SYSCTL_ADD_PROC(&sc
->tz_sysctl_ctx
, SYSCTL_CHILDREN(sc
->tz_sysctl_tree
),
242 OID_AUTO
, "active", CTLTYPE_INT
| CTLFLAG_RW
,
243 sc
, 0, acpi_tz_active_sysctl
, "I", "");
245 SYSCTL_ADD_INT(&sc
->tz_sysctl_ctx
, SYSCTL_CHILDREN(sc
->tz_sysctl_tree
),
246 OID_AUTO
, "thermal_flags", CTLFLAG_RD
,
247 &sc
->tz_thflags
, 0, "thermal zone flags");
248 SYSCTL_ADD_INT(&sc
->tz_sysctl_ctx
, SYSCTL_CHILDREN(sc
->tz_sysctl_tree
),
249 OID_AUTO
, "_PSV", CTLFLAG_RD
,
250 &sc
->tz_zone
.psv
, 0, "");
251 SYSCTL_ADD_INT(&sc
->tz_sysctl_ctx
, SYSCTL_CHILDREN(sc
->tz_sysctl_tree
),
252 OID_AUTO
, "_HOT", CTLFLAG_RD
,
253 &sc
->tz_zone
.hot
, 0, "");
254 SYSCTL_ADD_INT(&sc
->tz_sysctl_ctx
, SYSCTL_CHILDREN(sc
->tz_sysctl_tree
),
255 OID_AUTO
, "_CRT", CTLFLAG_RD
,
256 &sc
->tz_zone
.crt
, 0, "");
257 SYSCTL_ADD_OPAQUE(&sc
->tz_sysctl_ctx
, SYSCTL_CHILDREN(sc
->tz_sysctl_tree
),
258 OID_AUTO
, "_ACx", CTLFLAG_RD
, &sc
->tz_zone
.ac
,
259 sizeof(sc
->tz_zone
.ac
), "I", "");
262 * Register our power profile event handler, and flag it for a manual
263 * invocation by our timeout. We defer it like this so that the rest
264 * of the subsystem has time to come up.
266 EVENTHANDLER_REGISTER(power_profile_change
, acpi_tz_power_profile
, sc
, 0);
267 sc
->tz_flags
|= TZ_FLAG_GETPROFILE
;
270 * Don't bother evaluating/printing the temperature at this point;
271 * on many systems it'll be bogus until the EC is running.
275 * Create our thread; we only need one, it will service all of the
278 if (acpi_tz_td
== NULL
) {
279 error
= kthread_create(acpi_tz_thread
, NULL
, &acpi_tz_td
,
280 RFHIGHPID
, 0, "acpi_thermal");
282 device_printf(sc
->tz_dev
, "could not create thread - %d",
291 return_VALUE (error
);
295 * Parse the current state of this thermal zone and set up to use it.
297 * Note that we may have previous state, which will have to be discarded.
300 acpi_tz_establish(struct acpi_tz_softc
*sc
)
306 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
310 /* Power everything off and erase any existing state. */
312 for (i
= 0; i
< TZ_NUMLEVELS
; i
++)
313 if (sc
->tz_zone
.al
[i
].Pointer
!= NULL
)
314 AcpiOsFree(sc
->tz_zone
.al
[i
].Pointer
);
315 if (sc
->tz_zone
.psl
.Pointer
!= NULL
)
316 AcpiOsFree(sc
->tz_zone
.psl
.Pointer
);
317 bzero(&sc
->tz_zone
, sizeof(sc
->tz_zone
));
319 /* Evaluate thermal zone parameters. */
320 for (i
= 0; i
< TZ_NUMLEVELS
; i
++) {
321 ksprintf(nbuf
, "_AC%d", i
);
322 acpi_tz_getparam(sc
, nbuf
, &sc
->tz_zone
.ac
[i
]);
323 ksprintf(nbuf
, "_AL%d", i
);
324 sc
->tz_zone
.al
[i
].Length
= ACPI_ALLOCATE_BUFFER
;
325 sc
->tz_zone
.al
[i
].Pointer
= NULL
;
326 AcpiEvaluateObject(sc
->tz_handle
, nbuf
, NULL
, &sc
->tz_zone
.al
[i
]);
327 obj
= (ACPI_OBJECT
*)sc
->tz_zone
.al
[i
].Pointer
;
329 /* Should be a package containing a list of power objects */
330 if (obj
->Type
!= ACPI_TYPE_PACKAGE
) {
331 device_printf(sc
->tz_dev
, "%s has unknown type %d, rejecting\n",
333 return_VALUE (ENXIO
);
337 acpi_tz_getparam(sc
, "_CRT", &sc
->tz_zone
.crt
);
338 acpi_tz_getparam(sc
, "_HOT", &sc
->tz_zone
.hot
);
339 sc
->tz_zone
.psl
.Length
= ACPI_ALLOCATE_BUFFER
;
340 sc
->tz_zone
.psl
.Pointer
= NULL
;
341 AcpiEvaluateObject(sc
->tz_handle
, "_PSL", NULL
, &sc
->tz_zone
.psl
);
342 acpi_tz_getparam(sc
, "_PSV", &sc
->tz_zone
.psv
);
343 acpi_tz_getparam(sc
, "_TC1", &sc
->tz_zone
.tc1
);
344 acpi_tz_getparam(sc
, "_TC2", &sc
->tz_zone
.tc2
);
345 acpi_tz_getparam(sc
, "_TSP", &sc
->tz_zone
.tsp
);
346 acpi_tz_getparam(sc
, "_TZP", &sc
->tz_zone
.tzp
);
349 * Sanity-check the values we've been given.
351 * XXX what do we do about systems that give us the same value for
352 * more than one of these setpoints?
354 acpi_tz_sanity(sc
, &sc
->tz_zone
.crt
, "_CRT");
355 acpi_tz_sanity(sc
, &sc
->tz_zone
.hot
, "_HOT");
356 acpi_tz_sanity(sc
, &sc
->tz_zone
.psv
, "_PSV");
357 for (i
= 0; i
< TZ_NUMLEVELS
; i
++)
358 acpi_tz_sanity(sc
, &sc
->tz_zone
.ac
[i
], "_ACx");
361 * Power off everything that we've just been given.
368 static char *aclevel_string
[] = {
369 "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4",
370 "_AC5", "_AC6", "_AC7", "_AC8", "_AC9" };
372 static __inline
const char *
373 acpi_tz_aclevel_string(int active
)
375 if (active
< -1 || active
>= TZ_NUMLEVELS
)
376 return (aclevel_string
[0]);
378 return (aclevel_string
[active
+1]);
382 * Evaluate the condition of a thermal zone, take appropriate actions.
385 acpi_tz_monitor(void *Context
)
387 struct acpi_tz_softc
*sc
;
388 struct timespec curtime
;
391 int newactive
, newflags
;
394 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
398 sc
= (struct acpi_tz_softc
*)Context
;
399 if (sc
->tz_tmp_updating
)
401 sc
->tz_tmp_updating
= 1;
403 /* Get the current temperature. */
404 status
= acpi_GetInteger(sc
->tz_handle
, "_TMP", &temp
);
405 if (ACPI_FAILURE(status
)) {
406 ACPI_VPRINT(sc
->tz_dev
, acpi_device_get_parent_softc(sc
->tz_dev
),
407 "error fetching current temperature -- %s\n",
408 AcpiFormatException(status
));
409 /* XXX disable zone? go to max cooling? */
413 ACPI_DEBUG_PRINT((ACPI_DB_VALUES
, "got %d.%dC\n", TZ_KELVTOC(temp
)));
414 sc
->tz_temperature
= temp
;
417 * Work out what we ought to be doing right now.
419 * Note that the _ACx levels sort from hot to cold.
421 newactive
= TZ_ACTIVE_NONE
;
422 for (i
= TZ_NUMLEVELS
- 1; i
>= 0; i
--) {
423 if ((sc
->tz_zone
.ac
[i
] != -1) && (temp
>= sc
->tz_zone
.ac
[i
])) {
425 if (sc
->tz_active
!= newactive
) {
426 ACPI_VPRINT(sc
->tz_dev
,
427 acpi_device_get_parent_softc(sc
->tz_dev
),
428 "_AC%d: temperature %d.%d >= setpoint %d.%d\n", i
,
429 TZ_KELVTOC(temp
), TZ_KELVTOC(sc
->tz_zone
.ac
[i
]));
430 getnanotime(&sc
->tz_cooling_started
);
436 * We are going to get _ACx level down (colder side), but give a guaranteed
437 * minimum cooling run time if requested.
439 if (acpi_tz_min_runtime
> 0 && sc
->tz_active
!= TZ_ACTIVE_NONE
&&
440 (newactive
== TZ_ACTIVE_NONE
|| newactive
> sc
->tz_active
)) {
442 getnanotime(&curtime
);
443 timespecsub(&curtime
, &sc
->tz_cooling_started
);
444 if (curtime
.tv_sec
< acpi_tz_min_runtime
)
445 newactive
= sc
->tz_active
;
448 /* Handle user override of active mode */
449 if (sc
->tz_requested
!= TZ_ACTIVE_NONE
&& sc
->tz_requested
< newactive
)
450 newactive
= sc
->tz_requested
;
452 /* update temperature-related flags */
453 newflags
= TZ_THFLAG_NONE
;
454 if (sc
->tz_zone
.psv
!= -1 && temp
>= sc
->tz_zone
.psv
)
455 newflags
|= TZ_THFLAG_PSV
;
456 if (sc
->tz_zone
.hot
!= -1 && temp
>= sc
->tz_zone
.hot
)
457 newflags
|= TZ_THFLAG_HOT
;
458 if (sc
->tz_zone
.crt
!= -1 && temp
>= sc
->tz_zone
.crt
)
459 newflags
|= TZ_THFLAG_CRT
;
461 /* If the active cooling state has changed, we have to switch things. */
462 if (newactive
!= sc
->tz_active
) {
463 /* Turn off the cooling devices that are on, if any are */
464 if (sc
->tz_active
!= TZ_ACTIVE_NONE
)
465 acpi_ForeachPackageObject(
466 (ACPI_OBJECT
*)sc
->tz_zone
.al
[sc
->tz_active
].Pointer
,
467 acpi_tz_switch_cooler_off
, sc
);
469 /* Turn on cooling devices that are required, if any are */
470 if (newactive
!= TZ_ACTIVE_NONE
) {
471 acpi_ForeachPackageObject(
472 (ACPI_OBJECT
*)sc
->tz_zone
.al
[newactive
].Pointer
,
473 acpi_tz_switch_cooler_on
, sc
);
475 ACPI_VPRINT(sc
->tz_dev
, acpi_device_get_parent_softc(sc
->tz_dev
),
476 "switched from %s to %s: %d.%dC\n",
477 acpi_tz_aclevel_string(sc
->tz_active
),
478 acpi_tz_aclevel_string(newactive
), TZ_KELVTOC(temp
));
479 sc
->tz_active
= newactive
;
482 /* XXX (de)activate any passive cooling that may be required. */
485 * If the temperature is at _HOT or _CRT, increment our event count.
486 * If it has occurred enough times, shutdown the system. This is
487 * needed because some systems will report an invalid high temperature
488 * for one poll cycle. It is suspected this is due to the embedded
489 * controller timing out. A typical value is 138C for one cycle on
490 * a system that is otherwise 65C.
492 * If we're almost at that threshold, notify the user through devd(8).
494 if ((newflags
& (TZ_THFLAG_HOT
| TZ_THFLAG_CRT
)) != 0) {
495 sc
->tz_validchecks
++;
496 if (sc
->tz_validchecks
== TZ_VALIDCHECKS
) {
497 device_printf(sc
->tz_dev
,
498 "WARNING - current temperature (%d.%dC) exceeds safe limits\n",
499 TZ_KELVTOC(sc
->tz_temperature
));
500 shutdown_nice(RB_POWEROFF
);
501 } else if (sc
->tz_validchecks
== TZ_NOTIFYCOUNT
)
502 acpi_UserNotify("Thermal", sc
->tz_handle
, TZ_NOTIFY_CRITICAL
);
504 sc
->tz_validchecks
= 0;
506 sc
->tz_thflags
= newflags
;
509 sc
->tz_tmp_updating
= 0;
514 * Turn off all the cooling devices.
517 acpi_tz_all_off(struct acpi_tz_softc
*sc
)
521 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
525 /* Scan all the _ALx objects and turn them all off. */
526 for (i
= 0; i
< TZ_NUMLEVELS
; i
++) {
527 if (sc
->tz_zone
.al
[i
].Pointer
== NULL
)
529 acpi_ForeachPackageObject((ACPI_OBJECT
*)sc
->tz_zone
.al
[i
].Pointer
,
530 acpi_tz_switch_cooler_off
, sc
);
534 * XXX revert any passive-cooling options.
537 sc
->tz_active
= TZ_ACTIVE_NONE
;
538 sc
->tz_thflags
= TZ_THFLAG_NONE
;
544 * Given an object, verify that it's a reference to a device of some sort,
545 * and try to switch it off.
548 acpi_tz_switch_cooler_off(ACPI_OBJECT
*obj
, void *arg
)
552 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
556 cooler
= acpi_GetReference(NULL
, obj
);
557 if (cooler
== NULL
) {
558 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS
, "can't get handle\n"));
562 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS
, "called to turn %s off\n",
564 acpi_pwr_switch_consumer(cooler
, ACPI_STATE_D3
);
570 * Given an object, verify that it's a reference to a device of some sort,
571 * and try to switch it on.
573 * XXX replication of off/on function code is bad.
576 acpi_tz_switch_cooler_on(ACPI_OBJECT
*obj
, void *arg
)
578 struct acpi_tz_softc
*sc
= (struct acpi_tz_softc
*)arg
;
582 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
586 cooler
= acpi_GetReference(NULL
, obj
);
587 if (cooler
== NULL
) {
588 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS
, "can't get handle\n"));
592 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS
, "called to turn %s on\n",
594 status
= acpi_pwr_switch_consumer(cooler
, ACPI_STATE_D0
);
595 if (ACPI_FAILURE(status
)) {
596 ACPI_VPRINT(sc
->tz_dev
, acpi_device_get_parent_softc(sc
->tz_dev
),
597 "failed to activate %s - %s\n", acpi_name(cooler
),
598 AcpiFormatException(status
));
605 * Read/debug-print a parameter, default it to -1.
608 acpi_tz_getparam(struct acpi_tz_softc
*sc
, char *node
, int *data
)
611 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
615 if (ACPI_FAILURE(acpi_GetInteger(sc
->tz_handle
, node
, data
))) {
618 ACPI_DEBUG_PRINT((ACPI_DB_VALUES
, "%s.%s = %d\n",
619 acpi_name(sc
->tz_handle
), node
, *data
));
626 * Sanity-check a temperature value. Assume that setpoints
627 * should be between 0C and 150C.
630 acpi_tz_sanity(struct acpi_tz_softc
*sc
, int *val
, char *what
)
632 if (*val
!= -1 && (*val
< TZ_ZEROC
|| *val
> TZ_ZEROC
+ 1500)) {
633 device_printf(sc
->tz_dev
, "%s value is absurd, ignored (%d.%dC)\n",
634 what
, TZ_KELVTOC(*val
));
640 * Respond to a sysctl on the active state node.
643 acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS
)
645 struct acpi_tz_softc
*sc
;
652 sc
= (struct acpi_tz_softc
*)oidp
->oid_arg1
;
653 active
= sc
->tz_active
;
654 error
= sysctl_handle_int(oidp
, &active
, 0, req
);
656 /* Error or no new value */
657 if (error
!= 0 || req
->newptr
== NULL
)
659 if (active
< -1 || active
>= TZ_NUMLEVELS
) {
664 /* Set new preferred level and re-switch */
665 sc
->tz_requested
= active
;
674 * Respond to a Notify event sent to the zone.
677 acpi_tz_notify_handler(ACPI_HANDLE h
, UINT32 notify
, void *context
)
679 struct acpi_tz_softc
*sc
= (struct acpi_tz_softc
*)context
;
681 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
686 case TZ_NOTIFY_TEMPERATURE
:
687 /* Temperature change occurred */
688 AcpiOsExecute(OSL_NOTIFY_HANDLER
, acpi_tz_monitor
, sc
);
690 case TZ_NOTIFY_DEVICES
:
691 case TZ_NOTIFY_LEVELS
:
692 /* Zone devices/setpoints changed */
693 AcpiOsExecute(OSL_NOTIFY_HANDLER
,
694 (ACPI_OSD_EXEC_CALLBACK
)acpi_tz_establish
, sc
);
697 ACPI_VPRINT(sc
->tz_dev
, acpi_device_get_parent_softc(sc
->tz_dev
),
698 "unknown Notify event 0x%x\n", notify
);
702 acpi_UserNotify("Thermal", h
, notify
);
708 * Poll the thermal zone.
711 acpi_tz_timeout(struct acpi_tz_softc
*sc
)
713 /* Do we need to get the power profile settings? */
714 if (sc
->tz_flags
& TZ_FLAG_GETPROFILE
) {
715 acpi_tz_power_profile((void *)sc
);
716 sc
->tz_flags
&= ~TZ_FLAG_GETPROFILE
;
721 /* Check the current temperature and take action based on it */
724 /* XXX passive cooling actions? */
728 * System power profile may have changed; fetch and notify the
729 * thermal zone accordingly.
731 * Since this can be called from an arbitrary eventhandler, it needs
732 * to get the ACPI lock itself.
735 acpi_tz_power_profile(void *arg
)
738 struct acpi_tz_softc
*sc
= (struct acpi_tz_softc
*)arg
;
742 state
= power_profile_get_state();
743 if (state
!= POWER_PROFILE_PERFORMANCE
&& state
!= POWER_PROFILE_ECONOMY
)
748 /* check that we haven't decided there's no _SCP method */
749 if ((sc
->tz_flags
& TZ_FLAG_NO_SCP
) == 0) {
751 /* Call _SCP to set the new profile */
752 status
= acpi_SetInteger(sc
->tz_handle
, "_SCP",
753 (state
== POWER_PROFILE_PERFORMANCE
) ? 0 : 1);
754 if (ACPI_FAILURE(status
)) {
755 if (status
!= AE_NOT_FOUND
)
756 ACPI_VPRINT(sc
->tz_dev
,
757 acpi_device_get_parent_softc(sc
->tz_dev
),
758 "can't evaluate %s._SCP - %s\n",
759 acpi_name(sc
->tz_handle
),
760 AcpiFormatException(status
));
761 sc
->tz_flags
|= TZ_FLAG_NO_SCP
;
763 /* We have to re-evaluate the entire zone now */
764 AcpiOsExecute(OSL_NOTIFY_HANDLER
,
765 (ACPI_OSD_EXEC_CALLBACK
)acpi_tz_establish
,
774 * Thermal zone monitor thread.
777 acpi_tz_thread(void *arg
)
783 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
789 tsleep(&acpi_tz_td
, 0, "tzpoll", hz
* acpi_tz_polling_rate
);
791 #if __FreeBSD_version >= 500000
796 devclass_get_devices(acpi_tz_devclass
, &devs
, &devcount
);
799 for (i
= 0; i
< devcount
; i
++)
800 acpi_tz_timeout(device_get_softc(devs
[i
]));
803 #if __FreeBSD_version >= 500000