xref: /onnv-gate/usr/src/uts/i86pc/os/cpupm/cpu_acpi.c (revision 8983:981f8c40440c)
18906SEric.Saxe@Sun.COM /*
28906SEric.Saxe@Sun.COM  * CDDL HEADER START
38906SEric.Saxe@Sun.COM  *
48906SEric.Saxe@Sun.COM  * The contents of this file are subject to the terms of the
58906SEric.Saxe@Sun.COM  * Common Development and Distribution License (the "License").
68906SEric.Saxe@Sun.COM  * You may not use this file except in compliance with the License.
78906SEric.Saxe@Sun.COM  *
88906SEric.Saxe@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98906SEric.Saxe@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108906SEric.Saxe@Sun.COM  * See the License for the specific language governing permissions
118906SEric.Saxe@Sun.COM  * and limitations under the License.
128906SEric.Saxe@Sun.COM  *
138906SEric.Saxe@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148906SEric.Saxe@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158906SEric.Saxe@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168906SEric.Saxe@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178906SEric.Saxe@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188906SEric.Saxe@Sun.COM  *
198906SEric.Saxe@Sun.COM  * CDDL HEADER END
208906SEric.Saxe@Sun.COM  */
218906SEric.Saxe@Sun.COM /*
228906SEric.Saxe@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
238906SEric.Saxe@Sun.COM  * Use is subject to license terms.
248906SEric.Saxe@Sun.COM  */
258906SEric.Saxe@Sun.COM 
268906SEric.Saxe@Sun.COM #include <sys/cpu_acpi.h>
27*8983SBill.Holler@Sun.COM #include <sys/cpu_idle.h>
288906SEric.Saxe@Sun.COM 
298906SEric.Saxe@Sun.COM /*
308906SEric.Saxe@Sun.COM  * List of the processor ACPI object types that are being used.
318906SEric.Saxe@Sun.COM  */
328906SEric.Saxe@Sun.COM typedef enum cpu_acpi_obj {
338906SEric.Saxe@Sun.COM 	PDC_OBJ = 0,
348906SEric.Saxe@Sun.COM 	PCT_OBJ,
358906SEric.Saxe@Sun.COM 	PSS_OBJ,
368906SEric.Saxe@Sun.COM 	PSD_OBJ,
378906SEric.Saxe@Sun.COM 	PPC_OBJ,
388906SEric.Saxe@Sun.COM 	PTC_OBJ,
398906SEric.Saxe@Sun.COM 	TSS_OBJ,
408906SEric.Saxe@Sun.COM 	TSD_OBJ,
418906SEric.Saxe@Sun.COM 	TPC_OBJ,
428906SEric.Saxe@Sun.COM 	CSD_OBJ,
438906SEric.Saxe@Sun.COM } cpu_acpi_obj_t;
448906SEric.Saxe@Sun.COM 
458906SEric.Saxe@Sun.COM /*
468906SEric.Saxe@Sun.COM  * Container to store object name.
478906SEric.Saxe@Sun.COM  * Other attributes can be added in the future as necessary.
488906SEric.Saxe@Sun.COM  */
498906SEric.Saxe@Sun.COM typedef struct cpu_acpi_obj_attr {
508906SEric.Saxe@Sun.COM 	char *name;
518906SEric.Saxe@Sun.COM } cpu_acpi_obj_attr_t;
528906SEric.Saxe@Sun.COM 
538906SEric.Saxe@Sun.COM /*
548906SEric.Saxe@Sun.COM  * List of object attributes.
558906SEric.Saxe@Sun.COM  * NOTE: Please keep the ordering of the list as same as cpu_acpi_obj_t.
568906SEric.Saxe@Sun.COM  */
578906SEric.Saxe@Sun.COM static cpu_acpi_obj_attr_t cpu_acpi_obj_attrs[] = {
588906SEric.Saxe@Sun.COM 	{"_PDC"},
598906SEric.Saxe@Sun.COM 	{"_PCT"},
608906SEric.Saxe@Sun.COM 	{"_PSS"},
618906SEric.Saxe@Sun.COM 	{"_PSD"},
628906SEric.Saxe@Sun.COM 	{"_PPC"},
638906SEric.Saxe@Sun.COM 	{"_PTC"},
648906SEric.Saxe@Sun.COM 	{"_TSS"},
658906SEric.Saxe@Sun.COM 	{"_TSD"},
668906SEric.Saxe@Sun.COM 	{"_TPC"},
678906SEric.Saxe@Sun.COM 	{"_CSD"}
688906SEric.Saxe@Sun.COM };
698906SEric.Saxe@Sun.COM 
708906SEric.Saxe@Sun.COM /*
718906SEric.Saxe@Sun.COM  * Cache the ACPI CPU control data objects.
728906SEric.Saxe@Sun.COM  */
738906SEric.Saxe@Sun.COM static int
748906SEric.Saxe@Sun.COM cpu_acpi_cache_ctrl_regs(cpu_acpi_handle_t handle, cpu_acpi_obj_t objtype,
758906SEric.Saxe@Sun.COM     cpu_acpi_ctrl_regs_t *regs)
768906SEric.Saxe@Sun.COM {
778906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
788906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj;
798906SEric.Saxe@Sun.COM 	AML_RESOURCE_GENERIC_REGISTER *greg;
808906SEric.Saxe@Sun.COM 	int ret = -1;
818906SEric.Saxe@Sun.COM 	int i;
828906SEric.Saxe@Sun.COM 
838906SEric.Saxe@Sun.COM 	/*
848906SEric.Saxe@Sun.COM 	 * Fetch the control registers (if present) for the CPU node.
858906SEric.Saxe@Sun.COM 	 * Since they are optional, non-existence is not a failure
868906SEric.Saxe@Sun.COM 	 * (we just consider it a fixed hardware case).
878906SEric.Saxe@Sun.COM 	 */
888906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
898906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
908906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle->cs_handle,
918906SEric.Saxe@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf,
928906SEric.Saxe@Sun.COM 	    ACPI_TYPE_PACKAGE))) {
938906SEric.Saxe@Sun.COM 		regs[0].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
948906SEric.Saxe@Sun.COM 		regs[1].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
958906SEric.Saxe@Sun.COM 		return (1);
968906SEric.Saxe@Sun.COM 	}
978906SEric.Saxe@Sun.COM 
988906SEric.Saxe@Sun.COM 	obj = abuf.Pointer;
998906SEric.Saxe@Sun.COM 	if (obj->Package.Count != 2) {
1008906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: %s package bad count %d.",
1018906SEric.Saxe@Sun.COM 		    cpu_acpi_obj_attrs[objtype].name, obj->Package.Count);
1028906SEric.Saxe@Sun.COM 		goto out;
1038906SEric.Saxe@Sun.COM 	}
1048906SEric.Saxe@Sun.COM 
1058906SEric.Saxe@Sun.COM 	/*
1068906SEric.Saxe@Sun.COM 	 * Does the package look coherent?
1078906SEric.Saxe@Sun.COM 	 */
1088906SEric.Saxe@Sun.COM 	for (i = 0; i < obj->Package.Count; i++) {
1098906SEric.Saxe@Sun.COM 		if (obj->Package.Elements[i].Type != ACPI_TYPE_BUFFER) {
1108906SEric.Saxe@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: "
1118906SEric.Saxe@Sun.COM 			    "Unexpected data in %s package.",
1128906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
1138906SEric.Saxe@Sun.COM 			goto out;
1148906SEric.Saxe@Sun.COM 		}
1158906SEric.Saxe@Sun.COM 
1168906SEric.Saxe@Sun.COM 		greg = (AML_RESOURCE_GENERIC_REGISTER *)
1178906SEric.Saxe@Sun.COM 		    obj->Package.Elements[i].Buffer.Pointer;
1188906SEric.Saxe@Sun.COM 		if (greg->DescriptorType !=
1198906SEric.Saxe@Sun.COM 		    ACPI_RESOURCE_NAME_GENERIC_REGISTER) {
1208906SEric.Saxe@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: "
1218906SEric.Saxe@Sun.COM 			    "%s package has format error.",
1228906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
1238906SEric.Saxe@Sun.COM 			goto out;
1248906SEric.Saxe@Sun.COM 		}
1258906SEric.Saxe@Sun.COM 		if (greg->ResourceLength !=
1268906SEric.Saxe@Sun.COM 		    ACPI_AML_SIZE_LARGE(AML_RESOURCE_GENERIC_REGISTER)) {
1278906SEric.Saxe@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: "
1288906SEric.Saxe@Sun.COM 			    "%s package not right size.",
1298906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
1308906SEric.Saxe@Sun.COM 			goto out;
1318906SEric.Saxe@Sun.COM 		}
1328906SEric.Saxe@Sun.COM 		if (greg->AddressSpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE &&
1338906SEric.Saxe@Sun.COM 		    greg->AddressSpaceId != ACPI_ADR_SPACE_SYSTEM_IO) {
1348906SEric.Saxe@Sun.COM 			cmn_err(CE_NOTE, "!cpu_apci: %s contains unsupported "
1358906SEric.Saxe@Sun.COM 			    "address space type %x",
1368906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name,
1378906SEric.Saxe@Sun.COM 			    greg->AddressSpaceId);
1388906SEric.Saxe@Sun.COM 			goto out;
1398906SEric.Saxe@Sun.COM 		}
1408906SEric.Saxe@Sun.COM 	}
1418906SEric.Saxe@Sun.COM 
1428906SEric.Saxe@Sun.COM 	/*
1438906SEric.Saxe@Sun.COM 	 * Looks good!
1448906SEric.Saxe@Sun.COM 	 */
1458906SEric.Saxe@Sun.COM 	for (i = 0; i < obj->Package.Count; i++) {
1468906SEric.Saxe@Sun.COM 		greg = (AML_RESOURCE_GENERIC_REGISTER *)
1478906SEric.Saxe@Sun.COM 		    obj->Package.Elements[i].Buffer.Pointer;
1488906SEric.Saxe@Sun.COM 		regs[i].cr_addrspace_id = greg->AddressSpaceId;
1498906SEric.Saxe@Sun.COM 		regs[i].cr_width = greg->BitWidth;
1508906SEric.Saxe@Sun.COM 		regs[i].cr_offset = greg->BitOffset;
1518906SEric.Saxe@Sun.COM 		regs[i].cr_asize = greg->AccessSize;
1528906SEric.Saxe@Sun.COM 		regs[i].cr_address = greg->Address;
1538906SEric.Saxe@Sun.COM 	}
1548906SEric.Saxe@Sun.COM 	ret = 0;
1558906SEric.Saxe@Sun.COM out:
1568906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
1578906SEric.Saxe@Sun.COM 	return (ret);
1588906SEric.Saxe@Sun.COM }
1598906SEric.Saxe@Sun.COM 
1608906SEric.Saxe@Sun.COM /*
1618906SEric.Saxe@Sun.COM  * Cache the ACPI _PCT data. The _PCT data defines the interface to use
1628906SEric.Saxe@Sun.COM  * when making power level transitions (i.e., system IO ports, fixed
1638906SEric.Saxe@Sun.COM  * hardware port, etc).
1648906SEric.Saxe@Sun.COM  */
1658906SEric.Saxe@Sun.COM static int
1668906SEric.Saxe@Sun.COM cpu_acpi_cache_pct(cpu_acpi_handle_t handle)
1678906SEric.Saxe@Sun.COM {
1688906SEric.Saxe@Sun.COM 	cpu_acpi_pct_t *pct;
1698906SEric.Saxe@Sun.COM 	int ret;
1708906SEric.Saxe@Sun.COM 
1718906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PCT_CACHED);
1728906SEric.Saxe@Sun.COM 	pct = &CPU_ACPI_PCT(handle)[0];
1738906SEric.Saxe@Sun.COM 	if ((ret = cpu_acpi_cache_ctrl_regs(handle, PCT_OBJ, pct)) == 0)
1748906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PCT_CACHED);
1758906SEric.Saxe@Sun.COM 	return (ret);
1768906SEric.Saxe@Sun.COM }
1778906SEric.Saxe@Sun.COM 
1788906SEric.Saxe@Sun.COM /*
1798906SEric.Saxe@Sun.COM  * Cache the ACPI _PTC data. The _PTC data defines the interface to use
1808906SEric.Saxe@Sun.COM  * when making T-state transitions (i.e., system IO ports, fixed
1818906SEric.Saxe@Sun.COM  * hardware port, etc).
1828906SEric.Saxe@Sun.COM  */
1838906SEric.Saxe@Sun.COM static int
1848906SEric.Saxe@Sun.COM cpu_acpi_cache_ptc(cpu_acpi_handle_t handle)
1858906SEric.Saxe@Sun.COM {
1868906SEric.Saxe@Sun.COM 	cpu_acpi_ptc_t *ptc;
1878906SEric.Saxe@Sun.COM 	int ret;
1888906SEric.Saxe@Sun.COM 
1898906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PTC_CACHED);
1908906SEric.Saxe@Sun.COM 	ptc = &CPU_ACPI_PTC(handle)[0];
1918906SEric.Saxe@Sun.COM 	if ((ret = cpu_acpi_cache_ctrl_regs(handle, PTC_OBJ, ptc)) == 0)
1928906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PTC_CACHED);
1938906SEric.Saxe@Sun.COM 	return (ret);
1948906SEric.Saxe@Sun.COM }
1958906SEric.Saxe@Sun.COM 
1968906SEric.Saxe@Sun.COM /*
1978906SEric.Saxe@Sun.COM  * Cache the ACPI CPU state dependency data objects.
1988906SEric.Saxe@Sun.COM  */
1998906SEric.Saxe@Sun.COM static int
2008906SEric.Saxe@Sun.COM cpu_acpi_cache_state_dependencies(cpu_acpi_handle_t handle,
2018906SEric.Saxe@Sun.COM     cpu_acpi_obj_t objtype, cpu_acpi_state_dependency_t *sd)
2028906SEric.Saxe@Sun.COM {
2038906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
2048906SEric.Saxe@Sun.COM 	ACPI_OBJECT *pkg, *elements;
2058906SEric.Saxe@Sun.COM 	int number;
2068906SEric.Saxe@Sun.COM 	int ret = -1;
2078906SEric.Saxe@Sun.COM 
2088906SEric.Saxe@Sun.COM 	if (objtype == CSD_OBJ) {
2098906SEric.Saxe@Sun.COM 		number = 6;
2108906SEric.Saxe@Sun.COM 	} else {
2118906SEric.Saxe@Sun.COM 		number = 5;
2128906SEric.Saxe@Sun.COM 	}
2138906SEric.Saxe@Sun.COM 	/*
2148906SEric.Saxe@Sun.COM 	 * Fetch the dependencies (if present) for the CPU node.
2158906SEric.Saxe@Sun.COM 	 * Since they are optional, non-existence is not a failure
2168906SEric.Saxe@Sun.COM 	 * (it's up to the caller to determine how to handle non-existence).
2178906SEric.Saxe@Sun.COM 	 */
2188906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
2198906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
2208906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle->cs_handle,
2218906SEric.Saxe@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf,
2228906SEric.Saxe@Sun.COM 	    ACPI_TYPE_PACKAGE))) {
2238906SEric.Saxe@Sun.COM 		return (1);
2248906SEric.Saxe@Sun.COM 	}
2258906SEric.Saxe@Sun.COM 
2268906SEric.Saxe@Sun.COM 	pkg = abuf.Pointer;
2278906SEric.Saxe@Sun.COM 
2288906SEric.Saxe@Sun.COM 	if (((objtype != CSD_OBJ) && (pkg->Package.Count != 1)) ||
2298906SEric.Saxe@Sun.COM 	    ((objtype == CSD_OBJ) && (pkg->Package.Count != 1) &&
2308906SEric.Saxe@Sun.COM 	    (pkg->Package.Count != 2))) {
2318906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: %s unsupported package "
2328906SEric.Saxe@Sun.COM 		    "count %d.", cpu_acpi_obj_attrs[objtype].name,
2338906SEric.Saxe@Sun.COM 		    pkg->Package.Count);
2348906SEric.Saxe@Sun.COM 		goto out;
2358906SEric.Saxe@Sun.COM 	}
2368906SEric.Saxe@Sun.COM 
2378906SEric.Saxe@Sun.COM 	/*
2388906SEric.Saxe@Sun.COM 	 * For C-state domain, we assume C2 and C3 have the same
2398906SEric.Saxe@Sun.COM 	 * domain information
2408906SEric.Saxe@Sun.COM 	 */
2418906SEric.Saxe@Sun.COM 	if (pkg->Package.Elements[0].Type != ACPI_TYPE_PACKAGE ||
2428906SEric.Saxe@Sun.COM 	    pkg->Package.Elements[0].Package.Count != number) {
2438906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in %s package.",
2448906SEric.Saxe@Sun.COM 		    cpu_acpi_obj_attrs[objtype].name);
2458906SEric.Saxe@Sun.COM 		goto out;
2468906SEric.Saxe@Sun.COM 	}
2478906SEric.Saxe@Sun.COM 	elements = pkg->Package.Elements[0].Package.Elements;
2488906SEric.Saxe@Sun.COM 	if (elements[0].Integer.Value != number ||
2498906SEric.Saxe@Sun.COM 	    elements[1].Integer.Value != 0) {
2508906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unexpected %s revision.",
2518906SEric.Saxe@Sun.COM 		    cpu_acpi_obj_attrs[objtype].name);
2528906SEric.Saxe@Sun.COM 		goto out;
2538906SEric.Saxe@Sun.COM 	}
2548906SEric.Saxe@Sun.COM 
2558906SEric.Saxe@Sun.COM 	sd->sd_entries = elements[0].Integer.Value;
2568906SEric.Saxe@Sun.COM 	sd->sd_revision = elements[1].Integer.Value;
2578906SEric.Saxe@Sun.COM 	sd->sd_domain = elements[2].Integer.Value;
2588906SEric.Saxe@Sun.COM 	sd->sd_type = elements[3].Integer.Value;
2598906SEric.Saxe@Sun.COM 	sd->sd_num = elements[4].Integer.Value;
2608906SEric.Saxe@Sun.COM 	if (objtype == CSD_OBJ) {
2618906SEric.Saxe@Sun.COM 		sd->sd_index = elements[5].Integer.Value;
2628906SEric.Saxe@Sun.COM 	}
2638906SEric.Saxe@Sun.COM 
2648906SEric.Saxe@Sun.COM 	ret = 0;
2658906SEric.Saxe@Sun.COM out:
2668906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
2678906SEric.Saxe@Sun.COM 	return (ret);
2688906SEric.Saxe@Sun.COM }
2698906SEric.Saxe@Sun.COM 
2708906SEric.Saxe@Sun.COM /*
2718906SEric.Saxe@Sun.COM  * Cache the ACPI _PSD data. The _PSD data defines P-state CPU dependencies
2728906SEric.Saxe@Sun.COM  * (think CPU domains).
2738906SEric.Saxe@Sun.COM  */
2748906SEric.Saxe@Sun.COM static int
2758906SEric.Saxe@Sun.COM cpu_acpi_cache_psd(cpu_acpi_handle_t handle)
2768906SEric.Saxe@Sun.COM {
2778906SEric.Saxe@Sun.COM 	cpu_acpi_psd_t *psd;
2788906SEric.Saxe@Sun.COM 	int ret;
2798906SEric.Saxe@Sun.COM 
2808906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSD_CACHED);
2818906SEric.Saxe@Sun.COM 	psd = &CPU_ACPI_PSD(handle);
2828906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_state_dependencies(handle, PSD_OBJ, psd);
2838906SEric.Saxe@Sun.COM 	if (ret == 0)
2848906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSD_CACHED);
2858906SEric.Saxe@Sun.COM 	return (ret);
2868906SEric.Saxe@Sun.COM 
2878906SEric.Saxe@Sun.COM }
2888906SEric.Saxe@Sun.COM 
2898906SEric.Saxe@Sun.COM /*
2908906SEric.Saxe@Sun.COM  * Cache the ACPI _TSD data. The _TSD data defines T-state CPU dependencies
2918906SEric.Saxe@Sun.COM  * (think CPU domains).
2928906SEric.Saxe@Sun.COM  */
2938906SEric.Saxe@Sun.COM static int
2948906SEric.Saxe@Sun.COM cpu_acpi_cache_tsd(cpu_acpi_handle_t handle)
2958906SEric.Saxe@Sun.COM {
2968906SEric.Saxe@Sun.COM 	cpu_acpi_tsd_t *tsd;
2978906SEric.Saxe@Sun.COM 	int ret;
2988906SEric.Saxe@Sun.COM 
2998906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSD_CACHED);
3008906SEric.Saxe@Sun.COM 	tsd = &CPU_ACPI_TSD(handle);
3018906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_state_dependencies(handle, TSD_OBJ, tsd);
3028906SEric.Saxe@Sun.COM 	if (ret == 0)
3038906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSD_CACHED);
3048906SEric.Saxe@Sun.COM 	return (ret);
3058906SEric.Saxe@Sun.COM 
3068906SEric.Saxe@Sun.COM }
3078906SEric.Saxe@Sun.COM 
3088906SEric.Saxe@Sun.COM /*
3098906SEric.Saxe@Sun.COM  * Cache the ACPI _CSD data. The _CSD data defines C-state CPU dependencies
3108906SEric.Saxe@Sun.COM  * (think CPU domains).
3118906SEric.Saxe@Sun.COM  */
3128906SEric.Saxe@Sun.COM static int
3138906SEric.Saxe@Sun.COM cpu_acpi_cache_csd(cpu_acpi_handle_t handle)
3148906SEric.Saxe@Sun.COM {
3158906SEric.Saxe@Sun.COM 	cpu_acpi_csd_t *csd;
3168906SEric.Saxe@Sun.COM 	int ret;
3178906SEric.Saxe@Sun.COM 
3188906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CSD_CACHED);
3198906SEric.Saxe@Sun.COM 	csd = &CPU_ACPI_CSD(handle);
3208906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_state_dependencies(handle, CSD_OBJ, csd);
3218906SEric.Saxe@Sun.COM 	if (ret == 0)
3228906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CSD_CACHED);
3238906SEric.Saxe@Sun.COM 	return (ret);
3248906SEric.Saxe@Sun.COM 
3258906SEric.Saxe@Sun.COM }
3268906SEric.Saxe@Sun.COM 
3278906SEric.Saxe@Sun.COM static void
3288906SEric.Saxe@Sun.COM cpu_acpi_cache_pstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
3298906SEric.Saxe@Sun.COM {
3308906SEric.Saxe@Sun.COM 	cpu_acpi_pstate_t *pstate;
3318906SEric.Saxe@Sun.COM 	ACPI_OBJECT *q, *l;
3328906SEric.Saxe@Sun.COM 	int i, j;
3338906SEric.Saxe@Sun.COM 
3348906SEric.Saxe@Sun.COM 	CPU_ACPI_PSTATES_COUNT(handle) = cnt;
3358906SEric.Saxe@Sun.COM 	CPU_ACPI_PSTATES(handle) = kmem_zalloc(CPU_ACPI_PSTATES_SIZE(cnt),
3368906SEric.Saxe@Sun.COM 	    KM_SLEEP);
3378906SEric.Saxe@Sun.COM 	pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
3388906SEric.Saxe@Sun.COM 	for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
3398906SEric.Saxe@Sun.COM 		uint32_t *up;
3408906SEric.Saxe@Sun.COM 
3418906SEric.Saxe@Sun.COM 		q = obj->Package.Elements[i].Package.Elements;
3428906SEric.Saxe@Sun.COM 
3438906SEric.Saxe@Sun.COM 		/*
3448906SEric.Saxe@Sun.COM 		 * Skip duplicate entries.
3458906SEric.Saxe@Sun.COM 		 */
3468906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
3478906SEric.Saxe@Sun.COM 			continue;
3488906SEric.Saxe@Sun.COM 
3498906SEric.Saxe@Sun.COM 		up = (uint32_t *)pstate;
3508906SEric.Saxe@Sun.COM 		for (j = 0; j < CPU_ACPI_PSS_CNT; j++)
3518906SEric.Saxe@Sun.COM 			up[j] = q[j].Integer.Value;
3528906SEric.Saxe@Sun.COM 		pstate++;
3538906SEric.Saxe@Sun.COM 		cnt--;
3548906SEric.Saxe@Sun.COM 	}
3558906SEric.Saxe@Sun.COM }
3568906SEric.Saxe@Sun.COM 
3578906SEric.Saxe@Sun.COM static void
3588906SEric.Saxe@Sun.COM cpu_acpi_cache_tstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
3598906SEric.Saxe@Sun.COM {
3608906SEric.Saxe@Sun.COM 	cpu_acpi_tstate_t *tstate;
3618906SEric.Saxe@Sun.COM 	ACPI_OBJECT *q, *l;
3628906SEric.Saxe@Sun.COM 	int i, j;
3638906SEric.Saxe@Sun.COM 
3648906SEric.Saxe@Sun.COM 	CPU_ACPI_TSTATES_COUNT(handle) = cnt;
3658906SEric.Saxe@Sun.COM 	CPU_ACPI_TSTATES(handle) = kmem_zalloc(CPU_ACPI_TSTATES_SIZE(cnt),
3668906SEric.Saxe@Sun.COM 	    KM_SLEEP);
3678906SEric.Saxe@Sun.COM 	tstate = (cpu_acpi_tstate_t *)CPU_ACPI_TSTATES(handle);
3688906SEric.Saxe@Sun.COM 	for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
3698906SEric.Saxe@Sun.COM 		uint32_t *up;
3708906SEric.Saxe@Sun.COM 
3718906SEric.Saxe@Sun.COM 		q = obj->Package.Elements[i].Package.Elements;
3728906SEric.Saxe@Sun.COM 
3738906SEric.Saxe@Sun.COM 		/*
3748906SEric.Saxe@Sun.COM 		 * Skip duplicate entries.
3758906SEric.Saxe@Sun.COM 		 */
3768906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
3778906SEric.Saxe@Sun.COM 			continue;
3788906SEric.Saxe@Sun.COM 
3798906SEric.Saxe@Sun.COM 		up = (uint32_t *)tstate;
3808906SEric.Saxe@Sun.COM 		for (j = 0; j < CPU_ACPI_TSS_CNT; j++)
3818906SEric.Saxe@Sun.COM 			up[j] = q[j].Integer.Value;
3828906SEric.Saxe@Sun.COM 		tstate++;
3838906SEric.Saxe@Sun.COM 		cnt--;
3848906SEric.Saxe@Sun.COM 	}
3858906SEric.Saxe@Sun.COM }
3868906SEric.Saxe@Sun.COM 
3878906SEric.Saxe@Sun.COM /*
3888906SEric.Saxe@Sun.COM  * Cache the _PSS or _TSS data.
3898906SEric.Saxe@Sun.COM  */
3908906SEric.Saxe@Sun.COM static int
3918906SEric.Saxe@Sun.COM cpu_acpi_cache_supported_states(cpu_acpi_handle_t handle,
3928906SEric.Saxe@Sun.COM     cpu_acpi_obj_t objtype, int fcnt)
3938906SEric.Saxe@Sun.COM {
3948906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
3958906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj, *q, *l;
3968906SEric.Saxe@Sun.COM 	boolean_t eot = B_FALSE;
3978906SEric.Saxe@Sun.COM 	int ret = -1;
3988906SEric.Saxe@Sun.COM 	int cnt;
3998906SEric.Saxe@Sun.COM 	int i, j;
4008906SEric.Saxe@Sun.COM 
4018906SEric.Saxe@Sun.COM 	/*
4028906SEric.Saxe@Sun.COM 	 * Fetch the data (if present) for the CPU node.
4038906SEric.Saxe@Sun.COM 	 */
4048906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
4058906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
4068906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle->cs_handle,
4078906SEric.Saxe@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf,
4088906SEric.Saxe@Sun.COM 	    ACPI_TYPE_PACKAGE))) {
4098906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: %s package not found.",
4108906SEric.Saxe@Sun.COM 		    cpu_acpi_obj_attrs[objtype].name);
4118906SEric.Saxe@Sun.COM 		return (1);
4128906SEric.Saxe@Sun.COM 	}
4138906SEric.Saxe@Sun.COM 	obj = abuf.Pointer;
4148906SEric.Saxe@Sun.COM 	if (obj->Package.Count < 2) {
4158906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: %s package bad count %d.",
4168906SEric.Saxe@Sun.COM 		    cpu_acpi_obj_attrs[objtype].name, obj->Package.Count);
4178906SEric.Saxe@Sun.COM 		goto out;
4188906SEric.Saxe@Sun.COM 	}
4198906SEric.Saxe@Sun.COM 
4208906SEric.Saxe@Sun.COM 	/*
4218906SEric.Saxe@Sun.COM 	 * Does the package look coherent?
4228906SEric.Saxe@Sun.COM 	 */
4238906SEric.Saxe@Sun.COM 	cnt = 0;
4248906SEric.Saxe@Sun.COM 	for (i = 0, l = NULL; i < obj->Package.Count; i++, l = q) {
4258906SEric.Saxe@Sun.COM 		if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE ||
4268906SEric.Saxe@Sun.COM 		    obj->Package.Elements[i].Package.Count != fcnt) {
4278906SEric.Saxe@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: "
4288906SEric.Saxe@Sun.COM 			    "Unexpected data in %s package.",
4298906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
4308906SEric.Saxe@Sun.COM 			goto out;
4318906SEric.Saxe@Sun.COM 		}
4328906SEric.Saxe@Sun.COM 
4338906SEric.Saxe@Sun.COM 		q = obj->Package.Elements[i].Package.Elements;
4348906SEric.Saxe@Sun.COM 		for (j = 0; j < fcnt; j++) {
4358906SEric.Saxe@Sun.COM 			if (q[j].Type != ACPI_TYPE_INTEGER) {
4368906SEric.Saxe@Sun.COM 				cmn_err(CE_NOTE, "!cpu_acpi: "
4378906SEric.Saxe@Sun.COM 				    "%s element invalid (type)",
4388906SEric.Saxe@Sun.COM 				    cpu_acpi_obj_attrs[objtype].name);
4398906SEric.Saxe@Sun.COM 				goto out;
4408906SEric.Saxe@Sun.COM 			}
4418906SEric.Saxe@Sun.COM 		}
4428906SEric.Saxe@Sun.COM 
4438906SEric.Saxe@Sun.COM 		/*
4448906SEric.Saxe@Sun.COM 		 * Ignore duplicate entries.
4458906SEric.Saxe@Sun.COM 		 */
4468906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
4478906SEric.Saxe@Sun.COM 			continue;
4488906SEric.Saxe@Sun.COM 
4498906SEric.Saxe@Sun.COM 		/*
4508906SEric.Saxe@Sun.COM 		 * Some supported state tables are larger than required
4518906SEric.Saxe@Sun.COM 		 * and unused elements are filled with patterns
4528906SEric.Saxe@Sun.COM 		 * of 0xff.  Simply check here for frequency = 0xffff
4538906SEric.Saxe@Sun.COM 		 * and stop counting if found.
4548906SEric.Saxe@Sun.COM 		 */
4558906SEric.Saxe@Sun.COM 		if (q[0].Integer.Value == 0xffff) {
4568906SEric.Saxe@Sun.COM 			eot = B_TRUE;
4578906SEric.Saxe@Sun.COM 			continue;
4588906SEric.Saxe@Sun.COM 		}
4598906SEric.Saxe@Sun.COM 
4608906SEric.Saxe@Sun.COM 		/*
4618906SEric.Saxe@Sun.COM 		 * We should never find a valid entry after we've hit
4628906SEric.Saxe@Sun.COM 		 * an the end-of-table entry.
4638906SEric.Saxe@Sun.COM 		 */
4648906SEric.Saxe@Sun.COM 		if (eot) {
4658906SEric.Saxe@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: "
4668906SEric.Saxe@Sun.COM 			    "Unexpected data in %s package after eot.",
4678906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
4688906SEric.Saxe@Sun.COM 			goto out;
4698906SEric.Saxe@Sun.COM 		}
4708906SEric.Saxe@Sun.COM 
4718906SEric.Saxe@Sun.COM 		/*
4728906SEric.Saxe@Sun.COM 		 * states must be defined in order from highest to lowest.
4738906SEric.Saxe@Sun.COM 		 */
4748906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value < q[0].Integer.Value) {
4758906SEric.Saxe@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: "
4768906SEric.Saxe@Sun.COM 			    "%s package state definitions out of order.",
4778906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
4788906SEric.Saxe@Sun.COM 			goto out;
4798906SEric.Saxe@Sun.COM 		}
4808906SEric.Saxe@Sun.COM 
4818906SEric.Saxe@Sun.COM 		/*
4828906SEric.Saxe@Sun.COM 		 * This entry passes.
4838906SEric.Saxe@Sun.COM 		 */
4848906SEric.Saxe@Sun.COM 		cnt++;
4858906SEric.Saxe@Sun.COM 	}
4868906SEric.Saxe@Sun.COM 	if (cnt == 0)
4878906SEric.Saxe@Sun.COM 		goto out;
4888906SEric.Saxe@Sun.COM 
4898906SEric.Saxe@Sun.COM 	/*
4908906SEric.Saxe@Sun.COM 	 * Yes, fill in the structure.
4918906SEric.Saxe@Sun.COM 	 */
4928906SEric.Saxe@Sun.COM 	ASSERT(objtype == PSS_OBJ || objtype == TSS_OBJ);
4938906SEric.Saxe@Sun.COM 	(objtype == PSS_OBJ) ? cpu_acpi_cache_pstate(handle, obj, cnt) :
4948906SEric.Saxe@Sun.COM 	    cpu_acpi_cache_tstate(handle, obj, cnt);
4958906SEric.Saxe@Sun.COM 
4968906SEric.Saxe@Sun.COM 	ret = 0;
4978906SEric.Saxe@Sun.COM out:
4988906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
4998906SEric.Saxe@Sun.COM 	return (ret);
5008906SEric.Saxe@Sun.COM }
5018906SEric.Saxe@Sun.COM 
5028906SEric.Saxe@Sun.COM /*
5038906SEric.Saxe@Sun.COM  * Cache the _PSS data. The _PSS data defines the different power levels
5048906SEric.Saxe@Sun.COM  * supported by the CPU and the attributes associated with each power level
5058906SEric.Saxe@Sun.COM  * (i.e., frequency, voltage, etc.). The power levels are number from
5068906SEric.Saxe@Sun.COM  * highest to lowest. That is, the highest power level is _PSS entry 0
5078906SEric.Saxe@Sun.COM  * and the lowest power level is the last _PSS entry.
5088906SEric.Saxe@Sun.COM  */
5098906SEric.Saxe@Sun.COM static int
5108906SEric.Saxe@Sun.COM cpu_acpi_cache_pstates(cpu_acpi_handle_t handle)
5118906SEric.Saxe@Sun.COM {
5128906SEric.Saxe@Sun.COM 	int ret;
5138906SEric.Saxe@Sun.COM 
5148906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSS_CACHED);
5158906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_supported_states(handle, PSS_OBJ,
5168906SEric.Saxe@Sun.COM 	    CPU_ACPI_PSS_CNT);
5178906SEric.Saxe@Sun.COM 	if (ret == 0)
5188906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSS_CACHED);
5198906SEric.Saxe@Sun.COM 	return (ret);
5208906SEric.Saxe@Sun.COM }
5218906SEric.Saxe@Sun.COM 
5228906SEric.Saxe@Sun.COM /*
5238906SEric.Saxe@Sun.COM  * Cache the _TSS data. The _TSS data defines the different freq throttle
5248906SEric.Saxe@Sun.COM  * levels supported by the CPU and the attributes associated with each
5258906SEric.Saxe@Sun.COM  * throttle level (i.e., frequency throttle percentage, voltage, etc.).
5268906SEric.Saxe@Sun.COM  * The throttle levels are number from highest to lowest.
5278906SEric.Saxe@Sun.COM  */
5288906SEric.Saxe@Sun.COM static int
5298906SEric.Saxe@Sun.COM cpu_acpi_cache_tstates(cpu_acpi_handle_t handle)
5308906SEric.Saxe@Sun.COM {
5318906SEric.Saxe@Sun.COM 	int ret;
5328906SEric.Saxe@Sun.COM 
5338906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSS_CACHED);
5348906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_supported_states(handle, TSS_OBJ,
5358906SEric.Saxe@Sun.COM 	    CPU_ACPI_TSS_CNT);
5368906SEric.Saxe@Sun.COM 	if (ret == 0)
5378906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSS_CACHED);
5388906SEric.Saxe@Sun.COM 	return (ret);
5398906SEric.Saxe@Sun.COM }
5408906SEric.Saxe@Sun.COM 
5418906SEric.Saxe@Sun.COM /*
5428906SEric.Saxe@Sun.COM  * Cache the ACPI CPU present capabilities data objects.
5438906SEric.Saxe@Sun.COM  */
5448906SEric.Saxe@Sun.COM static int
5458906SEric.Saxe@Sun.COM cpu_acpi_cache_present_capabilities(cpu_acpi_handle_t handle,
5468906SEric.Saxe@Sun.COM     cpu_acpi_obj_t objtype, cpu_acpi_present_capabilities_t *pc)
5478906SEric.Saxe@Sun.COM 
5488906SEric.Saxe@Sun.COM {
5498906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
5508906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj;
5518906SEric.Saxe@Sun.COM 
5528906SEric.Saxe@Sun.COM 	/*
5538906SEric.Saxe@Sun.COM 	 * Fetch the present capabilites object (if present) for the CPU node.
5548906SEric.Saxe@Sun.COM 	 * Since they are optional, non-existence is not a failure.
5558906SEric.Saxe@Sun.COM 	 */
5568906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
5578906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
5588906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObject(handle->cs_handle,
5598906SEric.Saxe@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf)) ||
5608906SEric.Saxe@Sun.COM 	    abuf.Length == 0) {
5618906SEric.Saxe@Sun.COM 		*pc = 0;
5628906SEric.Saxe@Sun.COM 		return (1);
5638906SEric.Saxe@Sun.COM 	}
5648906SEric.Saxe@Sun.COM 
5658906SEric.Saxe@Sun.COM 	obj = (ACPI_OBJECT *)abuf.Pointer;
5668906SEric.Saxe@Sun.COM 	*pc = obj->Integer.Value;
5678906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
5688906SEric.Saxe@Sun.COM 	return (0);
5698906SEric.Saxe@Sun.COM }
5708906SEric.Saxe@Sun.COM 
5718906SEric.Saxe@Sun.COM /*
5728906SEric.Saxe@Sun.COM  * Cache the _PPC data. The _PPC simply contains an integer value which
5738906SEric.Saxe@Sun.COM  * represents the highest power level that a CPU should transition to.
5748906SEric.Saxe@Sun.COM  * That is, it's an index into the array of _PSS entries and will be
5758906SEric.Saxe@Sun.COM  * greater than or equal to zero.
5768906SEric.Saxe@Sun.COM  */
5778906SEric.Saxe@Sun.COM void
5788906SEric.Saxe@Sun.COM cpu_acpi_cache_ppc(cpu_acpi_handle_t handle)
5798906SEric.Saxe@Sun.COM {
5808906SEric.Saxe@Sun.COM 	cpu_acpi_ppc_t *ppc;
5818906SEric.Saxe@Sun.COM 	int ret;
5828906SEric.Saxe@Sun.COM 
5838906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PPC_CACHED);
5848906SEric.Saxe@Sun.COM 	ppc = &CPU_ACPI_PPC(handle);
5858906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_present_capabilities(handle, PPC_OBJ, ppc);
5868906SEric.Saxe@Sun.COM 	if (ret == 0)
5878906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PPC_CACHED);
5888906SEric.Saxe@Sun.COM }
5898906SEric.Saxe@Sun.COM 
5908906SEric.Saxe@Sun.COM /*
5918906SEric.Saxe@Sun.COM  * Cache the _TPC data. The _TPC simply contains an integer value which
5928906SEric.Saxe@Sun.COM  * represents the throttle level that a CPU should transition to.
5938906SEric.Saxe@Sun.COM  * That is, it's an index into the array of _TSS entries and will be
5948906SEric.Saxe@Sun.COM  * greater than or equal to zero.
5958906SEric.Saxe@Sun.COM  */
5968906SEric.Saxe@Sun.COM void
5978906SEric.Saxe@Sun.COM cpu_acpi_cache_tpc(cpu_acpi_handle_t handle)
5988906SEric.Saxe@Sun.COM {
5998906SEric.Saxe@Sun.COM 	cpu_acpi_tpc_t *tpc;
6008906SEric.Saxe@Sun.COM 	int ret;
6018906SEric.Saxe@Sun.COM 
6028906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TPC_CACHED);
6038906SEric.Saxe@Sun.COM 	tpc = &CPU_ACPI_TPC(handle);
6048906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_present_capabilities(handle, TPC_OBJ, tpc);
6058906SEric.Saxe@Sun.COM 	if (ret == 0)
6068906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TPC_CACHED);
6078906SEric.Saxe@Sun.COM }
6088906SEric.Saxe@Sun.COM 
6098906SEric.Saxe@Sun.COM int
6108906SEric.Saxe@Sun.COM cpu_acpi_verify_cstate(cpu_acpi_cstate_t *cstate)
6118906SEric.Saxe@Sun.COM {
6128906SEric.Saxe@Sun.COM 	uint32_t addrspaceid = cstate->cs_addrspace_id;
6138906SEric.Saxe@Sun.COM 
6148906SEric.Saxe@Sun.COM 	if ((addrspaceid != ACPI_ADR_SPACE_FIXED_HARDWARE) &&
6158906SEric.Saxe@Sun.COM 	    (addrspaceid != ACPI_ADR_SPACE_SYSTEM_IO)) {
6168906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!_CST: unsupported address space id"
6178906SEric.Saxe@Sun.COM 		    ":C%d, type: %d\n", cstate->cs_type, addrspaceid);
6188906SEric.Saxe@Sun.COM 		return (1);
6198906SEric.Saxe@Sun.COM 	}
6208906SEric.Saxe@Sun.COM 	return (0);
6218906SEric.Saxe@Sun.COM }
6228906SEric.Saxe@Sun.COM 
6238906SEric.Saxe@Sun.COM int
6248906SEric.Saxe@Sun.COM cpu_acpi_cache_cst(cpu_acpi_handle_t handle)
6258906SEric.Saxe@Sun.COM {
6268906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
6278906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj;
6288906SEric.Saxe@Sun.COM 	ACPI_INTEGER cnt;
6298906SEric.Saxe@Sun.COM 	cpu_acpi_cstate_t *cstate, *p;
6308906SEric.Saxe@Sun.COM 	int i, count;
6318906SEric.Saxe@Sun.COM 
6328906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CST_CACHED);
6338906SEric.Saxe@Sun.COM 
6348906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
6358906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
6368906SEric.Saxe@Sun.COM 
6378906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObject(handle->cs_handle, "_CST",
6388906SEric.Saxe@Sun.COM 	    NULL, &abuf))) {
6398906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST evaluate failure");
6408906SEric.Saxe@Sun.COM 		return (-1);
6418906SEric.Saxe@Sun.COM 	}
6428906SEric.Saxe@Sun.COM 	obj = (ACPI_OBJECT *)abuf.Pointer;
6438906SEric.Saxe@Sun.COM 	if (obj->Package.Count < 2) {
6448906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST package bad count %d.",
6458906SEric.Saxe@Sun.COM 		    obj->Package.Count);
6468906SEric.Saxe@Sun.COM 		AcpiOsFree(abuf.Pointer);
6478906SEric.Saxe@Sun.COM 		return (-1);
6488906SEric.Saxe@Sun.COM 	}
6498906SEric.Saxe@Sun.COM 
6508906SEric.Saxe@Sun.COM 	/*
6518906SEric.Saxe@Sun.COM 	 * Does the package look coherent?
6528906SEric.Saxe@Sun.COM 	 */
6538906SEric.Saxe@Sun.COM 	cnt = obj->Package.Elements[0].Integer.Value;
6548906SEric.Saxe@Sun.COM 	if (cnt < 1 || cnt != obj->Package.Count - 1) {
6558906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid element count %d != "
6568906SEric.Saxe@Sun.COM 		    "Package count %d\n",
6578906SEric.Saxe@Sun.COM 		    (int)cnt, (int)obj->Package.Count - 1);
6588906SEric.Saxe@Sun.COM 		AcpiOsFree(abuf.Pointer);
6598906SEric.Saxe@Sun.COM 		return (-1);
6608906SEric.Saxe@Sun.COM 	}
6618906SEric.Saxe@Sun.COM 
6628906SEric.Saxe@Sun.COM 	CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)cnt;
6638906SEric.Saxe@Sun.COM 	CPU_ACPI_CSTATES(handle) = kmem_zalloc(CPU_ACPI_CSTATES_SIZE(cnt),
6648906SEric.Saxe@Sun.COM 	    KM_SLEEP);
6658906SEric.Saxe@Sun.COM 	CPU_ACPI_BM_INFO(handle) = 0;
6668906SEric.Saxe@Sun.COM 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
6678906SEric.Saxe@Sun.COM 	p = cstate;
6688906SEric.Saxe@Sun.COM 
6698906SEric.Saxe@Sun.COM 	for (i = 1, count = 1; i <= cnt; i++) {
6708906SEric.Saxe@Sun.COM 		ACPI_OBJECT *pkg;
6718906SEric.Saxe@Sun.COM 		AML_RESOURCE_GENERIC_REGISTER *reg;
6728906SEric.Saxe@Sun.COM 		ACPI_OBJECT *element;
6738906SEric.Saxe@Sun.COM 
6748906SEric.Saxe@Sun.COM 		pkg = &(obj->Package.Elements[i]);
6758906SEric.Saxe@Sun.COM 		reg = (AML_RESOURCE_GENERIC_REGISTER *)
6768906SEric.Saxe@Sun.COM 		    pkg->Package.Elements[0].Buffer.Pointer;
6778906SEric.Saxe@Sun.COM 		cstate->cs_addrspace_id = reg->AddressSpaceId;
6788906SEric.Saxe@Sun.COM 		cstate->cs_address = reg->Address;
6798906SEric.Saxe@Sun.COM 		element = &(pkg->Package.Elements[1]);
6808906SEric.Saxe@Sun.COM 		cstate->cs_type = element->Integer.Value;
6818906SEric.Saxe@Sun.COM 		element = &(pkg->Package.Elements[2]);
6828906SEric.Saxe@Sun.COM 		cstate->cs_latency = element->Integer.Value;
6838906SEric.Saxe@Sun.COM 		element = &(pkg->Package.Elements[3]);
6848906SEric.Saxe@Sun.COM 		cstate->cs_power = element->Integer.Value;
6858906SEric.Saxe@Sun.COM 
6868906SEric.Saxe@Sun.COM 		if (cpu_acpi_verify_cstate(cstate)) {
6878906SEric.Saxe@Sun.COM 			/*
6888906SEric.Saxe@Sun.COM 			 * ignore this entry if it's not valid
6898906SEric.Saxe@Sun.COM 			 */
6908906SEric.Saxe@Sun.COM 			continue;
6918906SEric.Saxe@Sun.COM 		}
6928906SEric.Saxe@Sun.COM 		if (cstate == p) {
6938906SEric.Saxe@Sun.COM 			cstate++;
6948906SEric.Saxe@Sun.COM 		} else if (p->cs_type == cstate->cs_type) {
6958906SEric.Saxe@Sun.COM 			/*
6968906SEric.Saxe@Sun.COM 			 * if there are duplicate entries, we keep the
6978906SEric.Saxe@Sun.COM 			 * last one. This fixes:
6988906SEric.Saxe@Sun.COM 			 * 1) some buggy BIOS have total duplicate entries.
6998906SEric.Saxe@Sun.COM 			 * 2) ACPI Spec allows the same cstate entry with
7008906SEric.Saxe@Sun.COM 			 *    different power and latency, we use the one
7018906SEric.Saxe@Sun.COM 			 *    with more power saving.
7028906SEric.Saxe@Sun.COM 			 */
7038906SEric.Saxe@Sun.COM 			(void) memcpy(p, cstate, sizeof (cpu_acpi_cstate_t));
7048906SEric.Saxe@Sun.COM 		} else {
7058906SEric.Saxe@Sun.COM 			/*
7068906SEric.Saxe@Sun.COM 			 * we got a valid entry, cache it to the
7078906SEric.Saxe@Sun.COM 			 * cstate structure
7088906SEric.Saxe@Sun.COM 			 */
7098906SEric.Saxe@Sun.COM 			p = cstate++;
7108906SEric.Saxe@Sun.COM 			count++;
7118906SEric.Saxe@Sun.COM 		}
7128906SEric.Saxe@Sun.COM 	}
7138906SEric.Saxe@Sun.COM 
7148906SEric.Saxe@Sun.COM 	if (count < 2) {
715*8983SBill.Holler@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid count %d < 2",
7168906SEric.Saxe@Sun.COM 		    count);
7178906SEric.Saxe@Sun.COM 		AcpiOsFree(abuf.Pointer);
7188906SEric.Saxe@Sun.COM 		return (-1);
7198906SEric.Saxe@Sun.COM 	}
720*8983SBill.Holler@Sun.COM 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
721*8983SBill.Holler@Sun.COM 	if (cstate[0].cs_type != CPU_ACPI_C1) {
722*8983SBill.Holler@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST first element type not C1: "
723*8983SBill.Holler@Sun.COM 		    "%d", (int)cstate->cs_type);
724*8983SBill.Holler@Sun.COM 		AcpiOsFree(abuf.Pointer);
725*8983SBill.Holler@Sun.COM 		return (-1);
726*8983SBill.Holler@Sun.COM 	}
7278906SEric.Saxe@Sun.COM 
7288906SEric.Saxe@Sun.COM 	if (count != cnt)
7298906SEric.Saxe@Sun.COM 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)count;
7308906SEric.Saxe@Sun.COM 
7318906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
7328906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CST_CACHED);
7338906SEric.Saxe@Sun.COM 	return (0);
7348906SEric.Saxe@Sun.COM }
7358906SEric.Saxe@Sun.COM 
7368906SEric.Saxe@Sun.COM /*
7378906SEric.Saxe@Sun.COM  * Cache the _PCT, _PSS, _PSD and _PPC data.
7388906SEric.Saxe@Sun.COM  */
7398906SEric.Saxe@Sun.COM int
7408906SEric.Saxe@Sun.COM cpu_acpi_cache_pstate_data(cpu_acpi_handle_t handle)
7418906SEric.Saxe@Sun.COM {
7428906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_pct(handle) < 0) {
7438906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _PCT for "
7448906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
7458906SEric.Saxe@Sun.COM 		return (-1);
7468906SEric.Saxe@Sun.COM 	}
7478906SEric.Saxe@Sun.COM 
7488906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_pstates(handle) != 0) {
7498906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _PSS for "
7508906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
7518906SEric.Saxe@Sun.COM 		return (-1);
7528906SEric.Saxe@Sun.COM 	}
7538906SEric.Saxe@Sun.COM 
7548906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_psd(handle) < 0) {
7558906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _PSD for "
7568906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
7578906SEric.Saxe@Sun.COM 		return (-1);
7588906SEric.Saxe@Sun.COM 	}
7598906SEric.Saxe@Sun.COM 
7608906SEric.Saxe@Sun.COM 	cpu_acpi_cache_ppc(handle);
7618906SEric.Saxe@Sun.COM 
7628906SEric.Saxe@Sun.COM 	return (0);
7638906SEric.Saxe@Sun.COM }
7648906SEric.Saxe@Sun.COM 
7658906SEric.Saxe@Sun.COM void
7668906SEric.Saxe@Sun.COM cpu_acpi_free_pstate_data(cpu_acpi_handle_t handle)
7678906SEric.Saxe@Sun.COM {
7688906SEric.Saxe@Sun.COM 	if (handle != NULL) {
7698906SEric.Saxe@Sun.COM 		if (CPU_ACPI_PSTATES(handle)) {
7708906SEric.Saxe@Sun.COM 			kmem_free(CPU_ACPI_PSTATES(handle),
7718906SEric.Saxe@Sun.COM 			    CPU_ACPI_PSTATES_SIZE(
7728906SEric.Saxe@Sun.COM 			    CPU_ACPI_PSTATES_COUNT(handle)));
7738906SEric.Saxe@Sun.COM 			CPU_ACPI_PSTATES(handle) = NULL;
7748906SEric.Saxe@Sun.COM 		}
7758906SEric.Saxe@Sun.COM 	}
7768906SEric.Saxe@Sun.COM }
7778906SEric.Saxe@Sun.COM 
7788906SEric.Saxe@Sun.COM /*
7798906SEric.Saxe@Sun.COM  * Cache the _PTC, _TSS, _TSD and _TPC data.
7808906SEric.Saxe@Sun.COM  */
7818906SEric.Saxe@Sun.COM int
7828906SEric.Saxe@Sun.COM cpu_acpi_cache_tstate_data(cpu_acpi_handle_t handle)
7838906SEric.Saxe@Sun.COM {
7848906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_ptc(handle) < 0) {
7858906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _PTC for "
7868906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
7878906SEric.Saxe@Sun.COM 		return (-1);
7888906SEric.Saxe@Sun.COM 	}
7898906SEric.Saxe@Sun.COM 
7908906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_tstates(handle) != 0) {
7918906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _TSS for "
7928906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
7938906SEric.Saxe@Sun.COM 		return (-1);
7948906SEric.Saxe@Sun.COM 	}
7958906SEric.Saxe@Sun.COM 
7968906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_tsd(handle) < 0) {
7978906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _TSD for "
7988906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
7998906SEric.Saxe@Sun.COM 		return (-1);
8008906SEric.Saxe@Sun.COM 	}
8018906SEric.Saxe@Sun.COM 
8028906SEric.Saxe@Sun.COM 	cpu_acpi_cache_tpc(handle);
8038906SEric.Saxe@Sun.COM 
8048906SEric.Saxe@Sun.COM 	return (0);
8058906SEric.Saxe@Sun.COM }
8068906SEric.Saxe@Sun.COM 
8078906SEric.Saxe@Sun.COM void
8088906SEric.Saxe@Sun.COM cpu_acpi_free_tstate_data(cpu_acpi_handle_t handle)
8098906SEric.Saxe@Sun.COM {
8108906SEric.Saxe@Sun.COM 	if (handle != NULL) {
8118906SEric.Saxe@Sun.COM 		if (CPU_ACPI_TSTATES(handle)) {
8128906SEric.Saxe@Sun.COM 			kmem_free(CPU_ACPI_TSTATES(handle),
8138906SEric.Saxe@Sun.COM 			    CPU_ACPI_TSTATES_SIZE(
8148906SEric.Saxe@Sun.COM 			    CPU_ACPI_TSTATES_COUNT(handle)));
8158906SEric.Saxe@Sun.COM 			CPU_ACPI_TSTATES(handle) = NULL;
8168906SEric.Saxe@Sun.COM 		}
8178906SEric.Saxe@Sun.COM 	}
8188906SEric.Saxe@Sun.COM }
8198906SEric.Saxe@Sun.COM 
8208906SEric.Saxe@Sun.COM /*
8218906SEric.Saxe@Sun.COM  * Cache the _CST data.
8228906SEric.Saxe@Sun.COM  */
8238906SEric.Saxe@Sun.COM int
8248906SEric.Saxe@Sun.COM cpu_acpi_cache_cstate_data(cpu_acpi_handle_t handle)
8258906SEric.Saxe@Sun.COM {
8268906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_cst(handle) < 0) {
8278906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _CST for "
8288906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
8298906SEric.Saxe@Sun.COM 		return (-1);
8308906SEric.Saxe@Sun.COM 	}
8318906SEric.Saxe@Sun.COM 
8328906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_csd(handle) < 0) {
8338906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _CSD for "
8348906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
8358906SEric.Saxe@Sun.COM 		return (-1);
8368906SEric.Saxe@Sun.COM 	}
8378906SEric.Saxe@Sun.COM 
8388906SEric.Saxe@Sun.COM 	return (0);
8398906SEric.Saxe@Sun.COM }
8408906SEric.Saxe@Sun.COM 
8418906SEric.Saxe@Sun.COM void
8428906SEric.Saxe@Sun.COM cpu_acpi_free_cstate_data(cpu_acpi_handle_t handle)
8438906SEric.Saxe@Sun.COM {
8448906SEric.Saxe@Sun.COM 	if (handle != NULL) {
8458906SEric.Saxe@Sun.COM 		if (CPU_ACPI_CSTATES(handle)) {
8468906SEric.Saxe@Sun.COM 			kmem_free(CPU_ACPI_CSTATES(handle),
8478906SEric.Saxe@Sun.COM 			    CPU_ACPI_CSTATES_SIZE(
8488906SEric.Saxe@Sun.COM 			    CPU_ACPI_CSTATES_COUNT(handle)));
8498906SEric.Saxe@Sun.COM 			CPU_ACPI_CSTATES(handle) = NULL;
8508906SEric.Saxe@Sun.COM 		}
8518906SEric.Saxe@Sun.COM 	}
8528906SEric.Saxe@Sun.COM }
8538906SEric.Saxe@Sun.COM 
8548906SEric.Saxe@Sun.COM /*
8558906SEric.Saxe@Sun.COM  * Register a handler for processor change notifications.
8568906SEric.Saxe@Sun.COM  */
8578906SEric.Saxe@Sun.COM void
8588906SEric.Saxe@Sun.COM cpu_acpi_install_notify_handler(cpu_acpi_handle_t handle,
8598906SEric.Saxe@Sun.COM     ACPI_NOTIFY_HANDLER handler, void *ctx)
8608906SEric.Saxe@Sun.COM {
8618906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiInstallNotifyHandler(handle->cs_handle,
8628906SEric.Saxe@Sun.COM 	    ACPI_DEVICE_NOTIFY, handler, ctx)))
8638906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unable to register "
8648906SEric.Saxe@Sun.COM 		    "notify handler for CPU");
8658906SEric.Saxe@Sun.COM }
8668906SEric.Saxe@Sun.COM 
8678906SEric.Saxe@Sun.COM /*
8688906SEric.Saxe@Sun.COM  * Remove a handler for processor change notifications.
8698906SEric.Saxe@Sun.COM  */
8708906SEric.Saxe@Sun.COM void
8718906SEric.Saxe@Sun.COM cpu_acpi_remove_notify_handler(cpu_acpi_handle_t handle,
8728906SEric.Saxe@Sun.COM     ACPI_NOTIFY_HANDLER handler)
8738906SEric.Saxe@Sun.COM {
8748906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiRemoveNotifyHandler(handle->cs_handle,
8758906SEric.Saxe@Sun.COM 	    ACPI_DEVICE_NOTIFY, handler)))
8768906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unable to remove "
8778906SEric.Saxe@Sun.COM 		    "notify handler for CPU");
8788906SEric.Saxe@Sun.COM }
8798906SEric.Saxe@Sun.COM 
8808906SEric.Saxe@Sun.COM /*
8818906SEric.Saxe@Sun.COM  * Write _PDC.
8828906SEric.Saxe@Sun.COM  */
8838906SEric.Saxe@Sun.COM int
8848906SEric.Saxe@Sun.COM cpu_acpi_write_pdc(cpu_acpi_handle_t handle, uint32_t revision, uint32_t count,
8858906SEric.Saxe@Sun.COM     uint32_t *capabilities)
8868906SEric.Saxe@Sun.COM {
8878906SEric.Saxe@Sun.COM 	ACPI_OBJECT obj;
8888906SEric.Saxe@Sun.COM 	ACPI_OBJECT_LIST list = { 1, &obj};
8898906SEric.Saxe@Sun.COM 	uint32_t *buffer;
8908906SEric.Saxe@Sun.COM 	uint32_t *bufptr;
8918906SEric.Saxe@Sun.COM 	uint32_t bufsize;
8928906SEric.Saxe@Sun.COM 	int i;
8938906SEric.Saxe@Sun.COM 
8948906SEric.Saxe@Sun.COM 	bufsize = (count + 2) * sizeof (uint32_t);
8958906SEric.Saxe@Sun.COM 	buffer = kmem_zalloc(bufsize, KM_SLEEP);
8968906SEric.Saxe@Sun.COM 	buffer[0] = revision;
8978906SEric.Saxe@Sun.COM 	buffer[1] = count;
8988906SEric.Saxe@Sun.COM 	bufptr = &buffer[2];
8998906SEric.Saxe@Sun.COM 	for (i = 0; i < count; i++)
9008906SEric.Saxe@Sun.COM 		*bufptr++ = *capabilities++;
9018906SEric.Saxe@Sun.COM 
9028906SEric.Saxe@Sun.COM 	obj.Type = ACPI_TYPE_BUFFER;
9038906SEric.Saxe@Sun.COM 	obj.Buffer.Length = bufsize;
9048906SEric.Saxe@Sun.COM 	obj.Buffer.Pointer = (void *)buffer;
9058906SEric.Saxe@Sun.COM 
9068906SEric.Saxe@Sun.COM 	/*
9078906SEric.Saxe@Sun.COM 	 * _PDC is optional, so don't log failure.
9088906SEric.Saxe@Sun.COM 	 */
9098906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObject(handle->cs_handle, "_PDC",
9108906SEric.Saxe@Sun.COM 	    &list, NULL))) {
9118906SEric.Saxe@Sun.COM 		kmem_free(buffer, bufsize);
9128906SEric.Saxe@Sun.COM 		return (-1);
9138906SEric.Saxe@Sun.COM 	}
9148906SEric.Saxe@Sun.COM 
9158906SEric.Saxe@Sun.COM 	kmem_free(buffer, bufsize);
9168906SEric.Saxe@Sun.COM 	return (0);
9178906SEric.Saxe@Sun.COM }
9188906SEric.Saxe@Sun.COM 
9198906SEric.Saxe@Sun.COM /*
9208906SEric.Saxe@Sun.COM  * Write to system IO port.
9218906SEric.Saxe@Sun.COM  */
9228906SEric.Saxe@Sun.COM int
9238906SEric.Saxe@Sun.COM cpu_acpi_write_port(ACPI_IO_ADDRESS address, uint32_t value, uint32_t width)
9248906SEric.Saxe@Sun.COM {
9258906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiOsWritePort(address, value, width))) {
9268906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "cpu_acpi: error writing system IO port "
9278906SEric.Saxe@Sun.COM 		    "%lx.", (long)address);
9288906SEric.Saxe@Sun.COM 		return (-1);
9298906SEric.Saxe@Sun.COM 	}
9308906SEric.Saxe@Sun.COM 	return (0);
9318906SEric.Saxe@Sun.COM }
9328906SEric.Saxe@Sun.COM 
9338906SEric.Saxe@Sun.COM /*
9348906SEric.Saxe@Sun.COM  * Read from a system IO port.
9358906SEric.Saxe@Sun.COM  */
9368906SEric.Saxe@Sun.COM int
9378906SEric.Saxe@Sun.COM cpu_acpi_read_port(ACPI_IO_ADDRESS address, uint32_t *value, uint32_t width)
9388906SEric.Saxe@Sun.COM {
9398906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiOsReadPort(address, value, width))) {
9408906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "cpu_acpi: error reading system IO port "
9418906SEric.Saxe@Sun.COM 		    "%lx.", (long)address);
9428906SEric.Saxe@Sun.COM 		return (-1);
9438906SEric.Saxe@Sun.COM 	}
9448906SEric.Saxe@Sun.COM 	return (0);
9458906SEric.Saxe@Sun.COM }
9468906SEric.Saxe@Sun.COM 
9478906SEric.Saxe@Sun.COM /*
9488906SEric.Saxe@Sun.COM  * Return supported frequencies.
9498906SEric.Saxe@Sun.COM  */
9508906SEric.Saxe@Sun.COM uint_t
9518906SEric.Saxe@Sun.COM cpu_acpi_get_speeds(cpu_acpi_handle_t handle, int **speeds)
9528906SEric.Saxe@Sun.COM {
9538906SEric.Saxe@Sun.COM 	cpu_acpi_pstate_t *pstate;
9548906SEric.Saxe@Sun.COM 	int *hspeeds;
9558906SEric.Saxe@Sun.COM 	uint_t nspeeds;
9568906SEric.Saxe@Sun.COM 	int i;
9578906SEric.Saxe@Sun.COM 
9588906SEric.Saxe@Sun.COM 	nspeeds = CPU_ACPI_PSTATES_COUNT(handle);
9598906SEric.Saxe@Sun.COM 	pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
9608906SEric.Saxe@Sun.COM 	hspeeds = kmem_zalloc(nspeeds * sizeof (int), KM_SLEEP);
9618906SEric.Saxe@Sun.COM 	for (i = 0; i < nspeeds; i++) {
9628906SEric.Saxe@Sun.COM 		hspeeds[i] = CPU_ACPI_FREQ(pstate);
9638906SEric.Saxe@Sun.COM 		pstate++;
9648906SEric.Saxe@Sun.COM 	}
9658906SEric.Saxe@Sun.COM 	*speeds = hspeeds;
9668906SEric.Saxe@Sun.COM 	return (nspeeds);
9678906SEric.Saxe@Sun.COM }
9688906SEric.Saxe@Sun.COM 
9698906SEric.Saxe@Sun.COM /*
9708906SEric.Saxe@Sun.COM  * Free resources allocated by cpu_acpi_get_speeds().
9718906SEric.Saxe@Sun.COM  */
9728906SEric.Saxe@Sun.COM void
9738906SEric.Saxe@Sun.COM cpu_acpi_free_speeds(int *speeds, uint_t nspeeds)
9748906SEric.Saxe@Sun.COM {
9758906SEric.Saxe@Sun.COM 	kmem_free(speeds, nspeeds * sizeof (int));
9768906SEric.Saxe@Sun.COM }
9778906SEric.Saxe@Sun.COM 
9788906SEric.Saxe@Sun.COM uint_t
9798906SEric.Saxe@Sun.COM cpu_acpi_get_max_cstates(cpu_acpi_handle_t handle)
9808906SEric.Saxe@Sun.COM {
9818906SEric.Saxe@Sun.COM 	if (CPU_ACPI_CSTATES(handle))
9828906SEric.Saxe@Sun.COM 		return (CPU_ACPI_CSTATES_COUNT(handle));
9838906SEric.Saxe@Sun.COM 	else
9848906SEric.Saxe@Sun.COM 		return (1);
9858906SEric.Saxe@Sun.COM }
9868906SEric.Saxe@Sun.COM 
9878906SEric.Saxe@Sun.COM void
9888906SEric.Saxe@Sun.COM cpu_acpi_set_register(uint32_t bitreg, uint32_t value)
9898906SEric.Saxe@Sun.COM {
9908906SEric.Saxe@Sun.COM 	AcpiSetRegister(bitreg, value);
9918906SEric.Saxe@Sun.COM }
9928906SEric.Saxe@Sun.COM 
9938906SEric.Saxe@Sun.COM void
9948906SEric.Saxe@Sun.COM cpu_acpi_get_register(uint32_t bitreg, uint32_t *value)
9958906SEric.Saxe@Sun.COM {
9968906SEric.Saxe@Sun.COM 	AcpiGetRegister(bitreg, value);
9978906SEric.Saxe@Sun.COM }
9988906SEric.Saxe@Sun.COM 
9998906SEric.Saxe@Sun.COM /*
10008906SEric.Saxe@Sun.COM  * Map the dip to an ACPI handle for the device.
10018906SEric.Saxe@Sun.COM  */
10028906SEric.Saxe@Sun.COM cpu_acpi_handle_t
10038906SEric.Saxe@Sun.COM cpu_acpi_init(cpu_t *cp)
10048906SEric.Saxe@Sun.COM {
10058906SEric.Saxe@Sun.COM 	cpu_acpi_handle_t handle;
10068906SEric.Saxe@Sun.COM 
10078906SEric.Saxe@Sun.COM 	handle = kmem_zalloc(sizeof (cpu_acpi_state_t), KM_SLEEP);
10088906SEric.Saxe@Sun.COM 
10098906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(acpica_get_handle_cpu(cp->cpu_id,
10108906SEric.Saxe@Sun.COM 	    &handle->cs_handle))) {
10118906SEric.Saxe@Sun.COM 		kmem_free(handle, sizeof (cpu_acpi_state_t));
10128906SEric.Saxe@Sun.COM 		return (NULL);
10138906SEric.Saxe@Sun.COM 	}
10148906SEric.Saxe@Sun.COM 	handle->cs_id = cp->cpu_id;
10158906SEric.Saxe@Sun.COM 	return (handle);
10168906SEric.Saxe@Sun.COM }
10178906SEric.Saxe@Sun.COM 
10188906SEric.Saxe@Sun.COM /*
10198906SEric.Saxe@Sun.COM  * Free any resources.
10208906SEric.Saxe@Sun.COM  */
10218906SEric.Saxe@Sun.COM void
10228906SEric.Saxe@Sun.COM cpu_acpi_fini(cpu_acpi_handle_t handle)
10238906SEric.Saxe@Sun.COM {
10248906SEric.Saxe@Sun.COM 	if (handle)
10258906SEric.Saxe@Sun.COM 		kmem_free(handle, sizeof (cpu_acpi_state_t));
10268906SEric.Saxe@Sun.COM }
1027