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