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