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