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