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