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