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