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