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