acpi_cpu_pstate.c revision 1.19 1 /* $NetBSD: acpi_cpu_pstate.c,v 1.19 2010/08/14 17:27:34 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.19 2010/08/14 17:27:34 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 *sc);
48 static ACPI_STATUS acpicpu_pstate_pss_add(struct acpicpu_pstate *,
49 ACPI_OBJECT *);
50 static ACPI_STATUS acpicpu_pstate_pct(struct acpicpu_softc *);
51 static int acpicpu_pstate_max(struct acpicpu_softc *);
52 static void acpicpu_pstate_change(struct acpicpu_softc *);
53 static void acpicpu_pstate_bios(void);
54
55 void
56 acpicpu_pstate_attach(device_t self)
57 {
58 struct acpicpu_softc *sc = device_private(self);
59 const char *str;
60 ACPI_STATUS rv;
61
62 /*
63 * Three control methods are mandatory
64 * for P-states; _PSS, _PCT, and _PPC.
65 */
66 rv = acpicpu_pstate_pss(sc);
67
68 if (ACPI_FAILURE(rv)) {
69 str = "_PSS";
70 goto fail;
71 }
72
73 rv = acpicpu_pstate_pct(sc);
74
75 if (ACPI_FAILURE(rv)) {
76 str = "_PCT";
77 goto fail;
78 }
79
80 rv = acpicpu_pstate_max(sc);
81
82 if (rv != 0) {
83 str = "_PPC";
84 goto fail;
85 }
86
87 sc->sc_flags |= ACPICPU_FLAG_P;
88 sc->sc_pstate_current = sc->sc_pstate[0].ps_freq;
89
90 acpicpu_pstate_bios();
91 acpicpu_pstate_attach_evcnt(sc);
92 acpicpu_pstate_attach_print(sc);
93
94 return;
95
96 fail:
97 switch (rv) {
98
99 case AE_NOT_FOUND:
100 return;
101
102 case AE_SUPPORT:
103 aprint_verbose_dev(sc->sc_dev, "P-states not supported\n");
104 return;
105
106 default:
107 aprint_error_dev(sc->sc_dev, "failed to evaluate "
108 "%s: %s\n", str, AcpiFormatException(rv));
109 }
110 }
111
112 static void
113 acpicpu_pstate_attach_print(struct acpicpu_softc *sc)
114 {
115 const uint8_t method = sc->sc_pstate_control.reg_spaceid;
116 struct acpicpu_pstate *ps;
117 static bool once = false;
118 const char *str;
119 uint32_t i;
120
121 if (once != false)
122 return;
123
124 str = (method != ACPI_ADR_SPACE_SYSTEM_IO) ? "FFH" : "I/O";
125
126 for (i = 0; i < sc->sc_pstate_count; i++) {
127
128 ps = &sc->sc_pstate[i];
129
130 if (ps->ps_freq == 0)
131 continue;
132
133 aprint_debug_dev(sc->sc_dev, "P%d: %3s, "
134 "lat %3u us, pow %5u mW, %4u MHz\n", i, str,
135 ps->ps_latency, ps->ps_power, ps->ps_freq);
136 }
137
138 once = true;
139 }
140
141 static void
142 acpicpu_pstate_attach_evcnt(struct acpicpu_softc *sc)
143 {
144 struct acpicpu_pstate *ps;
145 uint32_t i;
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 (void)snprintf(ps->ps_name, sizeof(ps->ps_name),
155 "P%u (%u MHz)", i, ps->ps_freq);
156
157 evcnt_attach_dynamic(&ps->ps_evcnt, EVCNT_TYPE_MISC,
158 NULL, device_xname(sc->sc_dev), ps->ps_name);
159 }
160 }
161
162 int
163 acpicpu_pstate_detach(device_t self)
164 {
165 struct acpicpu_softc *sc = device_private(self);
166 static ONCE_DECL(once_detach);
167 size_t size;
168 int rv;
169
170 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0)
171 return 0;
172
173 rv = RUN_ONCE(&once_detach, acpicpu_md_pstate_stop);
174
175 if (rv != 0)
176 return rv;
177
178 size = sc->sc_pstate_count * sizeof(*sc->sc_pstate);
179
180 if (sc->sc_pstate != NULL)
181 kmem_free(sc->sc_pstate, size);
182
183 sc->sc_flags &= ~ACPICPU_FLAG_P;
184 acpicpu_pstate_detach_evcnt(sc);
185
186 return 0;
187 }
188
189 static void
190 acpicpu_pstate_detach_evcnt(struct acpicpu_softc *sc)
191 {
192 struct acpicpu_pstate *ps;
193 uint32_t i;
194
195 for (i = 0; i < sc->sc_pstate_count; i++) {
196
197 ps = &sc->sc_pstate[i];
198
199 if (ps->ps_freq != 0)
200 evcnt_detach(&ps->ps_evcnt);
201 }
202 }
203
204 int
205 acpicpu_pstate_start(device_t self)
206 {
207 struct acpicpu_softc *sc = device_private(self);
208 static ONCE_DECL(once_start);
209
210 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0)
211 return 0;
212
213 return RUN_ONCE(&once_start, acpicpu_md_pstate_start);
214 }
215
216 bool
217 acpicpu_pstate_suspend(device_t self)
218 {
219
220 return true;
221 }
222
223 bool
224 acpicpu_pstate_resume(device_t self)
225 {
226
227 acpicpu_pstate_callback(self);
228
229 return true;
230 }
231
232 void
233 acpicpu_pstate_callback(void *aux)
234 {
235 struct acpicpu_softc *sc;
236 device_t self = aux;
237 uint32_t old, new;
238
239 sc = device_private(self);
240
241 mutex_enter(&sc->sc_mtx);
242 old = sc->sc_pstate_max;
243 acpicpu_pstate_change(sc);
244 new = sc->sc_pstate_max;
245 mutex_exit(&sc->sc_mtx);
246
247 if (old != new) {
248
249 aprint_debug_dev(sc->sc_dev, "maximum frequency "
250 "changed from P%u (%u MHz) to P%u (%u MHz)\n",
251 old, sc->sc_pstate[old].ps_freq, new,
252 sc->sc_pstate[sc->sc_pstate_max].ps_freq);
253 #if 0
254 /*
255 * If the maximum changed, proactively
256 * raise or lower the target frequency.
257 */
258 acpicpu_pstate_set(sc, sc->sc_pstate[new].ps_freq);
259
260 #endif
261 }
262 }
263
264 ACPI_STATUS
265 acpicpu_pstate_pss(struct acpicpu_softc *sc)
266 {
267 struct acpicpu_pstate *ps;
268 ACPI_OBJECT *obj;
269 ACPI_BUFFER buf;
270 ACPI_STATUS rv;
271 uint32_t count;
272 uint32_t i, j;
273
274 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PSS", &buf);
275
276 if (ACPI_FAILURE(rv))
277 return rv;
278
279 obj = buf.Pointer;
280
281 if (obj->Type != ACPI_TYPE_PACKAGE) {
282 rv = AE_TYPE;
283 goto out;
284 }
285
286 sc->sc_pstate_count = obj->Package.Count;
287
288 if (sc->sc_pstate_count == 0) {
289 rv = AE_NOT_EXIST;
290 goto out;
291 }
292
293 if (sc->sc_pstate_count > ACPICPU_P_STATE_MAX) {
294 rv = AE_LIMIT;
295 goto out;
296 }
297
298 sc->sc_pstate = kmem_zalloc(sc->sc_pstate_count *
299 sizeof(struct acpicpu_pstate), KM_SLEEP);
300
301 if (sc->sc_pstate == NULL) {
302 rv = AE_NO_MEMORY;
303 goto out;
304 }
305
306 for (count = i = 0; i < sc->sc_pstate_count; i++) {
307
308 ps = &sc->sc_pstate[i];
309 rv = acpicpu_pstate_pss_add(ps, &obj->Package.Elements[i]);
310
311 if (ACPI_FAILURE(rv)) {
312 ps->ps_freq = 0;
313 continue;
314 }
315
316 for (j = 0; j < i; j++) {
317
318 if (ps->ps_freq >= sc->sc_pstate[j].ps_freq) {
319 ps->ps_freq = 0;
320 break;
321 }
322 }
323
324 if (ps->ps_freq != 0)
325 count++;
326 }
327
328 rv = (count != 0) ? AE_OK : AE_NOT_EXIST;
329
330 out:
331 if (buf.Pointer != NULL)
332 ACPI_FREE(buf.Pointer);
333
334 return rv;
335 }
336
337 static ACPI_STATUS
338 acpicpu_pstate_pss_add(struct acpicpu_pstate *ps, ACPI_OBJECT *obj)
339 {
340 ACPI_OBJECT *elm;
341 uint32_t val[6];
342 uint32_t *p;
343 int i;
344
345 if (obj->Type != ACPI_TYPE_PACKAGE)
346 return AE_TYPE;
347
348 if (obj->Package.Count != 6)
349 return AE_BAD_DATA;
350
351 elm = obj->Package.Elements;
352
353 for (i = 0; i < 6; i++) {
354
355 if (elm[i].Type != ACPI_TYPE_INTEGER)
356 return AE_TYPE;
357
358 if (elm[i].Integer.Value > UINT32_MAX)
359 return AE_AML_NUMERIC_OVERFLOW;
360
361 val[i] = elm[i].Integer.Value;
362 }
363
364 p = &ps->ps_freq;
365
366 for (i = 0; i < 6; i++, p++)
367 *p = val[i];
368
369 if (ps->ps_freq == 0 || ps->ps_freq > 9999)
370 return AE_BAD_DECIMAL_CONSTANT;
371
372 /*
373 * The latency is typically around 10 usec
374 * on Intel CPUs. Use that as the minimum.
375 */
376 if (ps->ps_latency < 10)
377 ps->ps_latency = 10;
378
379 return AE_OK;
380 }
381
382 ACPI_STATUS
383 acpicpu_pstate_pct(struct acpicpu_softc *sc)
384 {
385 static const size_t size = sizeof(struct acpicpu_reg);
386 struct acpicpu_reg *reg[2];
387 ACPI_OBJECT *elm, *obj;
388 ACPI_BUFFER buf;
389 ACPI_STATUS rv;
390 uint8_t width;
391 int i;
392
393 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PCT", &buf);
394
395 if (ACPI_FAILURE(rv))
396 return rv;
397
398 obj = buf.Pointer;
399
400 if (obj->Type != ACPI_TYPE_PACKAGE) {
401 rv = AE_TYPE;
402 goto out;
403 }
404
405 if (obj->Package.Count != 2) {
406 rv = AE_LIMIT;
407 goto out;
408 }
409
410 for (i = 0; i < 2; i++) {
411
412 elm = &obj->Package.Elements[i];
413
414 if (elm->Type != ACPI_TYPE_BUFFER) {
415 rv = AE_TYPE;
416 goto out;
417 }
418
419 if (size > elm->Buffer.Length) {
420 rv = AE_AML_BAD_RESOURCE_LENGTH;
421 goto out;
422 }
423
424 reg[i] = (struct acpicpu_reg *)elm->Buffer.Pointer;
425
426 switch (reg[i]->reg_spaceid) {
427
428 case ACPI_ADR_SPACE_SYSTEM_IO:
429
430 if (reg[i]->reg_addr == 0) {
431 rv = AE_AML_ILLEGAL_ADDRESS;
432 goto out;
433 }
434
435 width = reg[i]->reg_bitwidth;
436
437 if (width + reg[i]->reg_bitoffset > 32) {
438 rv = AE_AML_BAD_RESOURCE_VALUE;
439 goto out;
440 }
441
442 if (width != 8 && width != 16 && width != 32) {
443 rv = AE_AML_BAD_RESOURCE_VALUE;
444 goto out;
445 }
446
447 break;
448
449 case ACPI_ADR_SPACE_FIXED_HARDWARE:
450
451 if ((sc->sc_flags & ACPICPU_FLAG_P_FFH) == 0) {
452 rv = AE_SUPPORT;
453 goto out;
454 }
455
456 break;
457
458 default:
459 rv = AE_AML_INVALID_SPACE_ID;
460 goto out;
461 }
462 }
463
464 if (reg[0]->reg_spaceid != reg[1]->reg_spaceid) {
465 rv = AE_AML_INVALID_SPACE_ID;
466 goto out;
467 }
468
469 (void)memcpy(&sc->sc_pstate_control, reg[0], size);
470 (void)memcpy(&sc->sc_pstate_status, reg[1], size);
471
472 out:
473 if (buf.Pointer != NULL)
474 ACPI_FREE(buf.Pointer);
475
476 return rv;
477 }
478
479 static int
480 acpicpu_pstate_max(struct acpicpu_softc *sc)
481 {
482 ACPI_INTEGER val;
483 ACPI_STATUS rv;
484
485 /*
486 * Evaluate the currently highest P-state that can be used.
487 * If available, we can use either this state or any lower
488 * power (i.e. higher numbered) state from the _PSS object.
489 */
490 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_PPC", &val);
491
492 sc->sc_pstate_max = 0;
493
494 if (ACPI_FAILURE(rv))
495 return 1;
496
497 if (val > sc->sc_pstate_count - 1)
498 return 1;
499
500 if (sc->sc_pstate[val].ps_freq == 0)
501 return 1;
502
503 sc->sc_pstate_max = val;
504
505 return 0;
506 }
507
508 static void
509 acpicpu_pstate_change(struct acpicpu_softc *sc)
510 {
511 ACPI_OBJECT_LIST arg;
512 ACPI_OBJECT obj[2];
513
514 arg.Count = 2;
515 arg.Pointer = obj;
516
517 obj[0].Type = ACPI_TYPE_INTEGER;
518 obj[1].Type = ACPI_TYPE_INTEGER;
519
520 obj[0].Integer.Value = ACPICPU_P_NOTIFY;
521 obj[1].Integer.Value = acpicpu_pstate_max(sc);
522
523 (void)AcpiEvaluateObject(sc->sc_node->ad_handle, "_OST", &arg, NULL);
524 }
525
526 static void
527 acpicpu_pstate_bios(void)
528 {
529 const uint8_t val = AcpiGbl_FADT.PstateControl;
530 const uint32_t addr = AcpiGbl_FADT.SmiCommand;
531
532 if (addr == 0 || val == 0)
533 return;
534
535 (void)AcpiOsWritePort(addr, val, 8);
536 }
537
538 int
539 acpicpu_pstate_get(struct acpicpu_softc *sc, uint32_t *freq)
540 {
541 const uint8_t method = sc->sc_pstate_control.reg_spaceid;
542 struct acpicpu_pstate *ps = NULL;
543 uint32_t i, val = 0;
544 uint64_t addr;
545 uint8_t width;
546 int rv;
547
548 if (sc->sc_cold != false) {
549 rv = EBUSY;
550 goto fail;
551 }
552
553 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0) {
554 rv = ENODEV;
555 goto fail;
556 }
557
558 mutex_enter(&sc->sc_mtx);
559
560 if (sc->sc_pstate_current != ACPICPU_P_STATE_UNKNOWN) {
561 *freq = sc->sc_pstate_current;
562 mutex_exit(&sc->sc_mtx);
563 return 0;
564 }
565
566 mutex_exit(&sc->sc_mtx);
567
568 switch (method) {
569
570 case ACPI_ADR_SPACE_FIXED_HARDWARE:
571
572 rv = acpicpu_md_pstate_get(sc, freq);
573
574 if (rv != 0)
575 goto fail;
576
577 break;
578
579 case ACPI_ADR_SPACE_SYSTEM_IO:
580
581 addr = sc->sc_pstate_status.reg_addr;
582 width = sc->sc_pstate_status.reg_bitwidth;
583
584 (void)AcpiOsReadPort(addr, &val, width);
585
586 if (val == 0) {
587 rv = EIO;
588 goto fail;
589 }
590
591 for (i = 0; i < sc->sc_pstate_count; i++) {
592
593 if (sc->sc_pstate[i].ps_freq == 0)
594 continue;
595
596 if (val == sc->sc_pstate[i].ps_status) {
597 ps = &sc->sc_pstate[i];
598 break;
599 }
600 }
601
602 if (__predict_false(ps == NULL)) {
603 rv = EIO;
604 goto fail;
605 }
606
607 *freq = ps->ps_freq;
608 break;
609
610 default:
611 rv = ENOTTY;
612 goto fail;
613 }
614
615 mutex_enter(&sc->sc_mtx);
616 sc->sc_pstate_current = *freq;
617 mutex_exit(&sc->sc_mtx);
618
619 return 0;
620
621 fail:
622 aprint_error_dev(sc->sc_dev, "failed "
623 "to get frequency (err %d)\n", rv);
624
625 mutex_enter(&sc->sc_mtx);
626 *freq = sc->sc_pstate_current = ACPICPU_P_STATE_UNKNOWN;
627 mutex_exit(&sc->sc_mtx);
628
629 return rv;
630 }
631
632 int
633 acpicpu_pstate_set(struct acpicpu_softc *sc, uint32_t freq)
634 {
635 const uint8_t method = sc->sc_pstate_control.reg_spaceid;
636 struct acpicpu_pstate *ps = NULL;
637 uint32_t i, val;
638 uint64_t addr;
639 uint8_t width;
640 int rv;
641
642 if (sc->sc_cold != false) {
643 rv = EBUSY;
644 goto fail;
645 }
646
647 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0) {
648 rv = ENODEV;
649 goto fail;
650 }
651
652 mutex_enter(&sc->sc_mtx);
653
654 for (i = sc->sc_pstate_max; i < sc->sc_pstate_count; i++) {
655
656 if (sc->sc_pstate[i].ps_freq == 0)
657 continue;
658
659 if (sc->sc_pstate[i].ps_freq == freq) {
660 ps = &sc->sc_pstate[i];
661 break;
662 }
663 }
664
665 mutex_exit(&sc->sc_mtx);
666
667 if (__predict_false(ps == NULL)) {
668 rv = EINVAL;
669 goto fail;
670 }
671
672 switch (method) {
673
674 case ACPI_ADR_SPACE_FIXED_HARDWARE:
675
676 rv = acpicpu_md_pstate_set(ps);
677
678 if (rv != 0)
679 goto fail;
680
681 break;
682
683 case ACPI_ADR_SPACE_SYSTEM_IO:
684
685 addr = sc->sc_pstate_control.reg_addr;
686 width = sc->sc_pstate_control.reg_bitwidth;
687
688 (void)AcpiOsWritePort(addr, ps->ps_control, width);
689
690 addr = sc->sc_pstate_status.reg_addr;
691 width = sc->sc_pstate_status.reg_bitwidth;
692
693 /*
694 * Some systems take longer to respond
695 * than the reported worst-case latency.
696 */
697 for (i = val = 0; i < ACPICPU_P_STATE_RETRY; i++) {
698
699 (void)AcpiOsReadPort(addr, &val, width);
700
701 if (val == ps->ps_status)
702 break;
703
704 DELAY(ps->ps_latency);
705 }
706
707 if (i == ACPICPU_P_STATE_RETRY) {
708 rv = EAGAIN;
709 goto fail;
710 }
711
712 break;
713
714 default:
715 rv = ENOTTY;
716 goto fail;
717 }
718
719 mutex_enter(&sc->sc_mtx);
720 ps->ps_evcnt.ev_count++;
721 sc->sc_pstate_current = freq;
722 mutex_exit(&sc->sc_mtx);
723
724 return 0;
725
726 fail:
727 aprint_error_dev(sc->sc_dev, "failed to set "
728 "frequency to %u (err %d)\n", freq, rv);
729
730 mutex_enter(&sc->sc_mtx);
731 sc->sc_pstate_current = ACPICPU_P_STATE_UNKNOWN;
732 mutex_exit(&sc->sc_mtx);
733
734 return rv;
735 }
736