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