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