acpi_cpu_pstate.c revision 1.16 1 /* $NetBSD: acpi_cpu_pstate.c,v 1.16 2010/08/13 18:44:24 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.16 2010/08/13 18:44:24 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 static const ACPI_OSD_EXEC_CALLBACK func = acpicpu_pstate_callback;
227 struct acpicpu_softc *sc = device_private(self);
228
229 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, func, sc->sc_dev);
230
231 return true;
232 }
233
234 void
235 acpicpu_pstate_callback(void *aux)
236 {
237 struct acpicpu_softc *sc;
238 device_t self = aux;
239 uint32_t old, new;
240
241 sc = device_private(self);
242
243 mutex_enter(&sc->sc_mtx);
244 old = sc->sc_pstate_max;
245 acpicpu_pstate_change(sc);
246 new = sc->sc_pstate_max;
247 mutex_exit(&sc->sc_mtx);
248
249 if (old != new) {
250
251 aprint_debug_dev(sc->sc_dev, "maximum frequency "
252 "changed from P%u (%u MHz) to P%u (%u MHz)\n",
253 old, sc->sc_pstate[old].ps_freq, new,
254 sc->sc_pstate[sc->sc_pstate_max].ps_freq);
255 #if 0
256 /*
257 * If the maximum changed, proactively
258 * raise or lower the target frequency.
259 */
260 acpicpu_pstate_set(sc, sc->sc_pstate[new].ps_freq);
261
262 #endif
263 }
264 }
265
266 ACPI_STATUS
267 acpicpu_pstate_pss(struct acpicpu_softc *sc)
268 {
269 struct acpicpu_pstate *ps;
270 ACPI_OBJECT *obj;
271 ACPI_BUFFER buf;
272 ACPI_STATUS rv;
273 uint32_t count;
274 uint32_t i, j;
275
276 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PSS", &buf);
277
278 if (ACPI_FAILURE(rv))
279 return rv;
280
281 obj = buf.Pointer;
282
283 if (obj->Type != ACPI_TYPE_PACKAGE) {
284 rv = AE_TYPE;
285 goto out;
286 }
287
288 sc->sc_pstate_count = obj->Package.Count;
289
290 if (sc->sc_pstate_count == 0) {
291 rv = AE_NOT_EXIST;
292 goto out;
293 }
294
295 if (sc->sc_pstate_count > ACPICPU_P_STATE_MAX) {
296 rv = AE_LIMIT;
297 goto out;
298 }
299
300 sc->sc_pstate = kmem_zalloc(sc->sc_pstate_count *
301 sizeof(struct acpicpu_pstate), KM_SLEEP);
302
303 if (sc->sc_pstate == NULL) {
304 rv = AE_NO_MEMORY;
305 goto out;
306 }
307
308 for (count = i = 0; i < sc->sc_pstate_count; i++) {
309
310 ps = &sc->sc_pstate[i];
311 rv = acpicpu_pstate_pss_add(ps, &obj->Package.Elements[i]);
312
313 if (ACPI_FAILURE(rv)) {
314 ps->ps_freq = 0;
315 continue;
316 }
317
318 for (j = 0; j < i; j++) {
319
320 if (ps->ps_freq >= sc->sc_pstate[j].ps_freq) {
321 ps->ps_freq = 0;
322 break;
323 }
324 }
325
326 if (ps->ps_freq != 0)
327 count++;
328 }
329
330 rv = (count != 0) ? AE_OK : AE_NOT_EXIST;
331
332 out:
333 if (buf.Pointer != NULL)
334 ACPI_FREE(buf.Pointer);
335
336 return rv;
337 }
338
339 static ACPI_STATUS
340 acpicpu_pstate_pss_add(struct acpicpu_pstate *ps, ACPI_OBJECT *obj)
341 {
342 ACPI_OBJECT *elm;
343 uint32_t val[6];
344 uint32_t *p;
345 int i;
346
347 if (obj->Type != ACPI_TYPE_PACKAGE)
348 return AE_TYPE;
349
350 if (obj->Package.Count != 6)
351 return AE_BAD_DATA;
352
353 elm = obj->Package.Elements;
354
355 for (i = 0; i < 6; i++) {
356
357 if (elm[i].Type != ACPI_TYPE_INTEGER)
358 return AE_TYPE;
359
360 if (elm[i].Integer.Value > UINT32_MAX)
361 return AE_AML_NUMERIC_OVERFLOW;
362
363 val[i] = elm[i].Integer.Value;
364 }
365
366 CTASSERT(sizeof(val) == sizeof(struct acpicpu_pstate) -
367 offsetof(struct acpicpu_pstate, ps_freq));
368
369 p = &ps->ps_freq;
370
371 for (i = 0; i < 6; i++, p++)
372 *p = val[i];
373
374 if (ps->ps_freq == 0 || ps->ps_freq > 9999)
375 return AE_BAD_DECIMAL_CONSTANT;
376
377 /*
378 * The latency is typically around 10 usec
379 * on Intel CPUs. Use that as the minimum.
380 */
381 if (ps->ps_latency < 10)
382 ps->ps_latency = 10;
383
384 return AE_OK;
385 }
386
387 ACPI_STATUS
388 acpicpu_pstate_pct(struct acpicpu_softc *sc)
389 {
390 static const size_t size = sizeof(struct acpicpu_reg);
391 struct acpicpu_reg *reg[2];
392 ACPI_OBJECT *elm, *obj;
393 ACPI_BUFFER buf;
394 ACPI_STATUS rv;
395 uint8_t width;
396 int i;
397
398 rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PCT", &buf);
399
400 if (ACPI_FAILURE(rv))
401 return rv;
402
403 obj = buf.Pointer;
404
405 if (obj->Type != ACPI_TYPE_PACKAGE) {
406 rv = AE_TYPE;
407 goto out;
408 }
409
410 if (obj->Package.Count != 2) {
411 rv = AE_LIMIT;
412 goto out;
413 }
414
415 for (i = 0; i < 2; i++) {
416
417 elm = &obj->Package.Elements[i];
418
419 if (elm->Type != ACPI_TYPE_BUFFER) {
420 rv = AE_TYPE;
421 goto out;
422 }
423
424 if (size > elm->Buffer.Length) {
425 rv = AE_AML_BAD_RESOURCE_LENGTH;
426 goto out;
427 }
428
429 reg[i] = (struct acpicpu_reg *)elm->Buffer.Pointer;
430
431 switch (reg[i]->reg_spaceid) {
432
433 case ACPI_ADR_SPACE_SYSTEM_IO:
434
435 if (reg[i]->reg_addr == 0) {
436 rv = AE_AML_ILLEGAL_ADDRESS;
437 goto out;
438 }
439
440 width = reg[i]->reg_bitwidth;
441
442 if (width + reg[i]->reg_bitoffset > 32) {
443 rv = AE_AML_BAD_RESOURCE_VALUE;
444 goto out;
445 }
446
447 if (width != 8 && width != 16 && width != 32) {
448 rv = AE_AML_BAD_RESOURCE_VALUE;
449 goto out;
450 }
451
452 break;
453
454 case ACPI_ADR_SPACE_FIXED_HARDWARE:
455
456 if ((sc->sc_flags & ACPICPU_FLAG_P_FFH) == 0) {
457 rv = AE_SUPPORT;
458 goto out;
459 }
460
461 break;
462
463 default:
464 rv = AE_AML_INVALID_SPACE_ID;
465 goto out;
466 }
467 }
468
469 if (reg[0]->reg_spaceid != reg[1]->reg_spaceid) {
470 rv = AE_AML_INVALID_SPACE_ID;
471 goto out;
472 }
473
474 (void)memcpy(&sc->sc_pstate_control, reg[0], size);
475 (void)memcpy(&sc->sc_pstate_status, reg[1], size);
476
477 out:
478 if (buf.Pointer != NULL)
479 ACPI_FREE(buf.Pointer);
480
481 return rv;
482 }
483
484 static int
485 acpicpu_pstate_max(struct acpicpu_softc *sc)
486 {
487 ACPI_INTEGER val;
488 ACPI_STATUS rv;
489
490 /*
491 * Evaluate the currently highest P-state that can be used.
492 * If available, we can use either this state or any lower
493 * power (i.e. higher numbered) state from the _PSS object.
494 */
495 rv = acpi_eval_integer(sc->sc_node->ad_handle, "_PPC", &val);
496
497 sc->sc_pstate_max = 0;
498
499 if (ACPI_FAILURE(rv))
500 return 1;
501
502 if (val > sc->sc_pstate_count - 1)
503 return 1;
504
505 if (sc->sc_pstate[val].ps_freq == 0)
506 return 1;
507
508 sc->sc_pstate_max = val;
509
510 return 0;
511 }
512
513 static void
514 acpicpu_pstate_change(struct acpicpu_softc *sc)
515 {
516 ACPI_OBJECT_LIST arg;
517 ACPI_OBJECT obj[2];
518
519 arg.Count = 2;
520 arg.Pointer = obj;
521
522 obj[0].Type = ACPI_TYPE_INTEGER;
523 obj[1].Type = ACPI_TYPE_INTEGER;
524
525 obj[0].Integer.Value = ACPICPU_P_NOTIFY;
526 obj[1].Integer.Value = acpicpu_pstate_max(sc);
527
528 (void)AcpiEvaluateObject(sc->sc_node->ad_handle, "_OST", &arg, NULL);
529 }
530
531 static void
532 acpicpu_pstate_bios(void)
533 {
534 const uint8_t val = AcpiGbl_FADT.PstateControl;
535 const uint32_t addr = AcpiGbl_FADT.SmiCommand;
536
537 if (addr == 0)
538 return;
539
540 (void)AcpiOsWritePort(addr, val, 8);
541 }
542
543 int
544 acpicpu_pstate_get(struct acpicpu_softc *sc, uint32_t *freq)
545 {
546 const uint8_t method = sc->sc_pstate_control.reg_spaceid;
547 struct acpicpu_pstate *ps = NULL;
548 uint32_t i, val = 0;
549 uint64_t addr;
550 uint8_t width;
551 int rv;
552
553 if (sc->sc_cold != false) {
554 rv = EBUSY;
555 goto fail;
556 }
557
558 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0) {
559 rv = ENODEV;
560 goto fail;
561 }
562
563 mutex_enter(&sc->sc_mtx);
564
565 if (sc->sc_pstate_current != ACPICPU_P_STATE_UNKNOWN) {
566 *freq = sc->sc_pstate_current;
567 mutex_exit(&sc->sc_mtx);
568 return 0;
569 }
570
571 mutex_exit(&sc->sc_mtx);
572
573 switch (method) {
574
575 case ACPI_ADR_SPACE_FIXED_HARDWARE:
576
577 rv = acpicpu_md_pstate_get(sc, freq);
578
579 if (rv != 0)
580 goto fail;
581
582 break;
583
584 case ACPI_ADR_SPACE_SYSTEM_IO:
585
586 addr = sc->sc_pstate_status.reg_addr;
587 width = sc->sc_pstate_status.reg_bitwidth;
588
589 (void)AcpiOsReadPort(addr, &val, width);
590
591 if (val == 0) {
592 rv = EIO;
593 goto fail;
594 }
595
596 for (i = 0; i < sc->sc_pstate_count; i++) {
597
598 if (sc->sc_pstate[i].ps_freq == 0)
599 continue;
600
601 if (val == sc->sc_pstate[i].ps_status) {
602 ps = &sc->sc_pstate[i];
603 break;
604 }
605 }
606
607 if (__predict_false(ps == NULL)) {
608 rv = EIO;
609 goto fail;
610 }
611
612 *freq = ps->ps_freq;
613 break;
614
615 default:
616 rv = ENOTTY;
617 goto fail;
618 }
619
620 mutex_enter(&sc->sc_mtx);
621 sc->sc_pstate_current = *freq;
622 mutex_exit(&sc->sc_mtx);
623
624 return 0;
625
626 fail:
627 aprint_error_dev(sc->sc_dev, "failed "
628 "to get frequency (err %d)\n", rv);
629
630 mutex_enter(&sc->sc_mtx);
631 *freq = sc->sc_pstate_current = ACPICPU_P_STATE_UNKNOWN;
632 mutex_exit(&sc->sc_mtx);
633
634 return rv;
635 }
636
637 int
638 acpicpu_pstate_set(struct acpicpu_softc *sc, uint32_t freq)
639 {
640 const uint8_t method = sc->sc_pstate_control.reg_spaceid;
641 struct acpicpu_pstate *ps = NULL;
642 uint32_t i, val;
643 uint64_t addr;
644 uint8_t width;
645 int rv;
646
647 if (sc->sc_cold != false) {
648 rv = EBUSY;
649 goto fail;
650 }
651
652 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0) {
653 rv = ENODEV;
654 goto fail;
655 }
656
657 mutex_enter(&sc->sc_mtx);
658
659 for (i = sc->sc_pstate_max; i < sc->sc_pstate_count; i++) {
660
661 if (sc->sc_pstate[i].ps_freq == 0)
662 continue;
663
664 if (sc->sc_pstate[i].ps_freq == freq) {
665 ps = &sc->sc_pstate[i];
666 break;
667 }
668 }
669
670 mutex_exit(&sc->sc_mtx);
671
672 if (__predict_false(ps == NULL)) {
673 rv = EINVAL;
674 goto fail;
675 }
676
677 switch (method) {
678
679 case ACPI_ADR_SPACE_FIXED_HARDWARE:
680
681 rv = acpicpu_md_pstate_set(ps);
682
683 if (rv != 0)
684 goto fail;
685
686 break;
687
688 case ACPI_ADR_SPACE_SYSTEM_IO:
689
690 addr = sc->sc_pstate_control.reg_addr;
691 width = sc->sc_pstate_control.reg_bitwidth;
692
693 (void)AcpiOsWritePort(addr, ps->ps_control, width);
694
695 addr = sc->sc_pstate_status.reg_addr;
696 width = sc->sc_pstate_status.reg_bitwidth;
697
698 /*
699 * Some systems take longer to respond
700 * than the reported worst-case latency.
701 */
702 for (i = val = 0; i < ACPICPU_P_STATE_RETRY; i++) {
703
704 (void)AcpiOsReadPort(addr, &val, width);
705
706 if (val == ps->ps_status)
707 break;
708
709 DELAY(ps->ps_latency);
710 }
711
712 if (i == ACPICPU_P_STATE_RETRY) {
713 rv = EAGAIN;
714 goto fail;
715 }
716
717 break;
718
719 default:
720 rv = ENOTTY;
721 goto fail;
722 }
723
724 mutex_enter(&sc->sc_mtx);
725 ps->ps_evcnt.ev_count++;
726 sc->sc_pstate_current = freq;
727 mutex_exit(&sc->sc_mtx);
728
729 return 0;
730
731 fail:
732 aprint_error_dev(sc->sc_dev, "failed to set "
733 "frequency to %u (err %d)\n", freq, rv);
734
735 mutex_enter(&sc->sc_mtx);
736 sc->sc_pstate_current = ACPICPU_P_STATE_UNKNOWN;
737 mutex_exit(&sc->sc_mtx);
738
739 return rv;
740 }
741