acpi_cpu_tstate.c revision 1.30.6.1 1 /* $NetBSD: acpi_cpu_tstate.c,v 1.30.6.1 2012/04/29 23:04:48 mrg 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.30.6.1 2012/04/29 23:04:48 mrg 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