1 /* $NetBSD: acpi_cpu_tstate.c,v 1.32 2013/11/20 13:39:59 jruoho 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.32 2013/11/20 13:39:59 jruoho 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 568 if (sc->sc_tstate == NULL) 569 return ENOMEM; 570 571 sc->sc_tstate_count = count; 572 573 /* 574 * Approximate duty cycles and set the MSR values. 575 */ 576 for (beta = 100 / count, i = 0; i < count; i++) { 577 sc->sc_tstate[i].ts_percent = 100 - beta * i; 578 sc->sc_tstate[i].ts_latency = 1; 579 } 580 581 for (i = 1; i < count; i++) 582 sc->sc_tstate[i].ts_control = (count - i) | __BIT(3); 583 584 /* 585 * Fake values for throttling registers. 586 */ 587 (void)memset(&sc->sc_tstate_status, 0, sizeof(struct acpicpu_reg)); 588 (void)memset(&sc->sc_tstate_control, 0, sizeof(struct acpicpu_reg)); 589 590 sc->sc_tstate_status.reg_bitwidth = width; 591 sc->sc_tstate_status.reg_bitoffset = offset; 592 sc->sc_tstate_status.reg_addr = sc->sc_object.ao_pblkaddr; 593 sc->sc_tstate_status.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 594 595 sc->sc_tstate_control.reg_bitwidth = width; 596 sc->sc_tstate_control.reg_bitoffset = offset; 597 sc->sc_tstate_control.reg_addr = sc->sc_object.ao_pblkaddr; 598 sc->sc_tstate_control.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 599 600 return AE_OK; 601 } 602 603 static ACPI_STATUS 604 acpicpu_tstate_change(struct acpicpu_softc *sc) 605 { 606 ACPI_INTEGER val; 607 ACPI_STATUS rv; 608 609 acpicpu_tstate_reset(sc); 610 611 /* 612 * Evaluate the available T-state window: 613 * 614 * _TPC : either this maximum or any lower power 615 * (i.e. higher numbered) state may be used. 616 * 617 * _TDL : either this minimum or any higher power 618 * (i.e. lower numbered) state may be used. 619 * 620 * _TDL >= _TPC || _TDL >= _TSS[last entry]. 621 */ 622 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TPC", &val); 623 624 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 625 626 if (sc->sc_tstate[val].ts_percent != 0) 627 sc->sc_tstate_max = val; 628 } 629 630 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TDL", &val); 631 632 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 633 634 if (val >= sc->sc_tstate_max && 635 sc->sc_tstate[val].ts_percent != 0) 636 sc->sc_tstate_min = val; 637 } 638 639 return AE_OK; 640 } 641 642 static void 643 acpicpu_tstate_reset(struct acpicpu_softc *sc) 644 { 645 646 sc->sc_tstate_max = 0; 647 sc->sc_tstate_min = sc->sc_tstate_count - 1; 648 } 649 650 int 651 acpicpu_tstate_get(struct cpu_info *ci, uint32_t *percent) 652 { 653 struct acpicpu_tstate *ts = NULL; 654 struct acpicpu_softc *sc; 655 uint32_t i, val = 0; 656 uint8_t offset; 657 uint64_t addr; 658 int rv; 659 660 sc = acpicpu_sc[ci->ci_acpiid]; 661 662 if (__predict_false(sc == NULL)) { 663 rv = ENXIO; 664 goto fail; 665 } 666 667 if (__predict_false(sc->sc_cold != false)) { 668 rv = EBUSY; 669 goto fail; 670 } 671 672 if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) { 673 rv = ENODEV; 674 goto fail; 675 } 676 677 mutex_enter(&sc->sc_mtx); 678 679 if (sc->sc_tstate_current != ACPICPU_T_STATE_UNKNOWN) { 680 *percent = sc->sc_tstate_current; 681 mutex_exit(&sc->sc_mtx); 682 return 0; 683 } 684 685 mutex_exit(&sc->sc_mtx); 686 687 switch (sc->sc_tstate_status.reg_spaceid) { 688 689 case ACPI_ADR_SPACE_FIXED_HARDWARE: 690 691 rv = acpicpu_md_tstate_get(sc, percent); 692 693 if (__predict_false(rv != 0)) 694 goto fail; 695 696 break; 697 698 case ACPI_ADR_SPACE_SYSTEM_IO: 699 700 addr = sc->sc_tstate_status.reg_addr; 701 offset = sc->sc_tstate_status.reg_bitoffset; 702 703 (void)AcpiOsReadPort(addr, &val, 8); 704 705 val = (val >> offset) & 0x0F; 706 707 for (i = 0; i < sc->sc_tstate_count; i++) { 708 709 if (sc->sc_tstate[i].ts_percent == 0) 710 continue; 711 712 if (val == sc->sc_tstate[i].ts_status) { 713 ts = &sc->sc_tstate[i]; 714 break; 715 } 716 } 717 718 if (ts == NULL) { 719 rv = EIO; 720 goto fail; 721 } 722 723 *percent = ts->ts_percent; 724 break; 725 726 default: 727 rv = ENOTTY; 728 goto fail; 729 } 730 731 mutex_enter(&sc->sc_mtx); 732 sc->sc_tstate_current = *percent; 733 mutex_exit(&sc->sc_mtx); 734 735 return 0; 736 737 fail: 738 aprint_error_dev(sc->sc_dev, "failed " 739 "to get T-state (err %d)\n", rv); 740 741 mutex_enter(&sc->sc_mtx); 742 *percent = sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 743 mutex_exit(&sc->sc_mtx); 744 745 return rv; 746 } 747 748 void 749 acpicpu_tstate_set(struct cpu_info *ci, uint32_t percent) 750 { 751 uint64_t xc; 752 753 xc = xc_broadcast(0, acpicpu_tstate_set_xcall, &percent, NULL); 754 xc_wait(xc); 755 } 756 757 static void 758 acpicpu_tstate_set_xcall(void *arg1, void *arg2) 759 { 760 struct acpicpu_tstate *ts = NULL; 761 struct cpu_info *ci = curcpu(); 762 struct acpicpu_softc *sc; 763 uint32_t i, percent, val; 764 uint8_t offset; 765 uint64_t addr; 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 824 addr = sc->sc_tstate_control.reg_addr; 825 offset = sc->sc_tstate_control.reg_bitoffset; 826 827 val = (ts->ts_control & 0x0F) << offset; 828 829 if (ts->ts_percent != 100 && (val & __BIT(4)) == 0) { 830 rv = EINVAL; 831 goto fail; 832 } 833 834 (void)AcpiOsWritePort(addr, val, 8); 835 836 /* 837 * If the status field is zero, the transition is 838 * specified to be "asynchronous" and there is no 839 * need to check the status (ACPI 4.0, 8.4.3.2). 840 */ 841 if (ts->ts_status == 0) 842 break; 843 844 addr = sc->sc_tstate_status.reg_addr; 845 offset = sc->sc_tstate_status.reg_bitoffset; 846 847 for (i = val = 0; i < ACPICPU_T_STATE_RETRY; i++) { 848 849 (void)AcpiOsReadPort(addr, &val, 8); 850 851 val = (val >> offset) & 0x0F; 852 853 if (val == ts->ts_status) 854 break; 855 856 DELAY(ts->ts_latency); 857 } 858 859 if (i == ACPICPU_T_STATE_RETRY) { 860 rv = EAGAIN; 861 goto fail; 862 } 863 864 break; 865 866 default: 867 rv = ENOTTY; 868 goto fail; 869 } 870 871 mutex_enter(&sc->sc_mtx); 872 ts->ts_evcnt.ev_count++; 873 sc->sc_tstate_current = percent; 874 mutex_exit(&sc->sc_mtx); 875 876 return; 877 878 fail: 879 if (rv != EINVAL) 880 aprint_error_dev(sc->sc_dev, "failed to " 881 "throttle to %u %% (err %d)\n", percent, rv); 882 883 mutex_enter(&sc->sc_mtx); 884 sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 885 mutex_exit(&sc->sc_mtx); 886 } 887