acpi_cpu_pstate.c revision 1.21 1 /* $NetBSD: acpi_cpu_pstate.c,v 1.21 2010/08/16 07:38:38 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_pstate.c,v 1.21 2010/08/16 07:38:38 jruoho Exp $");
31
32 #include <sys/param.h>
33 #include <sys/evcnt.h>
34 #include <sys/kmem.h>
35 #include <sys/once.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_pstate")
43
44 static void acpicpu_pstate_attach_print(struct acpicpu_softc *);
45 static void acpicpu_pstate_attach_evcnt(struct acpicpu_softc *);
46 static void acpicpu_pstate_detach_evcnt(struct acpicpu_softc *);
47 static ACPI_STATUS acpicpu_pstate_pss(struct acpicpu_softc *);
48 static ACPI_STATUS acpicpu_pstate_pss_add(struct acpicpu_pstate *,
49 ACPI_OBJECT *);
50 static ACPI_STATUS acpicpu_pstate_xpss(struct acpicpu_softc *);
51 static ACPI_STATUS acpicpu_pstate_xpss_add(struct acpicpu_pstate *,
52 ACPI_OBJECT *);
53 static ACPI_STATUS acpicpu_pstate_pct(struct acpicpu_softc *);
54 static int acpicpu_pstate_max(struct acpicpu_softc *);
55 static void acpicpu_pstate_change(struct acpicpu_softc *);
56 static void acpicpu_pstate_bios(void);
57
58 void
59 acpicpu_pstate_attach(device_t self)
60 {
61 struct acpicpu_softc *sc = device_private(self);
62 const char *str;
63 ACPI_STATUS rv;
64
65 /*
66 * The ACPI 3.0 and 4.0 specifications mandate three
67 * objects for P-states: _PSS, _PCT, and _PPC. A less
68 * strict wording is however used in the earlier 2.0
69 * standard, and some systems conforming to ACPI 2.0
70 * do not have _PPC, the method for dynamic maximum.
71 */
72 rv = acpicpu_pstate_pss(sc);
73
74 if (ACPI_FAILURE(rv)) {
75 str = "_PSS";
76 goto fail;
77 }
78
79 /*
80 * Check the availability of extended _PSS.
81 * If present, this will override the data.
82 * Note that XPSS can not be used on Intel
83 * systems where _PDC or _OSC may be used.
84 */
85 if (sc->sc_cap == 0) {
86
87 rv = acpicpu_pstate_xpss(sc);
88
89 if (ACPI_SUCCESS(rv))
90 sc->sc_flags |= ACPICPU_FLAG_P_XPSS;
91
92 if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) {
93 str = "XPSS";
94 goto fail;
95 }
96 }
97
98 rv = acpicpu_pstate_pct(sc);
99
100 if (ACPI_FAILURE(rv)) {
101 str = "_PCT";
102 goto fail;
103 }
104
105 (void)acpicpu_pstate_max(sc);
106
107 sc->sc_flags |= ACPICPU_FLAG_P;
108 sc->sc_pstate_current = sc->sc_pstate[0].ps_freq;
109
110 acpicpu_pstate_bios();
111 acpicpu_pstate_attach_evcnt(sc);
112 acpicpu_pstate_attach_print(sc);
113
114 return;
115
116 fail:
117 switch (rv) {
118
119 case AE_NOT_FOUND:
120 return;
121
122 case AE_SUPPORT:
123 aprint_verbose_dev(sc->sc_dev, "P-states not supported\n");
124 return;
125
126 default:
127 aprint_error_dev(sc->sc_dev, "failed to evaluate "
128 "%s: %s\n", str, AcpiFormatException(rv));
129 }
130 }
131
132 static void
133 acpicpu_pstate_attach_print(struct acpicpu_softc *sc)
134 {
135 const uint8_t method = sc->sc_pstate_control.reg_spaceid;
136 struct acpicpu_pstate *ps;
137 static bool once = false;
138 const char *str;
139 uint32_t i;
140
141 if (once != false)
142 return;
143
144 str = (method != ACPI_ADR_SPACE_SYSTEM_IO) ? "FFH" : "I/O";
145
146 for (i = 0; i < sc->sc_pstate_count; i++) {
147
148 ps = &sc->sc_pstate[i];
149
150 if (ps->ps_freq == 0)
151 continue;
152
153 aprint_debug_dev(sc->sc_dev, "P%d: %3s, "
154 "lat %3u us, pow %5u mW, %4u MHz\n", i, str,
155 ps->ps_latency, ps->ps_power, ps->ps_freq);
156 }
157
158 once = true;
159 }
160
161 static void
162 acpicpu_pstate_attach_evcnt(struct acpicpu_softc *sc)
163 {
164 struct acpicpu_pstate *ps;
165 uint32_t i;
166
167 for (i = 0; i < sc->sc_pstate_count; i++) {
168
169 ps = &sc->sc_pstate[i];
170
171 if (ps->ps_freq == 0)
172 continue;
173
174 (void)snprintf(ps->ps_name, sizeof(ps->ps_name),
175 "P%u (%u MHz)", i, ps->ps_freq);
176
177 evcnt_attach_dynamic(&ps->ps_evcnt, EVCNT_TYPE_MISC,
178 NULL, device_xname(sc->sc_dev), ps->ps_name);
179 }
180 }
181
182 int
183 acpicpu_pstate_detach(device_t self)
184 {
185 struct acpicpu_softc *sc = device_private(self);
186 static ONCE_DECL(once_detach);
187 size_t size;
188 int rv;
189
190 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0)
191 return 0;
192
193 rv = RUN_ONCE(&once_detach, acpicpu_md_pstate_stop);
194
195 if (rv != 0)
196 return rv;
197
198 size = sc->sc_pstate_count * sizeof(*sc->sc_pstate);
199
200 if (sc->sc_pstate != NULL)
201 kmem_free(sc->sc_pstate, size);
202
203 sc->sc_flags &= ~ACPICPU_FLAG_P;
204 acpicpu_pstate_detach_evcnt(sc);
205
206 return 0;
207 }
208
209 static void
210 acpicpu_pstate_detach_evcnt(struct acpicpu_softc *sc)
211 {
212 struct acpicpu_pstate *ps;
213 uint32_t i;
214
215 for (i = 0; i < sc->sc_pstate_count; i++) {
216
217 ps = &sc->sc_pstate[i];
218
219 if (ps->ps_freq != 0)
220 evcnt_detach(&ps->ps_evcnt);
221 }
222 }
223
224 int
225 acpicpu_pstate_start(device_t self)
226 {
227 struct acpicpu_softc *sc = device_private(self);
228 static ONCE_DECL(once_start);
229
230 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0)
231 return 0;
232
233 return RUN_ONCE(&once_start, acpicpu_md_pstate_start);
234 }
235
236 bool
237 acpicpu_pstate_suspend(device_t self)
238 {
239
240 return true;
241 }
242
243 bool
244 acpicpu_pstate_resume(device_t self)
245 {
246
247 acpicpu_pstate_callback(self);
248
249 return true;
250 }
251
252 void
253 acpicpu_pstate_callback(void *aux)
254 {
255 struct acpicpu_softc *sc;
256 device_t self = aux;
257 uint32_t old, new;
258
259 sc = device_private(self);
260
261 mutex_enter(&sc->sc_mtx);
262 old = sc->sc_pstate_max;
263 acpicpu_pstate_change(sc);
264 new = sc->sc_pstate_max;
265 mutex_exit(&sc->sc_mtx);
266
267 if (old != new) {
268
269 aprint_debug_dev(sc->sc_dev, "maximum frequency "
270 "changed from P%u (%u MHz) to P%u (%u MHz)\n",
271 old, sc->sc_pstate[old].ps_freq, new,
272 sc->sc_pstate[sc->sc_pstate_max].ps_freq);
273 #if 0
274 /*
275 * If the maximum changed, proactively
276 * raise or lower the target frequency.
277 */
278 acpicpu_pstate_set(sc, sc->sc_pstate[new].ps_freq);
279
280 #endif
281 }
282 }
283
284 ACPI_STATUS
285 acpicpu_pstate_pss(struct acpicpu_softc *sc)
286 {
287 struct acpicpu_pstate *ps;
288 ACPI_OBJECT *obj;
289 ACPI_BUFFER buf;
290 ACPI_STATUS rv;
291 uint32_t count;
292 uint32_t i, j;
293
294 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PSS", &buf);
295
296 if (ACPI_FAILURE(rv))
297 return rv;
298
299 obj = buf.Pointer;
300
301 if (obj->Type != ACPI_TYPE_PACKAGE) {
302 rv = AE_TYPE;
303 goto out;
304 }
305
306 sc->sc_pstate_count = obj->Package.Count;
307
308 if (sc->sc_pstate_count == 0) {
309 rv = AE_NOT_EXIST;
310 goto out;
311 }
312
313 if (sc->sc_pstate_count > ACPICPU_P_STATE_MAX) {
314 rv = AE_LIMIT;
315 goto out;
316 }
317
318 sc->sc_pstate = kmem_zalloc(sc->sc_pstate_count *
319 sizeof(struct acpicpu_pstate), KM_SLEEP);
320
321 if (sc->sc_pstate == NULL) {
322 rv = AE_NO_MEMORY;
323 goto out;
324 }
325
326 for (count = i = 0; i < sc->sc_pstate_count; i++) {
327
328 ps = &sc->sc_pstate[i];
329 rv = acpicpu_pstate_pss_add(ps, &obj->Package.Elements[i]);
330
331 if (ACPI_FAILURE(rv)) {
332 ps->ps_freq = 0;
333 continue;
334 }
335
336 for (j = 0; j < i; j++) {
337
338 if (ps->ps_freq >= sc->sc_pstate[j].ps_freq) {
339 ps->ps_freq = 0;
340 break;
341 }
342 }
343
344 if (ps->ps_freq != 0)
345 count++;
346 }
347
348 rv = (count != 0) ? AE_OK : AE_NOT_EXIST;
349
350 out:
351 if (buf.Pointer != NULL)
352 ACPI_FREE(buf.Pointer);
353
354 return rv;
355 }
356
357 static ACPI_STATUS
358 acpicpu_pstate_pss_add(struct acpicpu_pstate *ps, ACPI_OBJECT *obj)
359 {
360 ACPI_OBJECT *elm;
361 int i;
362
363 if (obj->Type != ACPI_TYPE_PACKAGE)
364 return AE_TYPE;
365
366 if (obj->Package.Count != 6)
367 return AE_BAD_DATA;
368
369 elm = obj->Package.Elements;
370
371 for (i = 0; i < 6; i++) {
372
373 if (elm[i].Type != ACPI_TYPE_INTEGER)
374 return AE_TYPE;
375
376 if (elm[i].Integer.Value > UINT32_MAX)
377 return AE_AML_NUMERIC_OVERFLOW;
378 }
379
380 ps->ps_freq = elm[0].Integer.Value;
381 ps->ps_power = elm[1].Integer.Value;
382 ps->ps_latency = elm[2].Integer.Value;
383 ps->ps_latency_bm = elm[3].Integer.Value;
384 ps->ps_control = elm[4].Integer.Value;
385 ps->ps_status = elm[5].Integer.Value;
386
387 if (ps->ps_freq == 0 || ps->ps_freq > 9999)
388 return AE_BAD_DECIMAL_CONSTANT;
389
390 /*
391 * The latency is typically around 10 usec
392 * on Intel CPUs. Use that as the minimum.
393 */
394 if (ps->ps_latency < 10)
395 ps->ps_latency = 10;
396
397 return AE_OK;
398 }
399
400 static ACPI_STATUS
401 acpicpu_pstate_xpss(struct acpicpu_softc *sc)
402 {
403 static const size_t size = sizeof(struct acpicpu_pstate);
404 struct acpicpu_pstate *ps;
405 ACPI_OBJECT *obj;
406 ACPI_BUFFER buf;
407 ACPI_STATUS rv;
408 uint32_t count;
409 uint32_t i, j;
410
411 rv = acpi_eval_struct(sc->sc_node->ad_handle, "XPSS", &buf);
412
413 if (ACPI_FAILURE(rv))
414 return rv;
415
416 obj = buf.Pointer;
417
418 if (obj->Type != ACPI_TYPE_PACKAGE) {
419 rv = AE_TYPE;
420 goto out;
421 }
422
423 count = obj->Package.Count;
424
425 if (count == 0) {
426 rv = AE_NOT_EXIST;
427 goto out;
428 }
429
430 if (count > ACPICPU_P_STATE_MAX) {
431 rv = AE_LIMIT;
432 goto out;
433 }
434
435 if (sc->sc_pstate != NULL)
436 kmem_free(sc->sc_pstate, sc->sc_pstate_count * size);
437
438 sc->sc_pstate = kmem_zalloc(count * size, KM_SLEEP);
439
440 if (sc->sc_pstate == NULL) {
441 rv = AE_NO_MEMORY;
442 goto out;
443 }
444
445 sc->sc_pstate_count = count;
446
447 for (count = i = 0; i < sc->sc_pstate_count; i++) {
448
449 ps = &sc->sc_pstate[i];
450 rv = acpicpu_pstate_xpss_add(ps, &obj->Package.Elements[i]);
451
452 if (ACPI_FAILURE(rv)) {
453 ps->ps_freq = 0;
454 continue;
455 }
456
457 for (j = 0; j < i; j++) {
458
459 if (ps->ps_freq >= sc->sc_pstate[j].ps_freq) {
460 ps->ps_freq = 0;
461 break;
462 }
463 }
464
465 if (ps->ps_freq != 0)
466 count++;
467 }
468
469 rv = (count != 0) ? AE_OK : AE_NOT_EXIST;
470
471 out:
472 if (buf.Pointer != NULL)
473 ACPI_FREE(buf.Pointer);
474
475 return rv;
476 }
477
478 static ACPI_STATUS
479 acpicpu_pstate_xpss_add(struct acpicpu_pstate *ps, ACPI_OBJECT *obj)
480 {
481 static const size_t size = sizeof(uint64_t);
482 ACPI_OBJECT *elm;
483 int i;
484
485 if (obj->Type != ACPI_TYPE_PACKAGE)
486 return AE_TYPE;
487
488 if (obj->Package.Count != 8)
489 return AE_BAD_DATA;
490
491 elm = obj->Package.Elements;
492
493 for (i = 0; i < 4; i++) {
494
495 if (elm[i].Type != ACPI_TYPE_INTEGER)
496 return AE_TYPE;
497
498 if (elm[i].Integer.Value > UINT32_MAX)
499 return AE_AML_NUMERIC_OVERFLOW;
500 }
501
502 for (; i < 8; i++) {
503
504 if (elm[i].Type != ACPI_TYPE_BUFFER)
505 return AE_TYPE;
506
507 if (elm[i].Buffer.Length > size)
508 return AE_LIMIT;
509 }
510
511 ps->ps_freq = elm[0].Integer.Value;
512 ps->ps_power = elm[1].Integer.Value;
513 ps->ps_latency = elm[2].Integer.Value;
514 ps->ps_latency_bm = elm[3].Integer.Value;
515
516 if (ps->ps_freq == 0 || ps->ps_freq > 9999)
517 return AE_BAD_DECIMAL_CONSTANT;
518
519 (void)memcpy(&ps->ps_control, elm[4].Buffer.Pointer, size);
520 (void)memcpy(&ps->ps_status, elm[5].Buffer.Pointer, size);
521
522 (void)memcpy(&ps->ps_control_mask, elm[6].Buffer.Pointer, size);
523 (void)memcpy(&ps->ps_status_mask, elm[7].Buffer.Pointer, size);
524
525 /*
526 * The latency is often defined to be
527 * zero on AMD systems. Raise that to 1.
528 */
529 if (ps->ps_latency == 0)
530 ps->ps_latency = 1;
531
532 ps->ps_flags |= ACPICPU_FLAG_P_XPSS;
533
534 return AE_OK;
535 }
536
537 ACPI_STATUS
538 acpicpu_pstate_pct(struct acpicpu_softc *sc)
539 {
540 static const size_t size = sizeof(struct acpicpu_reg);
541 struct acpicpu_reg *reg[2];
542 struct acpicpu_pstate *ps;
543 ACPI_OBJECT *elm, *obj;
544 ACPI_BUFFER buf;
545 ACPI_STATUS rv;
546 uint8_t width;
547 uint32_t i;
548
549 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PCT", &buf);
550
551 if (ACPI_FAILURE(rv))
552 return rv;
553
554 obj = buf.Pointer;
555
556 if (obj->Type != ACPI_TYPE_PACKAGE) {
557 rv = AE_TYPE;
558 goto out;
559 }
560
561 if (obj->Package.Count != 2) {
562 rv = AE_LIMIT;
563 goto out;
564 }
565
566 for (i = 0; i < 2; i++) {
567
568 elm = &obj->Package.Elements[i];
569
570 if (elm->Type != ACPI_TYPE_BUFFER) {
571 rv = AE_TYPE;
572 goto out;
573 }
574
575 if (size > elm->Buffer.Length) {
576 rv = AE_AML_BAD_RESOURCE_LENGTH;
577 goto out;
578 }
579
580 reg[i] = (struct acpicpu_reg *)elm->Buffer.Pointer;
581
582 switch (reg[i]->reg_spaceid) {
583
584 case ACPI_ADR_SPACE_SYSTEM_IO:
585
586 if (reg[i]->reg_addr == 0) {
587 rv = AE_AML_ILLEGAL_ADDRESS;
588 goto out;
589 }
590
591 width = reg[i]->reg_bitwidth;
592
593 if (width + reg[i]->reg_bitoffset > 32) {
594 rv = AE_AML_BAD_RESOURCE_VALUE;
595 goto out;
596 }
597
598 if (width != 8 && width != 16 && width != 32) {
599 rv = AE_AML_BAD_RESOURCE_VALUE;
600 goto out;
601 }
602
603 break;
604
605 case ACPI_ADR_SPACE_FIXED_HARDWARE:
606
607 /*
608 * With XPSS the _PCT registers incorporate
609 * the addresses of the appropriate MSRs.
610 */
611 if ((sc->sc_flags & ACPICPU_FLAG_P_XPSS) != 0) {
612
613 if (reg[i]->reg_addr == 0) {
614 rv = AE_AML_ILLEGAL_ADDRESS;
615 goto out;
616 }
617
618 if (reg[i]->reg_bitwidth != 64) {
619 rv = AE_AML_BAD_RESOURCE_VALUE;
620 goto out;
621 }
622
623 if (reg[i]->reg_bitoffset != 0) {
624 rv = AE_AML_BAD_RESOURCE_VALUE;
625 goto out;
626 }
627
628 break;
629 }
630
631 if ((sc->sc_flags & ACPICPU_FLAG_P_FFH) == 0) {
632 rv = AE_SUPPORT;
633 goto out;
634 }
635
636 break;
637
638 default:
639 rv = AE_AML_INVALID_SPACE_ID;
640 goto out;
641 }
642 }
643
644 if (reg[0]->reg_spaceid != reg[1]->reg_spaceid) {
645 rv = AE_AML_INVALID_SPACE_ID;
646 goto out;
647 }
648
649 (void)memcpy(&sc->sc_pstate_control, reg[0], size);
650 (void)memcpy(&sc->sc_pstate_status, reg[1], size);
651
652 /*
653 * If XPSS is present, copy the MSR addresses
654 * to the P-state structures for convenience.
655 */
656 if ((sc->sc_flags & ACPICPU_FLAG_P_XPSS) == 0)
657 goto out;
658
659 for (i = 0; i < sc->sc_pstate_count; i++) {
660
661 ps = &sc->sc_pstate[i];
662
663 if (ps->ps_freq == 0)
664 continue;
665
666 ps->ps_status_addr = sc->sc_pstate_status.reg_addr;
667 ps->ps_control_addr = sc->sc_pstate_control.reg_addr;
668 }
669
670 out:
671 if (buf.Pointer != NULL)
672 ACPI_FREE(buf.Pointer);
673
674 return rv;
675 }
676
677 static int
678 acpicpu_pstate_max(struct acpicpu_softc *sc)
679 {
680 ACPI_INTEGER val;
681 ACPI_STATUS rv;
682
683 /*
684 * Evaluate the currently highest P-state that can be used.
685 * If available, we can use either this state or any lower
686 * power (i.e. higher numbered) state from the _PSS object.
687 */
688 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_PPC", &val);
689
690 sc->sc_pstate_max = 0;
691
692 if (ACPI_FAILURE(rv))
693 return 1;
694
695 if (val > sc->sc_pstate_count - 1)
696 return 1;
697
698 if (sc->sc_pstate[val].ps_freq == 0)
699 return 1;
700
701 sc->sc_pstate_max = val;
702
703 return 0;
704 }
705
706 static void
707 acpicpu_pstate_change(struct acpicpu_softc *sc)
708 {
709 ACPI_OBJECT_LIST arg;
710 ACPI_OBJECT obj[2];
711
712 arg.Count = 2;
713 arg.Pointer = obj;
714
715 obj[0].Type = ACPI_TYPE_INTEGER;
716 obj[1].Type = ACPI_TYPE_INTEGER;
717
718 obj[0].Integer.Value = ACPICPU_P_NOTIFY;
719 obj[1].Integer.Value = acpicpu_pstate_max(sc);
720
721 (void)AcpiEvaluateObject(sc->sc_node->ad_handle, "_OST", &arg, NULL);
722 }
723
724 static void
725 acpicpu_pstate_bios(void)
726 {
727 const uint8_t val = AcpiGbl_FADT.PstateControl;
728 const uint32_t addr = AcpiGbl_FADT.SmiCommand;
729
730 if (addr == 0 || val == 0)
731 return;
732
733 (void)AcpiOsWritePort(addr, val, 8);
734 }
735
736 int
737 acpicpu_pstate_get(struct acpicpu_softc *sc, uint32_t *freq)
738 {
739 const uint8_t method = sc->sc_pstate_control.reg_spaceid;
740 struct acpicpu_pstate *ps = NULL;
741 uint32_t i, val = 0;
742 uint64_t addr;
743 uint8_t width;
744 int rv;
745
746 if (sc->sc_cold != false) {
747 rv = EBUSY;
748 goto fail;
749 }
750
751 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0) {
752 rv = ENODEV;
753 goto fail;
754 }
755
756 mutex_enter(&sc->sc_mtx);
757
758 if (sc->sc_pstate_current != ACPICPU_P_STATE_UNKNOWN) {
759 *freq = sc->sc_pstate_current;
760 mutex_exit(&sc->sc_mtx);
761 return 0;
762 }
763
764 mutex_exit(&sc->sc_mtx);
765
766 switch (method) {
767
768 case ACPI_ADR_SPACE_FIXED_HARDWARE:
769
770 rv = acpicpu_md_pstate_get(sc, freq);
771
772 if (rv != 0)
773 goto fail;
774
775 break;
776
777 case ACPI_ADR_SPACE_SYSTEM_IO:
778
779 addr = sc->sc_pstate_status.reg_addr;
780 width = sc->sc_pstate_status.reg_bitwidth;
781
782 (void)AcpiOsReadPort(addr, &val, width);
783
784 if (val == 0) {
785 rv = EIO;
786 goto fail;
787 }
788
789 for (i = 0; i < sc->sc_pstate_count; i++) {
790
791 if (sc->sc_pstate[i].ps_freq == 0)
792 continue;
793
794 if (val == sc->sc_pstate[i].ps_status) {
795 ps = &sc->sc_pstate[i];
796 break;
797 }
798 }
799
800 if (__predict_false(ps == NULL)) {
801 rv = EIO;
802 goto fail;
803 }
804
805 *freq = ps->ps_freq;
806 break;
807
808 default:
809 rv = ENOTTY;
810 goto fail;
811 }
812
813 mutex_enter(&sc->sc_mtx);
814 sc->sc_pstate_current = *freq;
815 mutex_exit(&sc->sc_mtx);
816
817 return 0;
818
819 fail:
820 aprint_error_dev(sc->sc_dev, "failed "
821 "to get frequency (err %d)\n", rv);
822
823 mutex_enter(&sc->sc_mtx);
824 *freq = sc->sc_pstate_current = ACPICPU_P_STATE_UNKNOWN;
825 mutex_exit(&sc->sc_mtx);
826
827 return rv;
828 }
829
830 int
831 acpicpu_pstate_set(struct acpicpu_softc *sc, uint32_t freq)
832 {
833 const uint8_t method = sc->sc_pstate_control.reg_spaceid;
834 struct acpicpu_pstate *ps = NULL;
835 uint32_t i, val;
836 uint64_t addr;
837 uint8_t width;
838 int rv;
839
840 if (sc->sc_cold != false) {
841 rv = EBUSY;
842 goto fail;
843 }
844
845 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0) {
846 rv = ENODEV;
847 goto fail;
848 }
849
850 mutex_enter(&sc->sc_mtx);
851
852 for (i = sc->sc_pstate_max; i < sc->sc_pstate_count; i++) {
853
854 if (sc->sc_pstate[i].ps_freq == 0)
855 continue;
856
857 if (sc->sc_pstate[i].ps_freq == freq) {
858 ps = &sc->sc_pstate[i];
859 break;
860 }
861 }
862
863 mutex_exit(&sc->sc_mtx);
864
865 if (__predict_false(ps == NULL)) {
866 rv = EINVAL;
867 goto fail;
868 }
869
870 switch (method) {
871
872 case ACPI_ADR_SPACE_FIXED_HARDWARE:
873
874 rv = acpicpu_md_pstate_set(ps);
875
876 if (rv != 0)
877 goto fail;
878
879 break;
880
881 case ACPI_ADR_SPACE_SYSTEM_IO:
882
883 addr = sc->sc_pstate_control.reg_addr;
884 width = sc->sc_pstate_control.reg_bitwidth;
885
886 (void)AcpiOsWritePort(addr, ps->ps_control, width);
887
888 addr = sc->sc_pstate_status.reg_addr;
889 width = sc->sc_pstate_status.reg_bitwidth;
890
891 /*
892 * Some systems take longer to respond
893 * than the reported worst-case latency.
894 */
895 for (i = val = 0; i < ACPICPU_P_STATE_RETRY; i++) {
896
897 (void)AcpiOsReadPort(addr, &val, width);
898
899 if (val == ps->ps_status)
900 break;
901
902 DELAY(ps->ps_latency);
903 }
904
905 if (i == ACPICPU_P_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 ps->ps_evcnt.ev_count++;
919 sc->sc_pstate_current = freq;
920 mutex_exit(&sc->sc_mtx);
921
922 return 0;
923
924 fail:
925 aprint_error_dev(sc->sc_dev, "failed to set "
926 "frequency to %u (err %d)\n", freq, rv);
927
928 mutex_enter(&sc->sc_mtx);
929 sc->sc_pstate_current = ACPICPU_P_STATE_UNKNOWN;
930 mutex_exit(&sc->sc_mtx);
931
932 return rv;
933 }
934