acpi_cpu_tstate.c revision 1.27.2.1 1 /* $NetBSD: acpi_cpu_tstate.c,v 1.27.2.1 2011/06/23 14:19:56 cherry Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Jukka Ruohonen <jruohonen (at) 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.2.1 2011/06/23 14:19:56 cherry 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_debug_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_debug_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