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