Add flag to indicate that the NIC does not have power control capability.
[dragonfly.git] / sys / dev / acpica5 / acpi_thermal.c
blob39327523ca89bde638221579544b7fccdab20c71
1 /*-
2 * Copyright (c) 2000, 2001 Michael Smith
3 * Copyright (c) 2000 BSDi
4 * All rights reserved.
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.
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.
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 17:31:19 y0netan1 Exp $
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 #include <sys/thread2.h>
44 #include "acpi.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")
51 #define TZ_ZEROC 2732
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
70 struct acpi_tz_zone {
71 int ac[TZ_NUMLEVELS];
72 ACPI_BUFFER al[TZ_NUMLEVELS];
73 int crt;
74 int hot;
75 ACPI_BUFFER psl;
76 int psv;
77 int tc1;
78 int tc2;
79 int tsp;
80 int tzp;
83 struct acpi_tz_softc {
84 device_t tz_dev;
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)
95 int tz_flags;
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*/
105 int tz_tmp_updating;
106 int tz_validchecks;
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,
117 int *data);
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,
121 void *context);
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),
131 {0, 0}
134 static driver_t acpi_tz_driver = {
135 "acpi_tz",
136 acpi_tz_methods,
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.
157 static int
158 acpi_tz_probe(device_t dev)
160 int result;
161 ACPI_LOCK_DECL;
163 ACPI_LOCK;
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");
169 result = -10;
170 } else {
171 result = ENXIO;
173 ACPI_UNLOCK;
174 return (result);
178 * Attach to an ACPI thermal zone.
180 static int
181 acpi_tz_attach(device_t dev)
183 struct acpi_tz_softc *sc;
184 struct acpi_softc *acpi_sc;
185 int error;
186 char oidname[8];
187 ACPI_LOCK_DECL;
189 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
191 ACPI_LOCK;
193 sc = device_get_softc(dev);
194 sc->tz_dev = 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
201 * structures.
203 if ((error = acpi_tz_establish(sc)) != 0)
204 goto out;
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
276 * thermal zones.
278 if (acpi_tz_td == NULL) {
279 error = kthread_create(acpi_tz_thread, NULL, &acpi_tz_td,
280 RFHIGHPID, 0, "acpi_thermal");
281 if (error != 0) {
282 device_printf(sc->tz_dev, "could not create thread - %d",
283 error);
284 goto out;
288 out:
289 ACPI_UNLOCK;
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.
299 static int
300 acpi_tz_establish(struct acpi_tz_softc *sc)
302 ACPI_OBJECT *obj;
303 int i;
304 char nbuf[8];
306 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
308 ACPI_ASSERTLOCK;
310 /* Power everything off and erase any existing state. */
311 acpi_tz_all_off(sc);
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;
328 if (obj != NULL) {
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",
332 nbuf, obj->Type);
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.
363 acpi_tz_all_off(sc);
365 return_VALUE (0);
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.
384 static void
385 acpi_tz_monitor(void *Context)
387 struct acpi_tz_softc *sc;
388 struct timespec curtime;
389 int temp;
390 int i;
391 int newactive, newflags;
392 ACPI_STATUS status;
394 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
396 ACPI_ASSERTLOCK;
398 sc = (struct acpi_tz_softc *)Context;
399 if (sc->tz_tmp_updating)
400 goto out;
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? */
410 goto out;
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])) {
424 newactive = 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);
503 } else {
504 sc->tz_validchecks = 0;
506 sc->tz_thflags = newflags;
508 out:
509 sc->tz_tmp_updating = 0;
510 return_VOID;
514 * Turn off all the cooling devices.
516 static void
517 acpi_tz_all_off(struct acpi_tz_softc *sc)
519 int i;
521 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
523 ACPI_ASSERTLOCK;
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)
528 continue;
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;
540 return_VOID;
544 * Given an object, verify that it's a reference to a device of some sort,
545 * and try to switch it off.
547 static void
548 acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg)
550 ACPI_HANDLE cooler;
552 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
554 ACPI_ASSERTLOCK;
556 cooler = acpi_GetReference(NULL, obj);
557 if (cooler == NULL) {
558 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n"));
559 return_VOID;
562 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n",
563 acpi_name(cooler)));
564 acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3);
566 return_VOID;
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.
575 static void
576 acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg)
578 struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg;
579 ACPI_HANDLE cooler;
580 ACPI_STATUS status;
582 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
584 ACPI_ASSERTLOCK;
586 cooler = acpi_GetReference(NULL, obj);
587 if (cooler == NULL) {
588 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n"));
589 return_VOID;
592 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n",
593 acpi_name(cooler)));
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));
601 return_VOID;
605 * Read/debug-print a parameter, default it to -1.
607 static void
608 acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data)
611 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
613 ACPI_ASSERTLOCK;
615 if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) {
616 *data = -1;
617 } else {
618 ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n",
619 acpi_name(sc->tz_handle), node, *data));
622 return_VOID;
626 * Sanity-check a temperature value. Assume that setpoints
627 * should be between 0C and 150C.
629 static void
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));
635 *val = -1;
640 * Respond to a sysctl on the active state node.
642 static int
643 acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS)
645 struct acpi_tz_softc *sc;
646 int active;
647 int error;
648 ACPI_LOCK_DECL;
650 ACPI_LOCK;
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)
658 goto out;
659 if (active < -1 || active >= TZ_NUMLEVELS) {
660 error = EINVAL;
661 goto out;
664 /* Set new preferred level and re-switch */
665 sc->tz_requested = active;
666 acpi_tz_monitor(sc);
668 out:
669 ACPI_UNLOCK;
670 return (error);
674 * Respond to a Notify event sent to the zone.
676 static void
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__);
683 ACPI_ASSERTLOCK;
685 switch(notify) {
686 case TZ_NOTIFY_TEMPERATURE:
687 /* Temperature change occurred */
688 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_tz_monitor, sc);
689 break;
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);
695 break;
696 default:
697 ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
698 "unknown Notify event 0x%x\n", notify);
699 break;
702 acpi_UserNotify("Thermal", h, notify);
704 return_VOID;
708 * Poll the thermal zone.
710 static void
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;
719 ACPI_ASSERTLOCK;
721 /* Check the current temperature and take action based on it */
722 acpi_tz_monitor(sc);
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.
734 static void
735 acpi_tz_power_profile(void *arg)
737 ACPI_STATUS status;
738 struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg;
739 int state;
740 ACPI_LOCK_DECL;
742 state = power_profile_get_state();
743 if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY)
744 return;
746 ACPI_LOCK;
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;
762 } else {
763 /* We have to re-evaluate the entire zone now */
764 AcpiOsExecute(OSL_NOTIFY_HANDLER,
765 (ACPI_OSD_EXEC_CALLBACK)acpi_tz_establish,
766 sc);
770 ACPI_UNLOCK;
774 * Thermal zone monitor thread.
776 static void
777 acpi_tz_thread(void *arg)
779 device_t *devs;
780 int devcount, i;
781 ACPI_LOCK_DECL;
783 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
785 devs = NULL;
786 devcount = 0;
788 for (;;) {
789 tsleep(&acpi_tz_td, 0, "tzpoll", hz * acpi_tz_polling_rate);
791 #if __FreeBSD_version >= 500000
792 mtx_lock(&Giant);
793 #endif
795 if (devcount == 0)
796 devclass_get_devices(acpi_tz_devclass, &devs, &devcount);
798 ACPI_LOCK;
799 for (i = 0; i < devcount; i++)
800 acpi_tz_timeout(device_get_softc(devs[i]));
801 ACPI_UNLOCK;
803 #if __FreeBSD_version >= 500000
804 mtx_unlock(&Giant);
805 #endif