xref: /onnv-gate/usr/src/uts/i86pc/os/cpupm/cpu_acpi.c (revision 9148:cbc850545d32)
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>
278983SBill.Holler@Sun.COM #include <sys/cpu_idle.h>
289004SNapanda.Pemmaiah@Sun.COM #include <sys/dtrace.h>
299004SNapanda.Pemmaiah@Sun.COM #include <sys/sdt.h>
308906SEric.Saxe@Sun.COM 
318906SEric.Saxe@Sun.COM /*
328906SEric.Saxe@Sun.COM  * List of the processor ACPI object types that are being used.
338906SEric.Saxe@Sun.COM  */
348906SEric.Saxe@Sun.COM typedef enum cpu_acpi_obj {
358906SEric.Saxe@Sun.COM 	PDC_OBJ = 0,
368906SEric.Saxe@Sun.COM 	PCT_OBJ,
378906SEric.Saxe@Sun.COM 	PSS_OBJ,
388906SEric.Saxe@Sun.COM 	PSD_OBJ,
398906SEric.Saxe@Sun.COM 	PPC_OBJ,
408906SEric.Saxe@Sun.COM 	PTC_OBJ,
418906SEric.Saxe@Sun.COM 	TSS_OBJ,
428906SEric.Saxe@Sun.COM 	TSD_OBJ,
438906SEric.Saxe@Sun.COM 	TPC_OBJ,
448906SEric.Saxe@Sun.COM 	CSD_OBJ,
458906SEric.Saxe@Sun.COM } cpu_acpi_obj_t;
468906SEric.Saxe@Sun.COM 
478906SEric.Saxe@Sun.COM /*
488906SEric.Saxe@Sun.COM  * Container to store object name.
498906SEric.Saxe@Sun.COM  * Other attributes can be added in the future as necessary.
508906SEric.Saxe@Sun.COM  */
518906SEric.Saxe@Sun.COM typedef struct cpu_acpi_obj_attr {
528906SEric.Saxe@Sun.COM 	char *name;
538906SEric.Saxe@Sun.COM } cpu_acpi_obj_attr_t;
548906SEric.Saxe@Sun.COM 
558906SEric.Saxe@Sun.COM /*
568906SEric.Saxe@Sun.COM  * List of object attributes.
578906SEric.Saxe@Sun.COM  * NOTE: Please keep the ordering of the list as same as cpu_acpi_obj_t.
588906SEric.Saxe@Sun.COM  */
598906SEric.Saxe@Sun.COM static cpu_acpi_obj_attr_t cpu_acpi_obj_attrs[] = {
608906SEric.Saxe@Sun.COM 	{"_PDC"},
618906SEric.Saxe@Sun.COM 	{"_PCT"},
628906SEric.Saxe@Sun.COM 	{"_PSS"},
638906SEric.Saxe@Sun.COM 	{"_PSD"},
648906SEric.Saxe@Sun.COM 	{"_PPC"},
658906SEric.Saxe@Sun.COM 	{"_PTC"},
668906SEric.Saxe@Sun.COM 	{"_TSS"},
678906SEric.Saxe@Sun.COM 	{"_TSD"},
688906SEric.Saxe@Sun.COM 	{"_TPC"},
698906SEric.Saxe@Sun.COM 	{"_CSD"}
708906SEric.Saxe@Sun.COM };
718906SEric.Saxe@Sun.COM 
728906SEric.Saxe@Sun.COM /*
739004SNapanda.Pemmaiah@Sun.COM  * To avoid user confusion about ACPI T-State related error log messages,
749004SNapanda.Pemmaiah@Sun.COM  * most of the T-State related error messages will be activated through
759004SNapanda.Pemmaiah@Sun.COM  * DTrace
769004SNapanda.Pemmaiah@Sun.COM  */
779004SNapanda.Pemmaiah@Sun.COM #define	ERR_MSG_SIZE 128
789004SNapanda.Pemmaiah@Sun.COM static char err_msg[ERR_MSG_SIZE];
799004SNapanda.Pemmaiah@Sun.COM 
809004SNapanda.Pemmaiah@Sun.COM #define	PRINT_ERR_MSG(err_lvl, msg, obj_type) { \
819004SNapanda.Pemmaiah@Sun.COM 	switch (obj_type) {\
829004SNapanda.Pemmaiah@Sun.COM 	case (PTC_OBJ): \
839004SNapanda.Pemmaiah@Sun.COM 	case (TSS_OBJ): \
849004SNapanda.Pemmaiah@Sun.COM 	case (TSD_OBJ): \
859004SNapanda.Pemmaiah@Sun.COM 	case (TPC_OBJ): \
869004SNapanda.Pemmaiah@Sun.COM 		DTRACE_PROBE1(cpu_ts_err_msg, char *, msg); \
879004SNapanda.Pemmaiah@Sun.COM 		break; \
889004SNapanda.Pemmaiah@Sun.COM 	default: \
899004SNapanda.Pemmaiah@Sun.COM 		cmn_err(err_lvl, "%s", msg); \
909004SNapanda.Pemmaiah@Sun.COM 		break; \
919004SNapanda.Pemmaiah@Sun.COM 	} \
929004SNapanda.Pemmaiah@Sun.COM }
939004SNapanda.Pemmaiah@Sun.COM 
949004SNapanda.Pemmaiah@Sun.COM 
959004SNapanda.Pemmaiah@Sun.COM /*
968906SEric.Saxe@Sun.COM  * Cache the ACPI CPU control data objects.
978906SEric.Saxe@Sun.COM  */
988906SEric.Saxe@Sun.COM static int
998906SEric.Saxe@Sun.COM cpu_acpi_cache_ctrl_regs(cpu_acpi_handle_t handle, cpu_acpi_obj_t objtype,
1008906SEric.Saxe@Sun.COM     cpu_acpi_ctrl_regs_t *regs)
1018906SEric.Saxe@Sun.COM {
1028906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
1038906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj;
1048906SEric.Saxe@Sun.COM 	AML_RESOURCE_GENERIC_REGISTER *greg;
1058906SEric.Saxe@Sun.COM 	int ret = -1;
1068906SEric.Saxe@Sun.COM 	int i;
1079004SNapanda.Pemmaiah@Sun.COM 	int p_res;
1088906SEric.Saxe@Sun.COM 
1098906SEric.Saxe@Sun.COM 	/*
1108906SEric.Saxe@Sun.COM 	 * Fetch the control registers (if present) for the CPU node.
1118906SEric.Saxe@Sun.COM 	 * Since they are optional, non-existence is not a failure
1128906SEric.Saxe@Sun.COM 	 * (we just consider it a fixed hardware case).
1138906SEric.Saxe@Sun.COM 	 */
1148906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
1158906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
1168906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle->cs_handle,
1178906SEric.Saxe@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf,
1188906SEric.Saxe@Sun.COM 	    ACPI_TYPE_PACKAGE))) {
1198906SEric.Saxe@Sun.COM 		regs[0].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
1208906SEric.Saxe@Sun.COM 		regs[1].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
1218906SEric.Saxe@Sun.COM 		return (1);
1228906SEric.Saxe@Sun.COM 	}
1238906SEric.Saxe@Sun.COM 
1248906SEric.Saxe@Sun.COM 	obj = abuf.Pointer;
1258906SEric.Saxe@Sun.COM 	if (obj->Package.Count != 2) {
1269004SNapanda.Pemmaiah@Sun.COM 		p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: %s package"
1279004SNapanda.Pemmaiah@Sun.COM 		    " bad count %d.", cpu_acpi_obj_attrs[objtype].name,
1289004SNapanda.Pemmaiah@Sun.COM 		    obj->Package.Count);
1299004SNapanda.Pemmaiah@Sun.COM 		if (p_res >= 0)
1309004SNapanda.Pemmaiah@Sun.COM 			PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
1319004SNapanda.Pemmaiah@Sun.COM 
1328906SEric.Saxe@Sun.COM 		goto out;
1338906SEric.Saxe@Sun.COM 	}
1348906SEric.Saxe@Sun.COM 
1358906SEric.Saxe@Sun.COM 	/*
1368906SEric.Saxe@Sun.COM 	 * Does the package look coherent?
1378906SEric.Saxe@Sun.COM 	 */
1388906SEric.Saxe@Sun.COM 	for (i = 0; i < obj->Package.Count; i++) {
1398906SEric.Saxe@Sun.COM 		if (obj->Package.Elements[i].Type != ACPI_TYPE_BUFFER) {
1409004SNapanda.Pemmaiah@Sun.COM 			p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: "
1418906SEric.Saxe@Sun.COM 			    "Unexpected data in %s package.",
1428906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
1439004SNapanda.Pemmaiah@Sun.COM 			if (p_res >= 0)
1449004SNapanda.Pemmaiah@Sun.COM 				PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
1458906SEric.Saxe@Sun.COM 			goto out;
1468906SEric.Saxe@Sun.COM 		}
1478906SEric.Saxe@Sun.COM 
1488906SEric.Saxe@Sun.COM 		greg = (AML_RESOURCE_GENERIC_REGISTER *)
1498906SEric.Saxe@Sun.COM 		    obj->Package.Elements[i].Buffer.Pointer;
1508906SEric.Saxe@Sun.COM 		if (greg->DescriptorType !=
1518906SEric.Saxe@Sun.COM 		    ACPI_RESOURCE_NAME_GENERIC_REGISTER) {
1529004SNapanda.Pemmaiah@Sun.COM 			p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: "
1538906SEric.Saxe@Sun.COM 			    "%s package has format error.",
1548906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
1559004SNapanda.Pemmaiah@Sun.COM 			if (p_res >= 0)
1569004SNapanda.Pemmaiah@Sun.COM 				PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
1578906SEric.Saxe@Sun.COM 			goto out;
1588906SEric.Saxe@Sun.COM 		}
1598906SEric.Saxe@Sun.COM 		if (greg->ResourceLength !=
1608906SEric.Saxe@Sun.COM 		    ACPI_AML_SIZE_LARGE(AML_RESOURCE_GENERIC_REGISTER)) {
1619004SNapanda.Pemmaiah@Sun.COM 			p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: "
1628906SEric.Saxe@Sun.COM 			    "%s package not right size.",
1638906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
1649004SNapanda.Pemmaiah@Sun.COM 			if (p_res >= 0)
1659004SNapanda.Pemmaiah@Sun.COM 				PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
1668906SEric.Saxe@Sun.COM 			goto out;
1678906SEric.Saxe@Sun.COM 		}
1688906SEric.Saxe@Sun.COM 		if (greg->AddressSpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE &&
1698906SEric.Saxe@Sun.COM 		    greg->AddressSpaceId != ACPI_ADR_SPACE_SYSTEM_IO) {
1709004SNapanda.Pemmaiah@Sun.COM 			p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_apci: "
1719004SNapanda.Pemmaiah@Sun.COM 			    "%s contains unsupported address space type %x",
1728906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name,
1738906SEric.Saxe@Sun.COM 			    greg->AddressSpaceId);
1749004SNapanda.Pemmaiah@Sun.COM 			if (p_res >= 0)
1759004SNapanda.Pemmaiah@Sun.COM 				PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
1768906SEric.Saxe@Sun.COM 			goto out;
1778906SEric.Saxe@Sun.COM 		}
1788906SEric.Saxe@Sun.COM 	}
1798906SEric.Saxe@Sun.COM 
1808906SEric.Saxe@Sun.COM 	/*
1818906SEric.Saxe@Sun.COM 	 * Looks good!
1828906SEric.Saxe@Sun.COM 	 */
1838906SEric.Saxe@Sun.COM 	for (i = 0; i < obj->Package.Count; i++) {
1848906SEric.Saxe@Sun.COM 		greg = (AML_RESOURCE_GENERIC_REGISTER *)
1858906SEric.Saxe@Sun.COM 		    obj->Package.Elements[i].Buffer.Pointer;
1868906SEric.Saxe@Sun.COM 		regs[i].cr_addrspace_id = greg->AddressSpaceId;
1878906SEric.Saxe@Sun.COM 		regs[i].cr_width = greg->BitWidth;
1888906SEric.Saxe@Sun.COM 		regs[i].cr_offset = greg->BitOffset;
1898906SEric.Saxe@Sun.COM 		regs[i].cr_asize = greg->AccessSize;
1908906SEric.Saxe@Sun.COM 		regs[i].cr_address = greg->Address;
1918906SEric.Saxe@Sun.COM 	}
1928906SEric.Saxe@Sun.COM 	ret = 0;
1938906SEric.Saxe@Sun.COM out:
1948906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
1958906SEric.Saxe@Sun.COM 	return (ret);
1968906SEric.Saxe@Sun.COM }
1978906SEric.Saxe@Sun.COM 
1988906SEric.Saxe@Sun.COM /*
1998906SEric.Saxe@Sun.COM  * Cache the ACPI _PCT data. The _PCT data defines the interface to use
2008906SEric.Saxe@Sun.COM  * when making power level transitions (i.e., system IO ports, fixed
2018906SEric.Saxe@Sun.COM  * hardware port, etc).
2028906SEric.Saxe@Sun.COM  */
2038906SEric.Saxe@Sun.COM static int
2048906SEric.Saxe@Sun.COM cpu_acpi_cache_pct(cpu_acpi_handle_t handle)
2058906SEric.Saxe@Sun.COM {
2068906SEric.Saxe@Sun.COM 	cpu_acpi_pct_t *pct;
2078906SEric.Saxe@Sun.COM 	int ret;
2088906SEric.Saxe@Sun.COM 
2098906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PCT_CACHED);
2108906SEric.Saxe@Sun.COM 	pct = &CPU_ACPI_PCT(handle)[0];
2118906SEric.Saxe@Sun.COM 	if ((ret = cpu_acpi_cache_ctrl_regs(handle, PCT_OBJ, pct)) == 0)
2128906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PCT_CACHED);
2138906SEric.Saxe@Sun.COM 	return (ret);
2148906SEric.Saxe@Sun.COM }
2158906SEric.Saxe@Sun.COM 
2168906SEric.Saxe@Sun.COM /*
2178906SEric.Saxe@Sun.COM  * Cache the ACPI _PTC data. The _PTC data defines the interface to use
2188906SEric.Saxe@Sun.COM  * when making T-state transitions (i.e., system IO ports, fixed
2198906SEric.Saxe@Sun.COM  * hardware port, etc).
2208906SEric.Saxe@Sun.COM  */
2218906SEric.Saxe@Sun.COM static int
2228906SEric.Saxe@Sun.COM cpu_acpi_cache_ptc(cpu_acpi_handle_t handle)
2238906SEric.Saxe@Sun.COM {
2248906SEric.Saxe@Sun.COM 	cpu_acpi_ptc_t *ptc;
2258906SEric.Saxe@Sun.COM 	int ret;
2268906SEric.Saxe@Sun.COM 
2278906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PTC_CACHED);
2288906SEric.Saxe@Sun.COM 	ptc = &CPU_ACPI_PTC(handle)[0];
2298906SEric.Saxe@Sun.COM 	if ((ret = cpu_acpi_cache_ctrl_regs(handle, PTC_OBJ, ptc)) == 0)
2308906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PTC_CACHED);
2318906SEric.Saxe@Sun.COM 	return (ret);
2328906SEric.Saxe@Sun.COM }
2338906SEric.Saxe@Sun.COM 
2348906SEric.Saxe@Sun.COM /*
2358906SEric.Saxe@Sun.COM  * Cache the ACPI CPU state dependency data objects.
2368906SEric.Saxe@Sun.COM  */
2378906SEric.Saxe@Sun.COM static int
2388906SEric.Saxe@Sun.COM cpu_acpi_cache_state_dependencies(cpu_acpi_handle_t handle,
2398906SEric.Saxe@Sun.COM     cpu_acpi_obj_t objtype, cpu_acpi_state_dependency_t *sd)
2408906SEric.Saxe@Sun.COM {
2418906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
2428906SEric.Saxe@Sun.COM 	ACPI_OBJECT *pkg, *elements;
2438906SEric.Saxe@Sun.COM 	int number;
2448906SEric.Saxe@Sun.COM 	int ret = -1;
2459004SNapanda.Pemmaiah@Sun.COM 	int p_res;
2468906SEric.Saxe@Sun.COM 
2478906SEric.Saxe@Sun.COM 	if (objtype == CSD_OBJ) {
2488906SEric.Saxe@Sun.COM 		number = 6;
2498906SEric.Saxe@Sun.COM 	} else {
2508906SEric.Saxe@Sun.COM 		number = 5;
2518906SEric.Saxe@Sun.COM 	}
2528906SEric.Saxe@Sun.COM 	/*
2538906SEric.Saxe@Sun.COM 	 * Fetch the dependencies (if present) for the CPU node.
2548906SEric.Saxe@Sun.COM 	 * Since they are optional, non-existence is not a failure
2558906SEric.Saxe@Sun.COM 	 * (it's up to the caller to determine how to handle non-existence).
2568906SEric.Saxe@Sun.COM 	 */
2578906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
2588906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
2598906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle->cs_handle,
2608906SEric.Saxe@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf,
2618906SEric.Saxe@Sun.COM 	    ACPI_TYPE_PACKAGE))) {
2628906SEric.Saxe@Sun.COM 		return (1);
2638906SEric.Saxe@Sun.COM 	}
2648906SEric.Saxe@Sun.COM 
2658906SEric.Saxe@Sun.COM 	pkg = abuf.Pointer;
2668906SEric.Saxe@Sun.COM 
2678906SEric.Saxe@Sun.COM 	if (((objtype != CSD_OBJ) && (pkg->Package.Count != 1)) ||
2688906SEric.Saxe@Sun.COM 	    ((objtype == CSD_OBJ) && (pkg->Package.Count != 1) &&
2698906SEric.Saxe@Sun.COM 	    (pkg->Package.Count != 2))) {
2709004SNapanda.Pemmaiah@Sun.COM 		p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: %s "
2719004SNapanda.Pemmaiah@Sun.COM 		    "unsupported package count %d.",
2729004SNapanda.Pemmaiah@Sun.COM 		    cpu_acpi_obj_attrs[objtype].name, pkg->Package.Count);
2739004SNapanda.Pemmaiah@Sun.COM 		if (p_res >= 0)
2749004SNapanda.Pemmaiah@Sun.COM 			PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
2758906SEric.Saxe@Sun.COM 		goto out;
2768906SEric.Saxe@Sun.COM 	}
2778906SEric.Saxe@Sun.COM 
2788906SEric.Saxe@Sun.COM 	/*
2798906SEric.Saxe@Sun.COM 	 * For C-state domain, we assume C2 and C3 have the same
2808906SEric.Saxe@Sun.COM 	 * domain information
2818906SEric.Saxe@Sun.COM 	 */
2828906SEric.Saxe@Sun.COM 	if (pkg->Package.Elements[0].Type != ACPI_TYPE_PACKAGE ||
2838906SEric.Saxe@Sun.COM 	    pkg->Package.Elements[0].Package.Count != number) {
2849004SNapanda.Pemmaiah@Sun.COM 		p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: "
2859004SNapanda.Pemmaiah@Sun.COM 		    "Unexpected data in %s package.",
2868906SEric.Saxe@Sun.COM 		    cpu_acpi_obj_attrs[objtype].name);
2879004SNapanda.Pemmaiah@Sun.COM 		if (p_res >= 0)
2889004SNapanda.Pemmaiah@Sun.COM 			PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
2898906SEric.Saxe@Sun.COM 		goto out;
2908906SEric.Saxe@Sun.COM 	}
2918906SEric.Saxe@Sun.COM 	elements = pkg->Package.Elements[0].Package.Elements;
2928906SEric.Saxe@Sun.COM 	if (elements[0].Integer.Value != number ||
2938906SEric.Saxe@Sun.COM 	    elements[1].Integer.Value != 0) {
2949004SNapanda.Pemmaiah@Sun.COM 		p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: Unexpected"
2959004SNapanda.Pemmaiah@Sun.COM 		    " %s revision.", cpu_acpi_obj_attrs[objtype].name);
2969004SNapanda.Pemmaiah@Sun.COM 		if (p_res >= 0)
2979004SNapanda.Pemmaiah@Sun.COM 			PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
2988906SEric.Saxe@Sun.COM 		goto out;
2998906SEric.Saxe@Sun.COM 	}
3008906SEric.Saxe@Sun.COM 
3018906SEric.Saxe@Sun.COM 	sd->sd_entries = elements[0].Integer.Value;
3028906SEric.Saxe@Sun.COM 	sd->sd_revision = elements[1].Integer.Value;
3038906SEric.Saxe@Sun.COM 	sd->sd_domain = elements[2].Integer.Value;
3048906SEric.Saxe@Sun.COM 	sd->sd_type = elements[3].Integer.Value;
3058906SEric.Saxe@Sun.COM 	sd->sd_num = elements[4].Integer.Value;
3068906SEric.Saxe@Sun.COM 	if (objtype == CSD_OBJ) {
3078906SEric.Saxe@Sun.COM 		sd->sd_index = elements[5].Integer.Value;
3088906SEric.Saxe@Sun.COM 	}
3098906SEric.Saxe@Sun.COM 
3108906SEric.Saxe@Sun.COM 	ret = 0;
3118906SEric.Saxe@Sun.COM out:
3128906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
3138906SEric.Saxe@Sun.COM 	return (ret);
3148906SEric.Saxe@Sun.COM }
3158906SEric.Saxe@Sun.COM 
3168906SEric.Saxe@Sun.COM /*
3178906SEric.Saxe@Sun.COM  * Cache the ACPI _PSD data. The _PSD data defines P-state CPU dependencies
3188906SEric.Saxe@Sun.COM  * (think CPU domains).
3198906SEric.Saxe@Sun.COM  */
3208906SEric.Saxe@Sun.COM static int
3218906SEric.Saxe@Sun.COM cpu_acpi_cache_psd(cpu_acpi_handle_t handle)
3228906SEric.Saxe@Sun.COM {
3238906SEric.Saxe@Sun.COM 	cpu_acpi_psd_t *psd;
3248906SEric.Saxe@Sun.COM 	int ret;
3258906SEric.Saxe@Sun.COM 
3268906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSD_CACHED);
3278906SEric.Saxe@Sun.COM 	psd = &CPU_ACPI_PSD(handle);
3288906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_state_dependencies(handle, PSD_OBJ, psd);
3298906SEric.Saxe@Sun.COM 	if (ret == 0)
3308906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSD_CACHED);
3318906SEric.Saxe@Sun.COM 	return (ret);
3328906SEric.Saxe@Sun.COM 
3338906SEric.Saxe@Sun.COM }
3348906SEric.Saxe@Sun.COM 
3358906SEric.Saxe@Sun.COM /*
3368906SEric.Saxe@Sun.COM  * Cache the ACPI _TSD data. The _TSD data defines T-state CPU dependencies
3378906SEric.Saxe@Sun.COM  * (think CPU domains).
3388906SEric.Saxe@Sun.COM  */
3398906SEric.Saxe@Sun.COM static int
3408906SEric.Saxe@Sun.COM cpu_acpi_cache_tsd(cpu_acpi_handle_t handle)
3418906SEric.Saxe@Sun.COM {
3428906SEric.Saxe@Sun.COM 	cpu_acpi_tsd_t *tsd;
3438906SEric.Saxe@Sun.COM 	int ret;
3448906SEric.Saxe@Sun.COM 
3458906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSD_CACHED);
3468906SEric.Saxe@Sun.COM 	tsd = &CPU_ACPI_TSD(handle);
3478906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_state_dependencies(handle, TSD_OBJ, tsd);
3488906SEric.Saxe@Sun.COM 	if (ret == 0)
3498906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSD_CACHED);
3508906SEric.Saxe@Sun.COM 	return (ret);
3518906SEric.Saxe@Sun.COM 
3528906SEric.Saxe@Sun.COM }
3538906SEric.Saxe@Sun.COM 
3548906SEric.Saxe@Sun.COM /*
3558906SEric.Saxe@Sun.COM  * Cache the ACPI _CSD data. The _CSD data defines C-state CPU dependencies
3568906SEric.Saxe@Sun.COM  * (think CPU domains).
3578906SEric.Saxe@Sun.COM  */
3588906SEric.Saxe@Sun.COM static int
3598906SEric.Saxe@Sun.COM cpu_acpi_cache_csd(cpu_acpi_handle_t handle)
3608906SEric.Saxe@Sun.COM {
3618906SEric.Saxe@Sun.COM 	cpu_acpi_csd_t *csd;
3628906SEric.Saxe@Sun.COM 	int ret;
3638906SEric.Saxe@Sun.COM 
3648906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CSD_CACHED);
3658906SEric.Saxe@Sun.COM 	csd = &CPU_ACPI_CSD(handle);
3668906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_state_dependencies(handle, CSD_OBJ, csd);
3678906SEric.Saxe@Sun.COM 	if (ret == 0)
3688906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CSD_CACHED);
3698906SEric.Saxe@Sun.COM 	return (ret);
3708906SEric.Saxe@Sun.COM 
3718906SEric.Saxe@Sun.COM }
3728906SEric.Saxe@Sun.COM 
3738906SEric.Saxe@Sun.COM static void
3748906SEric.Saxe@Sun.COM cpu_acpi_cache_pstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
3758906SEric.Saxe@Sun.COM {
3768906SEric.Saxe@Sun.COM 	cpu_acpi_pstate_t *pstate;
3778906SEric.Saxe@Sun.COM 	ACPI_OBJECT *q, *l;
3788906SEric.Saxe@Sun.COM 	int i, j;
3798906SEric.Saxe@Sun.COM 
3808906SEric.Saxe@Sun.COM 	CPU_ACPI_PSTATES_COUNT(handle) = cnt;
3818906SEric.Saxe@Sun.COM 	CPU_ACPI_PSTATES(handle) = kmem_zalloc(CPU_ACPI_PSTATES_SIZE(cnt),
3828906SEric.Saxe@Sun.COM 	    KM_SLEEP);
3838906SEric.Saxe@Sun.COM 	pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
3848906SEric.Saxe@Sun.COM 	for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
3858906SEric.Saxe@Sun.COM 		uint32_t *up;
3868906SEric.Saxe@Sun.COM 
3878906SEric.Saxe@Sun.COM 		q = obj->Package.Elements[i].Package.Elements;
3888906SEric.Saxe@Sun.COM 
3898906SEric.Saxe@Sun.COM 		/*
3908906SEric.Saxe@Sun.COM 		 * Skip duplicate entries.
3918906SEric.Saxe@Sun.COM 		 */
3928906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
3938906SEric.Saxe@Sun.COM 			continue;
3948906SEric.Saxe@Sun.COM 
3958906SEric.Saxe@Sun.COM 		up = (uint32_t *)pstate;
3968906SEric.Saxe@Sun.COM 		for (j = 0; j < CPU_ACPI_PSS_CNT; j++)
3978906SEric.Saxe@Sun.COM 			up[j] = q[j].Integer.Value;
3988906SEric.Saxe@Sun.COM 		pstate++;
3998906SEric.Saxe@Sun.COM 		cnt--;
4008906SEric.Saxe@Sun.COM 	}
4018906SEric.Saxe@Sun.COM }
4028906SEric.Saxe@Sun.COM 
4038906SEric.Saxe@Sun.COM static void
4048906SEric.Saxe@Sun.COM cpu_acpi_cache_tstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
4058906SEric.Saxe@Sun.COM {
4068906SEric.Saxe@Sun.COM 	cpu_acpi_tstate_t *tstate;
4078906SEric.Saxe@Sun.COM 	ACPI_OBJECT *q, *l;
4088906SEric.Saxe@Sun.COM 	int i, j;
4098906SEric.Saxe@Sun.COM 
4108906SEric.Saxe@Sun.COM 	CPU_ACPI_TSTATES_COUNT(handle) = cnt;
4118906SEric.Saxe@Sun.COM 	CPU_ACPI_TSTATES(handle) = kmem_zalloc(CPU_ACPI_TSTATES_SIZE(cnt),
4128906SEric.Saxe@Sun.COM 	    KM_SLEEP);
4138906SEric.Saxe@Sun.COM 	tstate = (cpu_acpi_tstate_t *)CPU_ACPI_TSTATES(handle);
4148906SEric.Saxe@Sun.COM 	for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
4158906SEric.Saxe@Sun.COM 		uint32_t *up;
4168906SEric.Saxe@Sun.COM 
4178906SEric.Saxe@Sun.COM 		q = obj->Package.Elements[i].Package.Elements;
4188906SEric.Saxe@Sun.COM 
4198906SEric.Saxe@Sun.COM 		/*
4208906SEric.Saxe@Sun.COM 		 * Skip duplicate entries.
4218906SEric.Saxe@Sun.COM 		 */
4228906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
4238906SEric.Saxe@Sun.COM 			continue;
4248906SEric.Saxe@Sun.COM 
4258906SEric.Saxe@Sun.COM 		up = (uint32_t *)tstate;
4268906SEric.Saxe@Sun.COM 		for (j = 0; j < CPU_ACPI_TSS_CNT; j++)
4278906SEric.Saxe@Sun.COM 			up[j] = q[j].Integer.Value;
4288906SEric.Saxe@Sun.COM 		tstate++;
4298906SEric.Saxe@Sun.COM 		cnt--;
4308906SEric.Saxe@Sun.COM 	}
4318906SEric.Saxe@Sun.COM }
4328906SEric.Saxe@Sun.COM 
4338906SEric.Saxe@Sun.COM /*
4348906SEric.Saxe@Sun.COM  * Cache the _PSS or _TSS data.
4358906SEric.Saxe@Sun.COM  */
4368906SEric.Saxe@Sun.COM static int
4378906SEric.Saxe@Sun.COM cpu_acpi_cache_supported_states(cpu_acpi_handle_t handle,
4388906SEric.Saxe@Sun.COM     cpu_acpi_obj_t objtype, int fcnt)
4398906SEric.Saxe@Sun.COM {
4408906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
4418906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj, *q, *l;
4428906SEric.Saxe@Sun.COM 	boolean_t eot = B_FALSE;
4438906SEric.Saxe@Sun.COM 	int ret = -1;
4448906SEric.Saxe@Sun.COM 	int cnt;
4458906SEric.Saxe@Sun.COM 	int i, j;
4469004SNapanda.Pemmaiah@Sun.COM 	int p_res;
4478906SEric.Saxe@Sun.COM 
4488906SEric.Saxe@Sun.COM 	/*
4498906SEric.Saxe@Sun.COM 	 * Fetch the data (if present) for the CPU node.
4508906SEric.Saxe@Sun.COM 	 */
4518906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
4528906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
4538906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle->cs_handle,
4548906SEric.Saxe@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf,
4558906SEric.Saxe@Sun.COM 	    ACPI_TYPE_PACKAGE))) {
4569004SNapanda.Pemmaiah@Sun.COM 		p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: %s "
4579004SNapanda.Pemmaiah@Sun.COM 		    "package not found.", cpu_acpi_obj_attrs[objtype].name);
4589004SNapanda.Pemmaiah@Sun.COM 		if (p_res >= 0)
4599004SNapanda.Pemmaiah@Sun.COM 			PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
4608906SEric.Saxe@Sun.COM 		return (1);
4618906SEric.Saxe@Sun.COM 	}
4628906SEric.Saxe@Sun.COM 	obj = abuf.Pointer;
4638906SEric.Saxe@Sun.COM 	if (obj->Package.Count < 2) {
4649004SNapanda.Pemmaiah@Sun.COM 		p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: %s package"
4659004SNapanda.Pemmaiah@Sun.COM 		    " bad count %d.", cpu_acpi_obj_attrs[objtype].name,
4669004SNapanda.Pemmaiah@Sun.COM 		    obj->Package.Count);
4679004SNapanda.Pemmaiah@Sun.COM 		if (p_res >= 0)
4689004SNapanda.Pemmaiah@Sun.COM 			PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
4698906SEric.Saxe@Sun.COM 		goto out;
4708906SEric.Saxe@Sun.COM 	}
4718906SEric.Saxe@Sun.COM 
4728906SEric.Saxe@Sun.COM 	/*
4738906SEric.Saxe@Sun.COM 	 * Does the package look coherent?
4748906SEric.Saxe@Sun.COM 	 */
4758906SEric.Saxe@Sun.COM 	cnt = 0;
4768906SEric.Saxe@Sun.COM 	for (i = 0, l = NULL; i < obj->Package.Count; i++, l = q) {
4778906SEric.Saxe@Sun.COM 		if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE ||
4788906SEric.Saxe@Sun.COM 		    obj->Package.Elements[i].Package.Count != fcnt) {
4799004SNapanda.Pemmaiah@Sun.COM 			p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: "
4808906SEric.Saxe@Sun.COM 			    "Unexpected data in %s package.",
4818906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
4829004SNapanda.Pemmaiah@Sun.COM 			if (p_res >= 0)
4839004SNapanda.Pemmaiah@Sun.COM 				PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
4848906SEric.Saxe@Sun.COM 			goto out;
4858906SEric.Saxe@Sun.COM 		}
4868906SEric.Saxe@Sun.COM 
4878906SEric.Saxe@Sun.COM 		q = obj->Package.Elements[i].Package.Elements;
4888906SEric.Saxe@Sun.COM 		for (j = 0; j < fcnt; j++) {
4898906SEric.Saxe@Sun.COM 			if (q[j].Type != ACPI_TYPE_INTEGER) {
4909004SNapanda.Pemmaiah@Sun.COM 				p_res = snprintf(err_msg, ERR_MSG_SIZE,
4919004SNapanda.Pemmaiah@Sun.COM 				    "!cpu_acpi: %s element invalid (type)",
4928906SEric.Saxe@Sun.COM 				    cpu_acpi_obj_attrs[objtype].name);
4939004SNapanda.Pemmaiah@Sun.COM 				if (p_res >= 0)
4949004SNapanda.Pemmaiah@Sun.COM 					PRINT_ERR_MSG(CE_NOTE, err_msg,
4959004SNapanda.Pemmaiah@Sun.COM 					    objtype);
4968906SEric.Saxe@Sun.COM 				goto out;
4978906SEric.Saxe@Sun.COM 			}
4988906SEric.Saxe@Sun.COM 		}
4998906SEric.Saxe@Sun.COM 
5008906SEric.Saxe@Sun.COM 		/*
5018906SEric.Saxe@Sun.COM 		 * Ignore duplicate entries.
5028906SEric.Saxe@Sun.COM 		 */
5038906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
5048906SEric.Saxe@Sun.COM 			continue;
5058906SEric.Saxe@Sun.COM 
5068906SEric.Saxe@Sun.COM 		/*
5078906SEric.Saxe@Sun.COM 		 * Some supported state tables are larger than required
5088906SEric.Saxe@Sun.COM 		 * and unused elements are filled with patterns
5098906SEric.Saxe@Sun.COM 		 * of 0xff.  Simply check here for frequency = 0xffff
5108906SEric.Saxe@Sun.COM 		 * and stop counting if found.
5118906SEric.Saxe@Sun.COM 		 */
5128906SEric.Saxe@Sun.COM 		if (q[0].Integer.Value == 0xffff) {
5138906SEric.Saxe@Sun.COM 			eot = B_TRUE;
5148906SEric.Saxe@Sun.COM 			continue;
5158906SEric.Saxe@Sun.COM 		}
5168906SEric.Saxe@Sun.COM 
5178906SEric.Saxe@Sun.COM 		/*
5188906SEric.Saxe@Sun.COM 		 * We should never find a valid entry after we've hit
5198906SEric.Saxe@Sun.COM 		 * an the end-of-table entry.
5208906SEric.Saxe@Sun.COM 		 */
5218906SEric.Saxe@Sun.COM 		if (eot) {
5229004SNapanda.Pemmaiah@Sun.COM 			p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: "
5238906SEric.Saxe@Sun.COM 			    "Unexpected data in %s package after eot.",
5248906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
5259004SNapanda.Pemmaiah@Sun.COM 			if (p_res >= 0)
5269004SNapanda.Pemmaiah@Sun.COM 				PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
5278906SEric.Saxe@Sun.COM 			goto out;
5288906SEric.Saxe@Sun.COM 		}
5298906SEric.Saxe@Sun.COM 
5308906SEric.Saxe@Sun.COM 		/*
5318906SEric.Saxe@Sun.COM 		 * states must be defined in order from highest to lowest.
5328906SEric.Saxe@Sun.COM 		 */
5338906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value < q[0].Integer.Value) {
5349004SNapanda.Pemmaiah@Sun.COM 			p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: "
5358906SEric.Saxe@Sun.COM 			    "%s package state definitions out of order.",
5368906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name);
5379004SNapanda.Pemmaiah@Sun.COM 			if (p_res >= 0)
5389004SNapanda.Pemmaiah@Sun.COM 				PRINT_ERR_MSG(CE_NOTE, err_msg, objtype);
5398906SEric.Saxe@Sun.COM 			goto out;
5408906SEric.Saxe@Sun.COM 		}
5418906SEric.Saxe@Sun.COM 
5428906SEric.Saxe@Sun.COM 		/*
5438906SEric.Saxe@Sun.COM 		 * This entry passes.
5448906SEric.Saxe@Sun.COM 		 */
5458906SEric.Saxe@Sun.COM 		cnt++;
5468906SEric.Saxe@Sun.COM 	}
5478906SEric.Saxe@Sun.COM 	if (cnt == 0)
5488906SEric.Saxe@Sun.COM 		goto out;
5498906SEric.Saxe@Sun.COM 
5508906SEric.Saxe@Sun.COM 	/*
5518906SEric.Saxe@Sun.COM 	 * Yes, fill in the structure.
5528906SEric.Saxe@Sun.COM 	 */
5538906SEric.Saxe@Sun.COM 	ASSERT(objtype == PSS_OBJ || objtype == TSS_OBJ);
5548906SEric.Saxe@Sun.COM 	(objtype == PSS_OBJ) ? cpu_acpi_cache_pstate(handle, obj, cnt) :
5558906SEric.Saxe@Sun.COM 	    cpu_acpi_cache_tstate(handle, obj, cnt);
5568906SEric.Saxe@Sun.COM 
5578906SEric.Saxe@Sun.COM 	ret = 0;
5588906SEric.Saxe@Sun.COM out:
5598906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
5608906SEric.Saxe@Sun.COM 	return (ret);
5618906SEric.Saxe@Sun.COM }
5628906SEric.Saxe@Sun.COM 
5638906SEric.Saxe@Sun.COM /*
5648906SEric.Saxe@Sun.COM  * Cache the _PSS data. The _PSS data defines the different power levels
5658906SEric.Saxe@Sun.COM  * supported by the CPU and the attributes associated with each power level
5668906SEric.Saxe@Sun.COM  * (i.e., frequency, voltage, etc.). The power levels are number from
5678906SEric.Saxe@Sun.COM  * highest to lowest. That is, the highest power level is _PSS entry 0
5688906SEric.Saxe@Sun.COM  * and the lowest power level is the last _PSS entry.
5698906SEric.Saxe@Sun.COM  */
5708906SEric.Saxe@Sun.COM static int
5718906SEric.Saxe@Sun.COM cpu_acpi_cache_pstates(cpu_acpi_handle_t handle)
5728906SEric.Saxe@Sun.COM {
5738906SEric.Saxe@Sun.COM 	int ret;
5748906SEric.Saxe@Sun.COM 
5758906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSS_CACHED);
5768906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_supported_states(handle, PSS_OBJ,
5778906SEric.Saxe@Sun.COM 	    CPU_ACPI_PSS_CNT);
5788906SEric.Saxe@Sun.COM 	if (ret == 0)
5798906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSS_CACHED);
5808906SEric.Saxe@Sun.COM 	return (ret);
5818906SEric.Saxe@Sun.COM }
5828906SEric.Saxe@Sun.COM 
5838906SEric.Saxe@Sun.COM /*
5848906SEric.Saxe@Sun.COM  * Cache the _TSS data. The _TSS data defines the different freq throttle
5858906SEric.Saxe@Sun.COM  * levels supported by the CPU and the attributes associated with each
5868906SEric.Saxe@Sun.COM  * throttle level (i.e., frequency throttle percentage, voltage, etc.).
5878906SEric.Saxe@Sun.COM  * The throttle levels are number from highest to lowest.
5888906SEric.Saxe@Sun.COM  */
5898906SEric.Saxe@Sun.COM static int
5908906SEric.Saxe@Sun.COM cpu_acpi_cache_tstates(cpu_acpi_handle_t handle)
5918906SEric.Saxe@Sun.COM {
5928906SEric.Saxe@Sun.COM 	int ret;
5938906SEric.Saxe@Sun.COM 
5948906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSS_CACHED);
5958906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_supported_states(handle, TSS_OBJ,
5968906SEric.Saxe@Sun.COM 	    CPU_ACPI_TSS_CNT);
5978906SEric.Saxe@Sun.COM 	if (ret == 0)
5988906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSS_CACHED);
5998906SEric.Saxe@Sun.COM 	return (ret);
6008906SEric.Saxe@Sun.COM }
6018906SEric.Saxe@Sun.COM 
6028906SEric.Saxe@Sun.COM /*
6038906SEric.Saxe@Sun.COM  * Cache the ACPI CPU present capabilities data objects.
6048906SEric.Saxe@Sun.COM  */
6058906SEric.Saxe@Sun.COM static int
6068906SEric.Saxe@Sun.COM cpu_acpi_cache_present_capabilities(cpu_acpi_handle_t handle,
6078906SEric.Saxe@Sun.COM     cpu_acpi_obj_t objtype, cpu_acpi_present_capabilities_t *pc)
6088906SEric.Saxe@Sun.COM 
6098906SEric.Saxe@Sun.COM {
6108906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
6118906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj;
6128906SEric.Saxe@Sun.COM 
6138906SEric.Saxe@Sun.COM 	/*
6148906SEric.Saxe@Sun.COM 	 * Fetch the present capabilites object (if present) for the CPU node.
6158906SEric.Saxe@Sun.COM 	 * Since they are optional, non-existence is not a failure.
6168906SEric.Saxe@Sun.COM 	 */
6178906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
6188906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
6198906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObject(handle->cs_handle,
6208906SEric.Saxe@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf)) ||
6218906SEric.Saxe@Sun.COM 	    abuf.Length == 0) {
6228906SEric.Saxe@Sun.COM 		*pc = 0;
6238906SEric.Saxe@Sun.COM 		return (1);
6248906SEric.Saxe@Sun.COM 	}
6258906SEric.Saxe@Sun.COM 
6268906SEric.Saxe@Sun.COM 	obj = (ACPI_OBJECT *)abuf.Pointer;
6278906SEric.Saxe@Sun.COM 	*pc = obj->Integer.Value;
6288906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
6298906SEric.Saxe@Sun.COM 	return (0);
6308906SEric.Saxe@Sun.COM }
6318906SEric.Saxe@Sun.COM 
6328906SEric.Saxe@Sun.COM /*
6338906SEric.Saxe@Sun.COM  * Cache the _PPC data. The _PPC simply contains an integer value which
6348906SEric.Saxe@Sun.COM  * represents the highest power level that a CPU should transition to.
6358906SEric.Saxe@Sun.COM  * That is, it's an index into the array of _PSS entries and will be
6368906SEric.Saxe@Sun.COM  * greater than or equal to zero.
6378906SEric.Saxe@Sun.COM  */
6388906SEric.Saxe@Sun.COM void
6398906SEric.Saxe@Sun.COM cpu_acpi_cache_ppc(cpu_acpi_handle_t handle)
6408906SEric.Saxe@Sun.COM {
6418906SEric.Saxe@Sun.COM 	cpu_acpi_ppc_t *ppc;
6428906SEric.Saxe@Sun.COM 	int ret;
6438906SEric.Saxe@Sun.COM 
6448906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PPC_CACHED);
6458906SEric.Saxe@Sun.COM 	ppc = &CPU_ACPI_PPC(handle);
6468906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_present_capabilities(handle, PPC_OBJ, ppc);
6478906SEric.Saxe@Sun.COM 	if (ret == 0)
6488906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PPC_CACHED);
6498906SEric.Saxe@Sun.COM }
6508906SEric.Saxe@Sun.COM 
6518906SEric.Saxe@Sun.COM /*
6528906SEric.Saxe@Sun.COM  * Cache the _TPC data. The _TPC simply contains an integer value which
6538906SEric.Saxe@Sun.COM  * represents the throttle level that a CPU should transition to.
6548906SEric.Saxe@Sun.COM  * That is, it's an index into the array of _TSS entries and will be
6558906SEric.Saxe@Sun.COM  * greater than or equal to zero.
6568906SEric.Saxe@Sun.COM  */
6578906SEric.Saxe@Sun.COM void
6588906SEric.Saxe@Sun.COM cpu_acpi_cache_tpc(cpu_acpi_handle_t handle)
6598906SEric.Saxe@Sun.COM {
6608906SEric.Saxe@Sun.COM 	cpu_acpi_tpc_t *tpc;
6618906SEric.Saxe@Sun.COM 	int ret;
6628906SEric.Saxe@Sun.COM 
6638906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TPC_CACHED);
6648906SEric.Saxe@Sun.COM 	tpc = &CPU_ACPI_TPC(handle);
6658906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_present_capabilities(handle, TPC_OBJ, tpc);
6668906SEric.Saxe@Sun.COM 	if (ret == 0)
6678906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TPC_CACHED);
6688906SEric.Saxe@Sun.COM }
6698906SEric.Saxe@Sun.COM 
6708906SEric.Saxe@Sun.COM int
6718906SEric.Saxe@Sun.COM cpu_acpi_verify_cstate(cpu_acpi_cstate_t *cstate)
6728906SEric.Saxe@Sun.COM {
6738906SEric.Saxe@Sun.COM 	uint32_t addrspaceid = cstate->cs_addrspace_id;
6748906SEric.Saxe@Sun.COM 
6758906SEric.Saxe@Sun.COM 	if ((addrspaceid != ACPI_ADR_SPACE_FIXED_HARDWARE) &&
6768906SEric.Saxe@Sun.COM 	    (addrspaceid != ACPI_ADR_SPACE_SYSTEM_IO)) {
6778906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!_CST: unsupported address space id"
6788906SEric.Saxe@Sun.COM 		    ":C%d, type: %d\n", cstate->cs_type, addrspaceid);
6798906SEric.Saxe@Sun.COM 		return (1);
6808906SEric.Saxe@Sun.COM 	}
6818906SEric.Saxe@Sun.COM 	return (0);
6828906SEric.Saxe@Sun.COM }
6838906SEric.Saxe@Sun.COM 
6848906SEric.Saxe@Sun.COM int
6858906SEric.Saxe@Sun.COM cpu_acpi_cache_cst(cpu_acpi_handle_t handle)
6868906SEric.Saxe@Sun.COM {
6878906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
6888906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj;
6898906SEric.Saxe@Sun.COM 	ACPI_INTEGER cnt;
6908906SEric.Saxe@Sun.COM 	cpu_acpi_cstate_t *cstate, *p;
691*9148SBill.Holler@Sun.COM 	size_t alloc_size;
6928906SEric.Saxe@Sun.COM 	int i, count;
6938906SEric.Saxe@Sun.COM 
6948906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CST_CACHED);
6958906SEric.Saxe@Sun.COM 
6968906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
6978906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
6988906SEric.Saxe@Sun.COM 
6999147SBill.Holler@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle->cs_handle, "_CST",
7009147SBill.Holler@Sun.COM 	    NULL, &abuf, ACPI_TYPE_PACKAGE))) {
7018906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST evaluate failure");
7028906SEric.Saxe@Sun.COM 		return (-1);
7038906SEric.Saxe@Sun.COM 	}
7048906SEric.Saxe@Sun.COM 	obj = (ACPI_OBJECT *)abuf.Pointer;
7058906SEric.Saxe@Sun.COM 	if (obj->Package.Count < 2) {
7068906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST package bad count %d.",
7078906SEric.Saxe@Sun.COM 		    obj->Package.Count);
7088906SEric.Saxe@Sun.COM 		AcpiOsFree(abuf.Pointer);
7098906SEric.Saxe@Sun.COM 		return (-1);
7108906SEric.Saxe@Sun.COM 	}
7118906SEric.Saxe@Sun.COM 
7128906SEric.Saxe@Sun.COM 	/*
7138906SEric.Saxe@Sun.COM 	 * Does the package look coherent?
7148906SEric.Saxe@Sun.COM 	 */
7158906SEric.Saxe@Sun.COM 	cnt = obj->Package.Elements[0].Integer.Value;
7168906SEric.Saxe@Sun.COM 	if (cnt < 1 || cnt != obj->Package.Count - 1) {
7178906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid element count %d != "
7188906SEric.Saxe@Sun.COM 		    "Package count %d\n",
7198906SEric.Saxe@Sun.COM 		    (int)cnt, (int)obj->Package.Count - 1);
7208906SEric.Saxe@Sun.COM 		AcpiOsFree(abuf.Pointer);
7218906SEric.Saxe@Sun.COM 		return (-1);
7228906SEric.Saxe@Sun.COM 	}
7238906SEric.Saxe@Sun.COM 
7248906SEric.Saxe@Sun.COM 	CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)cnt;
725*9148SBill.Holler@Sun.COM 	alloc_size = CPU_ACPI_CSTATES_SIZE(cnt);
726*9148SBill.Holler@Sun.COM 	CPU_ACPI_CSTATES(handle) = kmem_zalloc(alloc_size, KM_SLEEP);
7278906SEric.Saxe@Sun.COM 	CPU_ACPI_BM_INFO(handle) = 0;
7288906SEric.Saxe@Sun.COM 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
7298906SEric.Saxe@Sun.COM 	p = cstate;
7308906SEric.Saxe@Sun.COM 
7318906SEric.Saxe@Sun.COM 	for (i = 1, count = 1; i <= cnt; i++) {
7328906SEric.Saxe@Sun.COM 		ACPI_OBJECT *pkg;
7338906SEric.Saxe@Sun.COM 		AML_RESOURCE_GENERIC_REGISTER *reg;
7348906SEric.Saxe@Sun.COM 		ACPI_OBJECT *element;
7358906SEric.Saxe@Sun.COM 
7368906SEric.Saxe@Sun.COM 		pkg = &(obj->Package.Elements[i]);
7378906SEric.Saxe@Sun.COM 		reg = (AML_RESOURCE_GENERIC_REGISTER *)
7388906SEric.Saxe@Sun.COM 		    pkg->Package.Elements[0].Buffer.Pointer;
7398906SEric.Saxe@Sun.COM 		cstate->cs_addrspace_id = reg->AddressSpaceId;
7408906SEric.Saxe@Sun.COM 		cstate->cs_address = reg->Address;
7418906SEric.Saxe@Sun.COM 		element = &(pkg->Package.Elements[1]);
7428906SEric.Saxe@Sun.COM 		cstate->cs_type = element->Integer.Value;
7438906SEric.Saxe@Sun.COM 		element = &(pkg->Package.Elements[2]);
7448906SEric.Saxe@Sun.COM 		cstate->cs_latency = element->Integer.Value;
7458906SEric.Saxe@Sun.COM 		element = &(pkg->Package.Elements[3]);
7468906SEric.Saxe@Sun.COM 		cstate->cs_power = element->Integer.Value;
7478906SEric.Saxe@Sun.COM 
7488906SEric.Saxe@Sun.COM 		if (cpu_acpi_verify_cstate(cstate)) {
7498906SEric.Saxe@Sun.COM 			/*
7508906SEric.Saxe@Sun.COM 			 * ignore this entry if it's not valid
7518906SEric.Saxe@Sun.COM 			 */
7528906SEric.Saxe@Sun.COM 			continue;
7538906SEric.Saxe@Sun.COM 		}
7548906SEric.Saxe@Sun.COM 		if (cstate == p) {
7558906SEric.Saxe@Sun.COM 			cstate++;
7568906SEric.Saxe@Sun.COM 		} else if (p->cs_type == cstate->cs_type) {
7578906SEric.Saxe@Sun.COM 			/*
7588906SEric.Saxe@Sun.COM 			 * if there are duplicate entries, we keep the
7598906SEric.Saxe@Sun.COM 			 * last one. This fixes:
7608906SEric.Saxe@Sun.COM 			 * 1) some buggy BIOS have total duplicate entries.
7618906SEric.Saxe@Sun.COM 			 * 2) ACPI Spec allows the same cstate entry with
7628906SEric.Saxe@Sun.COM 			 *    different power and latency, we use the one
7638906SEric.Saxe@Sun.COM 			 *    with more power saving.
7648906SEric.Saxe@Sun.COM 			 */
7658906SEric.Saxe@Sun.COM 			(void) memcpy(p, cstate, sizeof (cpu_acpi_cstate_t));
7668906SEric.Saxe@Sun.COM 		} else {
7678906SEric.Saxe@Sun.COM 			/*
7688906SEric.Saxe@Sun.COM 			 * we got a valid entry, cache it to the
7698906SEric.Saxe@Sun.COM 			 * cstate structure
7708906SEric.Saxe@Sun.COM 			 */
7718906SEric.Saxe@Sun.COM 			p = cstate++;
7728906SEric.Saxe@Sun.COM 			count++;
7738906SEric.Saxe@Sun.COM 		}
7748906SEric.Saxe@Sun.COM 	}
7758906SEric.Saxe@Sun.COM 
7768906SEric.Saxe@Sun.COM 	if (count < 2) {
7778983SBill.Holler@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid count %d < 2",
7788906SEric.Saxe@Sun.COM 		    count);
779*9148SBill.Holler@Sun.COM 		kmem_free(CPU_ACPI_CSTATES(handle), alloc_size);
780*9148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES(handle) = NULL;
781*9148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)0;
7828906SEric.Saxe@Sun.COM 		AcpiOsFree(abuf.Pointer);
7838906SEric.Saxe@Sun.COM 		return (-1);
7848906SEric.Saxe@Sun.COM 	}
7858983SBill.Holler@Sun.COM 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
7868983SBill.Holler@Sun.COM 	if (cstate[0].cs_type != CPU_ACPI_C1) {
7878983SBill.Holler@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST first element type not C1: "
7888983SBill.Holler@Sun.COM 		    "%d", (int)cstate->cs_type);
789*9148SBill.Holler@Sun.COM 		kmem_free(CPU_ACPI_CSTATES(handle), alloc_size);
790*9148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES(handle) = NULL;
791*9148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)0;
7928983SBill.Holler@Sun.COM 		AcpiOsFree(abuf.Pointer);
7938983SBill.Holler@Sun.COM 		return (-1);
7948983SBill.Holler@Sun.COM 	}
7958906SEric.Saxe@Sun.COM 
796*9148SBill.Holler@Sun.COM 	if (count != cnt) {
797*9148SBill.Holler@Sun.COM 		void	*orig = CPU_ACPI_CSTATES(handle);
798*9148SBill.Holler@Sun.COM 
7998906SEric.Saxe@Sun.COM 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)count;
800*9148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES(handle) = kmem_zalloc(
801*9148SBill.Holler@Sun.COM 		    CPU_ACPI_CSTATES_SIZE(count), KM_SLEEP);
802*9148SBill.Holler@Sun.COM 		(void) memcpy(CPU_ACPI_CSTATES(handle), orig,
803*9148SBill.Holler@Sun.COM 		    CPU_ACPI_CSTATES_SIZE(count));
804*9148SBill.Holler@Sun.COM 		kmem_free(orig, alloc_size);
805*9148SBill.Holler@Sun.COM 	}
8068906SEric.Saxe@Sun.COM 
8078906SEric.Saxe@Sun.COM 	AcpiOsFree(abuf.Pointer);
8088906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CST_CACHED);
8098906SEric.Saxe@Sun.COM 	return (0);
8108906SEric.Saxe@Sun.COM }
8118906SEric.Saxe@Sun.COM 
8128906SEric.Saxe@Sun.COM /*
8138906SEric.Saxe@Sun.COM  * Cache the _PCT, _PSS, _PSD and _PPC data.
8148906SEric.Saxe@Sun.COM  */
8158906SEric.Saxe@Sun.COM int
8168906SEric.Saxe@Sun.COM cpu_acpi_cache_pstate_data(cpu_acpi_handle_t handle)
8178906SEric.Saxe@Sun.COM {
8188906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_pct(handle) < 0) {
8198906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _PCT for "
8208906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
8218906SEric.Saxe@Sun.COM 		return (-1);
8228906SEric.Saxe@Sun.COM 	}
8238906SEric.Saxe@Sun.COM 
8248906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_pstates(handle) != 0) {
8258906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _PSS for "
8268906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
8278906SEric.Saxe@Sun.COM 		return (-1);
8288906SEric.Saxe@Sun.COM 	}
8298906SEric.Saxe@Sun.COM 
8308906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_psd(handle) < 0) {
8318906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _PSD for "
8328906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
8338906SEric.Saxe@Sun.COM 		return (-1);
8348906SEric.Saxe@Sun.COM 	}
8358906SEric.Saxe@Sun.COM 
8368906SEric.Saxe@Sun.COM 	cpu_acpi_cache_ppc(handle);
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_pstate_data(cpu_acpi_handle_t handle)
8438906SEric.Saxe@Sun.COM {
8448906SEric.Saxe@Sun.COM 	if (handle != NULL) {
8458906SEric.Saxe@Sun.COM 		if (CPU_ACPI_PSTATES(handle)) {
8468906SEric.Saxe@Sun.COM 			kmem_free(CPU_ACPI_PSTATES(handle),
8478906SEric.Saxe@Sun.COM 			    CPU_ACPI_PSTATES_SIZE(
8488906SEric.Saxe@Sun.COM 			    CPU_ACPI_PSTATES_COUNT(handle)));
8498906SEric.Saxe@Sun.COM 			CPU_ACPI_PSTATES(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  * Cache the _PTC, _TSS, _TSD and _TPC data.
8568906SEric.Saxe@Sun.COM  */
8578906SEric.Saxe@Sun.COM int
8588906SEric.Saxe@Sun.COM cpu_acpi_cache_tstate_data(cpu_acpi_handle_t handle)
8598906SEric.Saxe@Sun.COM {
8609004SNapanda.Pemmaiah@Sun.COM 	int p_res;
8619004SNapanda.Pemmaiah@Sun.COM 
8628906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_ptc(handle) < 0) {
8639004SNapanda.Pemmaiah@Sun.COM 		p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: error "
8649004SNapanda.Pemmaiah@Sun.COM 		    "parsing _PTC for CPU %d", handle->cs_id);
8659004SNapanda.Pemmaiah@Sun.COM 		if (p_res >= 0)
8669004SNapanda.Pemmaiah@Sun.COM 			PRINT_ERR_MSG(CE_NOTE, err_msg, PTC_OBJ);
8678906SEric.Saxe@Sun.COM 		return (-1);
8688906SEric.Saxe@Sun.COM 	}
8698906SEric.Saxe@Sun.COM 
8708906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_tstates(handle) != 0) {
8719004SNapanda.Pemmaiah@Sun.COM 		p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: error "
8729004SNapanda.Pemmaiah@Sun.COM 		    "parsing _TSS for CPU %d", handle->cs_id);
8739004SNapanda.Pemmaiah@Sun.COM 		if (p_res >= 0)
8749004SNapanda.Pemmaiah@Sun.COM 			PRINT_ERR_MSG(CE_NOTE, err_msg, TSS_OBJ);
8758906SEric.Saxe@Sun.COM 		return (-1);
8768906SEric.Saxe@Sun.COM 	}
8778906SEric.Saxe@Sun.COM 
8788906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_tsd(handle) < 0) {
8799004SNapanda.Pemmaiah@Sun.COM 		p_res = snprintf(err_msg, ERR_MSG_SIZE, "!cpu_acpi: error "
8809004SNapanda.Pemmaiah@Sun.COM 		    "parsing _TSD for CPU %d", handle->cs_id);
8819004SNapanda.Pemmaiah@Sun.COM 		if (p_res >= 0)
8829004SNapanda.Pemmaiah@Sun.COM 			PRINT_ERR_MSG(CE_NOTE, err_msg, TSD_OBJ);
8838906SEric.Saxe@Sun.COM 		return (-1);
8848906SEric.Saxe@Sun.COM 	}
8858906SEric.Saxe@Sun.COM 
8868906SEric.Saxe@Sun.COM 	cpu_acpi_cache_tpc(handle);
8878906SEric.Saxe@Sun.COM 
8888906SEric.Saxe@Sun.COM 	return (0);
8898906SEric.Saxe@Sun.COM }
8908906SEric.Saxe@Sun.COM 
8918906SEric.Saxe@Sun.COM void
8928906SEric.Saxe@Sun.COM cpu_acpi_free_tstate_data(cpu_acpi_handle_t handle)
8938906SEric.Saxe@Sun.COM {
8948906SEric.Saxe@Sun.COM 	if (handle != NULL) {
8958906SEric.Saxe@Sun.COM 		if (CPU_ACPI_TSTATES(handle)) {
8968906SEric.Saxe@Sun.COM 			kmem_free(CPU_ACPI_TSTATES(handle),
8978906SEric.Saxe@Sun.COM 			    CPU_ACPI_TSTATES_SIZE(
8988906SEric.Saxe@Sun.COM 			    CPU_ACPI_TSTATES_COUNT(handle)));
8998906SEric.Saxe@Sun.COM 			CPU_ACPI_TSTATES(handle) = NULL;
9008906SEric.Saxe@Sun.COM 		}
9018906SEric.Saxe@Sun.COM 	}
9028906SEric.Saxe@Sun.COM }
9038906SEric.Saxe@Sun.COM 
9048906SEric.Saxe@Sun.COM /*
9058906SEric.Saxe@Sun.COM  * Cache the _CST data.
9068906SEric.Saxe@Sun.COM  */
9078906SEric.Saxe@Sun.COM int
9088906SEric.Saxe@Sun.COM cpu_acpi_cache_cstate_data(cpu_acpi_handle_t handle)
9098906SEric.Saxe@Sun.COM {
9108906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_cst(handle) < 0) {
9118906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _CST for "
9128906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
9138906SEric.Saxe@Sun.COM 		return (-1);
9148906SEric.Saxe@Sun.COM 	}
9158906SEric.Saxe@Sun.COM 
9168906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_csd(handle) < 0) {
9178906SEric.Saxe@Sun.COM 		cmn_err(CE_WARN, "!cpu_acpi: error parsing _CSD for "
9188906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
9198906SEric.Saxe@Sun.COM 		return (-1);
9208906SEric.Saxe@Sun.COM 	}
9218906SEric.Saxe@Sun.COM 
9228906SEric.Saxe@Sun.COM 	return (0);
9238906SEric.Saxe@Sun.COM }
9248906SEric.Saxe@Sun.COM 
9258906SEric.Saxe@Sun.COM void
9268906SEric.Saxe@Sun.COM cpu_acpi_free_cstate_data(cpu_acpi_handle_t handle)
9278906SEric.Saxe@Sun.COM {
9288906SEric.Saxe@Sun.COM 	if (handle != NULL) {
9298906SEric.Saxe@Sun.COM 		if (CPU_ACPI_CSTATES(handle)) {
9308906SEric.Saxe@Sun.COM 			kmem_free(CPU_ACPI_CSTATES(handle),
9318906SEric.Saxe@Sun.COM 			    CPU_ACPI_CSTATES_SIZE(
9328906SEric.Saxe@Sun.COM 			    CPU_ACPI_CSTATES_COUNT(handle)));
9338906SEric.Saxe@Sun.COM 			CPU_ACPI_CSTATES(handle) = NULL;
9348906SEric.Saxe@Sun.COM 		}
9358906SEric.Saxe@Sun.COM 	}
9368906SEric.Saxe@Sun.COM }
9378906SEric.Saxe@Sun.COM 
9388906SEric.Saxe@Sun.COM /*
9398906SEric.Saxe@Sun.COM  * Register a handler for processor change notifications.
9408906SEric.Saxe@Sun.COM  */
9418906SEric.Saxe@Sun.COM void
9428906SEric.Saxe@Sun.COM cpu_acpi_install_notify_handler(cpu_acpi_handle_t handle,
9438906SEric.Saxe@Sun.COM     ACPI_NOTIFY_HANDLER handler, void *ctx)
9448906SEric.Saxe@Sun.COM {
9458906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiInstallNotifyHandler(handle->cs_handle,
9468906SEric.Saxe@Sun.COM 	    ACPI_DEVICE_NOTIFY, handler, ctx)))
9478906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unable to register "
9488906SEric.Saxe@Sun.COM 		    "notify handler for CPU");
9498906SEric.Saxe@Sun.COM }
9508906SEric.Saxe@Sun.COM 
9518906SEric.Saxe@Sun.COM /*
9528906SEric.Saxe@Sun.COM  * Remove a handler for processor change notifications.
9538906SEric.Saxe@Sun.COM  */
9548906SEric.Saxe@Sun.COM void
9558906SEric.Saxe@Sun.COM cpu_acpi_remove_notify_handler(cpu_acpi_handle_t handle,
9568906SEric.Saxe@Sun.COM     ACPI_NOTIFY_HANDLER handler)
9578906SEric.Saxe@Sun.COM {
9588906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiRemoveNotifyHandler(handle->cs_handle,
9598906SEric.Saxe@Sun.COM 	    ACPI_DEVICE_NOTIFY, handler)))
9608906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unable to remove "
9618906SEric.Saxe@Sun.COM 		    "notify handler for CPU");
9628906SEric.Saxe@Sun.COM }
9638906SEric.Saxe@Sun.COM 
9648906SEric.Saxe@Sun.COM /*
9658906SEric.Saxe@Sun.COM  * Write _PDC.
9668906SEric.Saxe@Sun.COM  */
9678906SEric.Saxe@Sun.COM int
9688906SEric.Saxe@Sun.COM cpu_acpi_write_pdc(cpu_acpi_handle_t handle, uint32_t revision, uint32_t count,
9698906SEric.Saxe@Sun.COM     uint32_t *capabilities)
9708906SEric.Saxe@Sun.COM {
9718906SEric.Saxe@Sun.COM 	ACPI_OBJECT obj;
9728906SEric.Saxe@Sun.COM 	ACPI_OBJECT_LIST list = { 1, &obj};
9738906SEric.Saxe@Sun.COM 	uint32_t *buffer;
9748906SEric.Saxe@Sun.COM 	uint32_t *bufptr;
9758906SEric.Saxe@Sun.COM 	uint32_t bufsize;
9768906SEric.Saxe@Sun.COM 	int i;
9778906SEric.Saxe@Sun.COM 
9788906SEric.Saxe@Sun.COM 	bufsize = (count + 2) * sizeof (uint32_t);
9798906SEric.Saxe@Sun.COM 	buffer = kmem_zalloc(bufsize, KM_SLEEP);
9808906SEric.Saxe@Sun.COM 	buffer[0] = revision;
9818906SEric.Saxe@Sun.COM 	buffer[1] = count;
9828906SEric.Saxe@Sun.COM 	bufptr = &buffer[2];
9838906SEric.Saxe@Sun.COM 	for (i = 0; i < count; i++)
9848906SEric.Saxe@Sun.COM 		*bufptr++ = *capabilities++;
9858906SEric.Saxe@Sun.COM 
9868906SEric.Saxe@Sun.COM 	obj.Type = ACPI_TYPE_BUFFER;
9878906SEric.Saxe@Sun.COM 	obj.Buffer.Length = bufsize;
9888906SEric.Saxe@Sun.COM 	obj.Buffer.Pointer = (void *)buffer;
9898906SEric.Saxe@Sun.COM 
9908906SEric.Saxe@Sun.COM 	/*
9918906SEric.Saxe@Sun.COM 	 * _PDC is optional, so don't log failure.
9928906SEric.Saxe@Sun.COM 	 */
9938906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiEvaluateObject(handle->cs_handle, "_PDC",
9948906SEric.Saxe@Sun.COM 	    &list, NULL))) {
9958906SEric.Saxe@Sun.COM 		kmem_free(buffer, bufsize);
9968906SEric.Saxe@Sun.COM 		return (-1);
9978906SEric.Saxe@Sun.COM 	}
9988906SEric.Saxe@Sun.COM 
9998906SEric.Saxe@Sun.COM 	kmem_free(buffer, bufsize);
10008906SEric.Saxe@Sun.COM 	return (0);
10018906SEric.Saxe@Sun.COM }
10028906SEric.Saxe@Sun.COM 
10038906SEric.Saxe@Sun.COM /*
10048906SEric.Saxe@Sun.COM  * Write to system IO port.
10058906SEric.Saxe@Sun.COM  */
10068906SEric.Saxe@Sun.COM int
10078906SEric.Saxe@Sun.COM cpu_acpi_write_port(ACPI_IO_ADDRESS address, uint32_t value, uint32_t width)
10088906SEric.Saxe@Sun.COM {
10098906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiOsWritePort(address, value, width))) {
10108906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "cpu_acpi: error writing system IO port "
10118906SEric.Saxe@Sun.COM 		    "%lx.", (long)address);
10128906SEric.Saxe@Sun.COM 		return (-1);
10138906SEric.Saxe@Sun.COM 	}
10148906SEric.Saxe@Sun.COM 	return (0);
10158906SEric.Saxe@Sun.COM }
10168906SEric.Saxe@Sun.COM 
10178906SEric.Saxe@Sun.COM /*
10188906SEric.Saxe@Sun.COM  * Read from a system IO port.
10198906SEric.Saxe@Sun.COM  */
10208906SEric.Saxe@Sun.COM int
10218906SEric.Saxe@Sun.COM cpu_acpi_read_port(ACPI_IO_ADDRESS address, uint32_t *value, uint32_t width)
10228906SEric.Saxe@Sun.COM {
10238906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiOsReadPort(address, value, width))) {
10248906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "cpu_acpi: error reading system IO port "
10258906SEric.Saxe@Sun.COM 		    "%lx.", (long)address);
10268906SEric.Saxe@Sun.COM 		return (-1);
10278906SEric.Saxe@Sun.COM 	}
10288906SEric.Saxe@Sun.COM 	return (0);
10298906SEric.Saxe@Sun.COM }
10308906SEric.Saxe@Sun.COM 
10318906SEric.Saxe@Sun.COM /*
10328906SEric.Saxe@Sun.COM  * Return supported frequencies.
10338906SEric.Saxe@Sun.COM  */
10348906SEric.Saxe@Sun.COM uint_t
10358906SEric.Saxe@Sun.COM cpu_acpi_get_speeds(cpu_acpi_handle_t handle, int **speeds)
10368906SEric.Saxe@Sun.COM {
10378906SEric.Saxe@Sun.COM 	cpu_acpi_pstate_t *pstate;
10388906SEric.Saxe@Sun.COM 	int *hspeeds;
10398906SEric.Saxe@Sun.COM 	uint_t nspeeds;
10408906SEric.Saxe@Sun.COM 	int i;
10418906SEric.Saxe@Sun.COM 
10428906SEric.Saxe@Sun.COM 	nspeeds = CPU_ACPI_PSTATES_COUNT(handle);
10438906SEric.Saxe@Sun.COM 	pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
10448906SEric.Saxe@Sun.COM 	hspeeds = kmem_zalloc(nspeeds * sizeof (int), KM_SLEEP);
10458906SEric.Saxe@Sun.COM 	for (i = 0; i < nspeeds; i++) {
10468906SEric.Saxe@Sun.COM 		hspeeds[i] = CPU_ACPI_FREQ(pstate);
10478906SEric.Saxe@Sun.COM 		pstate++;
10488906SEric.Saxe@Sun.COM 	}
10498906SEric.Saxe@Sun.COM 	*speeds = hspeeds;
10508906SEric.Saxe@Sun.COM 	return (nspeeds);
10518906SEric.Saxe@Sun.COM }
10528906SEric.Saxe@Sun.COM 
10538906SEric.Saxe@Sun.COM /*
10548906SEric.Saxe@Sun.COM  * Free resources allocated by cpu_acpi_get_speeds().
10558906SEric.Saxe@Sun.COM  */
10568906SEric.Saxe@Sun.COM void
10578906SEric.Saxe@Sun.COM cpu_acpi_free_speeds(int *speeds, uint_t nspeeds)
10588906SEric.Saxe@Sun.COM {
10598906SEric.Saxe@Sun.COM 	kmem_free(speeds, nspeeds * sizeof (int));
10608906SEric.Saxe@Sun.COM }
10618906SEric.Saxe@Sun.COM 
10628906SEric.Saxe@Sun.COM uint_t
10638906SEric.Saxe@Sun.COM cpu_acpi_get_max_cstates(cpu_acpi_handle_t handle)
10648906SEric.Saxe@Sun.COM {
10658906SEric.Saxe@Sun.COM 	if (CPU_ACPI_CSTATES(handle))
10668906SEric.Saxe@Sun.COM 		return (CPU_ACPI_CSTATES_COUNT(handle));
10678906SEric.Saxe@Sun.COM 	else
10688906SEric.Saxe@Sun.COM 		return (1);
10698906SEric.Saxe@Sun.COM }
10708906SEric.Saxe@Sun.COM 
10718906SEric.Saxe@Sun.COM void
10728906SEric.Saxe@Sun.COM cpu_acpi_set_register(uint32_t bitreg, uint32_t value)
10738906SEric.Saxe@Sun.COM {
10748906SEric.Saxe@Sun.COM 	AcpiSetRegister(bitreg, value);
10758906SEric.Saxe@Sun.COM }
10768906SEric.Saxe@Sun.COM 
10778906SEric.Saxe@Sun.COM void
10788906SEric.Saxe@Sun.COM cpu_acpi_get_register(uint32_t bitreg, uint32_t *value)
10798906SEric.Saxe@Sun.COM {
10808906SEric.Saxe@Sun.COM 	AcpiGetRegister(bitreg, value);
10818906SEric.Saxe@Sun.COM }
10828906SEric.Saxe@Sun.COM 
10838906SEric.Saxe@Sun.COM /*
10848906SEric.Saxe@Sun.COM  * Map the dip to an ACPI handle for the device.
10858906SEric.Saxe@Sun.COM  */
10868906SEric.Saxe@Sun.COM cpu_acpi_handle_t
10878906SEric.Saxe@Sun.COM cpu_acpi_init(cpu_t *cp)
10888906SEric.Saxe@Sun.COM {
10898906SEric.Saxe@Sun.COM 	cpu_acpi_handle_t handle;
10908906SEric.Saxe@Sun.COM 
10918906SEric.Saxe@Sun.COM 	handle = kmem_zalloc(sizeof (cpu_acpi_state_t), KM_SLEEP);
10928906SEric.Saxe@Sun.COM 
10938906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(acpica_get_handle_cpu(cp->cpu_id,
10948906SEric.Saxe@Sun.COM 	    &handle->cs_handle))) {
10958906SEric.Saxe@Sun.COM 		kmem_free(handle, sizeof (cpu_acpi_state_t));
10968906SEric.Saxe@Sun.COM 		return (NULL);
10978906SEric.Saxe@Sun.COM 	}
10988906SEric.Saxe@Sun.COM 	handle->cs_id = cp->cpu_id;
10998906SEric.Saxe@Sun.COM 	return (handle);
11008906SEric.Saxe@Sun.COM }
11018906SEric.Saxe@Sun.COM 
11028906SEric.Saxe@Sun.COM /*
11038906SEric.Saxe@Sun.COM  * Free any resources.
11048906SEric.Saxe@Sun.COM  */
11058906SEric.Saxe@Sun.COM void
11068906SEric.Saxe@Sun.COM cpu_acpi_fini(cpu_acpi_handle_t handle)
11078906SEric.Saxe@Sun.COM {
11088906SEric.Saxe@Sun.COM 	if (handle)
11098906SEric.Saxe@Sun.COM 		kmem_free(handle, sizeof (cpu_acpi_state_t));
11108906SEric.Saxe@Sun.COM }
1111