1 /* $NetBSD: acpi_cpu_tstate.c,v 1.32 2013/11/20 13:39:59 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.32 2013/11/20 13:39:59 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
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
acpicpu_tstate_attach(device_t self)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
acpicpu_tstate_detach(device_t self)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
acpicpu_tstate_start(device_t self)141 acpicpu_tstate_start(device_t self)
142 {
143 /* Nothing. */
144 }
145
146 void
acpicpu_tstate_suspend(void * aux)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
acpicpu_tstate_resume(void * aux)160 acpicpu_tstate_resume(void *aux)
161 {
162 /* Nothing. */
163 }
164
165 void
acpicpu_tstate_callback(void * aux)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
acpicpu_tstate_tss(struct acpicpu_softc * sc)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
acpicpu_tstate_tss_add(struct acpicpu_tstate * ts,ACPI_OBJECT * obj)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 either 12.5 % or 6.5 %,
333 * the latter 4-bit dynamic range being available
334 * in some newer models; see Section 14.5.3.1 in
335 *
336 * Intel 64 and IA-32 Architectures Software
337 * Developer's Manual. Volume 3B, Part 2. 2013.
338 */
339 if (ts->ts_percent < 6 || 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
348 ACPI_STATUS
acpicpu_tstate_ptc(struct acpicpu_softc * sc)349 acpicpu_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
441 out:
442 if (buf.Pointer != NULL)
443 ACPI_FREE(buf.Pointer);
444
445 return rv;
446 }
447
448 static ACPI_STATUS
acpicpu_tstate_dep(struct acpicpu_softc * sc)449 acpicpu_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
526 out:
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
537 static ACPI_STATUS
acpicpu_tstate_fadt(struct acpicpu_softc * sc)538 acpicpu_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 (sc->sc_tstate != NULL)
564 kmem_free(sc->sc_tstate, sc->sc_tstate_count * size);
565
566 sc->sc_tstate = kmem_zalloc(count * size, KM_SLEEP);
567
568 if (sc->sc_tstate == NULL)
569 return ENOMEM;
570
571 sc->sc_tstate_count = count;
572
573 /*
574 * Approximate duty cycles and set the MSR values.
575 */
576 for (beta = 100 / count, i = 0; i < count; i++) {
577 sc->sc_tstate[i].ts_percent = 100 - beta * i;
578 sc->sc_tstate[i].ts_latency = 1;
579 }
580
581 for (i = 1; i < count; i++)
582 sc->sc_tstate[i].ts_control = (count - i) | __BIT(3);
583
584 /*
585 * Fake values for throttling registers.
586 */
587 (void)memset(&sc->sc_tstate_status, 0, sizeof(struct acpicpu_reg));
588 (void)memset(&sc->sc_tstate_control, 0, sizeof(struct acpicpu_reg));
589
590 sc->sc_tstate_status.reg_bitwidth = width;
591 sc->sc_tstate_status.reg_bitoffset = offset;
592 sc->sc_tstate_status.reg_addr = sc->sc_object.ao_pblkaddr;
593 sc->sc_tstate_status.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO;
594
595 sc->sc_tstate_control.reg_bitwidth = width;
596 sc->sc_tstate_control.reg_bitoffset = offset;
597 sc->sc_tstate_control.reg_addr = sc->sc_object.ao_pblkaddr;
598 sc->sc_tstate_control.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO;
599
600 return AE_OK;
601 }
602
603 static ACPI_STATUS
acpicpu_tstate_change(struct acpicpu_softc * sc)604 acpicpu_tstate_change(struct acpicpu_softc *sc)
605 {
606 ACPI_INTEGER val;
607 ACPI_STATUS rv;
608
609 acpicpu_tstate_reset(sc);
610
611 /*
612 * Evaluate the available T-state window:
613 *
614 * _TPC : either this maximum or any lower power
615 * (i.e. higher numbered) state may be used.
616 *
617 * _TDL : either this minimum or any higher power
618 * (i.e. lower numbered) state may be used.
619 *
620 * _TDL >= _TPC || _TDL >= _TSS[last entry].
621 */
622 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TPC", &val);
623
624 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) {
625
626 if (sc->sc_tstate[val].ts_percent != 0)
627 sc->sc_tstate_max = val;
628 }
629
630 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TDL", &val);
631
632 if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) {
633
634 if (val >= sc->sc_tstate_max &&
635 sc->sc_tstate[val].ts_percent != 0)
636 sc->sc_tstate_min = val;
637 }
638
639 return AE_OK;
640 }
641
642 static void
acpicpu_tstate_reset(struct acpicpu_softc * sc)643 acpicpu_tstate_reset(struct acpicpu_softc *sc)
644 {
645
646 sc->sc_tstate_max = 0;
647 sc->sc_tstate_min = sc->sc_tstate_count - 1;
648 }
649
650 int
acpicpu_tstate_get(struct cpu_info * ci,uint32_t * percent)651 acpicpu_tstate_get(struct cpu_info *ci, uint32_t *percent)
652 {
653 struct acpicpu_tstate *ts = NULL;
654 struct acpicpu_softc *sc;
655 uint32_t i, val = 0;
656 uint8_t offset;
657 uint64_t addr;
658 int rv;
659
660 sc = acpicpu_sc[ci->ci_acpiid];
661
662 if (__predict_false(sc == NULL)) {
663 rv = ENXIO;
664 goto fail;
665 }
666
667 if (__predict_false(sc->sc_cold != false)) {
668 rv = EBUSY;
669 goto fail;
670 }
671
672 if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) {
673 rv = ENODEV;
674 goto fail;
675 }
676
677 mutex_enter(&sc->sc_mtx);
678
679 if (sc->sc_tstate_current != ACPICPU_T_STATE_UNKNOWN) {
680 *percent = sc->sc_tstate_current;
681 mutex_exit(&sc->sc_mtx);
682 return 0;
683 }
684
685 mutex_exit(&sc->sc_mtx);
686
687 switch (sc->sc_tstate_status.reg_spaceid) {
688
689 case ACPI_ADR_SPACE_FIXED_HARDWARE:
690
691 rv = acpicpu_md_tstate_get(sc, percent);
692
693 if (__predict_false(rv != 0))
694 goto fail;
695
696 break;
697
698 case ACPI_ADR_SPACE_SYSTEM_IO:
699
700 addr = sc->sc_tstate_status.reg_addr;
701 offset = sc->sc_tstate_status.reg_bitoffset;
702
703 (void)AcpiOsReadPort(addr, &val, 8);
704
705 val = (val >> offset) & 0x0F;
706
707 for (i = 0; i < sc->sc_tstate_count; i++) {
708
709 if (sc->sc_tstate[i].ts_percent == 0)
710 continue;
711
712 if (val == sc->sc_tstate[i].ts_status) {
713 ts = &sc->sc_tstate[i];
714 break;
715 }
716 }
717
718 if (ts == NULL) {
719 rv = EIO;
720 goto fail;
721 }
722
723 *percent = ts->ts_percent;
724 break;
725
726 default:
727 rv = ENOTTY;
728 goto fail;
729 }
730
731 mutex_enter(&sc->sc_mtx);
732 sc->sc_tstate_current = *percent;
733 mutex_exit(&sc->sc_mtx);
734
735 return 0;
736
737 fail:
738 aprint_error_dev(sc->sc_dev, "failed "
739 "to get T-state (err %d)\n", rv);
740
741 mutex_enter(&sc->sc_mtx);
742 *percent = sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN;
743 mutex_exit(&sc->sc_mtx);
744
745 return rv;
746 }
747
748 void
acpicpu_tstate_set(struct cpu_info * ci,uint32_t percent)749 acpicpu_tstate_set(struct cpu_info *ci, uint32_t percent)
750 {
751 uint64_t xc;
752
753 xc = xc_broadcast(0, acpicpu_tstate_set_xcall, &percent, NULL);
754 xc_wait(xc);
755 }
756
757 static void
acpicpu_tstate_set_xcall(void * arg1,void * arg2)758 acpicpu_tstate_set_xcall(void *arg1, void *arg2)
759 {
760 struct acpicpu_tstate *ts = NULL;
761 struct cpu_info *ci = curcpu();
762 struct acpicpu_softc *sc;
763 uint32_t i, percent, val;
764 uint8_t offset;
765 uint64_t addr;
766 int rv;
767
768 percent = *(uint32_t *)arg1;
769 sc = acpicpu_sc[ci->ci_acpiid];
770
771 if (__predict_false(sc == NULL)) {
772 rv = ENXIO;
773 goto fail;
774 }
775
776 if (__predict_false(sc->sc_cold != false)) {
777 rv = EBUSY;
778 goto fail;
779 }
780
781 if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) {
782 rv = ENODEV;
783 goto fail;
784 }
785
786 mutex_enter(&sc->sc_mtx);
787
788 if (sc->sc_tstate_current == percent) {
789 mutex_exit(&sc->sc_mtx);
790 return;
791 }
792
793 for (i = sc->sc_tstate_max; i <= sc->sc_tstate_min; i++) {
794
795 if (__predict_false(sc->sc_tstate[i].ts_percent == 0))
796 continue;
797
798 if (sc->sc_tstate[i].ts_percent == percent) {
799 ts = &sc->sc_tstate[i];
800 break;
801 }
802 }
803
804 mutex_exit(&sc->sc_mtx);
805
806 if (__predict_false(ts == NULL)) {
807 rv = EINVAL;
808 goto fail;
809 }
810
811 switch (sc->sc_tstate_control.reg_spaceid) {
812
813 case ACPI_ADR_SPACE_FIXED_HARDWARE:
814
815 rv = acpicpu_md_tstate_set(ts);
816
817 if (__predict_false(rv != 0))
818 goto fail;
819
820 break;
821
822 case ACPI_ADR_SPACE_SYSTEM_IO:
823
824 addr = sc->sc_tstate_control.reg_addr;
825 offset = sc->sc_tstate_control.reg_bitoffset;
826
827 val = (ts->ts_control & 0x0F) << offset;
828
829 if (ts->ts_percent != 100 && (val & __BIT(4)) == 0) {
830 rv = EINVAL;
831 goto fail;
832 }
833
834 (void)AcpiOsWritePort(addr, val, 8);
835
836 /*
837 * If the status field is zero, the transition is
838 * specified to be "asynchronous" and there is no
839 * need to check the status (ACPI 4.0, 8.4.3.2).
840 */
841 if (ts->ts_status == 0)
842 break;
843
844 addr = sc->sc_tstate_status.reg_addr;
845 offset = sc->sc_tstate_status.reg_bitoffset;
846
847 for (i = val = 0; i < ACPICPU_T_STATE_RETRY; i++) {
848
849 (void)AcpiOsReadPort(addr, &val, 8);
850
851 val = (val >> offset) & 0x0F;
852
853 if (val == ts->ts_status)
854 break;
855
856 DELAY(ts->ts_latency);
857 }
858
859 if (i == ACPICPU_T_STATE_RETRY) {
860 rv = EAGAIN;
861 goto fail;
862 }
863
864 break;
865
866 default:
867 rv = ENOTTY;
868 goto fail;
869 }
870
871 mutex_enter(&sc->sc_mtx);
872 ts->ts_evcnt.ev_count++;
873 sc->sc_tstate_current = percent;
874 mutex_exit(&sc->sc_mtx);
875
876 return;
877
878 fail:
879 if (rv != EINVAL)
880 aprint_error_dev(sc->sc_dev, "failed to "
881 "throttle to %u %% (err %d)\n", percent, rv);
882
883 mutex_enter(&sc->sc_mtx);
884 sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN;
885 mutex_exit(&sc->sc_mtx);
886 }
887