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