1 /* $NetBSD: acpi_cpu_tstate.c,v 1.31 2012/04/27 04:38:24 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.31 2012/04/27 04:38:24 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 around 100 / 8 = 12.5 %. 333 */ 334 if (ts->ts_percent < 10 || ts->ts_percent > 100) 335 return AE_BAD_DECIMAL_CONSTANT; 336 337 if (ts->ts_latency == 0 || ts->ts_latency > 1000) 338 ts->ts_latency = 1; 339 340 return AE_OK; 341 } 342 343 ACPI_STATUS 344 acpicpu_tstate_ptc(struct acpicpu_softc *sc) 345 { 346 static const size_t size = sizeof(struct acpicpu_reg); 347 struct acpicpu_reg *reg[2]; 348 ACPI_OBJECT *elm, *obj; 349 ACPI_BUFFER buf; 350 ACPI_STATUS rv; 351 int i; 352 353 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PTC", &buf); 354 355 if (ACPI_FAILURE(rv)) 356 return rv; 357 358 obj = buf.Pointer; 359 360 if (obj->Type != ACPI_TYPE_PACKAGE) { 361 rv = AE_TYPE; 362 goto out; 363 } 364 365 if (obj->Package.Count != 2) { 366 rv = AE_LIMIT; 367 goto out; 368 } 369 370 for (i = 0; i < 2; i++) { 371 372 elm = &obj->Package.Elements[i]; 373 374 if (elm->Type != ACPI_TYPE_BUFFER) { 375 rv = AE_TYPE; 376 goto out; 377 } 378 379 if (size > elm->Buffer.Length) { 380 rv = AE_AML_BAD_RESOURCE_LENGTH; 381 goto out; 382 } 383 384 reg[i] = (struct acpicpu_reg *)elm->Buffer.Pointer; 385 386 switch (reg[i]->reg_spaceid) { 387 388 case ACPI_ADR_SPACE_SYSTEM_IO: 389 390 if (reg[i]->reg_addr == 0) { 391 rv = AE_AML_ILLEGAL_ADDRESS; 392 goto out; 393 } 394 395 /* 396 * Check that the values match the IA32 clock 397 * modulation MSR, where the bit 0 is reserved, 398 * bits 1 through 3 define the duty cycle, and 399 * the fourth bit enables the modulation. 400 */ 401 if (reg[i]->reg_bitwidth != 4) { 402 rv = AE_AML_BAD_RESOURCE_VALUE; 403 goto out; 404 } 405 406 if (reg[i]->reg_bitoffset != 1) { 407 rv = AE_AML_BAD_RESOURCE_VALUE; 408 goto out; 409 } 410 411 break; 412 413 case ACPI_ADR_SPACE_FIXED_HARDWARE: 414 415 if ((sc->sc_flags & ACPICPU_FLAG_T_FFH) == 0) { 416 rv = AE_SUPPORT; 417 goto out; 418 } 419 420 break; 421 422 default: 423 rv = AE_AML_INVALID_SPACE_ID; 424 goto out; 425 } 426 } 427 428 if (reg[0]->reg_spaceid != reg[1]->reg_spaceid) { 429 rv = AE_AML_INVALID_SPACE_ID; 430 goto out; 431 } 432 433 (void)memcpy(&sc->sc_tstate_control, reg[0], size); 434 (void)memcpy(&sc->sc_tstate_status, reg[1], size); 435 436 out: 437 if (buf.Pointer != NULL) 438 ACPI_FREE(buf.Pointer); 439 440 return rv; 441 } 442 443 static ACPI_STATUS 444 acpicpu_tstate_dep(struct acpicpu_softc *sc) 445 { 446 ACPI_OBJECT *elm, *obj; 447 ACPI_BUFFER buf; 448 ACPI_STATUS rv; 449 uint32_t val; 450 uint8_t i, n; 451 452 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_TSD", &buf); 453 454 if (ACPI_FAILURE(rv)) 455 goto out; 456 457 obj = buf.Pointer; 458 459 if (obj->Type != ACPI_TYPE_PACKAGE) { 460 rv = AE_TYPE; 461 goto out; 462 } 463 464 if (obj->Package.Count != 1) { 465 rv = AE_LIMIT; 466 goto out; 467 } 468 469 elm = &obj->Package.Elements[0]; 470 471 if (obj->Type != ACPI_TYPE_PACKAGE) { 472 rv = AE_TYPE; 473 goto out; 474 } 475 476 n = elm->Package.Count; 477 478 if (n != 5) { 479 rv = AE_LIMIT; 480 goto out; 481 } 482 483 elm = elm->Package.Elements; 484 485 for (i = 0; i < n; i++) { 486 487 if (elm[i].Type != ACPI_TYPE_INTEGER) { 488 rv = AE_TYPE; 489 goto out; 490 } 491 492 if (elm[i].Integer.Value > UINT32_MAX) { 493 rv = AE_AML_NUMERIC_OVERFLOW; 494 goto out; 495 } 496 } 497 498 val = elm[1].Integer.Value; 499 500 if (val != 0) 501 aprint_debug_dev(sc->sc_dev, "invalid revision in _TSD\n"); 502 503 val = elm[3].Integer.Value; 504 505 if (val < ACPICPU_DEP_SW_ALL || val > ACPICPU_DEP_HW_ALL) { 506 rv = AE_AML_BAD_RESOURCE_VALUE; 507 goto out; 508 } 509 510 val = elm[4].Integer.Value; 511 512 if (val > sc->sc_ncpus) { 513 rv = AE_BAD_VALUE; 514 goto out; 515 } 516 517 sc->sc_tstate_dep.dep_domain = elm[2].Integer.Value; 518 sc->sc_tstate_dep.dep_type = elm[3].Integer.Value; 519 sc->sc_tstate_dep.dep_ncpus = elm[4].Integer.Value; 520 521 out: 522 if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) 523 aprint_debug_dev(sc->sc_dev, "failed to evaluate " 524 "_TSD: %s\n", AcpiFormatException(rv)); 525 526 if (buf.Pointer != NULL) 527 ACPI_FREE(buf.Pointer); 528 529 return rv; 530 } 531 532 static ACPI_STATUS 533 acpicpu_tstate_fadt(struct acpicpu_softc *sc) 534 { 535 static const size_t size = sizeof(struct acpicpu_tstate); 536 const uint8_t offset = AcpiGbl_FADT.DutyOffset; 537 const uint8_t width = AcpiGbl_FADT.DutyWidth; 538 uint8_t beta, count, i; 539 540 if (sc->sc_object.ao_pblkaddr == 0) 541 return AE_AML_ILLEGAL_ADDRESS; 542 543 /* 544 * A zero DUTY_WIDTH may be used announce 545 * that T-states are not available via FADT 546 * (ACPI 4.0, p. 121). See also (section 9.3): 547 * 548 * Advanced Micro Devices: BIOS and Kernel 549 * Developer's Guide for AMD Athlon 64 and 550 * AMD Opteron Processors. Revision 3.30, 551 * February 2006. 552 */ 553 if (width == 0 || width + offset > 4) 554 return AE_AML_BAD_RESOURCE_VALUE; 555 556 count = 1 << width; 557 558 if (sc->sc_tstate != NULL) 559 kmem_free(sc->sc_tstate, sc->sc_tstate_count * size); 560 561 sc->sc_tstate = kmem_zalloc(count * size, KM_SLEEP); 562 563 if (sc->sc_tstate == NULL) 564 return ENOMEM; 565 566 sc->sc_tstate_count = count; 567 568 /* 569 * Approximate duty cycles and set the MSR values. 570 */ 571 for (beta = 100 / count, i = 0; i < count; i++) { 572 sc->sc_tstate[i].ts_percent = 100 - beta * i; 573 sc->sc_tstate[i].ts_latency = 1; 574 } 575 576 for (i = 1; i < count; i++) 577 sc->sc_tstate[i].ts_control = (count - i) | __BIT(3); 578 579 /* 580 * Fake values for throttling registers. 581 */ 582 (void)memset(&sc->sc_tstate_status, 0, sizeof(struct acpicpu_reg)); 583 (void)memset(&sc->sc_tstate_control, 0, sizeof(struct acpicpu_reg)); 584 585 sc->sc_tstate_status.reg_bitwidth = width; 586 sc->sc_tstate_status.reg_bitoffset = offset; 587 sc->sc_tstate_status.reg_addr = sc->sc_object.ao_pblkaddr; 588 sc->sc_tstate_status.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 589 590 sc->sc_tstate_control.reg_bitwidth = width; 591 sc->sc_tstate_control.reg_bitoffset = offset; 592 sc->sc_tstate_control.reg_addr = sc->sc_object.ao_pblkaddr; 593 sc->sc_tstate_control.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 594 595 return AE_OK; 596 } 597 598 static ACPI_STATUS 599 acpicpu_tstate_change(struct acpicpu_softc *sc) 600 { 601 ACPI_INTEGER val; 602 ACPI_STATUS rv; 603 604 acpicpu_tstate_reset(sc); 605 606 /* 607 * Evaluate the available T-state window: 608 * 609 * _TPC : either this maximum or any lower power 610 * (i.e. higher numbered) state may be used. 611 * 612 * _TDL : either this minimum or any higher power 613 * (i.e. lower numbered) state may be used. 614 * 615 * _TDL >= _TPC || _TDL >= _TSS[last entry]. 616 */ 617 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TPC", &val); 618 619 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 620 621 if (sc->sc_tstate[val].ts_percent != 0) 622 sc->sc_tstate_max = val; 623 } 624 625 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TDL", &val); 626 627 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 628 629 if (val >= sc->sc_tstate_max && 630 sc->sc_tstate[val].ts_percent != 0) 631 sc->sc_tstate_min = val; 632 } 633 634 return AE_OK; 635 } 636 637 static void 638 acpicpu_tstate_reset(struct acpicpu_softc *sc) 639 { 640 641 sc->sc_tstate_max = 0; 642 sc->sc_tstate_min = sc->sc_tstate_count - 1; 643 } 644 645 int 646 acpicpu_tstate_get(struct cpu_info *ci, uint32_t *percent) 647 { 648 struct acpicpu_tstate *ts = NULL; 649 struct acpicpu_softc *sc; 650 uint32_t i, val = 0; 651 uint8_t offset; 652 uint64_t addr; 653 int rv; 654 655 sc = acpicpu_sc[ci->ci_acpiid]; 656 657 if (__predict_false(sc == NULL)) { 658 rv = ENXIO; 659 goto fail; 660 } 661 662 if (__predict_false(sc->sc_cold != false)) { 663 rv = EBUSY; 664 goto fail; 665 } 666 667 if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) { 668 rv = ENODEV; 669 goto fail; 670 } 671 672 mutex_enter(&sc->sc_mtx); 673 674 if (sc->sc_tstate_current != ACPICPU_T_STATE_UNKNOWN) { 675 *percent = sc->sc_tstate_current; 676 mutex_exit(&sc->sc_mtx); 677 return 0; 678 } 679 680 mutex_exit(&sc->sc_mtx); 681 682 switch (sc->sc_tstate_status.reg_spaceid) { 683 684 case ACPI_ADR_SPACE_FIXED_HARDWARE: 685 686 rv = acpicpu_md_tstate_get(sc, percent); 687 688 if (__predict_false(rv != 0)) 689 goto fail; 690 691 break; 692 693 case ACPI_ADR_SPACE_SYSTEM_IO: 694 695 addr = sc->sc_tstate_status.reg_addr; 696 offset = sc->sc_tstate_status.reg_bitoffset; 697 698 (void)AcpiOsReadPort(addr, &val, 8); 699 700 val = (val >> offset) & 0x0F; 701 702 for (i = 0; i < sc->sc_tstate_count; i++) { 703 704 if (sc->sc_tstate[i].ts_percent == 0) 705 continue; 706 707 if (val == sc->sc_tstate[i].ts_status) { 708 ts = &sc->sc_tstate[i]; 709 break; 710 } 711 } 712 713 if (ts == NULL) { 714 rv = EIO; 715 goto fail; 716 } 717 718 *percent = ts->ts_percent; 719 break; 720 721 default: 722 rv = ENOTTY; 723 goto fail; 724 } 725 726 mutex_enter(&sc->sc_mtx); 727 sc->sc_tstate_current = *percent; 728 mutex_exit(&sc->sc_mtx); 729 730 return 0; 731 732 fail: 733 aprint_error_dev(sc->sc_dev, "failed " 734 "to get T-state (err %d)\n", rv); 735 736 mutex_enter(&sc->sc_mtx); 737 *percent = sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 738 mutex_exit(&sc->sc_mtx); 739 740 return rv; 741 } 742 743 void 744 acpicpu_tstate_set(struct cpu_info *ci, uint32_t percent) 745 { 746 uint64_t xc; 747 748 xc = xc_broadcast(0, acpicpu_tstate_set_xcall, &percent, NULL); 749 xc_wait(xc); 750 } 751 752 static void 753 acpicpu_tstate_set_xcall(void *arg1, void *arg2) 754 { 755 struct acpicpu_tstate *ts = NULL; 756 struct cpu_info *ci = curcpu(); 757 struct acpicpu_softc *sc; 758 uint32_t i, percent, val; 759 uint8_t offset; 760 uint64_t addr; 761 int rv; 762 763 percent = *(uint32_t *)arg1; 764 sc = acpicpu_sc[ci->ci_acpiid]; 765 766 if (__predict_false(sc == NULL)) { 767 rv = ENXIO; 768 goto fail; 769 } 770 771 if (__predict_false(sc->sc_cold != false)) { 772 rv = EBUSY; 773 goto fail; 774 } 775 776 if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) { 777 rv = ENODEV; 778 goto fail; 779 } 780 781 mutex_enter(&sc->sc_mtx); 782 783 if (sc->sc_tstate_current == percent) { 784 mutex_exit(&sc->sc_mtx); 785 return; 786 } 787 788 for (i = sc->sc_tstate_max; i <= sc->sc_tstate_min; i++) { 789 790 if (__predict_false(sc->sc_tstate[i].ts_percent == 0)) 791 continue; 792 793 if (sc->sc_tstate[i].ts_percent == percent) { 794 ts = &sc->sc_tstate[i]; 795 break; 796 } 797 } 798 799 mutex_exit(&sc->sc_mtx); 800 801 if (__predict_false(ts == NULL)) { 802 rv = EINVAL; 803 goto fail; 804 } 805 806 switch (sc->sc_tstate_control.reg_spaceid) { 807 808 case ACPI_ADR_SPACE_FIXED_HARDWARE: 809 810 rv = acpicpu_md_tstate_set(ts); 811 812 if (__predict_false(rv != 0)) 813 goto fail; 814 815 break; 816 817 case ACPI_ADR_SPACE_SYSTEM_IO: 818 819 addr = sc->sc_tstate_control.reg_addr; 820 offset = sc->sc_tstate_control.reg_bitoffset; 821 822 val = (ts->ts_control & 0x0F) << offset; 823 824 if (ts->ts_percent != 100 && (val & __BIT(4)) == 0) { 825 rv = EINVAL; 826 goto fail; 827 } 828 829 (void)AcpiOsWritePort(addr, val, 8); 830 831 /* 832 * If the status field is zero, the transition is 833 * specified to be "asynchronous" and there is no 834 * need to check the status (ACPI 4.0, 8.4.3.2). 835 */ 836 if (ts->ts_status == 0) 837 break; 838 839 addr = sc->sc_tstate_status.reg_addr; 840 offset = sc->sc_tstate_status.reg_bitoffset; 841 842 for (i = val = 0; i < ACPICPU_T_STATE_RETRY; i++) { 843 844 (void)AcpiOsReadPort(addr, &val, 8); 845 846 val = (val >> offset) & 0x0F; 847 848 if (val == ts->ts_status) 849 break; 850 851 DELAY(ts->ts_latency); 852 } 853 854 if (i == ACPICPU_T_STATE_RETRY) { 855 rv = EAGAIN; 856 goto fail; 857 } 858 859 break; 860 861 default: 862 rv = ENOTTY; 863 goto fail; 864 } 865 866 mutex_enter(&sc->sc_mtx); 867 ts->ts_evcnt.ev_count++; 868 sc->sc_tstate_current = percent; 869 mutex_exit(&sc->sc_mtx); 870 871 return; 872 873 fail: 874 if (rv != EINVAL) 875 aprint_error_dev(sc->sc_dev, "failed to " 876 "throttle to %u %% (err %d)\n", percent, rv); 877 878 mutex_enter(&sc->sc_mtx); 879 sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 880 mutex_exit(&sc->sc_mtx); 881 } 882