1 /* $NetBSD: acpi_tz.c,v 1.78 2011/01/18 21:15:54 jmcneill Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * 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 /* 29 * ACPI Thermal Zone driver 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: acpi_tz.c,v 1.78 2011/01/18 21:15:54 jmcneill Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/device.h> 37 #include <sys/callout.h> 38 #include <sys/kernel.h> 39 #include <sys/module.h> 40 #include <sys/systm.h> 41 42 #include <dev/acpi/acpireg.h> 43 #include <dev/acpi/acpivar.h> 44 #include <dev/acpi/acpi_power.h> 45 46 #define _COMPONENT ACPI_TZ_COMPONENT 47 ACPI_MODULE_NAME ("acpi_tz") 48 49 #define ACPI_NOTIFY_TZ_ZONE 0x80 50 #define ACPI_NOTIFY_TZ_TRIP 0x81 51 #define ACPI_NOTIFY_TZ_DEVLIST 0x82 52 53 #define ATZ_F_CRITICAL 0x01 /* zone critical */ 54 #define ATZ_F_HOT 0x02 /* zone hot */ 55 #define ATZ_F_PASSIVE 0x04 /* zone passive cooling */ 56 #define ATZ_F_PASSIVEONLY 0x08 /* zone is passive cooling only */ 57 58 #define ATZ_ACTIVE_NONE -1 59 60 /* 61 * The constants are as follows: 62 * 63 * ATZ_TZP_RATE default polling interval (30 seconds) if no _TZP 64 * ATZ_NLEVELS number of cooling levels for _ACx and _ALx 65 * ATZ_ZEROC 0 C, measured in 0.1 Kelvin 66 * ATZ_TMP_INVALID temporarily invalid temperature 67 * ATZ_ZONE_EXPIRE zone info refetch interval (15 minutes) 68 */ 69 #define ATZ_TZP_RATE 300 70 #define ATZ_NLEVELS 10 71 #define ATZ_ZEROC 2732 72 #define ATZ_TMP_INVALID 0xffffffff 73 #define ATZ_ZONE_EXPIRE 9000 74 75 /* 76 * All temperatures are reported in 0.1 Kelvin. 77 * The ACPI specification assumes that K = C + 273.2 78 * rather than the nominal 273.15 used by envsys(4). 79 */ 80 #define ATZ2UKELVIN(t) ((t) * 100000 - 50000) 81 82 struct acpitz_zone { 83 ACPI_BUFFER al[ATZ_NLEVELS]; 84 uint32_t ac[ATZ_NLEVELS]; 85 uint32_t crt; 86 uint32_t hot; 87 uint32_t rtv; 88 uint32_t psv; 89 uint32_t tc1; 90 uint32_t tc2; 91 uint32_t tmp; 92 uint32_t prevtmp; 93 uint32_t tzp; 94 uint32_t fanmin; 95 uint32_t fanmax; 96 uint32_t fancurrent; 97 }; 98 99 struct acpitz_softc { 100 struct acpi_devnode *sc_node; 101 struct sysmon_envsys *sc_sme; 102 struct acpitz_zone sc_zone; 103 struct callout sc_callout; 104 envsys_data_t sc_temp_sensor; 105 envsys_data_t sc_fan_sensor; 106 int sc_active; 107 int sc_flags; 108 int sc_zone_expire; 109 bool sc_first; 110 bool sc_have_fan; 111 }; 112 113 static int acpitz_match(device_t, cfdata_t, void *); 114 static void acpitz_attach(device_t, device_t, void *); 115 static int acpitz_detach(device_t, int); 116 static void acpitz_get_status(void *); 117 static void acpitz_get_zone(void *, int); 118 static void acpitz_get_zone_quiet(void *); 119 static char *acpitz_celcius_string(int); 120 static void acpitz_power_off(struct acpitz_softc *); 121 static void acpitz_power_zone(struct acpitz_softc *, int, int); 122 static void acpitz_sane_temp(uint32_t *tmp); 123 static ACPI_STATUS acpitz_switch_cooler(ACPI_OBJECT *, void *); 124 static void acpitz_notify_handler(ACPI_HANDLE, uint32_t, void *); 125 static int acpitz_get_integer(device_t, const char *, uint32_t *); 126 static void acpitz_tick(void *); 127 static void acpitz_init_envsys(device_t); 128 static void acpitz_get_limits(struct sysmon_envsys *, 129 envsys_data_t *, 130 sysmon_envsys_lim_t *, uint32_t *); 131 static int acpitz_get_fanspeed(device_t, uint32_t *, 132 uint32_t *, uint32_t *); 133 #ifdef notyet 134 static ACPI_STATUS acpitz_set_fanspeed(device_t, uint32_t); 135 #endif 136 static void acpitz_print_processor_list(device_t); 137 static struct cpu_info *acpitz_find_processor(uint32_t); 138 139 CFATTACH_DECL_NEW(acpitz, sizeof(struct acpitz_softc), 140 acpitz_match, acpitz_attach, acpitz_detach, NULL); 141 142 /* 143 * acpitz_match: autoconf(9) match routine 144 */ 145 static int 146 acpitz_match(device_t parent, cfdata_t match, void *aux) 147 { 148 struct acpi_attach_args *aa = aux; 149 150 if (aa->aa_node->ad_type != ACPI_TYPE_THERMAL) 151 return 0; 152 153 return 1; 154 } 155 156 /* 157 * acpitz_attach: autoconf(9) attach routine 158 */ 159 static void 160 acpitz_attach(device_t parent, device_t self, void *aux) 161 { 162 struct acpitz_softc *sc = device_private(self); 163 struct acpi_attach_args *aa = aux; 164 ACPI_INTEGER val; 165 ACPI_STATUS rv; 166 167 sc->sc_first = true; 168 sc->sc_have_fan = false; 169 sc->sc_node = aa->aa_node; 170 sc->sc_zone.tzp = ATZ_TZP_RATE; 171 172 aprint_naive("\n"); 173 acpitz_print_processor_list(self); 174 aprint_normal("\n"); 175 176 /* 177 * The _TZP (ACPI 4.0, p. 430) defines the recommended 178 * polling interval (in tenths of seconds). A value zero 179 * means that polling "should not be necessary". 180 */ 181 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TZP", &val); 182 183 if (ACPI_SUCCESS(rv) && val != 0) 184 sc->sc_zone.tzp = val; 185 186 aprint_debug_dev(self, "polling interval %d.%d seconds\n", 187 sc->sc_zone.tzp / 10, sc->sc_zone.tzp % 10); 188 189 sc->sc_zone_expire = ATZ_ZONE_EXPIRE / sc->sc_zone.tzp; 190 191 /* 192 * XXX: The fan controls seen here are available on 193 * some HP laptops. Arguably these should not 194 * appear in a generic device driver like this. 195 */ 196 if (acpitz_get_fanspeed(self, &sc->sc_zone.fanmin, 197 &sc->sc_zone.fanmax, &sc->sc_zone.fancurrent) == 0) 198 sc->sc_have_fan = true; 199 200 acpitz_get_zone(self, 1); 201 acpitz_get_status(self); 202 203 (void)pmf_device_register(self, NULL, NULL); 204 (void)acpi_power_register(sc->sc_node->ad_handle); 205 (void)acpi_register_notify(sc->sc_node, acpitz_notify_handler); 206 207 callout_init(&sc->sc_callout, CALLOUT_MPSAFE); 208 callout_setfunc(&sc->sc_callout, acpitz_tick, self); 209 210 acpitz_init_envsys(self); 211 212 callout_schedule(&sc->sc_callout, sc->sc_zone.tzp * hz / 10); 213 } 214 215 static int 216 acpitz_detach(device_t self, int flags) 217 { 218 struct acpitz_softc *sc = device_private(self); 219 ACPI_HANDLE hdl; 220 ACPI_BUFFER al; 221 ACPI_STATUS rv; 222 int i; 223 224 callout_halt(&sc->sc_callout, NULL); 225 callout_destroy(&sc->sc_callout); 226 227 pmf_device_deregister(self); 228 acpi_deregister_notify(sc->sc_node); 229 230 /* 231 * Although the device itself should not contain any power 232 * resources, we have possibly used the resources of active 233 * cooling devices. To unregister these, first fetch a fresh 234 * active cooling zone, and then detach the resources from 235 * the reference handles contained in the cooling zone. 236 */ 237 acpitz_get_zone(self, 0); 238 239 for (i = 0; i < ATZ_NLEVELS; i++) { 240 241 if (sc->sc_zone.al[i].Pointer == NULL) 242 continue; 243 244 al = sc->sc_zone.al[i]; 245 rv = acpi_eval_reference_handle(al.Pointer, &hdl); 246 247 if (ACPI_SUCCESS(rv)) 248 acpi_power_deregister(hdl); 249 250 ACPI_FREE(sc->sc_zone.al[i].Pointer); 251 } 252 253 if (sc->sc_sme != NULL) 254 sysmon_envsys_unregister(sc->sc_sme); 255 256 return 0; 257 } 258 259 static void 260 acpitz_get_zone_quiet(void *opaque) 261 { 262 acpitz_get_zone(opaque, 0); 263 } 264 265 static void 266 acpitz_get_status(void *opaque) 267 { 268 device_t dv = opaque; 269 struct acpitz_softc *sc = device_private(dv); 270 uint32_t tmp, fmin, fmax, fcurrent; 271 int active, changed, flags, i; 272 273 sc->sc_zone_expire--; 274 275 if (sc->sc_zone_expire <= 0) { 276 sc->sc_zone_expire = ATZ_ZONE_EXPIRE / sc->sc_zone.tzp; 277 278 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 279 "%s: zone refetch forced\n", device_xname(dv))); 280 281 acpitz_get_zone(dv, 0); 282 } 283 284 if (acpitz_get_integer(dv, "_TMP", &tmp) != 0) 285 return; 286 287 sc->sc_zone.prevtmp = sc->sc_zone.tmp; 288 sc->sc_zone.tmp = tmp; 289 290 if (sc->sc_first != false) 291 sc->sc_zone.prevtmp = tmp; /* XXX: Sanity check? */ 292 293 if (acpitz_get_fanspeed(dv, &fmin, &fmax, &fcurrent) == 0) { 294 295 if (fcurrent != ATZ_TMP_INVALID) 296 sc->sc_zone.fancurrent = fcurrent; 297 } 298 299 sc->sc_temp_sensor.state = ENVSYS_SVALID; 300 sc->sc_temp_sensor.value_cur = ATZ2UKELVIN(sc->sc_zone.tmp); 301 302 sc->sc_fan_sensor.state = ENVSYS_SVALID; 303 sc->sc_fan_sensor.value_cur = sc->sc_zone.fancurrent; 304 305 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: zone temperature is %s C\n", 306 device_xname(dv), acpitz_celcius_string(sc->sc_zone.tmp))); 307 308 /* 309 * XXX: Passive cooling is not yet supported. 310 */ 311 if ((sc->sc_flags & ATZ_F_PASSIVEONLY) != 0) 312 return; 313 314 /* 315 * As noted in ACPI 4.0 (p. 420), the temperature 316 * thresholds are conveyed in the optional _ACx 317 * object (x = 0 ... 9). The smaller the x, the 318 * greater the cooling level. We prefer to keep 319 * the highest cooling mode when in "active". 320 */ 321 active = ATZ_ACTIVE_NONE; 322 323 for (i = ATZ_NLEVELS - 1; i >= 0; i--) { 324 325 if (sc->sc_zone.ac[i] == ATZ_TMP_INVALID) 326 continue; 327 328 if (sc->sc_zone.ac[i] <= tmp) 329 active = i; 330 } 331 332 flags = sc->sc_flags & ~(ATZ_F_CRITICAL | ATZ_F_HOT | ATZ_F_PASSIVE); 333 334 if (sc->sc_zone.psv != ATZ_TMP_INVALID && tmp >= sc->sc_zone.psv) 335 flags |= ATZ_F_PASSIVE; 336 337 if (sc->sc_zone.hot != ATZ_TMP_INVALID && tmp >= sc->sc_zone.hot) 338 flags |= ATZ_F_HOT; 339 340 if (sc->sc_zone.crt != ATZ_TMP_INVALID && tmp >= sc->sc_zone.crt) 341 flags |= ATZ_F_CRITICAL; 342 343 if (flags != sc->sc_flags) { 344 345 changed = (sc->sc_flags ^ flags) & flags; 346 sc->sc_flags = flags; 347 348 if ((changed & ATZ_F_CRITICAL) != 0) { 349 sc->sc_temp_sensor.state = ENVSYS_SCRITOVER; 350 351 aprint_debug_dev(dv, "zone went critical, %s C\n", 352 acpitz_celcius_string(tmp)); 353 354 } else if ((changed & ATZ_F_HOT) != 0) { 355 sc->sc_temp_sensor.state = ENVSYS_SCRITOVER; 356 357 aprint_debug_dev(dv, "zone went hot, %s C\n", 358 acpitz_celcius_string(tmp)); 359 } 360 } 361 362 /* Power on the fans. */ 363 if (sc->sc_active != active) { 364 365 if (sc->sc_active != ATZ_ACTIVE_NONE) 366 acpitz_power_zone(sc, sc->sc_active, 0); 367 368 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: active cooling " 369 "level %d\n", device_xname(dv), active)); 370 371 if (active != ATZ_ACTIVE_NONE) 372 acpitz_power_zone(sc, active, 1); 373 374 sc->sc_active = active; 375 } 376 } 377 378 static char * 379 acpitz_celcius_string(int dk) 380 { 381 static char buf[10]; 382 int dc; 383 384 dc = abs(dk - ATZ_ZEROC); 385 386 (void)snprintf(buf, sizeof(buf), "%s%d.%d", 387 (dk >= ATZ_ZEROC) ? "" : "-", dc / 10, dc % 10); 388 389 return buf; 390 } 391 392 static ACPI_STATUS 393 acpitz_switch_cooler(ACPI_OBJECT *obj, void *arg) 394 { 395 int flag, pwr_state; 396 ACPI_HANDLE cooler; 397 ACPI_STATUS rv; 398 399 /* 400 * The _ALx object is a package in which the elements 401 * are reference handles to an active cooling device 402 * (typically PNP0C0B, ACPI fan device). Try to turn 403 * on (or off) the power resources behind these handles 404 * to start (or terminate) the active cooling. 405 */ 406 flag = *(int *)arg; 407 pwr_state = (flag != 0) ? ACPI_STATE_D0 : ACPI_STATE_D3; 408 409 rv = acpi_eval_reference_handle(obj, &cooler); 410 411 if (ACPI_FAILURE(rv)) 412 return rv; 413 414 (void)acpi_power_set(cooler, pwr_state); 415 416 return AE_OK; 417 } 418 419 /* 420 * acpitz_power_zone: 421 * 422 * Power on or off the i:th part of the zone zone. 423 */ 424 static void 425 acpitz_power_zone(struct acpitz_softc *sc, int i, int on) 426 { 427 428 KASSERT(i >= 0 && i < ATZ_NLEVELS); 429 430 (void)acpi_foreach_package_object(sc->sc_zone.al[i].Pointer, 431 acpitz_switch_cooler, &on); 432 } 433 434 435 /* 436 * acpitz_power_off: 437 * 438 * Power off parts of the zone. 439 */ 440 static void 441 acpitz_power_off(struct acpitz_softc *sc) 442 { 443 int i; 444 445 for (i = 0 ; i < ATZ_NLEVELS; i++) { 446 447 if (sc->sc_zone.al[i].Pointer == NULL) 448 continue; 449 450 acpitz_power_zone(sc, i, 0); 451 } 452 453 sc->sc_active = ATZ_ACTIVE_NONE; 454 sc->sc_flags &= ~(ATZ_F_CRITICAL | ATZ_F_HOT | ATZ_F_PASSIVE); 455 } 456 457 static void 458 acpitz_get_zone(void *opaque, int verbose) 459 { 460 device_t dv = opaque; 461 struct acpitz_softc *sc = device_private(dv); 462 int comma, i, valid_levels; 463 ACPI_OBJECT *obj; 464 ACPI_STATUS rv; 465 char buf[5]; 466 467 if (sc->sc_first != true) { 468 acpitz_power_off(sc); 469 470 for (i = 0; i < ATZ_NLEVELS; i++) { 471 472 if (sc->sc_zone.al[i].Pointer != NULL) 473 ACPI_FREE(sc->sc_zone.al[i].Pointer); 474 475 sc->sc_zone.al[i].Pointer = NULL; 476 } 477 } 478 479 valid_levels = 0; 480 481 for (i = 0; i < ATZ_NLEVELS; i++) { 482 483 (void)snprintf(buf, sizeof(buf), "_AC%d", i); 484 485 if (acpitz_get_integer(dv, buf, &sc->sc_zone.ac[i])) 486 continue; 487 488 (void)snprintf(buf, sizeof(buf), "_AL%d", i); 489 490 rv = acpi_eval_struct(sc->sc_node->ad_handle, buf, 491 &sc->sc_zone.al[i]); 492 493 if (ACPI_FAILURE(rv)) { 494 sc->sc_zone.al[i].Pointer = NULL; 495 continue; 496 } 497 498 obj = sc->sc_zone.al[i].Pointer; 499 500 if (obj->Type != ACPI_TYPE_PACKAGE) { 501 sc->sc_zone.al[i].Pointer = NULL; 502 ACPI_FREE(obj); 503 continue; 504 } 505 506 if (sc->sc_first != false) 507 aprint_normal_dev(dv, "active cooling level %d: %sC\n", 508 i, acpitz_celcius_string(sc->sc_zone.ac[i])); 509 510 valid_levels++; 511 } 512 513 /* 514 * A brief summary (ACPI 4.0, section 11.4): 515 * 516 * _TMP : current temperature (in tenths of degrees) 517 * _CRT : critical trip-point at which to shutdown 518 * _HOT : critical trip-point at which to go to S4 519 * _PSV : passive cooling policy threshold 520 * _TC1 : thermal constant for passive cooling 521 * _TC2 : thermal constant for passive cooling 522 */ 523 (void)acpitz_get_integer(dv, "_TMP", &sc->sc_zone.tmp); 524 (void)acpitz_get_integer(dv, "_CRT", &sc->sc_zone.crt); 525 (void)acpitz_get_integer(dv, "_HOT", &sc->sc_zone.hot); 526 (void)acpitz_get_integer(dv, "_PSV", &sc->sc_zone.psv); 527 (void)acpitz_get_integer(dv, "_TC1", &sc->sc_zone.tc1); 528 (void)acpitz_get_integer(dv, "_TC2", &sc->sc_zone.tc2); 529 530 /* 531 * If _RTV is not present or present and zero, 532 * values are absolute (see ACPI 4.0, 425). 533 */ 534 acpitz_get_integer(dv, "_RTV", &sc->sc_zone.rtv); 535 536 if (sc->sc_zone.rtv == ATZ_TMP_INVALID) 537 sc->sc_zone.rtv = 0; 538 539 acpitz_sane_temp(&sc->sc_zone.tmp); 540 acpitz_sane_temp(&sc->sc_zone.crt); 541 acpitz_sane_temp(&sc->sc_zone.hot); 542 acpitz_sane_temp(&sc->sc_zone.psv); 543 544 if (verbose != 0) { 545 comma = 0; 546 547 aprint_verbose_dev(dv, "levels: "); 548 549 if (sc->sc_zone.crt != ATZ_TMP_INVALID) { 550 aprint_verbose("critical %s C", 551 acpitz_celcius_string(sc->sc_zone.crt)); 552 comma = 1; 553 } 554 555 if (sc->sc_zone.hot != ATZ_TMP_INVALID) { 556 aprint_verbose("%shot %s C", comma ? ", " : "", 557 acpitz_celcius_string(sc->sc_zone.hot)); 558 comma = 1; 559 } 560 561 if (sc->sc_zone.psv != ATZ_TMP_INVALID) { 562 aprint_verbose("%spassive %s C", comma ? ", " : "", 563 acpitz_celcius_string(sc->sc_zone.psv)); 564 comma = 1; 565 } 566 567 if (valid_levels == 0) { 568 sc->sc_flags |= ATZ_F_PASSIVEONLY; 569 570 if (sc->sc_first != false) 571 aprint_verbose("%spassive cooling", comma ? 572 ", " : ""); 573 } 574 575 aprint_verbose("\n"); 576 } 577 578 for (i = 0; i < ATZ_NLEVELS; i++) 579 acpitz_sane_temp(&sc->sc_zone.ac[i]); 580 581 acpitz_power_off(sc); 582 sc->sc_first = false; 583 } 584 585 static void 586 acpitz_notify_handler(ACPI_HANDLE hdl, uint32_t notify, void *opaque) 587 { 588 ACPI_OSD_EXEC_CALLBACK func = NULL; 589 device_t dv = opaque; 590 591 switch (notify) { 592 593 case ACPI_NOTIFY_TZ_ZONE: 594 func = acpitz_get_status; 595 break; 596 597 case ACPI_NOTIFY_TZ_TRIP: 598 case ACPI_NOTIFY_TZ_DEVLIST: 599 func = acpitz_get_zone_quiet; 600 break; 601 602 default: 603 aprint_debug_dev(dv, "unknown notify 0x%02X\n", notify); 604 return; 605 } 606 607 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, func, dv); 608 } 609 610 static void 611 acpitz_sane_temp(uint32_t *tmp) 612 { 613 /* Sane temperatures are beteen 0 and 150 C. */ 614 if (*tmp < ATZ_ZEROC || *tmp > ATZ_ZEROC + 1500) 615 *tmp = ATZ_TMP_INVALID; 616 } 617 618 static int 619 acpitz_get_integer(device_t dv, const char *cm, uint32_t *val) 620 { 621 struct acpitz_softc *sc = device_private(dv); 622 ACPI_INTEGER tmp; 623 ACPI_STATUS rv; 624 625 rv = acpi_eval_integer(sc->sc_node->ad_handle, cm, &tmp); 626 627 if (ACPI_FAILURE(rv)) { 628 *val = ATZ_TMP_INVALID; 629 630 ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, 631 "%s: failed to evaluate %s: %s\n", 632 device_xname(dv), cm, AcpiFormatException(rv))); 633 634 return 1; 635 } 636 637 *val = tmp; 638 639 return 0; 640 } 641 642 static int 643 acpitz_get_fanspeed(device_t dv, 644 uint32_t *fanmin, uint32_t *fanmax, uint32_t *fancurrent) 645 { 646 struct acpitz_softc *sc = device_private(dv); 647 ACPI_INTEGER fmin, fmax, fcurr; 648 ACPI_HANDLE handle; 649 ACPI_STATUS rv; 650 int rc = 0; 651 652 handle = sc->sc_node->ad_handle; 653 654 rv = acpi_eval_integer(handle, "FMIN", &fmin); 655 656 if (ACPI_FAILURE(rv)) { 657 fmin = ATZ_TMP_INVALID; 658 rc = 1; 659 } 660 661 rv = acpi_eval_integer(handle, "FMAX", &fmax); 662 663 if (ACPI_FAILURE(rv)) { 664 fmax = ATZ_TMP_INVALID; 665 rc = 1; 666 } 667 rv = acpi_eval_integer(handle, "FRSP", &fcurr); 668 669 if (ACPI_FAILURE(rv)) { 670 fcurr = ATZ_TMP_INVALID; 671 rc = 1; 672 } 673 674 if (fanmin != NULL) 675 *fanmin = fmin; 676 677 if (fanmax != NULL) 678 *fanmax = fmax; 679 680 if (fancurrent != NULL) 681 *fancurrent = fcurr; 682 683 return rc; 684 } 685 686 #ifdef notyet 687 static ACPI_STATUS 688 acpitz_set_fanspeed(device_t dv, uint32_t fanspeed) 689 { 690 struct acpitz_softc *sc = device_private(dv); 691 ACPI_HANDLE handle; 692 ACPI_STATUS rv; 693 694 handle = sc->sc_node->ad_handle; 695 696 rv = acpi_eval_set_integer(handle, "FSSP", fanspeed); 697 698 if (ACPI_FAILURE(rv)) 699 aprint_debug_dev(dv, "failed to set fan speed to %u RPM: %s\n", 700 fanspeed, AcpiFormatException(rv)); 701 702 return rv; 703 } 704 #endif 705 706 static void 707 acpitz_print_processor_list(device_t dv) 708 { 709 struct acpitz_softc *sc = device_private(dv); 710 ACPI_HANDLE handle = sc->sc_node->ad_handle; 711 ACPI_HANDLE prhandle; 712 ACPI_BUFFER buf, prbuf; 713 ACPI_OBJECT *obj, *pref, *pr; 714 ACPI_STATUS rv; 715 struct cpu_info *ci; 716 unsigned int i, cnt; 717 718 rv = acpi_eval_struct(handle, "_PSL", &buf); 719 if (ACPI_FAILURE(rv) || buf.Pointer == NULL) 720 return; 721 obj = buf.Pointer; 722 if (obj->Type != ACPI_TYPE_PACKAGE || obj->Package.Count == 0) 723 goto done; 724 725 for (i = 0, cnt = 0; i < obj->Package.Count; i++) { 726 pref = &obj->Package.Elements[i]; 727 rv = acpi_eval_reference_handle(pref, &prhandle); 728 if (ACPI_FAILURE(rv)) 729 continue; 730 rv = acpi_eval_struct(prhandle, NULL, &prbuf); 731 if (ACPI_FAILURE(rv) || prbuf.Pointer == NULL) 732 continue; 733 pr = prbuf.Pointer; 734 if (pr->Type != ACPI_TYPE_PROCESSOR) 735 goto next; 736 737 ci = acpitz_find_processor(pr->Processor.ProcId); 738 if (ci) { 739 if (cnt == 0) 740 aprint_normal(":"); 741 aprint_normal(" %s", device_xname(ci->ci_dev)); 742 ++cnt; 743 } 744 next: 745 ACPI_FREE(prbuf.Pointer); 746 } 747 748 done: 749 ACPI_FREE(buf.Pointer); 750 } 751 752 static struct cpu_info * 753 acpitz_find_processor(uint32_t id) 754 { 755 CPU_INFO_ITERATOR cii; 756 struct cpu_info *ci; 757 758 for (CPU_INFO_FOREACH(cii, ci)) 759 if (ci->ci_acpiid == id) 760 return ci; 761 762 return NULL; 763 } 764 765 static void 766 acpitz_tick(void *opaque) 767 { 768 device_t dv = opaque; 769 struct acpitz_softc *sc = device_private(dv); 770 771 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpitz_get_status, dv); 772 773 callout_schedule(&sc->sc_callout, sc->sc_zone.tzp * hz / 10); 774 } 775 776 static void 777 acpitz_init_envsys(device_t dv) 778 { 779 const int flags = ENVSYS_FMONLIMITS | ENVSYS_FMONNOTSUPP; 780 struct acpitz_softc *sc = device_private(dv); 781 782 sc->sc_sme = sysmon_envsys_create(); 783 784 sc->sc_sme->sme_cookie = sc; 785 sc->sc_sme->sme_name = device_xname(dv); 786 sc->sc_sme->sme_flags = SME_DISABLE_REFRESH; 787 sc->sc_sme->sme_get_limits = acpitz_get_limits; 788 789 sc->sc_temp_sensor.flags = flags; 790 sc->sc_temp_sensor.units = ENVSYS_STEMP; 791 792 (void)strlcpy(sc->sc_temp_sensor.desc, "temperature", 793 sizeof(sc->sc_temp_sensor.desc)); 794 795 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp_sensor)) 796 goto out; 797 798 if (sc->sc_have_fan != false) { 799 800 sc->sc_fan_sensor.flags = flags; 801 sc->sc_fan_sensor.units = ENVSYS_SFANRPM; 802 803 (void)strlcpy(sc->sc_fan_sensor.desc, 804 "FAN", sizeof(sc->sc_fan_sensor.desc)); 805 806 /* Ignore error because fan sensor is optional. */ 807 (void)sysmon_envsys_sensor_attach(sc->sc_sme, 808 &sc->sc_fan_sensor); 809 } 810 811 if (sysmon_envsys_register(sc->sc_sme) == 0) 812 return; 813 814 out: 815 aprint_error_dev(dv, "unable to register with sysmon\n"); 816 817 sysmon_envsys_destroy(sc->sc_sme); 818 sc->sc_sme = NULL; 819 } 820 821 static void 822 acpitz_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 823 sysmon_envsys_lim_t *limits, uint32_t *props) 824 { 825 struct acpitz_softc *sc = sme->sme_cookie; 826 int i; 827 828 switch (edata->units) { 829 case ENVSYS_STEMP: 830 *props = 0; 831 if (sc->sc_zone.hot != ATZ_TMP_INVALID) { 832 *props |= PROP_CRITMAX; 833 limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.hot); 834 } else if (sc->sc_zone.crt != ATZ_TMP_INVALID) { 835 *props |= PROP_CRITMAX; 836 limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.crt); 837 } 838 for (i = 0; i < ATZ_NLEVELS; i++) { 839 if (sc->sc_zone.ac[i] != ATZ_TMP_INVALID) { 840 limits->sel_warnmax = 841 ATZ2UKELVIN(sc->sc_zone.ac[i]); 842 *props |= PROP_WARNMAX; 843 break; 844 } 845 } 846 break; 847 848 case ENVSYS_SFANRPM: 849 *props = 0; 850 if (sc->sc_zone.fanmin != ATZ_TMP_INVALID) { 851 *props |= PROP_WARNMIN; 852 limits->sel_warnmin = sc->sc_zone.fanmin; 853 sc->sc_fan_sensor.flags |= ENVSYS_FVALID_MIN; 854 } 855 if (sc->sc_zone.fanmax != ATZ_TMP_INVALID) { 856 *props |= PROP_WARNMAX; 857 limits->sel_warnmax = sc->sc_zone.fanmax; 858 sc->sc_fan_sensor.flags |= ENVSYS_FVALID_MAX; 859 } 860 break; 861 } 862 } 863 864 #ifdef _MODULE 865 866 MODULE(MODULE_CLASS_DRIVER, acpitz, NULL); 867 868 #include "ioconf.c" 869 870 static int 871 acpitz_modcmd(modcmd_t cmd, void *context) 872 { 873 874 switch (cmd) { 875 876 case MODULE_CMD_INIT: 877 return config_init_component(cfdriver_ioconf_acpitz, 878 cfattach_ioconf_acpitz, cfdata_ioconf_acpitz); 879 880 case MODULE_CMD_FINI: 881 return config_fini_component(cfdriver_ioconf_acpitz, 882 cfattach_ioconf_acpitz, cfdata_ioconf_acpitz); 883 884 default: 885 return ENOTTY; 886 } 887 } 888 889 #endif /* _MODULE */ 890