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