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