1/* $NetBSD: acpi_cpu_tstate.c,v 1.29 2011/06/22 08:05:10 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.29 2011/06/22 08:05:10 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 41ACPI_MODULE_NAME ("acpi_cpu_tstate") 42 43static ACPI_STATUS acpicpu_tstate_tss(struct acpicpu_softc *); 44static ACPI_STATUS acpicpu_tstate_tss_add(struct acpicpu_tstate *, 45 ACPI_OBJECT *); 46static ACPI_STATUS acpicpu_tstate_ptc(struct acpicpu_softc *); 47static ACPI_STATUS acpicpu_tstate_dep(struct acpicpu_softc *); 48static ACPI_STATUS acpicpu_tstate_fadt(struct acpicpu_softc *); 49static ACPI_STATUS acpicpu_tstate_change(struct acpicpu_softc *); 50static void acpicpu_tstate_reset(struct acpicpu_softc *); 51static void acpicpu_tstate_set_xcall(void *, void *); 52 53extern struct acpicpu_softc **acpicpu_sc; 54 55void 56acpicpu_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 103out: 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 123void 124acpicpu_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 140void 141acpicpu_tstate_start(device_t self) 142{ 143 /* Nothing. */ 144} 145 146void 147acpicpu_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 159void 160acpicpu_tstate_resume(void *aux) 161{ 162 /* Nothing. */ 163} 164 165void 166acpicpu_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 217static ACPI_STATUS 218acpicpu_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 if (sc->sc_tstate_count > ACPICPU_T_STATE_MAX) { 247 rv = AE_LIMIT; 248 goto out; 249 } 250 251 sc->sc_tstate = kmem_zalloc(sc->sc_tstate_count * 252 sizeof(struct acpicpu_tstate), KM_SLEEP); 253 254 if (sc->sc_tstate == NULL) { 255 rv = AE_NO_MEMORY; 256 goto out; 257 } 258 259 for (count = i = 0; i < sc->sc_tstate_count; i++) { 260 261 ts = &sc->sc_tstate[i]; 262 rv = acpicpu_tstate_tss_add(ts, &obj->Package.Elements[i]); 263 264 if (ACPI_FAILURE(rv)) { 265 ts->ts_percent = 0; 266 continue; 267 } 268 269 for (j = 0; j < i; j++) { 270 271 if (ts->ts_percent >= sc->sc_tstate[j].ts_percent) { 272 ts->ts_percent = 0; 273 break; 274 } 275 } 276 277 if (ts->ts_percent != 0) 278 count++; 279 } 280 281 if (count == 0) { 282 rv = AE_NOT_EXIST; 283 goto out; 284 } 285 286 /* 287 * There must be an entry with the percent 288 * field of 100. If this is not true, and if 289 * this entry is not in the expected index, 290 * invalidate the use of T-states via _TSS. 291 */ 292 if (sc->sc_tstate[0].ts_percent != 100) { 293 rv = AE_BAD_DECIMAL_CONSTANT; 294 goto out; 295 } 296 297out: 298 if (buf.Pointer != NULL) 299 ACPI_FREE(buf.Pointer); 300 301 return rv; 302} 303 304static ACPI_STATUS 305acpicpu_tstate_tss_add(struct acpicpu_tstate *ts, ACPI_OBJECT *obj) 306{ 307 ACPI_OBJECT *elm; 308 uint32_t val[5]; 309 uint32_t *p; 310 int i; 311 312 if (obj->Type != ACPI_TYPE_PACKAGE) 313 return AE_TYPE; 314 315 if (obj->Package.Count != 5) 316 return AE_BAD_DATA; 317 318 elm = obj->Package.Elements; 319 320 for (i = 0; i < 5; i++) { 321 322 if (elm[i].Type != ACPI_TYPE_INTEGER) 323 return AE_TYPE; 324 325 if (elm[i].Integer.Value > UINT32_MAX) 326 return AE_AML_NUMERIC_OVERFLOW; 327 328 val[i] = elm[i].Integer.Value; 329 } 330 331 p = &ts->ts_percent; 332 333 for (i = 0; i < 5; i++, p++) 334 *p = val[i]; 335 336 /* 337 * The minimum should be around 100 / 8 = 12.5 %. 338 */ 339 if (ts->ts_percent < 10 || 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 348ACPI_STATUS 349acpicpu_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 441out: 442 if (buf.Pointer != NULL) 443 ACPI_FREE(buf.Pointer); 444 445 return rv; 446} 447 448static ACPI_STATUS 449acpicpu_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 526out: 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 537static ACPI_STATUS 538acpicpu_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 (count > ACPICPU_T_STATE_MAX) 564 return AE_LIMIT; 565 566 if (sc->sc_tstate != NULL) 567 kmem_free(sc->sc_tstate, sc->sc_tstate_count * size); 568 569 sc->sc_tstate = kmem_zalloc(count * size, KM_SLEEP); 570 571 if (sc->sc_tstate == NULL) 572 return ENOMEM; 573 574 sc->sc_tstate_count = count; 575 576 /* 577 * Approximate duty cycles and set the MSR values. 578 */ 579 for (beta = 100 / count, i = 0; i < count; i++) { 580 sc->sc_tstate[i].ts_percent = 100 - beta * i; 581 sc->sc_tstate[i].ts_latency = 1; 582 } 583 584 for (i = 1; i < count; i++) 585 sc->sc_tstate[i].ts_control = (count - i) | __BIT(3); 586 587 /* 588 * Fake values for throttling registers. 589 */ 590 (void)memset(&sc->sc_tstate_status, 0, sizeof(struct acpicpu_reg)); 591 (void)memset(&sc->sc_tstate_control, 0, sizeof(struct acpicpu_reg)); 592 593 sc->sc_tstate_status.reg_bitwidth = width; 594 sc->sc_tstate_status.reg_bitoffset = offset; 595 sc->sc_tstate_status.reg_addr = sc->sc_object.ao_pblkaddr; 596 sc->sc_tstate_status.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 597 598 sc->sc_tstate_control.reg_bitwidth = width; 599 sc->sc_tstate_control.reg_bitoffset = offset; 600 sc->sc_tstate_control.reg_addr = sc->sc_object.ao_pblkaddr; 601 sc->sc_tstate_control.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO; 602 603 return AE_OK; 604} 605 606static ACPI_STATUS 607acpicpu_tstate_change(struct acpicpu_softc *sc) 608{ 609 ACPI_INTEGER val; 610 ACPI_STATUS rv; 611 612 acpicpu_tstate_reset(sc); 613 614 /* 615 * Evaluate the available T-state window: 616 * 617 * _TPC : either this maximum or any lower power 618 * (i.e. higher numbered) state may be used. 619 * 620 * _TDL : either this minimum or any higher power 621 * (i.e. lower numbered) state may be used. 622 * 623 * _TDL >= _TPC || _TDL >= _TSS[last entry]. 624 */ 625 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TPC", &val); 626 627 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 628 629 if (sc->sc_tstate[val].ts_percent != 0) 630 sc->sc_tstate_max = val; 631 } 632 633 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TDL", &val); 634 635 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) { 636 637 if (val >= sc->sc_tstate_max && 638 sc->sc_tstate[val].ts_percent != 0) 639 sc->sc_tstate_min = val; 640 } 641 642 return AE_OK; 643} 644 645static void 646acpicpu_tstate_reset(struct acpicpu_softc *sc) 647{ 648 649 sc->sc_tstate_max = 0; 650 sc->sc_tstate_min = sc->sc_tstate_count - 1; 651} 652 653int 654acpicpu_tstate_get(struct cpu_info *ci, uint32_t *percent) 655{ 656 struct acpicpu_tstate *ts = NULL; 657 struct acpicpu_softc *sc; 658 uint32_t i, val = 0; 659 uint8_t offset; 660 uint64_t addr; 661 int rv; 662 663 sc = acpicpu_sc[ci->ci_acpiid]; 664 665 if (__predict_false(sc == NULL)) { 666 rv = ENXIO; 667 goto fail; 668 } 669 670 if (__predict_false(sc->sc_cold != false)) { 671 rv = EBUSY; 672 goto fail; 673 } 674 675 if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) { 676 rv = ENODEV; 677 goto fail; 678 } 679 680 mutex_enter(&sc->sc_mtx); 681 682 if (sc->sc_tstate_current != ACPICPU_T_STATE_UNKNOWN) { 683 *percent = sc->sc_tstate_current; 684 mutex_exit(&sc->sc_mtx); 685 return 0; 686 } 687 688 mutex_exit(&sc->sc_mtx); 689 690 switch (sc->sc_tstate_status.reg_spaceid) { 691 692 case ACPI_ADR_SPACE_FIXED_HARDWARE: 693 694 rv = acpicpu_md_tstate_get(sc, percent); 695 696 if (__predict_false(rv != 0)) 697 goto fail; 698 699 break; 700 701 case ACPI_ADR_SPACE_SYSTEM_IO: 702 703 addr = sc->sc_tstate_status.reg_addr; 704 offset = sc->sc_tstate_status.reg_bitoffset; 705 706 (void)AcpiOsReadPort(addr, &val, 8); 707 708 val = (val >> offset) & 0x0F; 709 710 for (i = 0; i < sc->sc_tstate_count; i++) { 711 712 if (sc->sc_tstate[i].ts_percent == 0) 713 continue; 714 715 if (val == sc->sc_tstate[i].ts_status) { 716 ts = &sc->sc_tstate[i]; 717 break; 718 } 719 } 720 721 if (ts == NULL) { 722 rv = EIO; 723 goto fail; 724 } 725 726 *percent = ts->ts_percent; 727 break; 728 729 default: 730 rv = ENOTTY; 731 goto fail; 732 } 733 734 mutex_enter(&sc->sc_mtx); 735 sc->sc_tstate_current = *percent; 736 mutex_exit(&sc->sc_mtx); 737 738 return 0; 739 740fail: 741 aprint_error_dev(sc->sc_dev, "failed " 742 "to get T-state (err %d)\n", rv); 743 744 mutex_enter(&sc->sc_mtx); 745 *percent = sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 746 mutex_exit(&sc->sc_mtx); 747 748 return rv; 749} 750 751void 752acpicpu_tstate_set(struct cpu_info *ci, uint32_t percent) 753{ 754 uint64_t xc; 755 756 xc = xc_broadcast(0, acpicpu_tstate_set_xcall, &percent, NULL); 757 xc_wait(xc); 758} 759 760static void 761acpicpu_tstate_set_xcall(void *arg1, void *arg2) 762{ 763 struct acpicpu_tstate *ts = NULL; 764 struct cpu_info *ci = curcpu(); 765 struct acpicpu_softc *sc; 766 uint32_t i, percent, val; 767 uint8_t offset; 768 uint64_t addr; 769 int rv; 770 771 percent = *(uint32_t *)arg1; 772 sc = acpicpu_sc[ci->ci_acpiid]; 773 774 if (__predict_false(sc == NULL)) { 775 rv = ENXIO; 776 goto fail; 777 } 778 779 if (__predict_false(sc->sc_cold != false)) { 780 rv = EBUSY; 781 goto fail; 782 } 783 784 if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) { 785 rv = ENODEV; 786 goto fail; 787 } 788 789 mutex_enter(&sc->sc_mtx); 790 791 if (sc->sc_tstate_current == percent) { 792 mutex_exit(&sc->sc_mtx); 793 return; 794 } 795 796 for (i = sc->sc_tstate_max; i <= sc->sc_tstate_min; i++) { 797 798 if (__predict_false(sc->sc_tstate[i].ts_percent == 0)) 799 continue; 800 801 if (sc->sc_tstate[i].ts_percent == percent) { 802 ts = &sc->sc_tstate[i]; 803 break; 804 } 805 } 806 807 mutex_exit(&sc->sc_mtx); 808 809 if (__predict_false(ts == NULL)) { 810 rv = EINVAL; 811 goto fail; 812 } 813 814 switch (sc->sc_tstate_control.reg_spaceid) { 815 816 case ACPI_ADR_SPACE_FIXED_HARDWARE: 817 818 rv = acpicpu_md_tstate_set(ts); 819 820 if (__predict_false(rv != 0)) 821 goto fail; 822 823 break; 824 825 case ACPI_ADR_SPACE_SYSTEM_IO: 826 827 addr = sc->sc_tstate_control.reg_addr; 828 offset = sc->sc_tstate_control.reg_bitoffset; 829 830 val = (ts->ts_control & 0x0F) << offset; 831 832 if (ts->ts_percent != 100 && (val & __BIT(4)) == 0) { 833 rv = EINVAL; 834 goto fail; 835 } 836 837 (void)AcpiOsWritePort(addr, val, 8); 838 839 /* 840 * If the status field is zero, the transition is 841 * specified to be "asynchronous" and there is no 842 * need to check the status (ACPI 4.0, 8.4.3.2). 843 */ 844 if (ts->ts_status == 0) 845 break; 846 847 addr = sc->sc_tstate_status.reg_addr; 848 offset = sc->sc_tstate_status.reg_bitoffset; 849 850 for (i = val = 0; i < ACPICPU_T_STATE_RETRY; i++) { 851 852 (void)AcpiOsReadPort(addr, &val, 8); 853 854 val = (val >> offset) & 0x0F; 855 856 if (val == ts->ts_status) 857 break; 858 859 DELAY(ts->ts_latency); 860 } 861 862 if (i == ACPICPU_T_STATE_RETRY) { 863 rv = EAGAIN; 864 goto fail; 865 } 866 867 break; 868 869 default: 870 rv = ENOTTY; 871 goto fail; 872 } 873 874 mutex_enter(&sc->sc_mtx); 875 ts->ts_evcnt.ev_count++; 876 sc->sc_tstate_current = percent; 877 mutex_exit(&sc->sc_mtx); 878 879 return; 880 881fail: 882 if (rv != EINVAL) 883 aprint_error_dev(sc->sc_dev, "failed to " 884 "throttle to %u %% (err %d)\n", percent, rv); 885 886 mutex_enter(&sc->sc_mtx); 887 sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN; 888 mutex_exit(&sc->sc_mtx); 889} 890