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