1 /* $NetBSD: acpi_cpu_tstate.c,v 1.33 2017/06/01 02:45:09 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 Jukka Ruohonen <jruohonen@iki.fi> 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 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: acpi_cpu_tstate.c,v 1.33 2017/06/01 02:45:09 chs Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/kmem.h> 34 #include <sys/xcall.h> 35 36 #include <dev/acpi/acpireg.h> 37 #include <dev/acpi/acpivar.h> 38 #include <dev/acpi/acpi_cpu.h> 39 40 #define _COMPONENT ACPI_BUS_COMPONENT 41 ACPI_MODULE_NAME ("acpi_cpu_tstate") 42 43 static ACPI_STATUS acpicpu_tstate_tss(struct acpicpu_softc *); 44 static ACPI_STATUS acpicpu_tstate_tss_add(struct acpicpu_tstate *, 45 ACPI_OBJECT *); 46 static ACPI_STATUS acpicpu_tstate_ptc(struct acpicpu_softc *); 47 static ACPI_STATUS acpicpu_tstate_dep(struct acpicpu_softc *); 48 static ACPI_STATUS acpicpu_tstate_fadt(struct acpicpu_softc *); 49 static ACPI_STATUS acpicpu_tstate_change(struct acpicpu_softc *); 50 static void acpicpu_tstate_reset(struct acpicpu_softc *); 51 static void acpicpu_tstate_set_xcall(void *, void *); 52 53 extern struct acpicpu_softc **acpicpu_sc; 54 55 void 56 acpicpu_tstate_attach(device_t self) 57 { 58 struct acpicpu_softc *sc = device_private(self); 59 const char *str; 60 ACPI_HANDLE tmp; 61 ACPI_STATUS rv; 62 63 /* 64 * Disable T-states for PIIX4. 65 */ 66 if ((sc->sc_flags & ACPICPU_FLAG_PIIX4) != 0) 67 return; 68 69 rv = acpicpu_tstate_tss(sc); 70 71 if (ACPI_FAILURE(rv)) { 72 str = "_TSS"; 73 goto out; 74 } 75 76 rv = acpicpu_tstate_ptc(sc); 77 78 if (ACPI_FAILURE(rv)) { 79 str = "_PTC"; 80 goto out; 81 } 82 83 /* 84 * Query the optional _TSD. 85 */ 86 rv = acpicpu_tstate_dep(sc); 87 88 if (ACPI_SUCCESS(rv)) 89 sc->sc_flags |= ACPICPU_FLAG_T_DEP; 90 91 /* 92 * Comparable to P-states, the _TPC object may 93 * be absent in some systems, even though it is 94 * required by ACPI 3.0 along with _TSS and _PTC. 95 */ 96 rv = AcpiGetHandle(sc->sc_node->ad_handle, "_TPC", &tmp); 97 98 if (ACPI_FAILURE(rv)) { 99 aprint_debug_dev(self, "_TPC missing\n"); 100 rv = AE_OK; 101 } 102 103 out: 104 if (ACPI_FAILURE(rv)) { 105 106 if (rv != AE_NOT_FOUND) 107 aprint_error_dev(sc->sc_dev, "failed to evaluate " 108 "%s: %s\n", str, AcpiFormatException(rv)); 109 110 rv = acpicpu_tstate_fadt(sc); 111 112 if (ACPI_FAILURE(rv)) 113 return; 114 115 sc->sc_flags |= ACPICPU_FLAG_T_FADT; 116 } 117 118 sc->sc_flags |= ACPICPU_FLAG_T; 119 120 acpicpu_tstate_reset(sc); 121 } 122 123 void 124 acpicpu_tstate_detach(device_t self) 125 { 126 struct acpicpu_softc *sc = device_private(self); 127 size_t size; 128 129 if ((sc->sc_flags & ACPICPU_FLAG_T) == 0) 130 return; 131 132 size = sc->sc_tstate_count * sizeof(*sc->sc_tstate); 133 134 if (sc->sc_tstate != NULL) 135 kmem_free(sc->sc_tstate, size); 136 137 sc->sc_flags &= ~ACPICPU_FLAG_T; 138 } 139 140 void 141 acpicpu_tstate_start(device_t self) 142 { 143 /* Nothing. */ 144 } 145 146 void 147 acpicpu_tstate_suspend(void *aux) 148 { 149 struct acpicpu_softc *sc; 150 device_t self = aux; 151 152 sc = device_private(self); 153 154 mutex_enter(&sc->sc_mtx); 155 acpicpu_tstate_reset(sc); 156 mutex_exit(&sc->sc_mtx); 157 } 158 159 void 160 acpicpu_tstate_resume(void *aux) 161 { 162 /* Nothing. */ 163 } 164 165 void 166 acpicpu_tstate_callback(void *aux) 167 { 168 struct acpicpu_softc *sc; 169 device_t self = aux; 170 uint32_t omax, omin; 171 int i; 172 173 sc = device_private(self); 174 175 if ((sc->sc_flags & ACPICPU_FLAG_T_FADT) != 0) 176 return; 177 178 mutex_enter(&sc->sc_mtx); 179 180 /* 181 * If P-states are in use, we should ignore 182 * the interrupt unless we are in the highest 183 * P-state (see ACPI 4.0, section 8.4.3.3). 184 */ 185 if ((sc->sc_flags & ACPICPU_FLAG_P) != 0) { 186 187 for (i = sc->sc_pstate_count - 1; i >= 0; i--) { 188 189 if (sc->sc_pstate[i].ps_freq != 0) 190 break; 191 } 192 193 if (sc->sc_pstate_current != sc->sc_pstate[i].ps_freq) { 194 mutex_exit(&sc->sc_mtx); 195 return; 196 } 197 } 198 199 omax = sc->sc_tstate_max; 200 omin = sc->sc_tstate_min; 201 202 (void)acpicpu_tstate_change(sc); 203 204 if (omax != sc->sc_tstate_max || omin != sc->sc_tstate_min) { 205 206 aprint_debug_dev(sc->sc_dev, "throttling window " 207 "changed from %u-%u %% to %u-%u %%\n", 208 sc->sc_tstate[omax].ts_percent, 209 sc->sc_tstate[omin].ts_percent, 210 sc->sc_tstate[sc->sc_tstate_max].ts_percent, 211 sc->sc_tstate[sc->sc_tstate_min].ts_percent); 212 } 213 214 mutex_exit(&sc->sc_mtx); 215 } 216 217 static ACPI_STATUS 218 acpicpu_tstate_tss(struct acpicpu_softc *sc) 219 { 220 struct acpicpu_tstate *ts; 221 ACPI_OBJECT *obj; 222 ACPI_BUFFER buf; 223 ACPI_STATUS rv; 224 uint32_t count; 225 uint32_t i, j; 226 227 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_TSS", &buf); 228 229 if (ACPI_FAILURE(rv)) 230 return rv; 231 232 obj = buf.Pointer; 233 234 if (obj->Type != ACPI_TYPE_PACKAGE) { 235 rv = AE_TYPE; 236 goto out; 237 } 238 239 sc->sc_tstate_count = obj->Package.Count; 240 241 if (sc->sc_tstate_count == 0) { 242 rv = AE_NOT_EXIST; 243 goto out; 244 } 245 246 sc->sc_tstate = kmem_zalloc(sc->sc_tstate_count * 247 sizeof(struct acpicpu_tstate), KM_SLEEP); 248 249 if (sc->sc_tstate == NULL) { 250 rv = AE_NO_MEMORY; 251 goto out; 252 } 253 254 for (count = i = 0; i < sc->sc_tstate_count; i++) { 255 256 ts = &sc->sc_tstate[i]; 257 rv = acpicpu_tstate_tss_add(ts, &obj->Package.Elements[i]); 258 259 if (ACPI_FAILURE(rv)) { 260 ts->ts_percent = 0; 261 continue; 262 } 263 264 for (j = 0; j < i; j++) { 265 266 if (ts->ts_percent >= sc->sc_tstate[j].ts_percent) { 267 ts->ts_percent = 0; 268 break; 269 } 270 } 271 272 if (ts->ts_percent != 0) 273 count++; 274 } 275 276 if (count == 0) { 277 rv = AE_NOT_EXIST; 278 goto out; 279 } 280 281 /* 282 * There must be an entry with the percent 283 * field of 100. If this is not true, and if 284 * this entry is not in the expected index, 285 * invalidate the use of T-states via _TSS. 286 */ 287 if (sc->sc_tstate[0].ts_percent != 100) { 288 rv = AE_BAD_DECIMAL_CONSTANT; 289 goto out; 290 } 291 292 out: 293 if (buf.Pointer != NULL) 294 ACPI_FREE(buf.Pointer); 295 296 return rv; 297 } 298 299 static ACPI_STATUS 300 acpicpu_tstate_tss_add(struct acpicpu_tstate *ts, ACPI_OBJECT *obj) 301 { 302 ACPI_OBJECT *elm; 303 uint32_t val[5]; 304 uint32_t *p; 305 int i; 306 307 if (obj->Type != ACPI_TYPE_PACKAGE) 308 return AE_TYPE; 309 310 if (obj->Package.Count != 5) 311 return AE_BAD_DATA; 312 313 elm = obj->Package.Elements; 314 315 for (i = 0; i < 5; i++) { 316 317 if (elm[i].Type != ACPI_TYPE_INTEGER) 318 return AE_TYPE; 319 320 if (elm[i].Integer.Value > UINT32_MAX) 321 return AE_AML_NUMERIC_OVERFLOW; 322 323 val[i] = elm[i].Integer.Value; 324 } 325 326 p = &ts->ts_percent; 327 328 for (i = 0; i < 5; i++, p++) 329 *p = val[i]; 330 331 /* 332 * The minimum should be either 12.5 % or 6.5 %, 333 * the latter 4-bit dynamic range being available 334 * in some newer models; see Section 14.5.3.1 in 335 * 336 * Intel 64 and IA-32 Architectures Software 337 * Developer's Manual. Volume 3B, Part 2. 2013. 338 */ 339 if (ts->ts_percent < 6 || ts->ts_percent > 100) 340 return AE_BAD_DECIMAL_CONSTANT; 341 342 if (ts->ts_latency == 0 || ts->ts_latency > 1000) 343 ts->ts_latency = 1; 344 345 return AE_OK; 346 } 347 348 ACPI_STATUS 349 acpicpu_tstate_ptc(struct acpicpu_softc *sc) 350 { 351 static const size_t size = sizeof(struct acpicpu_reg); 352 struct acpicpu_reg *reg[2]; 353 ACPI_OBJECT *elm, *obj; 354 ACPI_BUFFER buf; 355 ACPI_STATUS rv; 356 int i; 357 358 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PTC", &buf); 359 360 if (ACPI_FAILURE(rv)) 361 return rv; 362 363 obj = buf.Pointer; 364 365 if (obj->Type != ACPI_TYPE_PACKAGE) { 366 rv = AE_TYPE; 367 goto out; 368 } 369 370 if (obj->Package.Count != 2) { 371 rv = AE_LIMIT; 372 goto out; 373 } 374 375 for (i = 0; i < 2; i++) { 376 377 elm = &obj->Package.Elements[i]; 378 379 if (elm->Type != ACPI_TYPE_BUFFER) { 380 rv = AE_TYPE; 381 goto out; 382 } 383 384 if (size > elm->Buffer.Length) { 385 rv = AE_AML_BAD_RESOURCE_LENGTH; 386 goto out; 387 } 388 389 reg[i] = (struct acpicpu_reg *)elm->Buffer.Pointer; 390 391 switch (reg[i]->reg_spaceid) { 392 393 case ACPI_ADR_SPACE_SYSTEM_IO: 394 395 if (reg[i]->reg_addr == 0) { 396 rv = AE_AML_ILLEGAL_ADDRESS; 397 goto out; 398 } 399 400 /* 401 * Check that the values match the IA32 clock 402 * modulation MSR, where the bit 0 is reserved, 403 * bits 1 through 3 define the duty cycle, and 404 * the fourth bit enables the modulation. 405 */ 406 if (reg[i]->reg_bitwidth != 4) { 407 rv = AE_AML_BAD_RESOURCE_VALUE; 408 goto out; 409 } 410 411 if (reg[i]->reg_bitoffset != 1) { 412 rv = AE_AML_BAD_RESOURCE_VALUE; 413 goto out; 414 } 415 416 break; 417 418 case ACPI_ADR_SPACE_FIXED_HARDWARE: 419 420 if ((sc->sc_flags & ACPICPU_FLAG_T_FFH) == 0) { 421 rv = AE_SUPPORT; 422 goto out; 423 } 424 425 break; 426 427 default: 428 rv = AE_AML_INVALID_SPACE_ID; 429 goto out; 430 } 431 } 432 433 if (reg[0]->reg_spaceid != reg[1]->reg_spaceid) { 434 rv = AE_AML_INVALID_SPACE_ID; 435 goto out; 436 } 437 438 (void)memcpy(&sc->sc_tstate_control, reg[0], size); 439 (void)memcpy(&sc->sc_tstate_status, reg[1], size); 440 441 out: 442 if (buf.Pointer != NULL) 443 ACPI_FREE(buf.Pointer); 444 445 return rv; 446 } 447 448 static ACPI_STATUS 449 acpicpu_tstate_dep(struct acpicpu_softc *sc) 450 { 451 ACPI_OBJECT *elm, *obj; 452 ACPI_BUFFER buf; 453 ACPI_STATUS rv; 454 uint32_t val; 455 uint8_t i, n; 456 457 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_TSD", &buf); 458 459 if (ACPI_FAILURE(rv)) 460 goto out; 461 462 obj = buf.Pointer; 463 464 if (obj->Type != ACPI_TYPE_PACKAGE) { 465 rv = AE_TYPE; 466 goto out; 467 } 468 469 if (obj->Package.Count != 1) { 470 rv = AE_LIMIT; 471 goto out; 472 } 473 474 elm = &obj->Package.Elements[0]; 475 476 if (obj->Type != ACPI_TYPE_PACKAGE) { 477 rv = AE_TYPE; 478 goto out; 479 } 480 481 n = elm->Package.Count; 482 483 if (n != 5) { 484 rv = AE_LIMIT; 485 goto out; 486 } 487 488 elm = elm->Package.Elements; 489 490 for (i = 0; i < n; i++) { 491 492 if (elm[i].Type != ACPI_TYPE_INTEGER) { 493 rv = AE_TYPE; 494 goto out; 495 } 496 497 if (elm[i].Integer.Value > UINT32_MAX) { 498 rv = AE_AML_NUMERIC_OVERFLOW; 499 goto out; 500 } 501 } 502 503 val = elm[1].Integer.Value; 504 505 if (val != 0) 506 aprint_debug_dev(sc->sc_dev, "invalid revision in _TSD\n"); 507 508 val = elm[3].Integer.Value; 509 510 if (val < ACPICPU_DEP_SW_ALL || val > ACPICPU_DEP_HW_ALL) { 511 rv = AE_AML_BAD_RESOURCE_VALUE; 512 goto out; 513 } 514 515 val = elm[4].Integer.Value; 516 517 if (val > sc->sc_ncpus) { 518 rv = AE_BAD_VALUE; 519 goto out; 520 } 521 522 sc->sc_tstate_dep.dep_domain = elm[2].Integer.Value; 523 sc->sc_tstate_dep.dep_type = elm[3].Integer.Value; 524 sc->sc_tstate_dep.dep_ncpus = elm[4].Integer.Value; 525 526 out: 527 if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) 528 aprint_debug_dev(sc->sc_dev, "failed to evaluate " 529 "_TSD: %s\n", AcpiFormatException(rv)); 530 531 if (buf.Pointer != NULL) 532 ACPI_FREE(buf.Pointer); 533 534 return rv; 535 } 536 537 static ACPI_STATUS 538 acpicpu_tstate_fadt(struct acpicpu_softc *sc) 539 { 540 static const size_t size = sizeof(struct acpicpu_tstate); 541 const uint8_t offset = AcpiGbl_FADT.DutyOffset; 542 const uint8_t width = AcpiGbl_FADT.DutyWidth; 543 uint8_t beta, count, i; 544 545 if (sc->sc_object.ao_pblkaddr == 0) 546 return AE_AML_ILLEGAL_ADDRESS; 547 548 /* 549 * A zero DUTY_WIDTH may be used announce 550 * that T-states are not available via FADT 551 * (ACPI 4.0, p. 121). See also (section 9.3): 552 * 553 * Advanced Micro Devices: BIOS and Kernel 554 * Developer's Guide for AMD Athlon 64 and 555 * AMD Opteron Processors. Revision 3.30, 556 * February 2006. 557 */ 558 if (width == 0 || width + offset > 4) 559 return AE_AML_BAD_RESOURCE_VALUE; 560 561 count = 1 << width; 562 563 if (sc->sc_tstate != NULL) 564 kmem_free(sc->sc_tstate, sc->sc_tstate_count * size); 565 566 sc->sc_tstate = kmem_zalloc(count * size, KM_SLEEP); 567 sc->sc_tstate_count = count; 568 569 /* 570 * Approximate duty cycles and set the MSR values. 571 */ 572 for (beta = 100 / count, i = 0; i < count; i++) { 573 sc->sc_tstate[i].ts_percent = 100 - beta * i; 574 sc->sc_tstate[i].ts_latency = 1; 575 } 576 577 for (i = 1; i < count; i++) 578 sc->sc_tstate[i].ts_control = (count - i) | __BIT(3); 579 580 /* 581 * Fake values for throttling registers. 582 */ 583 (void)memset(&sc->sc_tstate_status, 0, sizeof(struct acpicpu_reg)); 584 (void)memset(&sc->sc_tstate_control, 0, sizeof(struct acpicpu_reg)); 585 586 sc->sc_tstate_status.reg_bitwidth = width; 587 sc->sc_tstate_status.reg_bitoffset = offset; 588 sc->sc_tstate_status.reg_addr = sc->sc_object.ao_pblkaddr; 589 sc->sc_tstate_status.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 590 591 sc->sc_tstate_control.reg_bitwidth = width; 592 sc->sc_tstate_control.reg_bitoffset = offset; 593 sc->sc_tstate_control.reg_addr = sc->sc_object.ao_pblkaddr; 594 sc->sc_tstate_control.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 595 596 return AE_OK; 597 } 598 599 static ACPI_STATUS 600 acpicpu_tstate_change(struct acpicpu_softc *sc) 601 { 602 ACPI_INTEGER val; 603 ACPI_STATUS rv; 604 605 acpicpu_tstate_reset(sc); 606 607 /* 608 * Evaluate the available T-state window: 609 * 610 * _TPC : either this maximum or any lower power 611 * (i.e. higher numbered) state may be used. 612 * 613 * _TDL : either this minimum or any higher power 614 * (i.e. lower numbered) state may be used. 615 * 616 * _TDL >= _TPC || _TDL >= _TSS[last entry]. 617 */ 618 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TPC", &val); 619 620 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 621 622 if (sc->sc_tstate[val].ts_percent != 0) 623 sc->sc_tstate_max = val; 624 } 625 626 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TDL", &val); 627 628 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 629 630 if (val >= sc->sc_tstate_max && 631 sc->sc_tstate[val].ts_percent != 0) 632 sc->sc_tstate_min = val; 633 } 634 635 return AE_OK; 636 } 637 638 static void 639 acpicpu_tstate_reset(struct acpicpu_softc *sc) 640 { 641 642 sc->sc_tstate_max = 0; 643 sc->sc_tstate_min = sc->sc_tstate_count - 1; 644 } 645 646 int 647 acpicpu_tstate_get(struct cpu_info *ci, uint32_t *percent) 648 { 649 struct acpicpu_tstate *ts = NULL; 650 struct acpicpu_softc *sc; 651 uint32_t i, val = 0; 652 uint8_t offset; 653 uint64_t addr; 654 int rv; 655 656 sc = acpicpu_sc[ci->ci_acpiid]; 657 658 if (__predict_false(sc == NULL)) { 659 rv = ENXIO; 660 goto fail; 661 } 662 663 if (__predict_false(sc->sc_cold != false)) { 664 rv = EBUSY; 665 goto fail; 666 } 667 668 if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) { 669 rv = ENODEV; 670 goto fail; 671 } 672 673 mutex_enter(&sc->sc_mtx); 674 675 if (sc->sc_tstate_current != ACPICPU_T_STATE_UNKNOWN) { 676 *percent = sc->sc_tstate_current; 677 mutex_exit(&sc->sc_mtx); 678 return 0; 679 } 680 681 mutex_exit(&sc->sc_mtx); 682 683 switch (sc->sc_tstate_status.reg_spaceid) { 684 685 case ACPI_ADR_SPACE_FIXED_HARDWARE: 686 687 rv = acpicpu_md_tstate_get(sc, percent); 688 689 if (__predict_false(rv != 0)) 690 goto fail; 691 692 break; 693 694 case ACPI_ADR_SPACE_SYSTEM_IO: 695 696 addr = sc->sc_tstate_status.reg_addr; 697 offset = sc->sc_tstate_status.reg_bitoffset; 698 699 (void)AcpiOsReadPort(addr, &val, 8); 700 701 val = (val >> offset) & 0x0F; 702 703 for (i = 0; i < sc->sc_tstate_count; i++) { 704 705 if (sc->sc_tstate[i].ts_percent == 0) 706 continue; 707 708 if (val == sc->sc_tstate[i].ts_status) { 709 ts = &sc->sc_tstate[i]; 710 break; 711 } 712 } 713 714 if (ts == NULL) { 715 rv = EIO; 716 goto fail; 717 } 718 719 *percent = ts->ts_percent; 720 break; 721 722 default: 723 rv = ENOTTY; 724 goto fail; 725 } 726 727 mutex_enter(&sc->sc_mtx); 728 sc->sc_tstate_current = *percent; 729 mutex_exit(&sc->sc_mtx); 730 731 return 0; 732 733 fail: 734 aprint_error_dev(sc->sc_dev, "failed " 735 "to get T-state (err %d)\n", rv); 736 737 mutex_enter(&sc->sc_mtx); 738 *percent = sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 739 mutex_exit(&sc->sc_mtx); 740 741 return rv; 742 } 743 744 void 745 acpicpu_tstate_set(struct cpu_info *ci, uint32_t percent) 746 { 747 uint64_t xc; 748 749 xc = xc_broadcast(0, acpicpu_tstate_set_xcall, &percent, NULL); 750 xc_wait(xc); 751 } 752 753 static void 754 acpicpu_tstate_set_xcall(void *arg1, void *arg2) 755 { 756 struct acpicpu_tstate *ts = NULL; 757 struct cpu_info *ci = curcpu(); 758 struct acpicpu_softc *sc; 759 uint32_t i, percent, val; 760 uint8_t offset; 761 uint64_t addr; 762 int rv; 763 764 percent = *(uint32_t *)arg1; 765 sc = acpicpu_sc[ci->ci_acpiid]; 766 767 if (__predict_false(sc == NULL)) { 768 rv = ENXIO; 769 goto fail; 770 } 771 772 if (__predict_false(sc->sc_cold != false)) { 773 rv = EBUSY; 774 goto fail; 775 } 776 777 if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) { 778 rv = ENODEV; 779 goto fail; 780 } 781 782 mutex_enter(&sc->sc_mtx); 783 784 if (sc->sc_tstate_current == percent) { 785 mutex_exit(&sc->sc_mtx); 786 return; 787 } 788 789 for (i = sc->sc_tstate_max; i <= sc->sc_tstate_min; i++) { 790 791 if (__predict_false(sc->sc_tstate[i].ts_percent == 0)) 792 continue; 793 794 if (sc->sc_tstate[i].ts_percent == percent) { 795 ts = &sc->sc_tstate[i]; 796 break; 797 } 798 } 799 800 mutex_exit(&sc->sc_mtx); 801 802 if (__predict_false(ts == NULL)) { 803 rv = EINVAL; 804 goto fail; 805 } 806 807 switch (sc->sc_tstate_control.reg_spaceid) { 808 809 case ACPI_ADR_SPACE_FIXED_HARDWARE: 810 811 rv = acpicpu_md_tstate_set(ts); 812 813 if (__predict_false(rv != 0)) 814 goto fail; 815 816 break; 817 818 case ACPI_ADR_SPACE_SYSTEM_IO: 819 820 addr = sc->sc_tstate_control.reg_addr; 821 offset = sc->sc_tstate_control.reg_bitoffset; 822 823 val = (ts->ts_control & 0x0F) << offset; 824 825 if (ts->ts_percent != 100 && (val & __BIT(4)) == 0) { 826 rv = EINVAL; 827 goto fail; 828 } 829 830 (void)AcpiOsWritePort(addr, val, 8); 831 832 /* 833 * If the status field is zero, the transition is 834 * specified to be "asynchronous" and there is no 835 * need to check the status (ACPI 4.0, 8.4.3.2). 836 */ 837 if (ts->ts_status == 0) 838 break; 839 840 addr = sc->sc_tstate_status.reg_addr; 841 offset = sc->sc_tstate_status.reg_bitoffset; 842 843 for (i = val = 0; i < ACPICPU_T_STATE_RETRY; i++) { 844 845 (void)AcpiOsReadPort(addr, &val, 8); 846 847 val = (val >> offset) & 0x0F; 848 849 if (val == ts->ts_status) 850 break; 851 852 DELAY(ts->ts_latency); 853 } 854 855 if (i == ACPICPU_T_STATE_RETRY) { 856 rv = EAGAIN; 857 goto fail; 858 } 859 860 break; 861 862 default: 863 rv = ENOTTY; 864 goto fail; 865 } 866 867 mutex_enter(&sc->sc_mtx); 868 ts->ts_evcnt.ev_count++; 869 sc->sc_tstate_current = percent; 870 mutex_exit(&sc->sc_mtx); 871 872 return; 873 874 fail: 875 if (rv != EINVAL) 876 aprint_error_dev(sc->sc_dev, "failed to " 877 "throttle to %u %% (err %d)\n", percent, rv); 878 879 mutex_enter(&sc->sc_mtx); 880 sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 881 mutex_exit(&sc->sc_mtx); 882 } 883