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