1/* $NetBSD: acpi_cpu_tstate.c,v 1.34 2020/12/07 10:57:41 jmcneill Exp $ */
2
3/*-
4 * Copyright (c) 2010 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_tstate.c,v 1.34 2020/12/07 10:57:41 jmcneill Exp $");
31
32#include <sys/param.h>
33#include <sys/kmem.h>
34#include <sys/xcall.h>
35#include <sys/cpu.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_tstate")
43
44static ACPI_STATUS	 acpicpu_tstate_tss(struct acpicpu_softc *);
45static ACPI_STATUS	 acpicpu_tstate_tss_add(struct acpicpu_tstate *,
46						ACPI_OBJECT *);
47static ACPI_STATUS	 acpicpu_tstate_ptc(struct acpicpu_softc *);
48static ACPI_STATUS	 acpicpu_tstate_dep(struct acpicpu_softc *);
49static ACPI_STATUS	 acpicpu_tstate_fadt(struct acpicpu_softc *);
50static ACPI_STATUS	 acpicpu_tstate_change(struct acpicpu_softc *);
51static void		 acpicpu_tstate_reset(struct acpicpu_softc *);
52static void		 acpicpu_tstate_set_xcall(void *, void *);
53
54extern struct acpicpu_softc **acpicpu_sc;
55
56void
57acpicpu_tstate_attach(device_t self)
58{
59	struct acpicpu_softc *sc = device_private(self);
60	const char *str;
61	ACPI_HANDLE tmp;
62	ACPI_STATUS rv;
63
64	/*
65	 * Disable T-states for PIIX4.
66	 */
67	if ((sc->sc_flags & ACPICPU_FLAG_PIIX4) != 0)
68		return;
69
70	rv  = acpicpu_tstate_tss(sc);
71
72	if (ACPI_FAILURE(rv)) {
73		str = "_TSS";
74		goto out;
75	}
76
77	rv = acpicpu_tstate_ptc(sc);
78
79	if (ACPI_FAILURE(rv)) {
80		str = "_PTC";
81		goto out;
82	}
83
84	/*
85	 * Query the optional _TSD.
86	 */
87	rv = acpicpu_tstate_dep(sc);
88
89	if (ACPI_SUCCESS(rv))
90		sc->sc_flags |= ACPICPU_FLAG_T_DEP;
91
92	/*
93	 * Comparable to P-states, the _TPC object may
94	 * be absent in some systems, even though it is
95	 * required by ACPI 3.0 along with _TSS and _PTC.
96	 */
97	rv = AcpiGetHandle(sc->sc_node->ad_handle, "_TPC", &tmp);
98
99	if (ACPI_FAILURE(rv)) {
100		aprint_debug_dev(self, "_TPC missing\n");
101		rv = AE_OK;
102	}
103
104out:
105	if (ACPI_FAILURE(rv)) {
106
107		if (rv != AE_NOT_FOUND)
108			aprint_error_dev(sc->sc_dev, "failed to evaluate "
109			    "%s: %s\n", str, AcpiFormatException(rv));
110
111		rv = acpicpu_tstate_fadt(sc);
112
113		if (ACPI_FAILURE(rv))
114			return;
115
116		sc->sc_flags |= ACPICPU_FLAG_T_FADT;
117	}
118
119	sc->sc_flags |= ACPICPU_FLAG_T;
120
121	acpicpu_tstate_reset(sc);
122}
123
124void
125acpicpu_tstate_detach(device_t self)
126{
127	struct acpicpu_softc *sc = device_private(self);
128	size_t size;
129
130	if ((sc->sc_flags & ACPICPU_FLAG_T) == 0)
131		return;
132
133	size = sc->sc_tstate_count * sizeof(*sc->sc_tstate);
134
135	if (sc->sc_tstate != NULL)
136		kmem_free(sc->sc_tstate, size);
137
138	sc->sc_flags &= ~ACPICPU_FLAG_T;
139}
140
141void
142acpicpu_tstate_start(device_t self)
143{
144	/* Nothing. */
145}
146
147void
148acpicpu_tstate_suspend(void *aux)
149{
150	struct acpicpu_softc *sc;
151	device_t self = aux;
152
153	sc = device_private(self);
154
155	mutex_enter(&sc->sc_mtx);
156	acpicpu_tstate_reset(sc);
157	mutex_exit(&sc->sc_mtx);
158}
159
160void
161acpicpu_tstate_resume(void *aux)
162{
163	/* Nothing. */
164}
165
166void
167acpicpu_tstate_callback(void *aux)
168{
169	struct acpicpu_softc *sc;
170	device_t self = aux;
171	uint32_t omax, omin;
172	int i;
173
174	sc = device_private(self);
175
176	if ((sc->sc_flags & ACPICPU_FLAG_T_FADT) != 0)
177		return;
178
179	mutex_enter(&sc->sc_mtx);
180
181	/*
182	 * If P-states are in use, we should ignore
183	 * the interrupt unless we are in the highest
184	 * P-state (see ACPI 4.0, section 8.4.3.3).
185	 */
186	if ((sc->sc_flags & ACPICPU_FLAG_P) != 0) {
187
188		for (i = sc->sc_pstate_count - 1; i >= 0; i--) {
189
190			if (sc->sc_pstate[i].ps_freq != 0)
191				break;
192		}
193
194		if (sc->sc_pstate_current != sc->sc_pstate[i].ps_freq) {
195			mutex_exit(&sc->sc_mtx);
196			return;
197		}
198	}
199
200	omax = sc->sc_tstate_max;
201	omin = sc->sc_tstate_min;
202
203	(void)acpicpu_tstate_change(sc);
204
205	if (omax != sc->sc_tstate_max || omin != sc->sc_tstate_min) {
206
207		aprint_debug_dev(sc->sc_dev, "throttling window "
208		    "changed from %u-%u %% to %u-%u %%\n",
209		    sc->sc_tstate[omax].ts_percent,
210		    sc->sc_tstate[omin].ts_percent,
211		    sc->sc_tstate[sc->sc_tstate_max].ts_percent,
212		    sc->sc_tstate[sc->sc_tstate_min].ts_percent);
213	}
214
215	mutex_exit(&sc->sc_mtx);
216}
217
218static ACPI_STATUS
219acpicpu_tstate_tss(struct acpicpu_softc *sc)
220{
221	struct acpicpu_tstate *ts;
222	ACPI_OBJECT *obj;
223	ACPI_BUFFER buf;
224	ACPI_STATUS rv;
225	uint32_t count;
226	uint32_t i, j;
227
228	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_TSS", &buf);
229
230	if (ACPI_FAILURE(rv))
231		return rv;
232
233	obj = buf.Pointer;
234
235	if (obj->Type != ACPI_TYPE_PACKAGE) {
236		rv = AE_TYPE;
237		goto out;
238	}
239
240	sc->sc_tstate_count = obj->Package.Count;
241
242	if (sc->sc_tstate_count == 0) {
243		rv = AE_NOT_EXIST;
244		goto out;
245	}
246
247	sc->sc_tstate = kmem_zalloc(sc->sc_tstate_count *
248	    sizeof(struct acpicpu_tstate), KM_SLEEP);
249
250	if (sc->sc_tstate == NULL) {
251		rv = AE_NO_MEMORY;
252		goto out;
253	}
254
255	for (count = i = 0; i < sc->sc_tstate_count; i++) {
256
257		ts = &sc->sc_tstate[i];
258		rv = acpicpu_tstate_tss_add(ts, &obj->Package.Elements[i]);
259
260		if (ACPI_FAILURE(rv)) {
261			ts->ts_percent = 0;
262			continue;
263		}
264
265		for (j = 0; j < i; j++) {
266
267			if (ts->ts_percent >= sc->sc_tstate[j].ts_percent) {
268				ts->ts_percent = 0;
269				break;
270			}
271		}
272
273		if (ts->ts_percent != 0)
274			count++;
275	}
276
277	if (count == 0) {
278		rv = AE_NOT_EXIST;
279		goto out;
280	}
281
282	/*
283	 * There must be an entry with the percent
284	 * field of 100. If this is not true, and if
285	 * this entry is not in the expected index,
286	 * invalidate the use of T-states via _TSS.
287	 */
288	if (sc->sc_tstate[0].ts_percent != 100) {
289		rv = AE_BAD_DECIMAL_CONSTANT;
290		goto out;
291	}
292
293out:
294	if (buf.Pointer != NULL)
295		ACPI_FREE(buf.Pointer);
296
297	return rv;
298}
299
300static ACPI_STATUS
301acpicpu_tstate_tss_add(struct acpicpu_tstate *ts, ACPI_OBJECT *obj)
302{
303	ACPI_OBJECT *elm;
304	uint32_t val[5];
305	uint32_t *p;
306	int i;
307
308	if (obj->Type != ACPI_TYPE_PACKAGE)
309		return AE_TYPE;
310
311	if (obj->Package.Count != 5)
312		return AE_BAD_DATA;
313
314	elm = obj->Package.Elements;
315
316	for (i = 0; i < 5; i++) {
317
318		if (elm[i].Type != ACPI_TYPE_INTEGER)
319			return AE_TYPE;
320
321		if (elm[i].Integer.Value > UINT32_MAX)
322			return AE_AML_NUMERIC_OVERFLOW;
323
324		val[i] = elm[i].Integer.Value;
325	}
326
327	p = &ts->ts_percent;
328
329	for (i = 0; i < 5; i++, p++)
330		*p = val[i];
331
332	/*
333	 * The minimum should be either 12.5 % or 6.5 %,
334	 * the latter 4-bit dynamic range being available
335	 * in some newer models; see Section 14.5.3.1 in
336	 *
337	 *	Intel 64 and IA-32 Architectures Software
338	 *	Developer's Manual. Volume 3B, Part 2. 2013.
339	 */
340        if (ts->ts_percent < 6 || ts->ts_percent > 100)
341		return AE_BAD_DECIMAL_CONSTANT;
342
343	if (ts->ts_latency == 0 || ts->ts_latency > 1000)
344		ts->ts_latency = 1;
345
346	return AE_OK;
347}
348
349ACPI_STATUS
350acpicpu_tstate_ptc(struct acpicpu_softc *sc)
351{
352	static const size_t size = sizeof(struct acpicpu_reg);
353	struct acpicpu_reg *reg[2];
354	ACPI_OBJECT *elm, *obj;
355	ACPI_BUFFER buf;
356	ACPI_STATUS rv;
357	int i;
358
359	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_PTC", &buf);
360
361	if (ACPI_FAILURE(rv))
362		return rv;
363
364	obj = buf.Pointer;
365
366	if (obj->Type != ACPI_TYPE_PACKAGE) {
367		rv = AE_TYPE;
368		goto out;
369	}
370
371	if (obj->Package.Count != 2) {
372		rv = AE_LIMIT;
373		goto out;
374	}
375
376	for (i = 0; i < 2; i++) {
377
378		elm = &obj->Package.Elements[i];
379
380		if (elm->Type != ACPI_TYPE_BUFFER) {
381			rv = AE_TYPE;
382			goto out;
383		}
384
385		if (size > elm->Buffer.Length) {
386			rv = AE_AML_BAD_RESOURCE_LENGTH;
387			goto out;
388		}
389
390		reg[i] = (struct acpicpu_reg *)elm->Buffer.Pointer;
391
392		switch (reg[i]->reg_spaceid) {
393
394		case ACPI_ADR_SPACE_SYSTEM_MEMORY:
395
396			if (reg[i]->reg_addr == 0) {
397				rv = AE_AML_ILLEGAL_ADDRESS;
398				goto out;
399			}
400
401			break;
402
403		case ACPI_ADR_SPACE_SYSTEM_IO:
404
405			if (reg[i]->reg_addr == 0) {
406				rv = AE_AML_ILLEGAL_ADDRESS;
407				goto out;
408			}
409
410#if defined(__i386__) || defined(__x86_64__)
411			/*
412			 * Check that the values match the IA32 clock
413			 * modulation MSR, where the bit 0 is reserved,
414			 * bits 1 through 3 define the duty cycle, and
415			 * the fourth bit enables the modulation.
416			 */
417			if (reg[i]->reg_bitwidth != 4) {
418				rv = AE_AML_BAD_RESOURCE_VALUE;
419				goto out;
420			}
421
422			if (reg[i]->reg_bitoffset != 1) {
423				rv = AE_AML_BAD_RESOURCE_VALUE;
424				goto out;
425			}
426#endif
427
428			break;
429
430		case ACPI_ADR_SPACE_FIXED_HARDWARE:
431
432			if ((sc->sc_flags & ACPICPU_FLAG_T_FFH) == 0) {
433				rv = AE_SUPPORT;
434				goto out;
435			}
436
437			break;
438
439		default:
440			rv = AE_AML_INVALID_SPACE_ID;
441			goto out;
442		}
443	}
444
445	if (reg[0]->reg_spaceid != reg[1]->reg_spaceid) {
446		rv = AE_AML_INVALID_SPACE_ID;
447		goto out;
448	}
449
450	(void)memcpy(&sc->sc_tstate_control, reg[0], size);
451	(void)memcpy(&sc->sc_tstate_status,  reg[1], size);
452
453out:
454	if (buf.Pointer != NULL)
455		ACPI_FREE(buf.Pointer);
456
457	return rv;
458}
459
460static ACPI_STATUS
461acpicpu_tstate_dep(struct acpicpu_softc *sc)
462{
463	ACPI_OBJECT *elm, *obj;
464	ACPI_BUFFER buf;
465	ACPI_STATUS rv;
466	uint32_t val;
467	uint8_t i, n;
468
469	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_TSD", &buf);
470
471	if (ACPI_FAILURE(rv))
472		goto out;
473
474	obj = buf.Pointer;
475
476	if (obj->Type != ACPI_TYPE_PACKAGE) {
477		rv = AE_TYPE;
478		goto out;
479	}
480
481	if (obj->Package.Count != 1) {
482		rv = AE_LIMIT;
483		goto out;
484	}
485
486	elm = &obj->Package.Elements[0];
487
488	if (obj->Type != ACPI_TYPE_PACKAGE) {
489		rv = AE_TYPE;
490		goto out;
491	}
492
493	n = elm->Package.Count;
494
495	if (n != 5) {
496		rv = AE_LIMIT;
497		goto out;
498	}
499
500	elm = elm->Package.Elements;
501
502	for (i = 0; i < n; i++) {
503
504		if (elm[i].Type != ACPI_TYPE_INTEGER) {
505			rv = AE_TYPE;
506			goto out;
507		}
508
509		if (elm[i].Integer.Value > UINT32_MAX) {
510			rv = AE_AML_NUMERIC_OVERFLOW;
511			goto out;
512		}
513	}
514
515	val = elm[1].Integer.Value;
516
517	if (val != 0)
518		aprint_debug_dev(sc->sc_dev, "invalid revision in _TSD\n");
519
520	val = elm[3].Integer.Value;
521
522	if (val < ACPICPU_DEP_SW_ALL || val > ACPICPU_DEP_HW_ALL) {
523		rv = AE_AML_BAD_RESOURCE_VALUE;
524		goto out;
525	}
526
527	val = elm[4].Integer.Value;
528
529	if (val > sc->sc_ncpus) {
530		rv = AE_BAD_VALUE;
531		goto out;
532	}
533
534	sc->sc_tstate_dep.dep_domain = elm[2].Integer.Value;
535	sc->sc_tstate_dep.dep_type   = elm[3].Integer.Value;
536	sc->sc_tstate_dep.dep_ncpus  = elm[4].Integer.Value;
537
538out:
539	if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND)
540		aprint_debug_dev(sc->sc_dev, "failed to evaluate "
541		    "_TSD: %s\n", AcpiFormatException(rv));
542
543	if (buf.Pointer != NULL)
544		ACPI_FREE(buf.Pointer);
545
546	return rv;
547}
548
549static ACPI_STATUS
550acpicpu_tstate_fadt(struct acpicpu_softc *sc)
551{
552	static const size_t size = sizeof(struct acpicpu_tstate);
553	const uint8_t offset = AcpiGbl_FADT.DutyOffset;
554	const uint8_t width = AcpiGbl_FADT.DutyWidth;
555	uint8_t beta, count, i;
556
557	if (sc->sc_object.ao_pblkaddr == 0)
558		return AE_AML_ILLEGAL_ADDRESS;
559
560	/*
561	 * A zero DUTY_WIDTH may be used announce
562	 * that T-states are not available via FADT
563	 * (ACPI 4.0, p. 121). See also (section 9.3):
564	 *
565	 *	Advanced Micro Devices: BIOS and Kernel
566	 *	Developer's Guide for AMD Athlon 64 and
567	 *	AMD Opteron Processors. Revision 3.30,
568	 *	February 2006.
569	 */
570	if (width == 0 || width + offset > 4)
571		return AE_AML_BAD_RESOURCE_VALUE;
572
573	count = 1 << width;
574
575	if (sc->sc_tstate != NULL)
576		kmem_free(sc->sc_tstate, sc->sc_tstate_count * size);
577
578	sc->sc_tstate = kmem_zalloc(count * size, KM_SLEEP);
579	sc->sc_tstate_count = count;
580
581	/*
582	 * Approximate duty cycles and set the MSR values.
583	 */
584	for (beta = 100 / count, i = 0; i < count; i++) {
585		sc->sc_tstate[i].ts_percent = 100 - beta * i;
586		sc->sc_tstate[i].ts_latency = 1;
587	}
588
589	for (i = 1; i < count; i++)
590		sc->sc_tstate[i].ts_control = (count - i) | __BIT(3);
591
592	/*
593	 * Fake values for throttling registers.
594	 */
595	(void)memset(&sc->sc_tstate_status, 0, sizeof(struct acpicpu_reg));
596	(void)memset(&sc->sc_tstate_control, 0, sizeof(struct acpicpu_reg));
597
598	sc->sc_tstate_status.reg_bitwidth = width;
599	sc->sc_tstate_status.reg_bitoffset = offset;
600	sc->sc_tstate_status.reg_addr = sc->sc_object.ao_pblkaddr;
601	sc->sc_tstate_status.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO;
602
603	sc->sc_tstate_control.reg_bitwidth = width;
604	sc->sc_tstate_control.reg_bitoffset = offset;
605	sc->sc_tstate_control.reg_addr = sc->sc_object.ao_pblkaddr;
606	sc->sc_tstate_control.reg_spaceid = ACPI_ADR_SPACE_SYSTEM_IO;
607
608	return AE_OK;
609}
610
611static ACPI_STATUS
612acpicpu_tstate_change(struct acpicpu_softc *sc)
613{
614	ACPI_INTEGER val;
615	ACPI_STATUS rv;
616
617	acpicpu_tstate_reset(sc);
618
619	/*
620	 * Evaluate the available T-state window:
621	 *
622	 *   _TPC : either this maximum or any lower power
623	 *          (i.e. higher numbered) state may be used.
624	 *
625	 *   _TDL : either this minimum or any higher power
626	 *	    (i.e. lower numbered) state may be used.
627	 *
628	 *   _TDL >= _TPC || _TDL >= _TSS[last entry].
629	 */
630	rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TPC", &val);
631
632	if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) {
633
634		if (sc->sc_tstate[val].ts_percent != 0)
635			sc->sc_tstate_max = val;
636	}
637
638	rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TDL", &val);
639
640	if (ACPI_SUCCESS(rv) && val < sc->sc_tstate_count) {
641
642		if (val >= sc->sc_tstate_max &&
643		    sc->sc_tstate[val].ts_percent != 0)
644			sc->sc_tstate_min = val;
645	}
646
647	return AE_OK;
648}
649
650static void
651acpicpu_tstate_reset(struct acpicpu_softc *sc)
652{
653
654	sc->sc_tstate_max = 0;
655	sc->sc_tstate_min = sc->sc_tstate_count - 1;
656}
657
658int
659acpicpu_tstate_get(struct cpu_info *ci, uint32_t *percent)
660{
661	struct acpicpu_tstate *ts = NULL;
662	struct acpicpu_softc *sc;
663	uint32_t i, val = 0;
664	int rv;
665
666	sc = acpicpu_sc[ci->ci_acpiid];
667
668	if (__predict_false(sc == NULL)) {
669		rv = ENXIO;
670		goto fail;
671	}
672
673	if (__predict_false(sc->sc_cold != false)) {
674		rv = EBUSY;
675		goto fail;
676	}
677
678	if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) {
679		rv = ENODEV;
680		goto fail;
681	}
682
683	mutex_enter(&sc->sc_mtx);
684
685	if (sc->sc_tstate_current != ACPICPU_T_STATE_UNKNOWN) {
686		*percent = sc->sc_tstate_current;
687		mutex_exit(&sc->sc_mtx);
688		return 0;
689	}
690
691	mutex_exit(&sc->sc_mtx);
692
693	switch (sc->sc_tstate_status.reg_spaceid) {
694
695	case ACPI_ADR_SPACE_FIXED_HARDWARE:
696
697		rv = acpicpu_md_tstate_get(sc, percent);
698
699		if (__predict_false(rv != 0))
700			goto fail;
701
702		break;
703
704	case ACPI_ADR_SPACE_SYSTEM_IO:
705	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
706
707		val = acpicpu_readreg(&sc->sc_tstate_status);
708
709		for (i = 0; i < sc->sc_tstate_count; i++) {
710
711			if (sc->sc_tstate[i].ts_percent == 0)
712				continue;
713
714			if (val == sc->sc_tstate[i].ts_status) {
715				ts = &sc->sc_tstate[i];
716				break;
717			}
718		}
719
720		if (ts == NULL) {
721			rv = EIO;
722			goto fail;
723		}
724
725		*percent = ts->ts_percent;
726		break;
727
728	default:
729		rv = ENOTTY;
730		goto fail;
731	}
732
733	mutex_enter(&sc->sc_mtx);
734	sc->sc_tstate_current = *percent;
735	mutex_exit(&sc->sc_mtx);
736
737	return 0;
738
739fail:
740	aprint_error_dev(sc->sc_dev, "failed "
741	    "to get T-state (err %d)\n", rv);
742
743	mutex_enter(&sc->sc_mtx);
744	*percent = sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN;
745	mutex_exit(&sc->sc_mtx);
746
747	return rv;
748}
749
750void
751acpicpu_tstate_set(struct cpu_info *ci, uint32_t percent)
752{
753	uint64_t xc;
754
755	xc = xc_broadcast(0, acpicpu_tstate_set_xcall, &percent, NULL);
756	xc_wait(xc);
757}
758
759static void
760acpicpu_tstate_set_xcall(void *arg1, void *arg2)
761{
762	struct acpicpu_tstate *ts = NULL;
763	struct cpu_info *ci = curcpu();
764	struct acpicpu_softc *sc;
765	uint32_t i, percent, val;
766	int rv;
767
768	percent = *(uint32_t *)arg1;
769	sc = acpicpu_sc[ci->ci_acpiid];
770
771	if (__predict_false(sc == NULL)) {
772		rv = ENXIO;
773		goto fail;
774	}
775
776	if (__predict_false(sc->sc_cold != false)) {
777		rv = EBUSY;
778		goto fail;
779	}
780
781	if (__predict_false((sc->sc_flags & ACPICPU_FLAG_T) == 0)) {
782		rv = ENODEV;
783		goto fail;
784	}
785
786	mutex_enter(&sc->sc_mtx);
787
788	if (sc->sc_tstate_current == percent) {
789		mutex_exit(&sc->sc_mtx);
790		return;
791	}
792
793	for (i = sc->sc_tstate_max; i <= sc->sc_tstate_min; i++) {
794
795		if (__predict_false(sc->sc_tstate[i].ts_percent == 0))
796			continue;
797
798		if (sc->sc_tstate[i].ts_percent == percent) {
799			ts = &sc->sc_tstate[i];
800			break;
801		}
802	}
803
804	mutex_exit(&sc->sc_mtx);
805
806	if (__predict_false(ts == NULL)) {
807		rv = EINVAL;
808		goto fail;
809	}
810
811	switch (sc->sc_tstate_control.reg_spaceid) {
812
813	case ACPI_ADR_SPACE_FIXED_HARDWARE:
814
815		rv = acpicpu_md_tstate_set(ts);
816
817		if (__predict_false(rv != 0))
818			goto fail;
819
820		break;
821
822	case ACPI_ADR_SPACE_SYSTEM_IO:
823	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
824
825		acpicpu_writereg(&sc->sc_tstate_control, ts->ts_control);
826
827		/*
828		 * If the status field is zero, the transition is
829		 * specified to be "asynchronous" and there is no
830		 * need to check the status (ACPI 4.0, 8.4.3.2).
831		 */
832		if (ts->ts_status == 0)
833			break;
834
835		for (i = 0; i < ACPICPU_T_STATE_RETRY; i++) {
836
837			val = acpicpu_readreg(&sc->sc_tstate_status);
838
839			if (val == ts->ts_status)
840				break;
841
842			DELAY(ts->ts_latency);
843		}
844
845		if (i == ACPICPU_T_STATE_RETRY) {
846			rv = EAGAIN;
847			goto fail;
848		}
849
850		break;
851
852	default:
853		rv = ENOTTY;
854		goto fail;
855	}
856
857	mutex_enter(&sc->sc_mtx);
858	ts->ts_evcnt.ev_count++;
859	sc->sc_tstate_current = percent;
860	mutex_exit(&sc->sc_mtx);
861
862	return;
863
864fail:
865	if (rv != EINVAL)
866		aprint_error_dev(sc->sc_dev, "failed to "
867		    "throttle to %u %% (err %d)\n", percent, rv);
868
869	mutex_enter(&sc->sc_mtx);
870	sc->sc_tstate_current = ACPICPU_T_STATE_UNKNOWN;
871	mutex_exit(&sc->sc_mtx);
872}
873