Home | History | Annotate | Line # | Download | only in acpi
      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 (at) iki.fi>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: acpi_cpu_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
     42 ACPI_MODULE_NAME	 ("acpi_cpu_tstate")
     43 
     44 static ACPI_STATUS	 acpicpu_tstate_tss(struct acpicpu_softc *);
     45 static ACPI_STATUS	 acpicpu_tstate_tss_add(struct acpicpu_tstate *,
     46 						ACPI_OBJECT *);
     47 static ACPI_STATUS	 acpicpu_tstate_ptc(struct acpicpu_softc *);
     48 static ACPI_STATUS	 acpicpu_tstate_dep(struct acpicpu_softc *);
     49 static ACPI_STATUS	 acpicpu_tstate_fadt(struct acpicpu_softc *);
     50 static ACPI_STATUS	 acpicpu_tstate_change(struct acpicpu_softc *);
     51 static void		 acpicpu_tstate_reset(struct acpicpu_softc *);
     52 static void		 acpicpu_tstate_set_xcall(void *, void *);
     53 
     54 extern struct acpicpu_softc **acpicpu_sc;
     55 
     56 void
     57 acpicpu_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 
    104 out:
    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 
    124 void
    125 acpicpu_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 
    141 void
    142 acpicpu_tstate_start(device_t self)
    143 {
    144 	/* Nothing. */
    145 }
    146 
    147 void
    148 acpicpu_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 
    160 void
    161 acpicpu_tstate_resume(void *aux)
    162 {
    163 	/* Nothing. */
    164 }
    165 
    166 void
    167 acpicpu_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 
    218 static ACPI_STATUS
    219 acpicpu_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 
    293 out:
    294 	if (buf.Pointer != NULL)
    295 		ACPI_FREE(buf.Pointer);
    296 
    297 	return rv;
    298 }
    299 
    300 static ACPI_STATUS
    301 acpicpu_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 
    349 ACPI_STATUS
    350 acpicpu_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 
    453 out:
    454 	if (buf.Pointer != NULL)
    455 		ACPI_FREE(buf.Pointer);
    456 
    457 	return rv;
    458 }
    459 
    460 static ACPI_STATUS
    461 acpicpu_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 
    538 out:
    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 
    549 static ACPI_STATUS
    550 acpicpu_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 
    611 static ACPI_STATUS
    612 acpicpu_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 
    650 static void
    651 acpicpu_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 
    658 int
    659 acpicpu_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 
    739 fail:
    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 
    750 void
    751 acpicpu_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 
    759 static void
    760 acpicpu_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 
    864 fail:
    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