xref: /onnv-gate/usr/src/uts/i86pc/os/cpupm/cpu_acpi.c (revision 10488:296c315b92df)
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,
4410075SMark.Haywood@Sun.COM 	CST_OBJ,
458906SEric.Saxe@Sun.COM 	CSD_OBJ,
468906SEric.Saxe@Sun.COM } cpu_acpi_obj_t;
478906SEric.Saxe@Sun.COM 
488906SEric.Saxe@Sun.COM /*
498906SEric.Saxe@Sun.COM  * Container to store object name.
508906SEric.Saxe@Sun.COM  * Other attributes can be added in the future as necessary.
518906SEric.Saxe@Sun.COM  */
528906SEric.Saxe@Sun.COM typedef struct cpu_acpi_obj_attr {
538906SEric.Saxe@Sun.COM 	char *name;
548906SEric.Saxe@Sun.COM } cpu_acpi_obj_attr_t;
558906SEric.Saxe@Sun.COM 
568906SEric.Saxe@Sun.COM /*
578906SEric.Saxe@Sun.COM  * List of object attributes.
588906SEric.Saxe@Sun.COM  * NOTE: Please keep the ordering of the list as same as cpu_acpi_obj_t.
598906SEric.Saxe@Sun.COM  */
608906SEric.Saxe@Sun.COM static cpu_acpi_obj_attr_t cpu_acpi_obj_attrs[] = {
618906SEric.Saxe@Sun.COM 	{"_PDC"},
628906SEric.Saxe@Sun.COM 	{"_PCT"},
638906SEric.Saxe@Sun.COM 	{"_PSS"},
648906SEric.Saxe@Sun.COM 	{"_PSD"},
658906SEric.Saxe@Sun.COM 	{"_PPC"},
668906SEric.Saxe@Sun.COM 	{"_PTC"},
678906SEric.Saxe@Sun.COM 	{"_TSS"},
688906SEric.Saxe@Sun.COM 	{"_TSD"},
698906SEric.Saxe@Sun.COM 	{"_TPC"},
7010075SMark.Haywood@Sun.COM 	{"_CST"},
718906SEric.Saxe@Sun.COM 	{"_CSD"}
728906SEric.Saxe@Sun.COM };
738906SEric.Saxe@Sun.COM 
748906SEric.Saxe@Sun.COM /*
758906SEric.Saxe@Sun.COM  * Cache the ACPI CPU control data objects.
768906SEric.Saxe@Sun.COM  */
778906SEric.Saxe@Sun.COM static int
788906SEric.Saxe@Sun.COM cpu_acpi_cache_ctrl_regs(cpu_acpi_handle_t handle, cpu_acpi_obj_t objtype,
798906SEric.Saxe@Sun.COM     cpu_acpi_ctrl_regs_t *regs)
808906SEric.Saxe@Sun.COM {
8110075SMark.Haywood@Sun.COM 	ACPI_STATUS astatus;
828906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
838906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj;
848906SEric.Saxe@Sun.COM 	AML_RESOURCE_GENERIC_REGISTER *greg;
858906SEric.Saxe@Sun.COM 	int ret = -1;
868906SEric.Saxe@Sun.COM 	int i;
878906SEric.Saxe@Sun.COM 
888906SEric.Saxe@Sun.COM 	/*
898906SEric.Saxe@Sun.COM 	 * Fetch the control registers (if present) for the CPU node.
908906SEric.Saxe@Sun.COM 	 * Since they are optional, non-existence is not a failure
918906SEric.Saxe@Sun.COM 	 * (we just consider it a fixed hardware case).
928906SEric.Saxe@Sun.COM 	 */
938906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
948906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
9510075SMark.Haywood@Sun.COM 	astatus = AcpiEvaluateObjectTyped(handle->cs_handle,
9610075SMark.Haywood@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf, ACPI_TYPE_PACKAGE);
9710075SMark.Haywood@Sun.COM 	if (ACPI_FAILURE(astatus)) {
9810075SMark.Haywood@Sun.COM 		if (astatus == AE_NOT_FOUND) {
9910075SMark.Haywood@Sun.COM 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
10010075SMark.Haywood@Sun.COM 			    int, objtype, int, astatus);
10110075SMark.Haywood@Sun.COM 			regs[0].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
10210075SMark.Haywood@Sun.COM 			regs[1].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
10310075SMark.Haywood@Sun.COM 			return (1);
10410075SMark.Haywood@Sun.COM 		}
10510075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s package "
10610075SMark.Haywood@Sun.COM 		    "for CPU %d.", astatus, cpu_acpi_obj_attrs[objtype].name,
10710075SMark.Haywood@Sun.COM 		    handle->cs_id);
10810075SMark.Haywood@Sun.COM 		goto out;
1098906SEric.Saxe@Sun.COM 	}
1108906SEric.Saxe@Sun.COM 
1118906SEric.Saxe@Sun.COM 	obj = abuf.Pointer;
1128906SEric.Saxe@Sun.COM 	if (obj->Package.Count != 2) {
11310075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: %s package bad count %d for "
11410075SMark.Haywood@Sun.COM 		    "CPU %d.", cpu_acpi_obj_attrs[objtype].name,
11510075SMark.Haywood@Sun.COM 		    obj->Package.Count, handle->cs_id);
1168906SEric.Saxe@Sun.COM 		goto out;
1178906SEric.Saxe@Sun.COM 	}
1188906SEric.Saxe@Sun.COM 
1198906SEric.Saxe@Sun.COM 	/*
1208906SEric.Saxe@Sun.COM 	 * Does the package look coherent?
1218906SEric.Saxe@Sun.COM 	 */
1228906SEric.Saxe@Sun.COM 	for (i = 0; i < obj->Package.Count; i++) {
1238906SEric.Saxe@Sun.COM 		if (obj->Package.Elements[i].Type != ACPI_TYPE_BUFFER) {
12410075SMark.Haywood@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in "
12510075SMark.Haywood@Sun.COM 			    "%s package for CPU %d.",
12610075SMark.Haywood@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name,
12710075SMark.Haywood@Sun.COM 			    handle->cs_id);
1288906SEric.Saxe@Sun.COM 			goto out;
1298906SEric.Saxe@Sun.COM 		}
1308906SEric.Saxe@Sun.COM 
1318906SEric.Saxe@Sun.COM 		greg = (AML_RESOURCE_GENERIC_REGISTER *)
1328906SEric.Saxe@Sun.COM 		    obj->Package.Elements[i].Buffer.Pointer;
1338906SEric.Saxe@Sun.COM 		if (greg->DescriptorType !=
1348906SEric.Saxe@Sun.COM 		    ACPI_RESOURCE_NAME_GENERIC_REGISTER) {
13510075SMark.Haywood@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: %s package has format "
13610075SMark.Haywood@Sun.COM 			    "error for CPU %d.",
13710075SMark.Haywood@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name,
13810075SMark.Haywood@Sun.COM 			    handle->cs_id);
1398906SEric.Saxe@Sun.COM 			goto out;
1408906SEric.Saxe@Sun.COM 		}
1418906SEric.Saxe@Sun.COM 		if (greg->ResourceLength !=
1428906SEric.Saxe@Sun.COM 		    ACPI_AML_SIZE_LARGE(AML_RESOURCE_GENERIC_REGISTER)) {
14310075SMark.Haywood@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: %s package not right "
14410075SMark.Haywood@Sun.COM 			    "size for CPU %d.",
14510075SMark.Haywood@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name,
14610075SMark.Haywood@Sun.COM 			    handle->cs_id);
1478906SEric.Saxe@Sun.COM 			goto out;
1488906SEric.Saxe@Sun.COM 		}
1498906SEric.Saxe@Sun.COM 		if (greg->AddressSpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE &&
1508906SEric.Saxe@Sun.COM 		    greg->AddressSpaceId != ACPI_ADR_SPACE_SYSTEM_IO) {
15110075SMark.Haywood@Sun.COM 			cmn_err(CE_NOTE, "!cpu_apci: %s contains unsupported "
15210075SMark.Haywood@Sun.COM 			    "address space type %x for CPU %d.",
1538906SEric.Saxe@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name,
15410075SMark.Haywood@Sun.COM 			    greg->AddressSpaceId,
15510075SMark.Haywood@Sun.COM 			    handle->cs_id);
1568906SEric.Saxe@Sun.COM 			goto out;
1578906SEric.Saxe@Sun.COM 		}
1588906SEric.Saxe@Sun.COM 	}
1598906SEric.Saxe@Sun.COM 
1608906SEric.Saxe@Sun.COM 	/*
1618906SEric.Saxe@Sun.COM 	 * Looks good!
1628906SEric.Saxe@Sun.COM 	 */
1638906SEric.Saxe@Sun.COM 	for (i = 0; i < obj->Package.Count; i++) {
1648906SEric.Saxe@Sun.COM 		greg = (AML_RESOURCE_GENERIC_REGISTER *)
1658906SEric.Saxe@Sun.COM 		    obj->Package.Elements[i].Buffer.Pointer;
1668906SEric.Saxe@Sun.COM 		regs[i].cr_addrspace_id = greg->AddressSpaceId;
1678906SEric.Saxe@Sun.COM 		regs[i].cr_width = greg->BitWidth;
1688906SEric.Saxe@Sun.COM 		regs[i].cr_offset = greg->BitOffset;
1698906SEric.Saxe@Sun.COM 		regs[i].cr_asize = greg->AccessSize;
1708906SEric.Saxe@Sun.COM 		regs[i].cr_address = greg->Address;
1718906SEric.Saxe@Sun.COM 	}
1728906SEric.Saxe@Sun.COM 	ret = 0;
1738906SEric.Saxe@Sun.COM out:
17410075SMark.Haywood@Sun.COM 	if (abuf.Pointer != NULL)
17510075SMark.Haywood@Sun.COM 		AcpiOsFree(abuf.Pointer);
1768906SEric.Saxe@Sun.COM 	return (ret);
1778906SEric.Saxe@Sun.COM }
1788906SEric.Saxe@Sun.COM 
1798906SEric.Saxe@Sun.COM /*
1808906SEric.Saxe@Sun.COM  * Cache the ACPI _PCT data. The _PCT data defines the interface to use
1818906SEric.Saxe@Sun.COM  * when making power level transitions (i.e., system IO ports, fixed
1828906SEric.Saxe@Sun.COM  * hardware port, etc).
1838906SEric.Saxe@Sun.COM  */
1848906SEric.Saxe@Sun.COM static int
1858906SEric.Saxe@Sun.COM cpu_acpi_cache_pct(cpu_acpi_handle_t handle)
1868906SEric.Saxe@Sun.COM {
1878906SEric.Saxe@Sun.COM 	cpu_acpi_pct_t *pct;
1888906SEric.Saxe@Sun.COM 	int ret;
1898906SEric.Saxe@Sun.COM 
1908906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PCT_CACHED);
1918906SEric.Saxe@Sun.COM 	pct = &CPU_ACPI_PCT(handle)[0];
1928906SEric.Saxe@Sun.COM 	if ((ret = cpu_acpi_cache_ctrl_regs(handle, PCT_OBJ, pct)) == 0)
1938906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PCT_CACHED);
1948906SEric.Saxe@Sun.COM 	return (ret);
1958906SEric.Saxe@Sun.COM }
1968906SEric.Saxe@Sun.COM 
1978906SEric.Saxe@Sun.COM /*
1988906SEric.Saxe@Sun.COM  * Cache the ACPI _PTC data. The _PTC data defines the interface to use
1998906SEric.Saxe@Sun.COM  * when making T-state transitions (i.e., system IO ports, fixed
2008906SEric.Saxe@Sun.COM  * hardware port, etc).
2018906SEric.Saxe@Sun.COM  */
2028906SEric.Saxe@Sun.COM static int
2038906SEric.Saxe@Sun.COM cpu_acpi_cache_ptc(cpu_acpi_handle_t handle)
2048906SEric.Saxe@Sun.COM {
2058906SEric.Saxe@Sun.COM 	cpu_acpi_ptc_t *ptc;
2068906SEric.Saxe@Sun.COM 	int ret;
2078906SEric.Saxe@Sun.COM 
2088906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PTC_CACHED);
2098906SEric.Saxe@Sun.COM 	ptc = &CPU_ACPI_PTC(handle)[0];
2108906SEric.Saxe@Sun.COM 	if ((ret = cpu_acpi_cache_ctrl_regs(handle, PTC_OBJ, ptc)) == 0)
2118906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PTC_CACHED);
2128906SEric.Saxe@Sun.COM 	return (ret);
2138906SEric.Saxe@Sun.COM }
2148906SEric.Saxe@Sun.COM 
2158906SEric.Saxe@Sun.COM /*
2168906SEric.Saxe@Sun.COM  * Cache the ACPI CPU state dependency data objects.
2178906SEric.Saxe@Sun.COM  */
2188906SEric.Saxe@Sun.COM static int
2198906SEric.Saxe@Sun.COM cpu_acpi_cache_state_dependencies(cpu_acpi_handle_t handle,
2208906SEric.Saxe@Sun.COM     cpu_acpi_obj_t objtype, cpu_acpi_state_dependency_t *sd)
2218906SEric.Saxe@Sun.COM {
22210075SMark.Haywood@Sun.COM 	ACPI_STATUS astatus;
2238906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
2248906SEric.Saxe@Sun.COM 	ACPI_OBJECT *pkg, *elements;
2258906SEric.Saxe@Sun.COM 	int number;
2268906SEric.Saxe@Sun.COM 	int ret = -1;
2278906SEric.Saxe@Sun.COM 
2288906SEric.Saxe@Sun.COM 	if (objtype == CSD_OBJ) {
2298906SEric.Saxe@Sun.COM 		number = 6;
2308906SEric.Saxe@Sun.COM 	} else {
2318906SEric.Saxe@Sun.COM 		number = 5;
2328906SEric.Saxe@Sun.COM 	}
2338906SEric.Saxe@Sun.COM 	/*
2348906SEric.Saxe@Sun.COM 	 * Fetch the dependencies (if present) for the CPU node.
2358906SEric.Saxe@Sun.COM 	 * Since they are optional, non-existence is not a failure
2368906SEric.Saxe@Sun.COM 	 * (it's up to the caller to determine how to handle non-existence).
2378906SEric.Saxe@Sun.COM 	 */
2388906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
2398906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
24010075SMark.Haywood@Sun.COM 	astatus = AcpiEvaluateObjectTyped(handle->cs_handle,
24110075SMark.Haywood@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf, ACPI_TYPE_PACKAGE);
24210075SMark.Haywood@Sun.COM 	if (ACPI_FAILURE(astatus)) {
24310075SMark.Haywood@Sun.COM 		if (astatus == AE_NOT_FOUND) {
24410075SMark.Haywood@Sun.COM 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
24510075SMark.Haywood@Sun.COM 			    int, objtype, int, astatus);
24610075SMark.Haywood@Sun.COM 			return (1);
24710075SMark.Haywood@Sun.COM 		}
24810075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s package "
24910075SMark.Haywood@Sun.COM 		    "for CPU %d.", astatus, cpu_acpi_obj_attrs[objtype].name,
25010075SMark.Haywood@Sun.COM 		    handle->cs_id);
25110075SMark.Haywood@Sun.COM 		goto out;
2528906SEric.Saxe@Sun.COM 	}
2538906SEric.Saxe@Sun.COM 
2548906SEric.Saxe@Sun.COM 	pkg = abuf.Pointer;
2558906SEric.Saxe@Sun.COM 
2568906SEric.Saxe@Sun.COM 	if (((objtype != CSD_OBJ) && (pkg->Package.Count != 1)) ||
2578906SEric.Saxe@Sun.COM 	    ((objtype == CSD_OBJ) && (pkg->Package.Count != 1) &&
2588906SEric.Saxe@Sun.COM 	    (pkg->Package.Count != 2))) {
25910075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: %s unsupported package count %d "
26010075SMark.Haywood@Sun.COM 		    "for CPU %d.", cpu_acpi_obj_attrs[objtype].name,
26110075SMark.Haywood@Sun.COM 		    pkg->Package.Count, handle->cs_id);
2628906SEric.Saxe@Sun.COM 		goto out;
2638906SEric.Saxe@Sun.COM 	}
2648906SEric.Saxe@Sun.COM 
2658906SEric.Saxe@Sun.COM 	/*
2668906SEric.Saxe@Sun.COM 	 * For C-state domain, we assume C2 and C3 have the same
2678906SEric.Saxe@Sun.COM 	 * domain information
2688906SEric.Saxe@Sun.COM 	 */
2698906SEric.Saxe@Sun.COM 	if (pkg->Package.Elements[0].Type != ACPI_TYPE_PACKAGE ||
2708906SEric.Saxe@Sun.COM 	    pkg->Package.Elements[0].Package.Count != number) {
27110075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in %s package "
27210075SMark.Haywood@Sun.COM 		    "for CPU %d.", cpu_acpi_obj_attrs[objtype].name,
27310075SMark.Haywood@Sun.COM 		    handle->cs_id);
2748906SEric.Saxe@Sun.COM 		goto out;
2758906SEric.Saxe@Sun.COM 	}
2768906SEric.Saxe@Sun.COM 	elements = pkg->Package.Elements[0].Package.Elements;
2778906SEric.Saxe@Sun.COM 	if (elements[0].Integer.Value != number ||
2788906SEric.Saxe@Sun.COM 	    elements[1].Integer.Value != 0) {
27910075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unexpected %s revision for "
28010075SMark.Haywood@Sun.COM 		    "CPU %d.", cpu_acpi_obj_attrs[objtype].name,
28110075SMark.Haywood@Sun.COM 		    handle->cs_id);
2828906SEric.Saxe@Sun.COM 		goto out;
2838906SEric.Saxe@Sun.COM 	}
2848906SEric.Saxe@Sun.COM 
2858906SEric.Saxe@Sun.COM 	sd->sd_entries = elements[0].Integer.Value;
2868906SEric.Saxe@Sun.COM 	sd->sd_revision = elements[1].Integer.Value;
2878906SEric.Saxe@Sun.COM 	sd->sd_domain = elements[2].Integer.Value;
2888906SEric.Saxe@Sun.COM 	sd->sd_type = elements[3].Integer.Value;
2898906SEric.Saxe@Sun.COM 	sd->sd_num = elements[4].Integer.Value;
2908906SEric.Saxe@Sun.COM 	if (objtype == CSD_OBJ) {
2918906SEric.Saxe@Sun.COM 		sd->sd_index = elements[5].Integer.Value;
2928906SEric.Saxe@Sun.COM 	}
2938906SEric.Saxe@Sun.COM 
2948906SEric.Saxe@Sun.COM 	ret = 0;
2958906SEric.Saxe@Sun.COM out:
29610075SMark.Haywood@Sun.COM 	if (abuf.Pointer != NULL)
29710075SMark.Haywood@Sun.COM 		AcpiOsFree(abuf.Pointer);
2988906SEric.Saxe@Sun.COM 	return (ret);
2998906SEric.Saxe@Sun.COM }
3008906SEric.Saxe@Sun.COM 
3018906SEric.Saxe@Sun.COM /*
3028906SEric.Saxe@Sun.COM  * Cache the ACPI _PSD data. The _PSD data defines P-state CPU dependencies
3038906SEric.Saxe@Sun.COM  * (think CPU domains).
3048906SEric.Saxe@Sun.COM  */
3058906SEric.Saxe@Sun.COM static int
3068906SEric.Saxe@Sun.COM cpu_acpi_cache_psd(cpu_acpi_handle_t handle)
3078906SEric.Saxe@Sun.COM {
3088906SEric.Saxe@Sun.COM 	cpu_acpi_psd_t *psd;
3098906SEric.Saxe@Sun.COM 	int ret;
3108906SEric.Saxe@Sun.COM 
3118906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSD_CACHED);
3128906SEric.Saxe@Sun.COM 	psd = &CPU_ACPI_PSD(handle);
3138906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_state_dependencies(handle, PSD_OBJ, psd);
3148906SEric.Saxe@Sun.COM 	if (ret == 0)
3158906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSD_CACHED);
3168906SEric.Saxe@Sun.COM 	return (ret);
3178906SEric.Saxe@Sun.COM 
3188906SEric.Saxe@Sun.COM }
3198906SEric.Saxe@Sun.COM 
3208906SEric.Saxe@Sun.COM /*
3218906SEric.Saxe@Sun.COM  * Cache the ACPI _TSD data. The _TSD data defines T-state CPU dependencies
3228906SEric.Saxe@Sun.COM  * (think CPU domains).
3238906SEric.Saxe@Sun.COM  */
3248906SEric.Saxe@Sun.COM static int
3258906SEric.Saxe@Sun.COM cpu_acpi_cache_tsd(cpu_acpi_handle_t handle)
3268906SEric.Saxe@Sun.COM {
3278906SEric.Saxe@Sun.COM 	cpu_acpi_tsd_t *tsd;
3288906SEric.Saxe@Sun.COM 	int ret;
3298906SEric.Saxe@Sun.COM 
3308906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSD_CACHED);
3318906SEric.Saxe@Sun.COM 	tsd = &CPU_ACPI_TSD(handle);
3328906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_state_dependencies(handle, TSD_OBJ, tsd);
3338906SEric.Saxe@Sun.COM 	if (ret == 0)
3348906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSD_CACHED);
3358906SEric.Saxe@Sun.COM 	return (ret);
3368906SEric.Saxe@Sun.COM 
3378906SEric.Saxe@Sun.COM }
3388906SEric.Saxe@Sun.COM 
3398906SEric.Saxe@Sun.COM /*
3408906SEric.Saxe@Sun.COM  * Cache the ACPI _CSD data. The _CSD data defines C-state CPU dependencies
3418906SEric.Saxe@Sun.COM  * (think CPU domains).
3428906SEric.Saxe@Sun.COM  */
3438906SEric.Saxe@Sun.COM static int
3448906SEric.Saxe@Sun.COM cpu_acpi_cache_csd(cpu_acpi_handle_t handle)
3458906SEric.Saxe@Sun.COM {
3468906SEric.Saxe@Sun.COM 	cpu_acpi_csd_t *csd;
3478906SEric.Saxe@Sun.COM 	int ret;
3488906SEric.Saxe@Sun.COM 
3498906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CSD_CACHED);
3508906SEric.Saxe@Sun.COM 	csd = &CPU_ACPI_CSD(handle);
3518906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_state_dependencies(handle, CSD_OBJ, csd);
3528906SEric.Saxe@Sun.COM 	if (ret == 0)
3538906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CSD_CACHED);
3548906SEric.Saxe@Sun.COM 	return (ret);
3558906SEric.Saxe@Sun.COM 
3568906SEric.Saxe@Sun.COM }
3578906SEric.Saxe@Sun.COM 
3588906SEric.Saxe@Sun.COM static void
3598906SEric.Saxe@Sun.COM cpu_acpi_cache_pstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
3608906SEric.Saxe@Sun.COM {
3618906SEric.Saxe@Sun.COM 	cpu_acpi_pstate_t *pstate;
3628906SEric.Saxe@Sun.COM 	ACPI_OBJECT *q, *l;
3638906SEric.Saxe@Sun.COM 	int i, j;
3648906SEric.Saxe@Sun.COM 
3658906SEric.Saxe@Sun.COM 	CPU_ACPI_PSTATES_COUNT(handle) = cnt;
3668906SEric.Saxe@Sun.COM 	CPU_ACPI_PSTATES(handle) = kmem_zalloc(CPU_ACPI_PSTATES_SIZE(cnt),
3678906SEric.Saxe@Sun.COM 	    KM_SLEEP);
3688906SEric.Saxe@Sun.COM 	pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
3698906SEric.Saxe@Sun.COM 	for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
3708906SEric.Saxe@Sun.COM 		uint32_t *up;
3718906SEric.Saxe@Sun.COM 
3728906SEric.Saxe@Sun.COM 		q = obj->Package.Elements[i].Package.Elements;
3738906SEric.Saxe@Sun.COM 
3748906SEric.Saxe@Sun.COM 		/*
3758906SEric.Saxe@Sun.COM 		 * Skip duplicate entries.
3768906SEric.Saxe@Sun.COM 		 */
3778906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
3788906SEric.Saxe@Sun.COM 			continue;
3798906SEric.Saxe@Sun.COM 
3808906SEric.Saxe@Sun.COM 		up = (uint32_t *)pstate;
3818906SEric.Saxe@Sun.COM 		for (j = 0; j < CPU_ACPI_PSS_CNT; j++)
3828906SEric.Saxe@Sun.COM 			up[j] = q[j].Integer.Value;
3838906SEric.Saxe@Sun.COM 		pstate++;
3848906SEric.Saxe@Sun.COM 		cnt--;
3858906SEric.Saxe@Sun.COM 	}
3868906SEric.Saxe@Sun.COM }
3878906SEric.Saxe@Sun.COM 
3888906SEric.Saxe@Sun.COM static void
3898906SEric.Saxe@Sun.COM cpu_acpi_cache_tstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
3908906SEric.Saxe@Sun.COM {
3918906SEric.Saxe@Sun.COM 	cpu_acpi_tstate_t *tstate;
3928906SEric.Saxe@Sun.COM 	ACPI_OBJECT *q, *l;
3938906SEric.Saxe@Sun.COM 	int i, j;
3948906SEric.Saxe@Sun.COM 
3958906SEric.Saxe@Sun.COM 	CPU_ACPI_TSTATES_COUNT(handle) = cnt;
3968906SEric.Saxe@Sun.COM 	CPU_ACPI_TSTATES(handle) = kmem_zalloc(CPU_ACPI_TSTATES_SIZE(cnt),
3978906SEric.Saxe@Sun.COM 	    KM_SLEEP);
3988906SEric.Saxe@Sun.COM 	tstate = (cpu_acpi_tstate_t *)CPU_ACPI_TSTATES(handle);
3998906SEric.Saxe@Sun.COM 	for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
4008906SEric.Saxe@Sun.COM 		uint32_t *up;
4018906SEric.Saxe@Sun.COM 
4028906SEric.Saxe@Sun.COM 		q = obj->Package.Elements[i].Package.Elements;
4038906SEric.Saxe@Sun.COM 
4048906SEric.Saxe@Sun.COM 		/*
4058906SEric.Saxe@Sun.COM 		 * Skip duplicate entries.
4068906SEric.Saxe@Sun.COM 		 */
4078906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
4088906SEric.Saxe@Sun.COM 			continue;
4098906SEric.Saxe@Sun.COM 
4108906SEric.Saxe@Sun.COM 		up = (uint32_t *)tstate;
4118906SEric.Saxe@Sun.COM 		for (j = 0; j < CPU_ACPI_TSS_CNT; j++)
4128906SEric.Saxe@Sun.COM 			up[j] = q[j].Integer.Value;
4138906SEric.Saxe@Sun.COM 		tstate++;
4148906SEric.Saxe@Sun.COM 		cnt--;
4158906SEric.Saxe@Sun.COM 	}
4168906SEric.Saxe@Sun.COM }
4178906SEric.Saxe@Sun.COM 
4188906SEric.Saxe@Sun.COM /*
4198906SEric.Saxe@Sun.COM  * Cache the _PSS or _TSS data.
4208906SEric.Saxe@Sun.COM  */
4218906SEric.Saxe@Sun.COM static int
4228906SEric.Saxe@Sun.COM cpu_acpi_cache_supported_states(cpu_acpi_handle_t handle,
4238906SEric.Saxe@Sun.COM     cpu_acpi_obj_t objtype, int fcnt)
4248906SEric.Saxe@Sun.COM {
42510075SMark.Haywood@Sun.COM 	ACPI_STATUS astatus;
4268906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
4278906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj, *q, *l;
4288906SEric.Saxe@Sun.COM 	boolean_t eot = B_FALSE;
4298906SEric.Saxe@Sun.COM 	int ret = -1;
4308906SEric.Saxe@Sun.COM 	int cnt;
4318906SEric.Saxe@Sun.COM 	int i, j;
4328906SEric.Saxe@Sun.COM 
4338906SEric.Saxe@Sun.COM 	/*
43410075SMark.Haywood@Sun.COM 	 * Fetch the state data (if present) for the CPU node.
4358906SEric.Saxe@Sun.COM 	 */
4368906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
4378906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
43810075SMark.Haywood@Sun.COM 	astatus = AcpiEvaluateObjectTyped(handle->cs_handle,
4398906SEric.Saxe@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf,
44010075SMark.Haywood@Sun.COM 	    ACPI_TYPE_PACKAGE);
44110075SMark.Haywood@Sun.COM 	if (ACPI_FAILURE(astatus)) {
44210075SMark.Haywood@Sun.COM 		if (astatus == AE_NOT_FOUND) {
44310075SMark.Haywood@Sun.COM 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
44410075SMark.Haywood@Sun.COM 			    int, objtype, int, astatus);
44510075SMark.Haywood@Sun.COM 			if (objtype == PSS_OBJ)
44610075SMark.Haywood@Sun.COM 				cmn_err(CE_NOTE, "!cpu_acpi: _PSS package "
44710075SMark.Haywood@Sun.COM 				    "evaluation failed for with status %d for "
44810075SMark.Haywood@Sun.COM 				    "CPU %d.", astatus, handle->cs_id);
44910075SMark.Haywood@Sun.COM 			return (1);
45010075SMark.Haywood@Sun.COM 		}
45110075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s package "
45210075SMark.Haywood@Sun.COM 		    "for CPU %d.", astatus, cpu_acpi_obj_attrs[objtype].name,
45310075SMark.Haywood@Sun.COM 		    handle->cs_id);
45410075SMark.Haywood@Sun.COM 		goto out;
4558906SEric.Saxe@Sun.COM 	}
4568906SEric.Saxe@Sun.COM 	obj = abuf.Pointer;
4578906SEric.Saxe@Sun.COM 	if (obj->Package.Count < 2) {
45810075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: %s package bad count %d for "
45910075SMark.Haywood@Sun.COM 		    "CPU %d.", cpu_acpi_obj_attrs[objtype].name,
46010075SMark.Haywood@Sun.COM 		    obj->Package.Count, handle->cs_id);
4618906SEric.Saxe@Sun.COM 		goto out;
4628906SEric.Saxe@Sun.COM 	}
4638906SEric.Saxe@Sun.COM 
4648906SEric.Saxe@Sun.COM 	/*
4658906SEric.Saxe@Sun.COM 	 * Does the package look coherent?
4668906SEric.Saxe@Sun.COM 	 */
4678906SEric.Saxe@Sun.COM 	cnt = 0;
4688906SEric.Saxe@Sun.COM 	for (i = 0, l = NULL; i < obj->Package.Count; i++, l = q) {
4698906SEric.Saxe@Sun.COM 		if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE ||
4708906SEric.Saxe@Sun.COM 		    obj->Package.Elements[i].Package.Count != fcnt) {
47110075SMark.Haywood@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in "
47210075SMark.Haywood@Sun.COM 			    "%s package for CPU %d.",
47310075SMark.Haywood@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name,
47410075SMark.Haywood@Sun.COM 			    handle->cs_id);
4758906SEric.Saxe@Sun.COM 			goto out;
4768906SEric.Saxe@Sun.COM 		}
4778906SEric.Saxe@Sun.COM 
4788906SEric.Saxe@Sun.COM 		q = obj->Package.Elements[i].Package.Elements;
4798906SEric.Saxe@Sun.COM 		for (j = 0; j < fcnt; j++) {
4808906SEric.Saxe@Sun.COM 			if (q[j].Type != ACPI_TYPE_INTEGER) {
48110075SMark.Haywood@Sun.COM 				cmn_err(CE_NOTE, "!cpu_acpi: %s element "
48210075SMark.Haywood@Sun.COM 				    "invalid (type) for CPU %d.",
48310075SMark.Haywood@Sun.COM 				    cpu_acpi_obj_attrs[objtype].name,
48410075SMark.Haywood@Sun.COM 				    handle->cs_id);
4858906SEric.Saxe@Sun.COM 				goto out;
4868906SEric.Saxe@Sun.COM 			}
4878906SEric.Saxe@Sun.COM 		}
4888906SEric.Saxe@Sun.COM 
4898906SEric.Saxe@Sun.COM 		/*
4908906SEric.Saxe@Sun.COM 		 * Ignore duplicate entries.
4918906SEric.Saxe@Sun.COM 		 */
4928906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
4938906SEric.Saxe@Sun.COM 			continue;
4948906SEric.Saxe@Sun.COM 
4958906SEric.Saxe@Sun.COM 		/*
4968906SEric.Saxe@Sun.COM 		 * Some supported state tables are larger than required
4978906SEric.Saxe@Sun.COM 		 * and unused elements are filled with patterns
4988906SEric.Saxe@Sun.COM 		 * of 0xff.  Simply check here for frequency = 0xffff
4998906SEric.Saxe@Sun.COM 		 * and stop counting if found.
5008906SEric.Saxe@Sun.COM 		 */
5018906SEric.Saxe@Sun.COM 		if (q[0].Integer.Value == 0xffff) {
5028906SEric.Saxe@Sun.COM 			eot = B_TRUE;
5038906SEric.Saxe@Sun.COM 			continue;
5048906SEric.Saxe@Sun.COM 		}
5058906SEric.Saxe@Sun.COM 
5068906SEric.Saxe@Sun.COM 		/*
5078906SEric.Saxe@Sun.COM 		 * We should never find a valid entry after we've hit
5088906SEric.Saxe@Sun.COM 		 * an the end-of-table entry.
5098906SEric.Saxe@Sun.COM 		 */
5108906SEric.Saxe@Sun.COM 		if (eot) {
51110075SMark.Haywood@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in %s "
51210075SMark.Haywood@Sun.COM 			    "package after eot for CPU %d.",
51310075SMark.Haywood@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name,
51410075SMark.Haywood@Sun.COM 			    handle->cs_id);
5158906SEric.Saxe@Sun.COM 			goto out;
5168906SEric.Saxe@Sun.COM 		}
5178906SEric.Saxe@Sun.COM 
5188906SEric.Saxe@Sun.COM 		/*
5198906SEric.Saxe@Sun.COM 		 * states must be defined in order from highest to lowest.
5208906SEric.Saxe@Sun.COM 		 */
5218906SEric.Saxe@Sun.COM 		if (l != NULL && l[0].Integer.Value < q[0].Integer.Value) {
52210075SMark.Haywood@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: %s package state "
52310075SMark.Haywood@Sun.COM 			    "definitions out of order for CPU %d.",
52410075SMark.Haywood@Sun.COM 			    cpu_acpi_obj_attrs[objtype].name,
52510075SMark.Haywood@Sun.COM 			    handle->cs_id);
5268906SEric.Saxe@Sun.COM 			goto out;
5278906SEric.Saxe@Sun.COM 		}
5288906SEric.Saxe@Sun.COM 
5298906SEric.Saxe@Sun.COM 		/*
5308906SEric.Saxe@Sun.COM 		 * This entry passes.
5318906SEric.Saxe@Sun.COM 		 */
5328906SEric.Saxe@Sun.COM 		cnt++;
5338906SEric.Saxe@Sun.COM 	}
5348906SEric.Saxe@Sun.COM 	if (cnt == 0)
5358906SEric.Saxe@Sun.COM 		goto out;
5368906SEric.Saxe@Sun.COM 
5378906SEric.Saxe@Sun.COM 	/*
5388906SEric.Saxe@Sun.COM 	 * Yes, fill in the structure.
5398906SEric.Saxe@Sun.COM 	 */
5408906SEric.Saxe@Sun.COM 	ASSERT(objtype == PSS_OBJ || objtype == TSS_OBJ);
5418906SEric.Saxe@Sun.COM 	(objtype == PSS_OBJ) ? cpu_acpi_cache_pstate(handle, obj, cnt) :
5428906SEric.Saxe@Sun.COM 	    cpu_acpi_cache_tstate(handle, obj, cnt);
5438906SEric.Saxe@Sun.COM 
5448906SEric.Saxe@Sun.COM 	ret = 0;
5458906SEric.Saxe@Sun.COM out:
54610075SMark.Haywood@Sun.COM 	if (abuf.Pointer != NULL)
54710075SMark.Haywood@Sun.COM 		AcpiOsFree(abuf.Pointer);
5488906SEric.Saxe@Sun.COM 	return (ret);
5498906SEric.Saxe@Sun.COM }
5508906SEric.Saxe@Sun.COM 
5518906SEric.Saxe@Sun.COM /*
5528906SEric.Saxe@Sun.COM  * Cache the _PSS data. The _PSS data defines the different power levels
5538906SEric.Saxe@Sun.COM  * supported by the CPU and the attributes associated with each power level
5548906SEric.Saxe@Sun.COM  * (i.e., frequency, voltage, etc.). The power levels are number from
5558906SEric.Saxe@Sun.COM  * highest to lowest. That is, the highest power level is _PSS entry 0
5568906SEric.Saxe@Sun.COM  * and the lowest power level is the last _PSS entry.
5578906SEric.Saxe@Sun.COM  */
5588906SEric.Saxe@Sun.COM static int
5598906SEric.Saxe@Sun.COM cpu_acpi_cache_pstates(cpu_acpi_handle_t handle)
5608906SEric.Saxe@Sun.COM {
5618906SEric.Saxe@Sun.COM 	int ret;
5628906SEric.Saxe@Sun.COM 
5638906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSS_CACHED);
5648906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_supported_states(handle, PSS_OBJ,
5658906SEric.Saxe@Sun.COM 	    CPU_ACPI_PSS_CNT);
5668906SEric.Saxe@Sun.COM 	if (ret == 0)
5678906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSS_CACHED);
5688906SEric.Saxe@Sun.COM 	return (ret);
5698906SEric.Saxe@Sun.COM }
5708906SEric.Saxe@Sun.COM 
5718906SEric.Saxe@Sun.COM /*
5728906SEric.Saxe@Sun.COM  * Cache the _TSS data. The _TSS data defines the different freq throttle
5738906SEric.Saxe@Sun.COM  * levels supported by the CPU and the attributes associated with each
5748906SEric.Saxe@Sun.COM  * throttle level (i.e., frequency throttle percentage, voltage, etc.).
5758906SEric.Saxe@Sun.COM  * The throttle levels are number from highest to lowest.
5768906SEric.Saxe@Sun.COM  */
5778906SEric.Saxe@Sun.COM static int
5788906SEric.Saxe@Sun.COM cpu_acpi_cache_tstates(cpu_acpi_handle_t handle)
5798906SEric.Saxe@Sun.COM {
5808906SEric.Saxe@Sun.COM 	int ret;
5818906SEric.Saxe@Sun.COM 
5828906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSS_CACHED);
5838906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_supported_states(handle, TSS_OBJ,
5848906SEric.Saxe@Sun.COM 	    CPU_ACPI_TSS_CNT);
5858906SEric.Saxe@Sun.COM 	if (ret == 0)
5868906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSS_CACHED);
5878906SEric.Saxe@Sun.COM 	return (ret);
5888906SEric.Saxe@Sun.COM }
5898906SEric.Saxe@Sun.COM 
5908906SEric.Saxe@Sun.COM /*
5918906SEric.Saxe@Sun.COM  * Cache the ACPI CPU present capabilities data objects.
5928906SEric.Saxe@Sun.COM  */
5938906SEric.Saxe@Sun.COM static int
5948906SEric.Saxe@Sun.COM cpu_acpi_cache_present_capabilities(cpu_acpi_handle_t handle,
5958906SEric.Saxe@Sun.COM     cpu_acpi_obj_t objtype, cpu_acpi_present_capabilities_t *pc)
5968906SEric.Saxe@Sun.COM 
5978906SEric.Saxe@Sun.COM {
59810075SMark.Haywood@Sun.COM 	ACPI_STATUS astatus;
5998906SEric.Saxe@Sun.COM 	ACPI_BUFFER abuf;
6008906SEric.Saxe@Sun.COM 	ACPI_OBJECT *obj;
60110075SMark.Haywood@Sun.COM 	int ret = -1;
6028906SEric.Saxe@Sun.COM 
6038906SEric.Saxe@Sun.COM 	/*
6048906SEric.Saxe@Sun.COM 	 * Fetch the present capabilites object (if present) for the CPU node.
6058906SEric.Saxe@Sun.COM 	 */
6068906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
6078906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
60810075SMark.Haywood@Sun.COM 	astatus = AcpiEvaluateObject(handle->cs_handle,
60910075SMark.Haywood@Sun.COM 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf);
61010075SMark.Haywood@Sun.COM 	if (ACPI_FAILURE(astatus) && astatus != AE_NOT_FOUND) {
61110075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s "
61210075SMark.Haywood@Sun.COM 		    "package for CPU %d.", astatus,
61310075SMark.Haywood@Sun.COM 		    cpu_acpi_obj_attrs[objtype].name, handle->cs_id);
61410075SMark.Haywood@Sun.COM 		goto out;
61510075SMark.Haywood@Sun.COM 	}
61610075SMark.Haywood@Sun.COM 	if (astatus == AE_NOT_FOUND || abuf.Length == 0) {
6178906SEric.Saxe@Sun.COM 		*pc = 0;
6188906SEric.Saxe@Sun.COM 		return (1);
6198906SEric.Saxe@Sun.COM 	}
6208906SEric.Saxe@Sun.COM 
6218906SEric.Saxe@Sun.COM 	obj = (ACPI_OBJECT *)abuf.Pointer;
6228906SEric.Saxe@Sun.COM 	*pc = obj->Integer.Value;
62310075SMark.Haywood@Sun.COM 
62410075SMark.Haywood@Sun.COM 	ret = 0;
62510075SMark.Haywood@Sun.COM out:
62610075SMark.Haywood@Sun.COM 	if (abuf.Pointer != NULL)
62710075SMark.Haywood@Sun.COM 		AcpiOsFree(abuf.Pointer);
62810075SMark.Haywood@Sun.COM 	return (ret);
6298906SEric.Saxe@Sun.COM }
6308906SEric.Saxe@Sun.COM 
6318906SEric.Saxe@Sun.COM /*
6328906SEric.Saxe@Sun.COM  * Cache the _PPC data. The _PPC simply contains an integer value which
6338906SEric.Saxe@Sun.COM  * represents the highest power level that a CPU should transition to.
6348906SEric.Saxe@Sun.COM  * That is, it's an index into the array of _PSS entries and will be
6358906SEric.Saxe@Sun.COM  * greater than or equal to zero.
6368906SEric.Saxe@Sun.COM  */
6378906SEric.Saxe@Sun.COM void
6388906SEric.Saxe@Sun.COM cpu_acpi_cache_ppc(cpu_acpi_handle_t handle)
6398906SEric.Saxe@Sun.COM {
6408906SEric.Saxe@Sun.COM 	cpu_acpi_ppc_t *ppc;
6418906SEric.Saxe@Sun.COM 	int ret;
6428906SEric.Saxe@Sun.COM 
6438906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PPC_CACHED);
6448906SEric.Saxe@Sun.COM 	ppc = &CPU_ACPI_PPC(handle);
6458906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_present_capabilities(handle, PPC_OBJ, ppc);
6468906SEric.Saxe@Sun.COM 	if (ret == 0)
6478906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PPC_CACHED);
6488906SEric.Saxe@Sun.COM }
6498906SEric.Saxe@Sun.COM 
6508906SEric.Saxe@Sun.COM /*
6518906SEric.Saxe@Sun.COM  * Cache the _TPC data. The _TPC simply contains an integer value which
6528906SEric.Saxe@Sun.COM  * represents the throttle level that a CPU should transition to.
6538906SEric.Saxe@Sun.COM  * That is, it's an index into the array of _TSS entries and will be
6548906SEric.Saxe@Sun.COM  * greater than or equal to zero.
6558906SEric.Saxe@Sun.COM  */
6568906SEric.Saxe@Sun.COM void
6578906SEric.Saxe@Sun.COM cpu_acpi_cache_tpc(cpu_acpi_handle_t handle)
6588906SEric.Saxe@Sun.COM {
6598906SEric.Saxe@Sun.COM 	cpu_acpi_tpc_t *tpc;
6608906SEric.Saxe@Sun.COM 	int ret;
6618906SEric.Saxe@Sun.COM 
6628906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TPC_CACHED);
6638906SEric.Saxe@Sun.COM 	tpc = &CPU_ACPI_TPC(handle);
6648906SEric.Saxe@Sun.COM 	ret = cpu_acpi_cache_present_capabilities(handle, TPC_OBJ, tpc);
6658906SEric.Saxe@Sun.COM 	if (ret == 0)
6668906SEric.Saxe@Sun.COM 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TPC_CACHED);
6678906SEric.Saxe@Sun.COM }
6688906SEric.Saxe@Sun.COM 
6698906SEric.Saxe@Sun.COM int
6708906SEric.Saxe@Sun.COM cpu_acpi_verify_cstate(cpu_acpi_cstate_t *cstate)
6718906SEric.Saxe@Sun.COM {
6728906SEric.Saxe@Sun.COM 	uint32_t addrspaceid = cstate->cs_addrspace_id;
6738906SEric.Saxe@Sun.COM 
6748906SEric.Saxe@Sun.COM 	if ((addrspaceid != ACPI_ADR_SPACE_FIXED_HARDWARE) &&
6758906SEric.Saxe@Sun.COM 	    (addrspaceid != ACPI_ADR_SPACE_SYSTEM_IO)) {
67610075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST unsupported address space id"
6778906SEric.Saxe@Sun.COM 		    ":C%d, type: %d\n", cstate->cs_type, addrspaceid);
6788906SEric.Saxe@Sun.COM 		return (1);
6798906SEric.Saxe@Sun.COM 	}
6808906SEric.Saxe@Sun.COM 	return (0);
6818906SEric.Saxe@Sun.COM }
6828906SEric.Saxe@Sun.COM 
6838906SEric.Saxe@Sun.COM int
6848906SEric.Saxe@Sun.COM cpu_acpi_cache_cst(cpu_acpi_handle_t handle)
6858906SEric.Saxe@Sun.COM {
68610075SMark.Haywood@Sun.COM 	ACPI_STATUS astatus;
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;
6919148SBill.Holler@Sun.COM 	size_t alloc_size;
6928906SEric.Saxe@Sun.COM 	int i, count;
69310075SMark.Haywood@Sun.COM 	int ret = 1;
6948906SEric.Saxe@Sun.COM 
6958906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CST_CACHED);
6968906SEric.Saxe@Sun.COM 
6978906SEric.Saxe@Sun.COM 	abuf.Length = ACPI_ALLOCATE_BUFFER;
6988906SEric.Saxe@Sun.COM 	abuf.Pointer = NULL;
6998906SEric.Saxe@Sun.COM 
70010075SMark.Haywood@Sun.COM 	/*
70110075SMark.Haywood@Sun.COM 	 * Fetch the C-state data (if present) for the CPU node.
70210075SMark.Haywood@Sun.COM 	 */
70310075SMark.Haywood@Sun.COM 	astatus = AcpiEvaluateObjectTyped(handle->cs_handle, "_CST",
70410075SMark.Haywood@Sun.COM 	    NULL, &abuf, ACPI_TYPE_PACKAGE);
70510075SMark.Haywood@Sun.COM 	if (ACPI_FAILURE(astatus)) {
70610075SMark.Haywood@Sun.COM 		if (astatus == AE_NOT_FOUND) {
70710075SMark.Haywood@Sun.COM 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
70810075SMark.Haywood@Sun.COM 			    int, CST_OBJ, int, astatus);
70910075SMark.Haywood@Sun.COM 			return (1);
71010075SMark.Haywood@Sun.COM 		}
71110075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating _CST package "
71210075SMark.Haywood@Sun.COM 		    "for CPU %d.", astatus, handle->cs_id);
71310075SMark.Haywood@Sun.COM 		goto out;
71410075SMark.Haywood@Sun.COM 
7158906SEric.Saxe@Sun.COM 	}
7168906SEric.Saxe@Sun.COM 	obj = (ACPI_OBJECT *)abuf.Pointer;
7178906SEric.Saxe@Sun.COM 	if (obj->Package.Count < 2) {
71810075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST unsupported package "
71910075SMark.Haywood@Sun.COM 		    "count %d for CPU %d.", obj->Package.Count, handle->cs_id);
72010075SMark.Haywood@Sun.COM 		goto out;
7218906SEric.Saxe@Sun.COM 	}
7228906SEric.Saxe@Sun.COM 
7238906SEric.Saxe@Sun.COM 	/*
7248906SEric.Saxe@Sun.COM 	 * Does the package look coherent?
7258906SEric.Saxe@Sun.COM 	 */
7268906SEric.Saxe@Sun.COM 	cnt = obj->Package.Elements[0].Integer.Value;
7278906SEric.Saxe@Sun.COM 	if (cnt < 1 || cnt != obj->Package.Count - 1) {
72810075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid element "
72910075SMark.Haywood@Sun.COM 		    "count %d != Package count %d for CPU %d",
73010075SMark.Haywood@Sun.COM 		    (int)cnt, (int)obj->Package.Count - 1, handle->cs_id);
73110075SMark.Haywood@Sun.COM 		goto out;
7328906SEric.Saxe@Sun.COM 	}
7338906SEric.Saxe@Sun.COM 
7348906SEric.Saxe@Sun.COM 	CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)cnt;
7359148SBill.Holler@Sun.COM 	alloc_size = CPU_ACPI_CSTATES_SIZE(cnt);
7369148SBill.Holler@Sun.COM 	CPU_ACPI_CSTATES(handle) = kmem_zalloc(alloc_size, KM_SLEEP);
7378906SEric.Saxe@Sun.COM 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
7388906SEric.Saxe@Sun.COM 	p = cstate;
7398906SEric.Saxe@Sun.COM 
7408906SEric.Saxe@Sun.COM 	for (i = 1, count = 1; i <= cnt; i++) {
7418906SEric.Saxe@Sun.COM 		ACPI_OBJECT *pkg;
7428906SEric.Saxe@Sun.COM 		AML_RESOURCE_GENERIC_REGISTER *reg;
7438906SEric.Saxe@Sun.COM 		ACPI_OBJECT *element;
7448906SEric.Saxe@Sun.COM 
7458906SEric.Saxe@Sun.COM 		pkg = &(obj->Package.Elements[i]);
7468906SEric.Saxe@Sun.COM 		reg = (AML_RESOURCE_GENERIC_REGISTER *)
7478906SEric.Saxe@Sun.COM 		    pkg->Package.Elements[0].Buffer.Pointer;
7488906SEric.Saxe@Sun.COM 		cstate->cs_addrspace_id = reg->AddressSpaceId;
7498906SEric.Saxe@Sun.COM 		cstate->cs_address = reg->Address;
7508906SEric.Saxe@Sun.COM 		element = &(pkg->Package.Elements[1]);
7518906SEric.Saxe@Sun.COM 		cstate->cs_type = element->Integer.Value;
7528906SEric.Saxe@Sun.COM 		element = &(pkg->Package.Elements[2]);
7538906SEric.Saxe@Sun.COM 		cstate->cs_latency = element->Integer.Value;
7548906SEric.Saxe@Sun.COM 		element = &(pkg->Package.Elements[3]);
7558906SEric.Saxe@Sun.COM 		cstate->cs_power = element->Integer.Value;
7568906SEric.Saxe@Sun.COM 
7578906SEric.Saxe@Sun.COM 		if (cpu_acpi_verify_cstate(cstate)) {
7588906SEric.Saxe@Sun.COM 			/*
7598906SEric.Saxe@Sun.COM 			 * ignore this entry if it's not valid
7608906SEric.Saxe@Sun.COM 			 */
7618906SEric.Saxe@Sun.COM 			continue;
7628906SEric.Saxe@Sun.COM 		}
7638906SEric.Saxe@Sun.COM 		if (cstate == p) {
7648906SEric.Saxe@Sun.COM 			cstate++;
7658906SEric.Saxe@Sun.COM 		} else if (p->cs_type == cstate->cs_type) {
7668906SEric.Saxe@Sun.COM 			/*
7678906SEric.Saxe@Sun.COM 			 * if there are duplicate entries, we keep the
7688906SEric.Saxe@Sun.COM 			 * last one. This fixes:
7698906SEric.Saxe@Sun.COM 			 * 1) some buggy BIOS have total duplicate entries.
7708906SEric.Saxe@Sun.COM 			 * 2) ACPI Spec allows the same cstate entry with
7718906SEric.Saxe@Sun.COM 			 *    different power and latency, we use the one
7728906SEric.Saxe@Sun.COM 			 *    with more power saving.
7738906SEric.Saxe@Sun.COM 			 */
7748906SEric.Saxe@Sun.COM 			(void) memcpy(p, cstate, sizeof (cpu_acpi_cstate_t));
7758906SEric.Saxe@Sun.COM 		} else {
7768906SEric.Saxe@Sun.COM 			/*
7778906SEric.Saxe@Sun.COM 			 * we got a valid entry, cache it to the
7788906SEric.Saxe@Sun.COM 			 * cstate structure
7798906SEric.Saxe@Sun.COM 			 */
7808906SEric.Saxe@Sun.COM 			p = cstate++;
7818906SEric.Saxe@Sun.COM 			count++;
7828906SEric.Saxe@Sun.COM 		}
7838906SEric.Saxe@Sun.COM 	}
7848906SEric.Saxe@Sun.COM 
7858906SEric.Saxe@Sun.COM 	if (count < 2) {
78610075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid count %d < 2 for "
78710075SMark.Haywood@Sun.COM 		    "CPU %d", count, handle->cs_id);
7889148SBill.Holler@Sun.COM 		kmem_free(CPU_ACPI_CSTATES(handle), alloc_size);
7899148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES(handle) = NULL;
7909148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)0;
79110075SMark.Haywood@Sun.COM 		goto out;
7928906SEric.Saxe@Sun.COM 	}
7938983SBill.Holler@Sun.COM 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
7948983SBill.Holler@Sun.COM 	if (cstate[0].cs_type != CPU_ACPI_C1) {
79510075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: _CST first element type not "
79610075SMark.Haywood@Sun.COM 		    "C1: %d for CPU %d", (int)cstate->cs_type, handle->cs_id);
7979148SBill.Holler@Sun.COM 		kmem_free(CPU_ACPI_CSTATES(handle), alloc_size);
7989148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES(handle) = NULL;
7999148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)0;
80010075SMark.Haywood@Sun.COM 		goto out;
8018983SBill.Holler@Sun.COM 	}
8028906SEric.Saxe@Sun.COM 
8039148SBill.Holler@Sun.COM 	if (count != cnt) {
8049148SBill.Holler@Sun.COM 		void	*orig = CPU_ACPI_CSTATES(handle);
8059148SBill.Holler@Sun.COM 
8068906SEric.Saxe@Sun.COM 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)count;
8079148SBill.Holler@Sun.COM 		CPU_ACPI_CSTATES(handle) = kmem_zalloc(
8089148SBill.Holler@Sun.COM 		    CPU_ACPI_CSTATES_SIZE(count), KM_SLEEP);
8099148SBill.Holler@Sun.COM 		(void) memcpy(CPU_ACPI_CSTATES(handle), orig,
8109148SBill.Holler@Sun.COM 		    CPU_ACPI_CSTATES_SIZE(count));
8119148SBill.Holler@Sun.COM 		kmem_free(orig, alloc_size);
8129148SBill.Holler@Sun.COM 	}
8138906SEric.Saxe@Sun.COM 
8148906SEric.Saxe@Sun.COM 	CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CST_CACHED);
81510075SMark.Haywood@Sun.COM 
81610075SMark.Haywood@Sun.COM 	ret = 0;
81710075SMark.Haywood@Sun.COM 
81810075SMark.Haywood@Sun.COM out:
81910075SMark.Haywood@Sun.COM 	if (abuf.Pointer != NULL)
82010075SMark.Haywood@Sun.COM 		AcpiOsFree(abuf.Pointer);
82110075SMark.Haywood@Sun.COM 	return (ret);
8228906SEric.Saxe@Sun.COM }
8238906SEric.Saxe@Sun.COM 
8248906SEric.Saxe@Sun.COM /*
8258906SEric.Saxe@Sun.COM  * Cache the _PCT, _PSS, _PSD and _PPC data.
8268906SEric.Saxe@Sun.COM  */
8278906SEric.Saxe@Sun.COM int
8288906SEric.Saxe@Sun.COM cpu_acpi_cache_pstate_data(cpu_acpi_handle_t handle)
8298906SEric.Saxe@Sun.COM {
8308906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_pct(handle) < 0) {
83110075SMark.Haywood@Sun.COM 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
83210075SMark.Haywood@Sun.COM 		    int, PCT_OBJ);
83310075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error parsing _PCT 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 	if (cpu_acpi_cache_pstates(handle) != 0) {
83910075SMark.Haywood@Sun.COM 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
84010075SMark.Haywood@Sun.COM 		    int, PSS_OBJ);
84110075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error parsing _PSS for "
8428906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
8438906SEric.Saxe@Sun.COM 		return (-1);
8448906SEric.Saxe@Sun.COM 	}
8458906SEric.Saxe@Sun.COM 
8468906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_psd(handle) < 0) {
84710075SMark.Haywood@Sun.COM 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
84810075SMark.Haywood@Sun.COM 		    int, PSD_OBJ);
84910075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error parsing _PSD for "
8508906SEric.Saxe@Sun.COM 		    "CPU %d", handle->cs_id);
8518906SEric.Saxe@Sun.COM 		return (-1);
8528906SEric.Saxe@Sun.COM 	}
8538906SEric.Saxe@Sun.COM 
8548906SEric.Saxe@Sun.COM 	cpu_acpi_cache_ppc(handle);
8558906SEric.Saxe@Sun.COM 
8568906SEric.Saxe@Sun.COM 	return (0);
8578906SEric.Saxe@Sun.COM }
8588906SEric.Saxe@Sun.COM 
8598906SEric.Saxe@Sun.COM void
8608906SEric.Saxe@Sun.COM cpu_acpi_free_pstate_data(cpu_acpi_handle_t handle)
8618906SEric.Saxe@Sun.COM {
8628906SEric.Saxe@Sun.COM 	if (handle != NULL) {
8638906SEric.Saxe@Sun.COM 		if (CPU_ACPI_PSTATES(handle)) {
8648906SEric.Saxe@Sun.COM 			kmem_free(CPU_ACPI_PSTATES(handle),
8658906SEric.Saxe@Sun.COM 			    CPU_ACPI_PSTATES_SIZE(
8668906SEric.Saxe@Sun.COM 			    CPU_ACPI_PSTATES_COUNT(handle)));
8678906SEric.Saxe@Sun.COM 			CPU_ACPI_PSTATES(handle) = NULL;
8688906SEric.Saxe@Sun.COM 		}
8698906SEric.Saxe@Sun.COM 	}
8708906SEric.Saxe@Sun.COM }
8718906SEric.Saxe@Sun.COM 
8728906SEric.Saxe@Sun.COM /*
8738906SEric.Saxe@Sun.COM  * Cache the _PTC, _TSS, _TSD and _TPC data.
8748906SEric.Saxe@Sun.COM  */
8758906SEric.Saxe@Sun.COM int
8768906SEric.Saxe@Sun.COM cpu_acpi_cache_tstate_data(cpu_acpi_handle_t handle)
8778906SEric.Saxe@Sun.COM {
87810075SMark.Haywood@Sun.COM 	int ret;
8799004SNapanda.Pemmaiah@Sun.COM 
8808906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_ptc(handle) < 0) {
88110075SMark.Haywood@Sun.COM 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
88210075SMark.Haywood@Sun.COM 		    int, PTC_OBJ);
8838906SEric.Saxe@Sun.COM 		return (-1);
8848906SEric.Saxe@Sun.COM 	}
8858906SEric.Saxe@Sun.COM 
88610075SMark.Haywood@Sun.COM 	if ((ret = cpu_acpi_cache_tstates(handle)) != 0) {
88710075SMark.Haywood@Sun.COM 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
88810075SMark.Haywood@Sun.COM 		    int, TSS_OBJ);
88910075SMark.Haywood@Sun.COM 		return (ret);
8908906SEric.Saxe@Sun.COM 	}
8918906SEric.Saxe@Sun.COM 
8928906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_tsd(handle) < 0) {
89310075SMark.Haywood@Sun.COM 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
89410075SMark.Haywood@Sun.COM 		    int, TSD_OBJ);
8958906SEric.Saxe@Sun.COM 		return (-1);
8968906SEric.Saxe@Sun.COM 	}
8978906SEric.Saxe@Sun.COM 
8988906SEric.Saxe@Sun.COM 	cpu_acpi_cache_tpc(handle);
8998906SEric.Saxe@Sun.COM 
9008906SEric.Saxe@Sun.COM 	return (0);
9018906SEric.Saxe@Sun.COM }
9028906SEric.Saxe@Sun.COM 
9038906SEric.Saxe@Sun.COM void
9048906SEric.Saxe@Sun.COM cpu_acpi_free_tstate_data(cpu_acpi_handle_t handle)
9058906SEric.Saxe@Sun.COM {
9068906SEric.Saxe@Sun.COM 	if (handle != NULL) {
9078906SEric.Saxe@Sun.COM 		if (CPU_ACPI_TSTATES(handle)) {
9088906SEric.Saxe@Sun.COM 			kmem_free(CPU_ACPI_TSTATES(handle),
9098906SEric.Saxe@Sun.COM 			    CPU_ACPI_TSTATES_SIZE(
9108906SEric.Saxe@Sun.COM 			    CPU_ACPI_TSTATES_COUNT(handle)));
9118906SEric.Saxe@Sun.COM 			CPU_ACPI_TSTATES(handle) = NULL;
9128906SEric.Saxe@Sun.COM 		}
9138906SEric.Saxe@Sun.COM 	}
9148906SEric.Saxe@Sun.COM }
9158906SEric.Saxe@Sun.COM 
9168906SEric.Saxe@Sun.COM /*
9178906SEric.Saxe@Sun.COM  * Cache the _CST data.
9188906SEric.Saxe@Sun.COM  */
9198906SEric.Saxe@Sun.COM int
9208906SEric.Saxe@Sun.COM cpu_acpi_cache_cstate_data(cpu_acpi_handle_t handle)
9218906SEric.Saxe@Sun.COM {
92210075SMark.Haywood@Sun.COM 	int ret;
92310075SMark.Haywood@Sun.COM 
92410075SMark.Haywood@Sun.COM 	if ((ret = cpu_acpi_cache_cst(handle)) != 0) {
92510075SMark.Haywood@Sun.COM 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
92610075SMark.Haywood@Sun.COM 		    int, CST_OBJ);
92710075SMark.Haywood@Sun.COM 		return (ret);
9288906SEric.Saxe@Sun.COM 	}
9298906SEric.Saxe@Sun.COM 
9308906SEric.Saxe@Sun.COM 	if (cpu_acpi_cache_csd(handle) < 0) {
93110075SMark.Haywood@Sun.COM 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
93210075SMark.Haywood@Sun.COM 		    int, CSD_OBJ);
9338906SEric.Saxe@Sun.COM 		return (-1);
9348906SEric.Saxe@Sun.COM 	}
9358906SEric.Saxe@Sun.COM 
9368906SEric.Saxe@Sun.COM 	return (0);
9378906SEric.Saxe@Sun.COM }
9388906SEric.Saxe@Sun.COM 
9398906SEric.Saxe@Sun.COM void
9408906SEric.Saxe@Sun.COM cpu_acpi_free_cstate_data(cpu_acpi_handle_t handle)
9418906SEric.Saxe@Sun.COM {
9428906SEric.Saxe@Sun.COM 	if (handle != NULL) {
9438906SEric.Saxe@Sun.COM 		if (CPU_ACPI_CSTATES(handle)) {
9448906SEric.Saxe@Sun.COM 			kmem_free(CPU_ACPI_CSTATES(handle),
9458906SEric.Saxe@Sun.COM 			    CPU_ACPI_CSTATES_SIZE(
9468906SEric.Saxe@Sun.COM 			    CPU_ACPI_CSTATES_COUNT(handle)));
9478906SEric.Saxe@Sun.COM 			CPU_ACPI_CSTATES(handle) = NULL;
9488906SEric.Saxe@Sun.COM 		}
9498906SEric.Saxe@Sun.COM 	}
9508906SEric.Saxe@Sun.COM }
9518906SEric.Saxe@Sun.COM 
9528906SEric.Saxe@Sun.COM /*
9538906SEric.Saxe@Sun.COM  * Register a handler for processor change notifications.
9548906SEric.Saxe@Sun.COM  */
9558906SEric.Saxe@Sun.COM void
9568906SEric.Saxe@Sun.COM cpu_acpi_install_notify_handler(cpu_acpi_handle_t handle,
9578906SEric.Saxe@Sun.COM     ACPI_NOTIFY_HANDLER handler, void *ctx)
9588906SEric.Saxe@Sun.COM {
9598906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiInstallNotifyHandler(handle->cs_handle,
9608906SEric.Saxe@Sun.COM 	    ACPI_DEVICE_NOTIFY, handler, ctx)))
9618906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unable to register "
96210075SMark.Haywood@Sun.COM 		    "notify handler for CPU %d.", handle->cs_id);
9638906SEric.Saxe@Sun.COM }
9648906SEric.Saxe@Sun.COM 
9658906SEric.Saxe@Sun.COM /*
9668906SEric.Saxe@Sun.COM  * Remove a handler for processor change notifications.
9678906SEric.Saxe@Sun.COM  */
9688906SEric.Saxe@Sun.COM void
9698906SEric.Saxe@Sun.COM cpu_acpi_remove_notify_handler(cpu_acpi_handle_t handle,
9708906SEric.Saxe@Sun.COM     ACPI_NOTIFY_HANDLER handler)
9718906SEric.Saxe@Sun.COM {
9728906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiRemoveNotifyHandler(handle->cs_handle,
9738906SEric.Saxe@Sun.COM 	    ACPI_DEVICE_NOTIFY, handler)))
9748906SEric.Saxe@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: Unable to remove "
97510075SMark.Haywood@Sun.COM 		    "notify handler for CPU %d.", handle->cs_id);
9768906SEric.Saxe@Sun.COM }
9778906SEric.Saxe@Sun.COM 
9788906SEric.Saxe@Sun.COM /*
9798906SEric.Saxe@Sun.COM  * Write _PDC.
9808906SEric.Saxe@Sun.COM  */
9818906SEric.Saxe@Sun.COM int
9828906SEric.Saxe@Sun.COM cpu_acpi_write_pdc(cpu_acpi_handle_t handle, uint32_t revision, uint32_t count,
9838906SEric.Saxe@Sun.COM     uint32_t *capabilities)
9848906SEric.Saxe@Sun.COM {
98510075SMark.Haywood@Sun.COM 	ACPI_STATUS astatus;
9868906SEric.Saxe@Sun.COM 	ACPI_OBJECT obj;
9878906SEric.Saxe@Sun.COM 	ACPI_OBJECT_LIST list = { 1, &obj};
9888906SEric.Saxe@Sun.COM 	uint32_t *buffer;
9898906SEric.Saxe@Sun.COM 	uint32_t *bufptr;
9908906SEric.Saxe@Sun.COM 	uint32_t bufsize;
9918906SEric.Saxe@Sun.COM 	int i;
99210075SMark.Haywood@Sun.COM 	int ret = 0;
9938906SEric.Saxe@Sun.COM 
9948906SEric.Saxe@Sun.COM 	bufsize = (count + 2) * sizeof (uint32_t);
9958906SEric.Saxe@Sun.COM 	buffer = kmem_zalloc(bufsize, KM_SLEEP);
9968906SEric.Saxe@Sun.COM 	buffer[0] = revision;
9978906SEric.Saxe@Sun.COM 	buffer[1] = count;
9988906SEric.Saxe@Sun.COM 	bufptr = &buffer[2];
9998906SEric.Saxe@Sun.COM 	for (i = 0; i < count; i++)
10008906SEric.Saxe@Sun.COM 		*bufptr++ = *capabilities++;
10018906SEric.Saxe@Sun.COM 
10028906SEric.Saxe@Sun.COM 	obj.Type = ACPI_TYPE_BUFFER;
10038906SEric.Saxe@Sun.COM 	obj.Buffer.Length = bufsize;
10048906SEric.Saxe@Sun.COM 	obj.Buffer.Pointer = (void *)buffer;
10058906SEric.Saxe@Sun.COM 
10068906SEric.Saxe@Sun.COM 	/*
100710075SMark.Haywood@Sun.COM 	 * Fetch the ??? (if present) for the CPU node.
10088906SEric.Saxe@Sun.COM 	 */
100910075SMark.Haywood@Sun.COM 	astatus = AcpiEvaluateObject(handle->cs_handle, "_PDC", &list, NULL);
101010075SMark.Haywood@Sun.COM 	if (ACPI_FAILURE(astatus)) {
101110075SMark.Haywood@Sun.COM 		if (astatus == AE_NOT_FOUND) {
101210075SMark.Haywood@Sun.COM 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
101310075SMark.Haywood@Sun.COM 			    int, PDC_OBJ, int, astatus);
101410075SMark.Haywood@Sun.COM 			ret = 1;
101510075SMark.Haywood@Sun.COM 		} else {
101610075SMark.Haywood@Sun.COM 			cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating _PDC "
101710075SMark.Haywood@Sun.COM 			    "package for CPU %d.", astatus, handle->cs_id);
101810075SMark.Haywood@Sun.COM 			ret = -1;
101910075SMark.Haywood@Sun.COM 		}
10208906SEric.Saxe@Sun.COM 	}
10218906SEric.Saxe@Sun.COM 
10228906SEric.Saxe@Sun.COM 	kmem_free(buffer, bufsize);
102310075SMark.Haywood@Sun.COM 	return (ret);
10248906SEric.Saxe@Sun.COM }
10258906SEric.Saxe@Sun.COM 
10268906SEric.Saxe@Sun.COM /*
10278906SEric.Saxe@Sun.COM  * Write to system IO port.
10288906SEric.Saxe@Sun.COM  */
10298906SEric.Saxe@Sun.COM int
10308906SEric.Saxe@Sun.COM cpu_acpi_write_port(ACPI_IO_ADDRESS address, uint32_t value, uint32_t width)
10318906SEric.Saxe@Sun.COM {
10328906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiOsWritePort(address, value, width))) {
103310075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error writing system IO port "
10348906SEric.Saxe@Sun.COM 		    "%lx.", (long)address);
10358906SEric.Saxe@Sun.COM 		return (-1);
10368906SEric.Saxe@Sun.COM 	}
10378906SEric.Saxe@Sun.COM 	return (0);
10388906SEric.Saxe@Sun.COM }
10398906SEric.Saxe@Sun.COM 
10408906SEric.Saxe@Sun.COM /*
10418906SEric.Saxe@Sun.COM  * Read from a system IO port.
10428906SEric.Saxe@Sun.COM  */
10438906SEric.Saxe@Sun.COM int
10448906SEric.Saxe@Sun.COM cpu_acpi_read_port(ACPI_IO_ADDRESS address, uint32_t *value, uint32_t width)
10458906SEric.Saxe@Sun.COM {
10468906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(AcpiOsReadPort(address, value, width))) {
104710075SMark.Haywood@Sun.COM 		cmn_err(CE_NOTE, "!cpu_acpi: error reading system IO port "
10488906SEric.Saxe@Sun.COM 		    "%lx.", (long)address);
10498906SEric.Saxe@Sun.COM 		return (-1);
10508906SEric.Saxe@Sun.COM 	}
10518906SEric.Saxe@Sun.COM 	return (0);
10528906SEric.Saxe@Sun.COM }
10538906SEric.Saxe@Sun.COM 
10548906SEric.Saxe@Sun.COM /*
10558906SEric.Saxe@Sun.COM  * Return supported frequencies.
10568906SEric.Saxe@Sun.COM  */
10578906SEric.Saxe@Sun.COM uint_t
10588906SEric.Saxe@Sun.COM cpu_acpi_get_speeds(cpu_acpi_handle_t handle, int **speeds)
10598906SEric.Saxe@Sun.COM {
10608906SEric.Saxe@Sun.COM 	cpu_acpi_pstate_t *pstate;
10618906SEric.Saxe@Sun.COM 	int *hspeeds;
10628906SEric.Saxe@Sun.COM 	uint_t nspeeds;
10638906SEric.Saxe@Sun.COM 	int i;
10648906SEric.Saxe@Sun.COM 
10658906SEric.Saxe@Sun.COM 	nspeeds = CPU_ACPI_PSTATES_COUNT(handle);
10668906SEric.Saxe@Sun.COM 	pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
10678906SEric.Saxe@Sun.COM 	hspeeds = kmem_zalloc(nspeeds * sizeof (int), KM_SLEEP);
10688906SEric.Saxe@Sun.COM 	for (i = 0; i < nspeeds; i++) {
10698906SEric.Saxe@Sun.COM 		hspeeds[i] = CPU_ACPI_FREQ(pstate);
10708906SEric.Saxe@Sun.COM 		pstate++;
10718906SEric.Saxe@Sun.COM 	}
10728906SEric.Saxe@Sun.COM 	*speeds = hspeeds;
10738906SEric.Saxe@Sun.COM 	return (nspeeds);
10748906SEric.Saxe@Sun.COM }
10758906SEric.Saxe@Sun.COM 
10768906SEric.Saxe@Sun.COM /*
10778906SEric.Saxe@Sun.COM  * Free resources allocated by cpu_acpi_get_speeds().
10788906SEric.Saxe@Sun.COM  */
10798906SEric.Saxe@Sun.COM void
10808906SEric.Saxe@Sun.COM cpu_acpi_free_speeds(int *speeds, uint_t nspeeds)
10818906SEric.Saxe@Sun.COM {
10828906SEric.Saxe@Sun.COM 	kmem_free(speeds, nspeeds * sizeof (int));
10838906SEric.Saxe@Sun.COM }
10848906SEric.Saxe@Sun.COM 
10858906SEric.Saxe@Sun.COM uint_t
10868906SEric.Saxe@Sun.COM cpu_acpi_get_max_cstates(cpu_acpi_handle_t handle)
10878906SEric.Saxe@Sun.COM {
10888906SEric.Saxe@Sun.COM 	if (CPU_ACPI_CSTATES(handle))
10898906SEric.Saxe@Sun.COM 		return (CPU_ACPI_CSTATES_COUNT(handle));
10908906SEric.Saxe@Sun.COM 	else
10918906SEric.Saxe@Sun.COM 		return (1);
10928906SEric.Saxe@Sun.COM }
10938906SEric.Saxe@Sun.COM 
10948906SEric.Saxe@Sun.COM void
10958906SEric.Saxe@Sun.COM cpu_acpi_set_register(uint32_t bitreg, uint32_t value)
10968906SEric.Saxe@Sun.COM {
1097*10488SMark.Haywood@Sun.COM 	(void) AcpiWriteBitRegister(bitreg, value);
10988906SEric.Saxe@Sun.COM }
10998906SEric.Saxe@Sun.COM 
11008906SEric.Saxe@Sun.COM void
11018906SEric.Saxe@Sun.COM cpu_acpi_get_register(uint32_t bitreg, uint32_t *value)
11028906SEric.Saxe@Sun.COM {
1103*10488SMark.Haywood@Sun.COM 	(void) AcpiReadBitRegister(bitreg, value);
11048906SEric.Saxe@Sun.COM }
11058906SEric.Saxe@Sun.COM 
11068906SEric.Saxe@Sun.COM /*
11078906SEric.Saxe@Sun.COM  * Map the dip to an ACPI handle for the device.
11088906SEric.Saxe@Sun.COM  */
11098906SEric.Saxe@Sun.COM cpu_acpi_handle_t
11108906SEric.Saxe@Sun.COM cpu_acpi_init(cpu_t *cp)
11118906SEric.Saxe@Sun.COM {
11128906SEric.Saxe@Sun.COM 	cpu_acpi_handle_t handle;
11138906SEric.Saxe@Sun.COM 
11148906SEric.Saxe@Sun.COM 	handle = kmem_zalloc(sizeof (cpu_acpi_state_t), KM_SLEEP);
11158906SEric.Saxe@Sun.COM 
11168906SEric.Saxe@Sun.COM 	if (ACPI_FAILURE(acpica_get_handle_cpu(cp->cpu_id,
11178906SEric.Saxe@Sun.COM 	    &handle->cs_handle))) {
11188906SEric.Saxe@Sun.COM 		kmem_free(handle, sizeof (cpu_acpi_state_t));
11198906SEric.Saxe@Sun.COM 		return (NULL);
11208906SEric.Saxe@Sun.COM 	}
11218906SEric.Saxe@Sun.COM 	handle->cs_id = cp->cpu_id;
11228906SEric.Saxe@Sun.COM 	return (handle);
11238906SEric.Saxe@Sun.COM }
11248906SEric.Saxe@Sun.COM 
11258906SEric.Saxe@Sun.COM /*
11268906SEric.Saxe@Sun.COM  * Free any resources.
11278906SEric.Saxe@Sun.COM  */
11288906SEric.Saxe@Sun.COM void
11298906SEric.Saxe@Sun.COM cpu_acpi_fini(cpu_acpi_handle_t handle)
11308906SEric.Saxe@Sun.COM {
11318906SEric.Saxe@Sun.COM 	if (handle)
11328906SEric.Saxe@Sun.COM 		kmem_free(handle, sizeof (cpu_acpi_state_t));
11338906SEric.Saxe@Sun.COM }
1134