xref: /illumos-gate/usr/src/uts/i86pc/os/cpupm/cpu_acpi.c (revision 511588bb)
17f606aceSMark Haywood /*
27f606aceSMark Haywood  * CDDL HEADER START
37f606aceSMark Haywood  *
47f606aceSMark Haywood  * The contents of this file are subject to the terms of the
57f606aceSMark Haywood  * Common Development and Distribution License (the "License").
67f606aceSMark Haywood  * You may not use this file except in compliance with the License.
77f606aceSMark Haywood  *
87f606aceSMark Haywood  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97f606aceSMark Haywood  * or http://www.opensolaris.org/os/licensing.
107f606aceSMark Haywood  * See the License for the specific language governing permissions
117f606aceSMark Haywood  * and limitations under the License.
127f606aceSMark Haywood  *
137f606aceSMark Haywood  * When distributing Covered Code, include this CDDL HEADER in each
147f606aceSMark Haywood  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157f606aceSMark Haywood  * If applicable, add the following below this CDDL HEADER, with the
167f606aceSMark Haywood  * fields enclosed by brackets "[]" replaced with your own identifying
177f606aceSMark Haywood  * information: Portions Copyright [yyyy] [name of copyright owner]
187f606aceSMark Haywood  *
197f606aceSMark Haywood  * CDDL HEADER END
207f606aceSMark Haywood  */
217f606aceSMark Haywood /*
22*b3ffafc5Sjiang.liu@intel.com  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
237f606aceSMark Haywood  */
247f606aceSMark Haywood 
257f606aceSMark Haywood #include <sys/cpu_acpi.h>
269aa01d98SBill Holler #include <sys/cpu_idle.h>
2737d22dc0SAnup Pemmaiah #include <sys/dtrace.h>
2837d22dc0SAnup Pemmaiah #include <sys/sdt.h>
297f606aceSMark Haywood 
307f606aceSMark Haywood /*
317f606aceSMark Haywood  * List of the processor ACPI object types that are being used.
327f606aceSMark Haywood  */
337f606aceSMark Haywood typedef enum cpu_acpi_obj {
347f606aceSMark Haywood 	PDC_OBJ = 0,
357f606aceSMark Haywood 	PCT_OBJ,
367f606aceSMark Haywood 	PSS_OBJ,
377f606aceSMark Haywood 	PSD_OBJ,
387f606aceSMark Haywood 	PPC_OBJ,
397f606aceSMark Haywood 	PTC_OBJ,
407f606aceSMark Haywood 	TSS_OBJ,
417f606aceSMark Haywood 	TSD_OBJ,
420e751525SEric Saxe 	TPC_OBJ,
4300f97612SMark Haywood 	CST_OBJ,
440e751525SEric Saxe 	CSD_OBJ,
457f606aceSMark Haywood } cpu_acpi_obj_t;
467f606aceSMark Haywood 
477f606aceSMark Haywood /*
487f606aceSMark Haywood  * Container to store object name.
497f606aceSMark Haywood  * Other attributes can be added in the future as necessary.
507f606aceSMark Haywood  */
517f606aceSMark Haywood typedef struct cpu_acpi_obj_attr {
527f606aceSMark Haywood 	char *name;
537f606aceSMark Haywood } cpu_acpi_obj_attr_t;
547f606aceSMark Haywood 
557f606aceSMark Haywood /*
567f606aceSMark Haywood  * List of object attributes.
577f606aceSMark Haywood  * NOTE: Please keep the ordering of the list as same as cpu_acpi_obj_t.
587f606aceSMark Haywood  */
597f606aceSMark Haywood static cpu_acpi_obj_attr_t cpu_acpi_obj_attrs[] = {
607f606aceSMark Haywood 	{"_PDC"},
617f606aceSMark Haywood 	{"_PCT"},
627f606aceSMark Haywood 	{"_PSS"},
637f606aceSMark Haywood 	{"_PSD"},
647f606aceSMark Haywood 	{"_PPC"},
657f606aceSMark Haywood 	{"_PTC"},
667f606aceSMark Haywood 	{"_TSS"},
677f606aceSMark Haywood 	{"_TSD"},
680e751525SEric Saxe 	{"_TPC"},
6900f97612SMark Haywood 	{"_CST"},
700e751525SEric Saxe 	{"_CSD"}
717f606aceSMark Haywood };
727f606aceSMark Haywood 
737f606aceSMark Haywood /*
747f606aceSMark Haywood  * Cache the ACPI CPU control data objects.
757f606aceSMark Haywood  */
767f606aceSMark Haywood static int
cpu_acpi_cache_ctrl_regs(cpu_acpi_handle_t handle,cpu_acpi_obj_t objtype,cpu_acpi_ctrl_regs_t * regs)777f606aceSMark Haywood cpu_acpi_cache_ctrl_regs(cpu_acpi_handle_t handle, cpu_acpi_obj_t objtype,
787f606aceSMark Haywood     cpu_acpi_ctrl_regs_t *regs)
797f606aceSMark Haywood {
8000f97612SMark Haywood 	ACPI_STATUS astatus;
817f606aceSMark Haywood 	ACPI_BUFFER abuf;
827f606aceSMark Haywood 	ACPI_OBJECT *obj;
837f606aceSMark Haywood 	AML_RESOURCE_GENERIC_REGISTER *greg;
847f606aceSMark Haywood 	int ret = -1;
857f606aceSMark Haywood 	int i;
867f606aceSMark Haywood 
877f606aceSMark Haywood 	/*
887f606aceSMark Haywood 	 * Fetch the control registers (if present) for the CPU node.
897f606aceSMark Haywood 	 * Since they are optional, non-existence is not a failure
907f606aceSMark Haywood 	 * (we just consider it a fixed hardware case).
917f606aceSMark Haywood 	 */
927f606aceSMark Haywood 	abuf.Length = ACPI_ALLOCATE_BUFFER;
937f606aceSMark Haywood 	abuf.Pointer = NULL;
9400f97612SMark Haywood 	astatus = AcpiEvaluateObjectTyped(handle->cs_handle,
9500f97612SMark Haywood 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf, ACPI_TYPE_PACKAGE);
9600f97612SMark Haywood 	if (ACPI_FAILURE(astatus)) {
9700f97612SMark Haywood 		if (astatus == AE_NOT_FOUND) {
9800f97612SMark Haywood 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
9900f97612SMark Haywood 			    int, objtype, int, astatus);
10000f97612SMark Haywood 			regs[0].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
10100f97612SMark Haywood 			regs[1].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
10200f97612SMark Haywood 			return (1);
10300f97612SMark Haywood 		}
10400f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s package "
10500f97612SMark Haywood 		    "for CPU %d.", astatus, cpu_acpi_obj_attrs[objtype].name,
10600f97612SMark Haywood 		    handle->cs_id);
10700f97612SMark Haywood 		goto out;
1087f606aceSMark Haywood 	}
1097f606aceSMark Haywood 
1107f606aceSMark Haywood 	obj = abuf.Pointer;
1117f606aceSMark Haywood 	if (obj->Package.Count != 2) {
11200f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: %s package bad count %d for "
11300f97612SMark Haywood 		    "CPU %d.", cpu_acpi_obj_attrs[objtype].name,
11400f97612SMark Haywood 		    obj->Package.Count, handle->cs_id);
1157f606aceSMark Haywood 		goto out;
1167f606aceSMark Haywood 	}
1177f606aceSMark Haywood 
1187f606aceSMark Haywood 	/*
1197f606aceSMark Haywood 	 * Does the package look coherent?
1207f606aceSMark Haywood 	 */
1217f606aceSMark Haywood 	for (i = 0; i < obj->Package.Count; i++) {
1227f606aceSMark Haywood 		if (obj->Package.Elements[i].Type != ACPI_TYPE_BUFFER) {
12300f97612SMark Haywood 			cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in "
12400f97612SMark Haywood 			    "%s package for CPU %d.",
12500f97612SMark Haywood 			    cpu_acpi_obj_attrs[objtype].name,
12600f97612SMark Haywood 			    handle->cs_id);
1277f606aceSMark Haywood 			goto out;
1287f606aceSMark Haywood 		}
1297f606aceSMark Haywood 
1307f606aceSMark Haywood 		greg = (AML_RESOURCE_GENERIC_REGISTER *)
1317f606aceSMark Haywood 		    obj->Package.Elements[i].Buffer.Pointer;
1327f606aceSMark Haywood 		if (greg->DescriptorType !=
1337f606aceSMark Haywood 		    ACPI_RESOURCE_NAME_GENERIC_REGISTER) {
13400f97612SMark Haywood 			cmn_err(CE_NOTE, "!cpu_acpi: %s package has format "
13500f97612SMark Haywood 			    "error for CPU %d.",
13600f97612SMark Haywood 			    cpu_acpi_obj_attrs[objtype].name,
13700f97612SMark Haywood 			    handle->cs_id);
1387f606aceSMark Haywood 			goto out;
1397f606aceSMark Haywood 		}
1407f606aceSMark Haywood 		if (greg->ResourceLength !=
1417f606aceSMark Haywood 		    ACPI_AML_SIZE_LARGE(AML_RESOURCE_GENERIC_REGISTER)) {
14200f97612SMark Haywood 			cmn_err(CE_NOTE, "!cpu_acpi: %s package not right "
14300f97612SMark Haywood 			    "size for CPU %d.",
14400f97612SMark Haywood 			    cpu_acpi_obj_attrs[objtype].name,
14500f97612SMark Haywood 			    handle->cs_id);
1467f606aceSMark Haywood 			goto out;
1477f606aceSMark Haywood 		}
1487f606aceSMark Haywood 		if (greg->AddressSpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE &&
1497f606aceSMark Haywood 		    greg->AddressSpaceId != ACPI_ADR_SPACE_SYSTEM_IO) {
15000f97612SMark Haywood 			cmn_err(CE_NOTE, "!cpu_apci: %s contains unsupported "
15100f97612SMark Haywood 			    "address space type %x for CPU %d.",
1527f606aceSMark Haywood 			    cpu_acpi_obj_attrs[objtype].name,
15300f97612SMark Haywood 			    greg->AddressSpaceId,
15400f97612SMark Haywood 			    handle->cs_id);
1557f606aceSMark Haywood 			goto out;
1567f606aceSMark Haywood 		}
1577f606aceSMark Haywood 	}
1587f606aceSMark Haywood 
1597f606aceSMark Haywood 	/*
1607f606aceSMark Haywood 	 * Looks good!
1617f606aceSMark Haywood 	 */
1627f606aceSMark Haywood 	for (i = 0; i < obj->Package.Count; i++) {
1637f606aceSMark Haywood 		greg = (AML_RESOURCE_GENERIC_REGISTER *)
1647f606aceSMark Haywood 		    obj->Package.Elements[i].Buffer.Pointer;
1657f606aceSMark Haywood 		regs[i].cr_addrspace_id = greg->AddressSpaceId;
1667f606aceSMark Haywood 		regs[i].cr_width = greg->BitWidth;
1677f606aceSMark Haywood 		regs[i].cr_offset = greg->BitOffset;
1687f606aceSMark Haywood 		regs[i].cr_asize = greg->AccessSize;
1697f606aceSMark Haywood 		regs[i].cr_address = greg->Address;
1707f606aceSMark Haywood 	}
1717f606aceSMark Haywood 	ret = 0;
1727f606aceSMark Haywood out:
17300f97612SMark Haywood 	if (abuf.Pointer != NULL)
17400f97612SMark Haywood 		AcpiOsFree(abuf.Pointer);
1757f606aceSMark Haywood 	return (ret);
1767f606aceSMark Haywood }
1777f606aceSMark Haywood 
1787f606aceSMark Haywood /*
1797f606aceSMark Haywood  * Cache the ACPI _PCT data. The _PCT data defines the interface to use
1807f606aceSMark Haywood  * when making power level transitions (i.e., system IO ports, fixed
1817f606aceSMark Haywood  * hardware port, etc).
1827f606aceSMark Haywood  */
1837f606aceSMark Haywood static int
cpu_acpi_cache_pct(cpu_acpi_handle_t handle)1847f606aceSMark Haywood cpu_acpi_cache_pct(cpu_acpi_handle_t handle)
1857f606aceSMark Haywood {
1867f606aceSMark Haywood 	cpu_acpi_pct_t *pct;
1877f606aceSMark Haywood 	int ret;
1887f606aceSMark Haywood 
1897f606aceSMark Haywood 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PCT_CACHED);
1907f606aceSMark Haywood 	pct = &CPU_ACPI_PCT(handle)[0];
1917f606aceSMark Haywood 	if ((ret = cpu_acpi_cache_ctrl_regs(handle, PCT_OBJ, pct)) == 0)
1927f606aceSMark Haywood 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PCT_CACHED);
1937f606aceSMark Haywood 	return (ret);
1947f606aceSMark Haywood }
1957f606aceSMark Haywood 
1967f606aceSMark Haywood /*
1977f606aceSMark Haywood  * Cache the ACPI _PTC data. The _PTC data defines the interface to use
1987f606aceSMark Haywood  * when making T-state transitions (i.e., system IO ports, fixed
1997f606aceSMark Haywood  * hardware port, etc).
2007f606aceSMark Haywood  */
2017f606aceSMark Haywood static int
cpu_acpi_cache_ptc(cpu_acpi_handle_t handle)2027f606aceSMark Haywood cpu_acpi_cache_ptc(cpu_acpi_handle_t handle)
2037f606aceSMark Haywood {
2047f606aceSMark Haywood 	cpu_acpi_ptc_t *ptc;
2057f606aceSMark Haywood 	int ret;
2067f606aceSMark Haywood 
2077f606aceSMark Haywood 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PTC_CACHED);
2087f606aceSMark Haywood 	ptc = &CPU_ACPI_PTC(handle)[0];
2097f606aceSMark Haywood 	if ((ret = cpu_acpi_cache_ctrl_regs(handle, PTC_OBJ, ptc)) == 0)
2107f606aceSMark Haywood 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PTC_CACHED);
2117f606aceSMark Haywood 	return (ret);
2127f606aceSMark Haywood }
2137f606aceSMark Haywood 
2147f606aceSMark Haywood /*
2157f606aceSMark Haywood  * Cache the ACPI CPU state dependency data objects.
2167f606aceSMark Haywood  */
2177f606aceSMark Haywood static int
cpu_acpi_cache_state_dependencies(cpu_acpi_handle_t handle,cpu_acpi_obj_t objtype,cpu_acpi_state_dependency_t * sd)2187f606aceSMark Haywood cpu_acpi_cache_state_dependencies(cpu_acpi_handle_t handle,
2197f606aceSMark Haywood     cpu_acpi_obj_t objtype, cpu_acpi_state_dependency_t *sd)
2207f606aceSMark Haywood {
22100f97612SMark Haywood 	ACPI_STATUS astatus;
2227f606aceSMark Haywood 	ACPI_BUFFER abuf;
2237f606aceSMark Haywood 	ACPI_OBJECT *pkg, *elements;
2240e751525SEric Saxe 	int number;
2257f606aceSMark Haywood 	int ret = -1;
2267f606aceSMark Haywood 
2270e751525SEric Saxe 	if (objtype == CSD_OBJ) {
2280e751525SEric Saxe 		number = 6;
2290e751525SEric Saxe 	} else {
2300e751525SEric Saxe 		number = 5;
2310e751525SEric Saxe 	}
2327f606aceSMark Haywood 	/*
2337f606aceSMark Haywood 	 * Fetch the dependencies (if present) for the CPU node.
2347f606aceSMark Haywood 	 * Since they are optional, non-existence is not a failure
2357f606aceSMark Haywood 	 * (it's up to the caller to determine how to handle non-existence).
2367f606aceSMark Haywood 	 */
2377f606aceSMark Haywood 	abuf.Length = ACPI_ALLOCATE_BUFFER;
2387f606aceSMark Haywood 	abuf.Pointer = NULL;
23900f97612SMark Haywood 	astatus = AcpiEvaluateObjectTyped(handle->cs_handle,
24000f97612SMark Haywood 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf, ACPI_TYPE_PACKAGE);
24100f97612SMark Haywood 	if (ACPI_FAILURE(astatus)) {
24200f97612SMark Haywood 		if (astatus == AE_NOT_FOUND) {
24300f97612SMark Haywood 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
24400f97612SMark Haywood 			    int, objtype, int, astatus);
24500f97612SMark Haywood 			return (1);
24600f97612SMark Haywood 		}
24700f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s package "
24800f97612SMark Haywood 		    "for CPU %d.", astatus, cpu_acpi_obj_attrs[objtype].name,
24900f97612SMark Haywood 		    handle->cs_id);
25000f97612SMark Haywood 		goto out;
2517f606aceSMark Haywood 	}
2527f606aceSMark Haywood 
2537f606aceSMark Haywood 	pkg = abuf.Pointer;
2540e751525SEric Saxe 
2550e751525SEric Saxe 	if (((objtype != CSD_OBJ) && (pkg->Package.Count != 1)) ||
2560e751525SEric Saxe 	    ((objtype == CSD_OBJ) && (pkg->Package.Count != 1) &&
2570e751525SEric Saxe 	    (pkg->Package.Count != 2))) {
25800f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: %s unsupported package count %d "
25900f97612SMark Haywood 		    "for CPU %d.", cpu_acpi_obj_attrs[objtype].name,
26000f97612SMark Haywood 		    pkg->Package.Count, handle->cs_id);
2617f606aceSMark Haywood 		goto out;
2627f606aceSMark Haywood 	}
2637f606aceSMark Haywood 
2640e751525SEric Saxe 	/*
2650e751525SEric Saxe 	 * For C-state domain, we assume C2 and C3 have the same
2660e751525SEric Saxe 	 * domain information
2670e751525SEric Saxe 	 */
2687f606aceSMark Haywood 	if (pkg->Package.Elements[0].Type != ACPI_TYPE_PACKAGE ||
2690e751525SEric Saxe 	    pkg->Package.Elements[0].Package.Count != number) {
27000f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in %s package "
27100f97612SMark Haywood 		    "for CPU %d.", cpu_acpi_obj_attrs[objtype].name,
27200f97612SMark Haywood 		    handle->cs_id);
2737f606aceSMark Haywood 		goto out;
2747f606aceSMark Haywood 	}
2757f606aceSMark Haywood 	elements = pkg->Package.Elements[0].Package.Elements;
2760e751525SEric Saxe 	if (elements[0].Integer.Value != number ||
2770e751525SEric Saxe 	    elements[1].Integer.Value != 0) {
27800f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: Unexpected %s revision for "
27900f97612SMark Haywood 		    "CPU %d.", cpu_acpi_obj_attrs[objtype].name,
28000f97612SMark Haywood 		    handle->cs_id);
2817f606aceSMark Haywood 		goto out;
2827f606aceSMark Haywood 	}
2837f606aceSMark Haywood 
2847f606aceSMark Haywood 	sd->sd_entries = elements[0].Integer.Value;
2857f606aceSMark Haywood 	sd->sd_revision = elements[1].Integer.Value;
2867f606aceSMark Haywood 	sd->sd_domain = elements[2].Integer.Value;
2877f606aceSMark Haywood 	sd->sd_type = elements[3].Integer.Value;
2887f606aceSMark Haywood 	sd->sd_num = elements[4].Integer.Value;
2890e751525SEric Saxe 	if (objtype == CSD_OBJ) {
2900e751525SEric Saxe 		sd->sd_index = elements[5].Integer.Value;
2910e751525SEric Saxe 	}
2927f606aceSMark Haywood 
2937f606aceSMark Haywood 	ret = 0;
2947f606aceSMark Haywood out:
29500f97612SMark Haywood 	if (abuf.Pointer != NULL)
29600f97612SMark Haywood 		AcpiOsFree(abuf.Pointer);
2977f606aceSMark Haywood 	return (ret);
2987f606aceSMark Haywood }
2997f606aceSMark Haywood 
3007f606aceSMark Haywood /*
3017f606aceSMark Haywood  * Cache the ACPI _PSD data. The _PSD data defines P-state CPU dependencies
3027f606aceSMark Haywood  * (think CPU domains).
3037f606aceSMark Haywood  */
3047f606aceSMark Haywood static int
cpu_acpi_cache_psd(cpu_acpi_handle_t handle)3057f606aceSMark Haywood cpu_acpi_cache_psd(cpu_acpi_handle_t handle)
3067f606aceSMark Haywood {
3077f606aceSMark Haywood 	cpu_acpi_psd_t *psd;
3087f606aceSMark Haywood 	int ret;
3097f606aceSMark Haywood 
3107f606aceSMark Haywood 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSD_CACHED);
3117f606aceSMark Haywood 	psd = &CPU_ACPI_PSD(handle);
3127f606aceSMark Haywood 	ret = cpu_acpi_cache_state_dependencies(handle, PSD_OBJ, psd);
3137f606aceSMark Haywood 	if (ret == 0)
3147f606aceSMark Haywood 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSD_CACHED);
3157f606aceSMark Haywood 	return (ret);
3167f606aceSMark Haywood 
3177f606aceSMark Haywood }
3187f606aceSMark Haywood 
3197f606aceSMark Haywood /*
3207f606aceSMark Haywood  * Cache the ACPI _TSD data. The _TSD data defines T-state CPU dependencies
3217f606aceSMark Haywood  * (think CPU domains).
3227f606aceSMark Haywood  */
3237f606aceSMark Haywood static int
cpu_acpi_cache_tsd(cpu_acpi_handle_t handle)3247f606aceSMark Haywood cpu_acpi_cache_tsd(cpu_acpi_handle_t handle)
3257f606aceSMark Haywood {
3267f606aceSMark Haywood 	cpu_acpi_tsd_t *tsd;
3277f606aceSMark Haywood 	int ret;
3287f606aceSMark Haywood 
3297f606aceSMark Haywood 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSD_CACHED);
3307f606aceSMark Haywood 	tsd = &CPU_ACPI_TSD(handle);
3317f606aceSMark Haywood 	ret = cpu_acpi_cache_state_dependencies(handle, TSD_OBJ, tsd);
3327f606aceSMark Haywood 	if (ret == 0)
3337f606aceSMark Haywood 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSD_CACHED);
3347f606aceSMark Haywood 	return (ret);
3357f606aceSMark Haywood 
3367f606aceSMark Haywood }
3377f606aceSMark Haywood 
3380e751525SEric Saxe /*
3390e751525SEric Saxe  * Cache the ACPI _CSD data. The _CSD data defines C-state CPU dependencies
3400e751525SEric Saxe  * (think CPU domains).
3410e751525SEric Saxe  */
3420e751525SEric Saxe static int
cpu_acpi_cache_csd(cpu_acpi_handle_t handle)3430e751525SEric Saxe cpu_acpi_cache_csd(cpu_acpi_handle_t handle)
3440e751525SEric Saxe {
3450e751525SEric Saxe 	cpu_acpi_csd_t *csd;
3460e751525SEric Saxe 	int ret;
3470e751525SEric Saxe 
3480e751525SEric Saxe 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CSD_CACHED);
3490e751525SEric Saxe 	csd = &CPU_ACPI_CSD(handle);
3500e751525SEric Saxe 	ret = cpu_acpi_cache_state_dependencies(handle, CSD_OBJ, csd);
3510e751525SEric Saxe 	if (ret == 0)
3520e751525SEric Saxe 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CSD_CACHED);
3530e751525SEric Saxe 	return (ret);
3540e751525SEric Saxe 
3550e751525SEric Saxe }
3560e751525SEric Saxe 
3577f606aceSMark Haywood static void
cpu_acpi_cache_pstate(cpu_acpi_handle_t handle,ACPI_OBJECT * obj,int cnt)3587f606aceSMark Haywood cpu_acpi_cache_pstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
3597f606aceSMark Haywood {
3607f606aceSMark Haywood 	cpu_acpi_pstate_t *pstate;
3617f606aceSMark Haywood 	ACPI_OBJECT *q, *l;
3627f606aceSMark Haywood 	int i, j;
3637f606aceSMark Haywood 
3647f606aceSMark Haywood 	CPU_ACPI_PSTATES_COUNT(handle) = cnt;
3657f606aceSMark Haywood 	CPU_ACPI_PSTATES(handle) = kmem_zalloc(CPU_ACPI_PSTATES_SIZE(cnt),
3667f606aceSMark Haywood 	    KM_SLEEP);
3677f606aceSMark Haywood 	pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
3687f606aceSMark Haywood 	for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
3697f606aceSMark Haywood 		uint32_t *up;
3707f606aceSMark Haywood 
3717f606aceSMark Haywood 		q = obj->Package.Elements[i].Package.Elements;
3727f606aceSMark Haywood 
3737f606aceSMark Haywood 		/*
3747f606aceSMark Haywood 		 * Skip duplicate entries.
3757f606aceSMark Haywood 		 */
3767f606aceSMark Haywood 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
3777f606aceSMark Haywood 			continue;
3787f606aceSMark Haywood 
3797f606aceSMark Haywood 		up = (uint32_t *)pstate;
3807f606aceSMark Haywood 		for (j = 0; j < CPU_ACPI_PSS_CNT; j++)
3817f606aceSMark Haywood 			up[j] = q[j].Integer.Value;
3827f606aceSMark Haywood 		pstate++;
3837f606aceSMark Haywood 		cnt--;
3847f606aceSMark Haywood 	}
3857f606aceSMark Haywood }
3867f606aceSMark Haywood 
3877f606aceSMark Haywood static void
cpu_acpi_cache_tstate(cpu_acpi_handle_t handle,ACPI_OBJECT * obj,int cnt)3887f606aceSMark Haywood cpu_acpi_cache_tstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
3897f606aceSMark Haywood {
3907f606aceSMark Haywood 	cpu_acpi_tstate_t *tstate;
3917f606aceSMark Haywood 	ACPI_OBJECT *q, *l;
3927f606aceSMark Haywood 	int i, j;
3937f606aceSMark Haywood 
3947f606aceSMark Haywood 	CPU_ACPI_TSTATES_COUNT(handle) = cnt;
3957f606aceSMark Haywood 	CPU_ACPI_TSTATES(handle) = kmem_zalloc(CPU_ACPI_TSTATES_SIZE(cnt),
3967f606aceSMark Haywood 	    KM_SLEEP);
3977f606aceSMark Haywood 	tstate = (cpu_acpi_tstate_t *)CPU_ACPI_TSTATES(handle);
3987f606aceSMark Haywood 	for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
3997f606aceSMark Haywood 		uint32_t *up;
4007f606aceSMark Haywood 
4017f606aceSMark Haywood 		q = obj->Package.Elements[i].Package.Elements;
4027f606aceSMark Haywood 
4037f606aceSMark Haywood 		/*
4047f606aceSMark Haywood 		 * Skip duplicate entries.
4057f606aceSMark Haywood 		 */
4067f606aceSMark Haywood 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
4077f606aceSMark Haywood 			continue;
4087f606aceSMark Haywood 
4097f606aceSMark Haywood 		up = (uint32_t *)tstate;
4107f606aceSMark Haywood 		for (j = 0; j < CPU_ACPI_TSS_CNT; j++)
4117f606aceSMark Haywood 			up[j] = q[j].Integer.Value;
4127f606aceSMark Haywood 		tstate++;
4137f606aceSMark Haywood 		cnt--;
4147f606aceSMark Haywood 	}
4157f606aceSMark Haywood }
4167f606aceSMark Haywood 
4177f606aceSMark Haywood /*
4187f606aceSMark Haywood  * Cache the _PSS or _TSS data.
4197f606aceSMark Haywood  */
4207f606aceSMark Haywood static int
cpu_acpi_cache_supported_states(cpu_acpi_handle_t handle,cpu_acpi_obj_t objtype,int fcnt)4217f606aceSMark Haywood cpu_acpi_cache_supported_states(cpu_acpi_handle_t handle,
4227f606aceSMark Haywood     cpu_acpi_obj_t objtype, int fcnt)
4237f606aceSMark Haywood {
42400f97612SMark Haywood 	ACPI_STATUS astatus;
4257f606aceSMark Haywood 	ACPI_BUFFER abuf;
4267f606aceSMark Haywood 	ACPI_OBJECT *obj, *q, *l;
4277f606aceSMark Haywood 	boolean_t eot = B_FALSE;
4287f606aceSMark Haywood 	int ret = -1;
4297f606aceSMark Haywood 	int cnt;
4307f606aceSMark Haywood 	int i, j;
4317f606aceSMark Haywood 
4327f606aceSMark Haywood 	/*
43300f97612SMark Haywood 	 * Fetch the state data (if present) for the CPU node.
4347f606aceSMark Haywood 	 */
4357f606aceSMark Haywood 	abuf.Length = ACPI_ALLOCATE_BUFFER;
4367f606aceSMark Haywood 	abuf.Pointer = NULL;
43700f97612SMark Haywood 	astatus = AcpiEvaluateObjectTyped(handle->cs_handle,
4387f606aceSMark Haywood 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf,
43900f97612SMark Haywood 	    ACPI_TYPE_PACKAGE);
44000f97612SMark Haywood 	if (ACPI_FAILURE(astatus)) {
44100f97612SMark Haywood 		if (astatus == AE_NOT_FOUND) {
44200f97612SMark Haywood 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
44300f97612SMark Haywood 			    int, objtype, int, astatus);
44400f97612SMark Haywood 			return (1);
44500f97612SMark Haywood 		}
44600f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s package "
44700f97612SMark Haywood 		    "for CPU %d.", astatus, cpu_acpi_obj_attrs[objtype].name,
44800f97612SMark Haywood 		    handle->cs_id);
44900f97612SMark Haywood 		goto out;
4507f606aceSMark Haywood 	}
4517f606aceSMark Haywood 	obj = abuf.Pointer;
4527f606aceSMark Haywood 	if (obj->Package.Count < 2) {
45300f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: %s package bad count %d for "
45400f97612SMark Haywood 		    "CPU %d.", cpu_acpi_obj_attrs[objtype].name,
45500f97612SMark Haywood 		    obj->Package.Count, handle->cs_id);
4567f606aceSMark Haywood 		goto out;
4577f606aceSMark Haywood 	}
4587f606aceSMark Haywood 
4597f606aceSMark Haywood 	/*
4607f606aceSMark Haywood 	 * Does the package look coherent?
4617f606aceSMark Haywood 	 */
4627f606aceSMark Haywood 	cnt = 0;
4637f606aceSMark Haywood 	for (i = 0, l = NULL; i < obj->Package.Count; i++, l = q) {
4647f606aceSMark Haywood 		if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE ||
4657f606aceSMark Haywood 		    obj->Package.Elements[i].Package.Count != fcnt) {
46600f97612SMark Haywood 			cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in "
46700f97612SMark Haywood 			    "%s package for CPU %d.",
46800f97612SMark Haywood 			    cpu_acpi_obj_attrs[objtype].name,
46900f97612SMark Haywood 			    handle->cs_id);
4707f606aceSMark Haywood 			goto out;
4717f606aceSMark Haywood 		}
4727f606aceSMark Haywood 
4737f606aceSMark Haywood 		q = obj->Package.Elements[i].Package.Elements;
4747f606aceSMark Haywood 		for (j = 0; j < fcnt; j++) {
4757f606aceSMark Haywood 			if (q[j].Type != ACPI_TYPE_INTEGER) {
47600f97612SMark Haywood 				cmn_err(CE_NOTE, "!cpu_acpi: %s element "
47700f97612SMark Haywood 				    "invalid (type) for CPU %d.",
47800f97612SMark Haywood 				    cpu_acpi_obj_attrs[objtype].name,
47900f97612SMark Haywood 				    handle->cs_id);
4807f606aceSMark Haywood 				goto out;
4817f606aceSMark Haywood 			}
4827f606aceSMark Haywood 		}
4837f606aceSMark Haywood 
4847f606aceSMark Haywood 		/*
4857f606aceSMark Haywood 		 * Ignore duplicate entries.
4867f606aceSMark Haywood 		 */
4877f606aceSMark Haywood 		if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
4887f606aceSMark Haywood 			continue;
4897f606aceSMark Haywood 
4907f606aceSMark Haywood 		/*
4917f606aceSMark Haywood 		 * Some supported state tables are larger than required
4927f606aceSMark Haywood 		 * and unused elements are filled with patterns
4937f606aceSMark Haywood 		 * of 0xff.  Simply check here for frequency = 0xffff
4947f606aceSMark Haywood 		 * and stop counting if found.
4957f606aceSMark Haywood 		 */
4967f606aceSMark Haywood 		if (q[0].Integer.Value == 0xffff) {
4977f606aceSMark Haywood 			eot = B_TRUE;
4987f606aceSMark Haywood 			continue;
4997f606aceSMark Haywood 		}
5007f606aceSMark Haywood 
5017f606aceSMark Haywood 		/*
5027f606aceSMark Haywood 		 * We should never find a valid entry after we've hit
5037f606aceSMark Haywood 		 * an the end-of-table entry.
5047f606aceSMark Haywood 		 */
5057f606aceSMark Haywood 		if (eot) {
50600f97612SMark Haywood 			cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in %s "
50700f97612SMark Haywood 			    "package after eot for CPU %d.",
50800f97612SMark Haywood 			    cpu_acpi_obj_attrs[objtype].name,
50900f97612SMark Haywood 			    handle->cs_id);
5107f606aceSMark Haywood 			goto out;
5117f606aceSMark Haywood 		}
5127f606aceSMark Haywood 
5137f606aceSMark Haywood 		/*
5147f606aceSMark Haywood 		 * states must be defined in order from highest to lowest.
5157f606aceSMark Haywood 		 */
5167f606aceSMark Haywood 		if (l != NULL && l[0].Integer.Value < q[0].Integer.Value) {
51700f97612SMark Haywood 			cmn_err(CE_NOTE, "!cpu_acpi: %s package state "
51800f97612SMark Haywood 			    "definitions out of order for CPU %d.",
51900f97612SMark Haywood 			    cpu_acpi_obj_attrs[objtype].name,
52000f97612SMark Haywood 			    handle->cs_id);
5217f606aceSMark Haywood 			goto out;
5227f606aceSMark Haywood 		}
5237f606aceSMark Haywood 
5247f606aceSMark Haywood 		/*
5257f606aceSMark Haywood 		 * This entry passes.
5267f606aceSMark Haywood 		 */
5277f606aceSMark Haywood 		cnt++;
5287f606aceSMark Haywood 	}
5297f606aceSMark Haywood 	if (cnt == 0)
5307f606aceSMark Haywood 		goto out;
5317f606aceSMark Haywood 
5327f606aceSMark Haywood 	/*
5337f606aceSMark Haywood 	 * Yes, fill in the structure.
5347f606aceSMark Haywood 	 */
5357f606aceSMark Haywood 	ASSERT(objtype == PSS_OBJ || objtype == TSS_OBJ);
5367f606aceSMark Haywood 	(objtype == PSS_OBJ) ? cpu_acpi_cache_pstate(handle, obj, cnt) :
5377f606aceSMark Haywood 	    cpu_acpi_cache_tstate(handle, obj, cnt);
5387f606aceSMark Haywood 
5397f606aceSMark Haywood 	ret = 0;
5407f606aceSMark Haywood out:
54100f97612SMark Haywood 	if (abuf.Pointer != NULL)
54200f97612SMark Haywood 		AcpiOsFree(abuf.Pointer);
5437f606aceSMark Haywood 	return (ret);
5447f606aceSMark Haywood }
5457f606aceSMark Haywood 
5467f606aceSMark Haywood /*
5477f606aceSMark Haywood  * Cache the _PSS data. The _PSS data defines the different power levels
5487f606aceSMark Haywood  * supported by the CPU and the attributes associated with each power level
5497f606aceSMark Haywood  * (i.e., frequency, voltage, etc.). The power levels are number from
5507f606aceSMark Haywood  * highest to lowest. That is, the highest power level is _PSS entry 0
5517f606aceSMark Haywood  * and the lowest power level is the last _PSS entry.
5527f606aceSMark Haywood  */
5537f606aceSMark Haywood static int
cpu_acpi_cache_pstates(cpu_acpi_handle_t handle)5547f606aceSMark Haywood cpu_acpi_cache_pstates(cpu_acpi_handle_t handle)
5557f606aceSMark Haywood {
5567f606aceSMark Haywood 	int ret;
5577f606aceSMark Haywood 
5587f606aceSMark Haywood 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSS_CACHED);
5597f606aceSMark Haywood 	ret = cpu_acpi_cache_supported_states(handle, PSS_OBJ,
5607f606aceSMark Haywood 	    CPU_ACPI_PSS_CNT);
5617f606aceSMark Haywood 	if (ret == 0)
5627f606aceSMark Haywood 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSS_CACHED);
5637f606aceSMark Haywood 	return (ret);
5647f606aceSMark Haywood }
5657f606aceSMark Haywood 
5667f606aceSMark Haywood /*
5677f606aceSMark Haywood  * Cache the _TSS data. The _TSS data defines the different freq throttle
5687f606aceSMark Haywood  * levels supported by the CPU and the attributes associated with each
5697f606aceSMark Haywood  * throttle level (i.e., frequency throttle percentage, voltage, etc.).
5707f606aceSMark Haywood  * The throttle levels are number from highest to lowest.
5717f606aceSMark Haywood  */
5727f606aceSMark Haywood static int
cpu_acpi_cache_tstates(cpu_acpi_handle_t handle)5737f606aceSMark Haywood cpu_acpi_cache_tstates(cpu_acpi_handle_t handle)
5747f606aceSMark Haywood {
5757f606aceSMark Haywood 	int ret;
5767f606aceSMark Haywood 
5777f606aceSMark Haywood 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSS_CACHED);
5787f606aceSMark Haywood 	ret = cpu_acpi_cache_supported_states(handle, TSS_OBJ,
5797f606aceSMark Haywood 	    CPU_ACPI_TSS_CNT);
5807f606aceSMark Haywood 	if (ret == 0)
5817f606aceSMark Haywood 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSS_CACHED);
5827f606aceSMark Haywood 	return (ret);
5837f606aceSMark Haywood }
5847f606aceSMark Haywood 
5857f606aceSMark Haywood /*
5867f606aceSMark Haywood  * Cache the ACPI CPU present capabilities data objects.
5877f606aceSMark Haywood  */
5887f606aceSMark Haywood static int
cpu_acpi_cache_present_capabilities(cpu_acpi_handle_t handle,cpu_acpi_obj_t objtype,cpu_acpi_present_capabilities_t * pc)5897f606aceSMark Haywood cpu_acpi_cache_present_capabilities(cpu_acpi_handle_t handle,
5907f606aceSMark Haywood     cpu_acpi_obj_t objtype, cpu_acpi_present_capabilities_t *pc)
5917f606aceSMark Haywood 
5927f606aceSMark Haywood {
59300f97612SMark Haywood 	ACPI_STATUS astatus;
5947f606aceSMark Haywood 	ACPI_BUFFER abuf;
5957f606aceSMark Haywood 	ACPI_OBJECT *obj;
59600f97612SMark Haywood 	int ret = -1;
5977f606aceSMark Haywood 
5987f606aceSMark Haywood 	/*
5997f606aceSMark Haywood 	 * Fetch the present capabilites object (if present) for the CPU node.
6007f606aceSMark Haywood 	 */
6017f606aceSMark Haywood 	abuf.Length = ACPI_ALLOCATE_BUFFER;
6027f606aceSMark Haywood 	abuf.Pointer = NULL;
60300f97612SMark Haywood 	astatus = AcpiEvaluateObject(handle->cs_handle,
60400f97612SMark Haywood 	    cpu_acpi_obj_attrs[objtype].name, NULL, &abuf);
60500f97612SMark Haywood 	if (ACPI_FAILURE(astatus) && astatus != AE_NOT_FOUND) {
60600f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s "
60700f97612SMark Haywood 		    "package for CPU %d.", astatus,
60800f97612SMark Haywood 		    cpu_acpi_obj_attrs[objtype].name, handle->cs_id);
60900f97612SMark Haywood 		goto out;
61000f97612SMark Haywood 	}
61100f97612SMark Haywood 	if (astatus == AE_NOT_FOUND || abuf.Length == 0) {
6127f606aceSMark Haywood 		*pc = 0;
6137f606aceSMark Haywood 		return (1);
6147f606aceSMark Haywood 	}
6157f606aceSMark Haywood 
6167f606aceSMark Haywood 	obj = (ACPI_OBJECT *)abuf.Pointer;
6177f606aceSMark Haywood 	*pc = obj->Integer.Value;
61800f97612SMark Haywood 
61900f97612SMark Haywood 	ret = 0;
62000f97612SMark Haywood out:
62100f97612SMark Haywood 	if (abuf.Pointer != NULL)
62200f97612SMark Haywood 		AcpiOsFree(abuf.Pointer);
62300f97612SMark Haywood 	return (ret);
6247f606aceSMark Haywood }
6257f606aceSMark Haywood 
6267f606aceSMark Haywood /*
6277f606aceSMark Haywood  * Cache the _PPC data. The _PPC simply contains an integer value which
6287f606aceSMark Haywood  * represents the highest power level that a CPU should transition to.
6297f606aceSMark Haywood  * That is, it's an index into the array of _PSS entries and will be
6307f606aceSMark Haywood  * greater than or equal to zero.
6317f606aceSMark Haywood  */
6327f606aceSMark Haywood void
cpu_acpi_cache_ppc(cpu_acpi_handle_t handle)6337f606aceSMark Haywood cpu_acpi_cache_ppc(cpu_acpi_handle_t handle)
6347f606aceSMark Haywood {
6357f606aceSMark Haywood 	cpu_acpi_ppc_t *ppc;
6367f606aceSMark Haywood 	int ret;
6377f606aceSMark Haywood 
6387f606aceSMark Haywood 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PPC_CACHED);
6397f606aceSMark Haywood 	ppc = &CPU_ACPI_PPC(handle);
6407f606aceSMark Haywood 	ret = cpu_acpi_cache_present_capabilities(handle, PPC_OBJ, ppc);
6417f606aceSMark Haywood 	if (ret == 0)
6427f606aceSMark Haywood 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PPC_CACHED);
6437f606aceSMark Haywood }
6447f606aceSMark Haywood 
6457f606aceSMark Haywood /*
6467f606aceSMark Haywood  * Cache the _TPC data. The _TPC simply contains an integer value which
6477f606aceSMark Haywood  * represents the throttle level that a CPU should transition to.
6487f606aceSMark Haywood  * That is, it's an index into the array of _TSS entries and will be
6497f606aceSMark Haywood  * greater than or equal to zero.
6507f606aceSMark Haywood  */
6517f606aceSMark Haywood void
cpu_acpi_cache_tpc(cpu_acpi_handle_t handle)6527f606aceSMark Haywood cpu_acpi_cache_tpc(cpu_acpi_handle_t handle)
6537f606aceSMark Haywood {
6547f606aceSMark Haywood 	cpu_acpi_tpc_t *tpc;
6557f606aceSMark Haywood 	int ret;
6567f606aceSMark Haywood 
6577f606aceSMark Haywood 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TPC_CACHED);
6587f606aceSMark Haywood 	tpc = &CPU_ACPI_TPC(handle);
6597f606aceSMark Haywood 	ret = cpu_acpi_cache_present_capabilities(handle, TPC_OBJ, tpc);
6607f606aceSMark Haywood 	if (ret == 0)
6617f606aceSMark Haywood 		CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TPC_CACHED);
6627f606aceSMark Haywood }
6637f606aceSMark Haywood 
6640e751525SEric Saxe int
cpu_acpi_verify_cstate(cpu_acpi_cstate_t * cstate)6650e751525SEric Saxe cpu_acpi_verify_cstate(cpu_acpi_cstate_t *cstate)
6660e751525SEric Saxe {
6670e751525SEric Saxe 	uint32_t addrspaceid = cstate->cs_addrspace_id;
6680e751525SEric Saxe 
6690e751525SEric Saxe 	if ((addrspaceid != ACPI_ADR_SPACE_FIXED_HARDWARE) &&
6700e751525SEric Saxe 	    (addrspaceid != ACPI_ADR_SPACE_SYSTEM_IO)) {
67100f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: _CST unsupported address space id"
6720e751525SEric Saxe 		    ":C%d, type: %d\n", cstate->cs_type, addrspaceid);
6730e751525SEric Saxe 		return (1);
6740e751525SEric Saxe 	}
6750e751525SEric Saxe 	return (0);
6760e751525SEric Saxe }
6770e751525SEric Saxe 
6780e751525SEric Saxe int
cpu_acpi_cache_cst(cpu_acpi_handle_t handle)6790e751525SEric Saxe cpu_acpi_cache_cst(cpu_acpi_handle_t handle)
6800e751525SEric Saxe {
68100f97612SMark Haywood 	ACPI_STATUS astatus;
6820e751525SEric Saxe 	ACPI_BUFFER abuf;
6830e751525SEric Saxe 	ACPI_OBJECT *obj;
684*b3ffafc5Sjiang.liu@intel.com 	ACPI_INTEGER cnt, old_cnt;
6850e751525SEric Saxe 	cpu_acpi_cstate_t *cstate, *p;
686621e6c37SBill Holler 	size_t alloc_size;
6870e751525SEric Saxe 	int i, count;
68800f97612SMark Haywood 	int ret = 1;
6890e751525SEric Saxe 
6900e751525SEric Saxe 	CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CST_CACHED);
6910e751525SEric Saxe 
6920e751525SEric Saxe 	abuf.Length = ACPI_ALLOCATE_BUFFER;
6930e751525SEric Saxe 	abuf.Pointer = NULL;
6940e751525SEric Saxe 
69500f97612SMark Haywood 	/*
69600f97612SMark Haywood 	 * Fetch the C-state data (if present) for the CPU node.
69700f97612SMark Haywood 	 */
69800f97612SMark Haywood 	astatus = AcpiEvaluateObjectTyped(handle->cs_handle, "_CST",
69900f97612SMark Haywood 	    NULL, &abuf, ACPI_TYPE_PACKAGE);
70000f97612SMark Haywood 	if (ACPI_FAILURE(astatus)) {
70100f97612SMark Haywood 		if (astatus == AE_NOT_FOUND) {
70200f97612SMark Haywood 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
70300f97612SMark Haywood 			    int, CST_OBJ, int, astatus);
70400f97612SMark Haywood 			return (1);
70500f97612SMark Haywood 		}
70600f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating _CST package "
70700f97612SMark Haywood 		    "for CPU %d.", astatus, handle->cs_id);
70800f97612SMark Haywood 		goto out;
70900f97612SMark Haywood 
7100e751525SEric Saxe 	}
7110e751525SEric Saxe 	obj = (ACPI_OBJECT *)abuf.Pointer;
7120e751525SEric Saxe 	if (obj->Package.Count < 2) {
71300f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: _CST unsupported package "
71400f97612SMark Haywood 		    "count %d for CPU %d.", obj->Package.Count, handle->cs_id);
71500f97612SMark Haywood 		goto out;
7160e751525SEric Saxe 	}
7170e751525SEric Saxe 
7180e751525SEric Saxe 	/*
7190e751525SEric Saxe 	 * Does the package look coherent?
7200e751525SEric Saxe 	 */
7210e751525SEric Saxe 	cnt = obj->Package.Elements[0].Integer.Value;
7220e751525SEric Saxe 	if (cnt < 1 || cnt != obj->Package.Count - 1) {
72300f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid element "
72400f97612SMark Haywood 		    "count %d != Package count %d for CPU %d",
72500f97612SMark Haywood 		    (int)cnt, (int)obj->Package.Count - 1, handle->cs_id);
72600f97612SMark Haywood 		goto out;
7270e751525SEric Saxe 	}
7280e751525SEric Saxe 
729*b3ffafc5Sjiang.liu@intel.com 	/*
730*b3ffafc5Sjiang.liu@intel.com 	 * Reuse the old buffer if the number of C states is the same.
731*b3ffafc5Sjiang.liu@intel.com 	 */
732*b3ffafc5Sjiang.liu@intel.com 	if (CPU_ACPI_CSTATES(handle) &&
733*b3ffafc5Sjiang.liu@intel.com 	    (old_cnt = CPU_ACPI_CSTATES_COUNT(handle)) != cnt) {
734*b3ffafc5Sjiang.liu@intel.com 		kmem_free(CPU_ACPI_CSTATES(handle),
735*b3ffafc5Sjiang.liu@intel.com 		    CPU_ACPI_CSTATES_SIZE(old_cnt));
736*b3ffafc5Sjiang.liu@intel.com 		CPU_ACPI_CSTATES(handle) = NULL;
737*b3ffafc5Sjiang.liu@intel.com 	}
738*b3ffafc5Sjiang.liu@intel.com 
7390e751525SEric Saxe 	CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)cnt;
740621e6c37SBill Holler 	alloc_size = CPU_ACPI_CSTATES_SIZE(cnt);
741a3114836SGerry Liu 	if (CPU_ACPI_CSTATES(handle) == NULL)
742a3114836SGerry Liu 		CPU_ACPI_CSTATES(handle) = kmem_zalloc(alloc_size, KM_SLEEP);
7430e751525SEric Saxe 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
7440e751525SEric Saxe 	p = cstate;
7450e751525SEric Saxe 
7460e751525SEric Saxe 	for (i = 1, count = 1; i <= cnt; i++) {
7470e751525SEric Saxe 		ACPI_OBJECT *pkg;
7480e751525SEric Saxe 		AML_RESOURCE_GENERIC_REGISTER *reg;
7490e751525SEric Saxe 		ACPI_OBJECT *element;
7500e751525SEric Saxe 
7510e751525SEric Saxe 		pkg = &(obj->Package.Elements[i]);
7520e751525SEric Saxe 		reg = (AML_RESOURCE_GENERIC_REGISTER *)
7530e751525SEric Saxe 		    pkg->Package.Elements[0].Buffer.Pointer;
7540e751525SEric Saxe 		cstate->cs_addrspace_id = reg->AddressSpaceId;
7550e751525SEric Saxe 		cstate->cs_address = reg->Address;
7560e751525SEric Saxe 		element = &(pkg->Package.Elements[1]);
7570e751525SEric Saxe 		cstate->cs_type = element->Integer.Value;
7580e751525SEric Saxe 		element = &(pkg->Package.Elements[2]);
7590e751525SEric Saxe 		cstate->cs_latency = element->Integer.Value;
7600e751525SEric Saxe 		element = &(pkg->Package.Elements[3]);
7610e751525SEric Saxe 		cstate->cs_power = element->Integer.Value;
7620e751525SEric Saxe 
7630e751525SEric Saxe 		if (cpu_acpi_verify_cstate(cstate)) {
7640e751525SEric Saxe 			/*
7650e751525SEric Saxe 			 * ignore this entry if it's not valid
7660e751525SEric Saxe 			 */
7670e751525SEric Saxe 			continue;
7680e751525SEric Saxe 		}
7690e751525SEric Saxe 		if (cstate == p) {
7700e751525SEric Saxe 			cstate++;
7710e751525SEric Saxe 		} else if (p->cs_type == cstate->cs_type) {
7720e751525SEric Saxe 			/*
7730e751525SEric Saxe 			 * if there are duplicate entries, we keep the
7740e751525SEric Saxe 			 * last one. This fixes:
7750e751525SEric Saxe 			 * 1) some buggy BIOS have total duplicate entries.
7760e751525SEric Saxe 			 * 2) ACPI Spec allows the same cstate entry with
7770e751525SEric Saxe 			 *    different power and latency, we use the one
7780e751525SEric Saxe 			 *    with more power saving.
7790e751525SEric Saxe 			 */
7800e751525SEric Saxe 			(void) memcpy(p, cstate, sizeof (cpu_acpi_cstate_t));
7810e751525SEric Saxe 		} else {
7820e751525SEric Saxe 			/*
7830e751525SEric Saxe 			 * we got a valid entry, cache it to the
7840e751525SEric Saxe 			 * cstate structure
7850e751525SEric Saxe 			 */
7860e751525SEric Saxe 			p = cstate++;
7870e751525SEric Saxe 			count++;
7880e751525SEric Saxe 		}
7890e751525SEric Saxe 	}
7900e751525SEric Saxe 
7910e751525SEric Saxe 	if (count < 2) {
79200f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid count %d < 2 for "
79300f97612SMark Haywood 		    "CPU %d", count, handle->cs_id);
794621e6c37SBill Holler 		kmem_free(CPU_ACPI_CSTATES(handle), alloc_size);
795621e6c37SBill Holler 		CPU_ACPI_CSTATES(handle) = NULL;
796621e6c37SBill Holler 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)0;
79700f97612SMark Haywood 		goto out;
7980e751525SEric Saxe 	}
7999aa01d98SBill Holler 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
8009aa01d98SBill Holler 	if (cstate[0].cs_type != CPU_ACPI_C1) {
80100f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: _CST first element type not "
80200f97612SMark Haywood 		    "C1: %d for CPU %d", (int)cstate->cs_type, handle->cs_id);
803621e6c37SBill Holler 		kmem_free(CPU_ACPI_CSTATES(handle), alloc_size);
804621e6c37SBill Holler 		CPU_ACPI_CSTATES(handle) = NULL;
805621e6c37SBill Holler 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)0;
80600f97612SMark Haywood 		goto out;
8079aa01d98SBill Holler 	}
8080e751525SEric Saxe 
809621e6c37SBill Holler 	if (count != cnt) {
810621e6c37SBill Holler 		void	*orig = CPU_ACPI_CSTATES(handle);
811621e6c37SBill Holler 
8120e751525SEric Saxe 		CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)count;
813621e6c37SBill Holler 		CPU_ACPI_CSTATES(handle) = kmem_zalloc(
814621e6c37SBill Holler 		    CPU_ACPI_CSTATES_SIZE(count), KM_SLEEP);
815621e6c37SBill Holler 		(void) memcpy(CPU_ACPI_CSTATES(handle), orig,
816621e6c37SBill Holler 		    CPU_ACPI_CSTATES_SIZE(count));
817621e6c37SBill Holler 		kmem_free(orig, alloc_size);
818621e6c37SBill Holler 	}
8190e751525SEric Saxe 
8200e751525SEric Saxe 	CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CST_CACHED);
82100f97612SMark Haywood 
82200f97612SMark Haywood 	ret = 0;
82300f97612SMark Haywood 
82400f97612SMark Haywood out:
82500f97612SMark Haywood 	if (abuf.Pointer != NULL)
82600f97612SMark Haywood 		AcpiOsFree(abuf.Pointer);
82700f97612SMark Haywood 	return (ret);
8280e751525SEric Saxe }
8290e751525SEric Saxe 
8307f606aceSMark Haywood /*
8317f606aceSMark Haywood  * Cache the _PCT, _PSS, _PSD and _PPC data.
8327f606aceSMark Haywood  */
8337f606aceSMark Haywood int
cpu_acpi_cache_pstate_data(cpu_acpi_handle_t handle)8347f606aceSMark Haywood cpu_acpi_cache_pstate_data(cpu_acpi_handle_t handle)
8357f606aceSMark Haywood {
8367f606aceSMark Haywood 	if (cpu_acpi_cache_pct(handle) < 0) {
83700f97612SMark Haywood 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
83800f97612SMark Haywood 		    int, PCT_OBJ);
8397f606aceSMark Haywood 		return (-1);
8407f606aceSMark Haywood 	}
8417f606aceSMark Haywood 
8427f606aceSMark Haywood 	if (cpu_acpi_cache_pstates(handle) != 0) {
84300f97612SMark Haywood 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
84400f97612SMark Haywood 		    int, PSS_OBJ);
8457f606aceSMark Haywood 		return (-1);
8467f606aceSMark Haywood 	}
8477f606aceSMark Haywood 
8487f606aceSMark Haywood 	if (cpu_acpi_cache_psd(handle) < 0) {
84900f97612SMark Haywood 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
85000f97612SMark Haywood 		    int, PSD_OBJ);
8517f606aceSMark Haywood 		return (-1);
8527f606aceSMark Haywood 	}
8537f606aceSMark Haywood 
8547f606aceSMark Haywood 	cpu_acpi_cache_ppc(handle);
8557f606aceSMark Haywood 
8567f606aceSMark Haywood 	return (0);
8577f606aceSMark Haywood }
8587f606aceSMark Haywood 
8597f606aceSMark Haywood void
cpu_acpi_free_pstate_data(cpu_acpi_handle_t handle)8607f606aceSMark Haywood cpu_acpi_free_pstate_data(cpu_acpi_handle_t handle)
8617f606aceSMark Haywood {
8627f606aceSMark Haywood 	if (handle != NULL) {
8637f606aceSMark Haywood 		if (CPU_ACPI_PSTATES(handle)) {
8647f606aceSMark Haywood 			kmem_free(CPU_ACPI_PSTATES(handle),
8657f606aceSMark Haywood 			    CPU_ACPI_PSTATES_SIZE(
8667f606aceSMark Haywood 			    CPU_ACPI_PSTATES_COUNT(handle)));
8677f606aceSMark Haywood 			CPU_ACPI_PSTATES(handle) = NULL;
8687f606aceSMark Haywood 		}
8697f606aceSMark Haywood 	}
8707f606aceSMark Haywood }
8717f606aceSMark Haywood 
8727f606aceSMark Haywood /*
8737f606aceSMark Haywood  * Cache the _PTC, _TSS, _TSD and _TPC data.
8747f606aceSMark Haywood  */
8757f606aceSMark Haywood int
cpu_acpi_cache_tstate_data(cpu_acpi_handle_t handle)8767f606aceSMark Haywood cpu_acpi_cache_tstate_data(cpu_acpi_handle_t handle)
8777f606aceSMark Haywood {
87800f97612SMark Haywood 	int ret;
87937d22dc0SAnup Pemmaiah 
8807f606aceSMark Haywood 	if (cpu_acpi_cache_ptc(handle) < 0) {
88100f97612SMark Haywood 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
88200f97612SMark Haywood 		    int, PTC_OBJ);
8837f606aceSMark Haywood 		return (-1);
8847f606aceSMark Haywood 	}
8857f606aceSMark Haywood 
88600f97612SMark Haywood 	if ((ret = cpu_acpi_cache_tstates(handle)) != 0) {
88700f97612SMark Haywood 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
88800f97612SMark Haywood 		    int, TSS_OBJ);
88900f97612SMark Haywood 		return (ret);
8907f606aceSMark Haywood 	}
8917f606aceSMark Haywood 
8927f606aceSMark Haywood 	if (cpu_acpi_cache_tsd(handle) < 0) {
89300f97612SMark Haywood 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
89400f97612SMark Haywood 		    int, TSD_OBJ);
8957f606aceSMark Haywood 		return (-1);
8967f606aceSMark Haywood 	}
8977f606aceSMark Haywood 
8987f606aceSMark Haywood 	cpu_acpi_cache_tpc(handle);
8997f606aceSMark Haywood 
9007f606aceSMark Haywood 	return (0);
9017f606aceSMark Haywood }
9027f606aceSMark Haywood 
9037f606aceSMark Haywood void
cpu_acpi_free_tstate_data(cpu_acpi_handle_t handle)9047f606aceSMark Haywood cpu_acpi_free_tstate_data(cpu_acpi_handle_t handle)
9057f606aceSMark Haywood {
9067f606aceSMark Haywood 	if (handle != NULL) {
9077f606aceSMark Haywood 		if (CPU_ACPI_TSTATES(handle)) {
9087f606aceSMark Haywood 			kmem_free(CPU_ACPI_TSTATES(handle),
9097f606aceSMark Haywood 			    CPU_ACPI_TSTATES_SIZE(
9107f606aceSMark Haywood 			    CPU_ACPI_TSTATES_COUNT(handle)));
9117f606aceSMark Haywood 			CPU_ACPI_TSTATES(handle) = NULL;
9127f606aceSMark Haywood 		}
9137f606aceSMark Haywood 	}
9147f606aceSMark Haywood }
9157f606aceSMark Haywood 
9160e751525SEric Saxe /*
9170e751525SEric Saxe  * Cache the _CST data.
9180e751525SEric Saxe  */
9190e751525SEric Saxe int
cpu_acpi_cache_cstate_data(cpu_acpi_handle_t handle)9200e751525SEric Saxe cpu_acpi_cache_cstate_data(cpu_acpi_handle_t handle)
9210e751525SEric Saxe {
92200f97612SMark Haywood 	int ret;
92300f97612SMark Haywood 
92400f97612SMark Haywood 	if ((ret = cpu_acpi_cache_cst(handle)) != 0) {
92500f97612SMark Haywood 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
92600f97612SMark Haywood 		    int, CST_OBJ);
92700f97612SMark Haywood 		return (ret);
9280e751525SEric Saxe 	}
9290e751525SEric Saxe 
9300e751525SEric Saxe 	if (cpu_acpi_cache_csd(handle) < 0) {
93100f97612SMark Haywood 		DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
93200f97612SMark Haywood 		    int, CSD_OBJ);
9330e751525SEric Saxe 		return (-1);
9340e751525SEric Saxe 	}
9350e751525SEric Saxe 
9360e751525SEric Saxe 	return (0);
9370e751525SEric Saxe }
9380e751525SEric Saxe 
9390e751525SEric Saxe void
cpu_acpi_free_cstate_data(cpu_acpi_handle_t handle)9400e751525SEric Saxe cpu_acpi_free_cstate_data(cpu_acpi_handle_t handle)
9410e751525SEric Saxe {
9420e751525SEric Saxe 	if (handle != NULL) {
9430e751525SEric Saxe 		if (CPU_ACPI_CSTATES(handle)) {
9440e751525SEric Saxe 			kmem_free(CPU_ACPI_CSTATES(handle),
9450e751525SEric Saxe 			    CPU_ACPI_CSTATES_SIZE(
9460e751525SEric Saxe 			    CPU_ACPI_CSTATES_COUNT(handle)));
9470e751525SEric Saxe 			CPU_ACPI_CSTATES(handle) = NULL;
9480e751525SEric Saxe 		}
9490e751525SEric Saxe 	}
9500e751525SEric Saxe }
9510e751525SEric Saxe 
9527f606aceSMark Haywood /*
9537f606aceSMark Haywood  * Register a handler for processor change notifications.
9547f606aceSMark Haywood  */
9557f606aceSMark Haywood void
cpu_acpi_install_notify_handler(cpu_acpi_handle_t handle,ACPI_NOTIFY_HANDLER handler,void * ctx)9567f606aceSMark Haywood cpu_acpi_install_notify_handler(cpu_acpi_handle_t handle,
9570e751525SEric Saxe     ACPI_NOTIFY_HANDLER handler, void *ctx)
9587f606aceSMark Haywood {
9597f606aceSMark Haywood 	if (ACPI_FAILURE(AcpiInstallNotifyHandler(handle->cs_handle,
9600e751525SEric Saxe 	    ACPI_DEVICE_NOTIFY, handler, ctx)))
9617f606aceSMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: Unable to register "
96200f97612SMark Haywood 		    "notify handler for CPU %d.", handle->cs_id);
9630e751525SEric Saxe }
9640e751525SEric Saxe 
9650e751525SEric Saxe /*
9660e751525SEric Saxe  * Remove a handler for processor change notifications.
9670e751525SEric Saxe  */
9680e751525SEric Saxe void
cpu_acpi_remove_notify_handler(cpu_acpi_handle_t handle,ACPI_NOTIFY_HANDLER handler)9690e751525SEric Saxe cpu_acpi_remove_notify_handler(cpu_acpi_handle_t handle,
9700e751525SEric Saxe     ACPI_NOTIFY_HANDLER handler)
9710e751525SEric Saxe {
9720e751525SEric Saxe 	if (ACPI_FAILURE(AcpiRemoveNotifyHandler(handle->cs_handle,
9730e751525SEric Saxe 	    ACPI_DEVICE_NOTIFY, handler)))
9740e751525SEric Saxe 		cmn_err(CE_NOTE, "!cpu_acpi: Unable to remove "
97500f97612SMark Haywood 		    "notify handler for CPU %d.", handle->cs_id);
9767f606aceSMark Haywood }
9777f606aceSMark Haywood 
9787f606aceSMark Haywood /*
9797f606aceSMark Haywood  * Write _PDC.
9807f606aceSMark Haywood  */
9817f606aceSMark Haywood int
cpu_acpi_write_pdc(cpu_acpi_handle_t handle,uint32_t revision,uint32_t count,uint32_t * capabilities)9827f606aceSMark Haywood cpu_acpi_write_pdc(cpu_acpi_handle_t handle, uint32_t revision, uint32_t count,
9837f606aceSMark Haywood     uint32_t *capabilities)
9847f606aceSMark Haywood {
98500f97612SMark Haywood 	ACPI_STATUS astatus;
9867f606aceSMark Haywood 	ACPI_OBJECT obj;
9877f606aceSMark Haywood 	ACPI_OBJECT_LIST list = { 1, &obj};
9887f606aceSMark Haywood 	uint32_t *buffer;
9897f606aceSMark Haywood 	uint32_t *bufptr;
9907f606aceSMark Haywood 	uint32_t bufsize;
9917f606aceSMark Haywood 	int i;
99200f97612SMark Haywood 	int ret = 0;
9937f606aceSMark Haywood 
9947f606aceSMark Haywood 	bufsize = (count + 2) * sizeof (uint32_t);
9957f606aceSMark Haywood 	buffer = kmem_zalloc(bufsize, KM_SLEEP);
9967f606aceSMark Haywood 	buffer[0] = revision;
9977f606aceSMark Haywood 	buffer[1] = count;
9987f606aceSMark Haywood 	bufptr = &buffer[2];
9997f606aceSMark Haywood 	for (i = 0; i < count; i++)
10007f606aceSMark Haywood 		*bufptr++ = *capabilities++;
10017f606aceSMark Haywood 
10027f606aceSMark Haywood 	obj.Type = ACPI_TYPE_BUFFER;
10037f606aceSMark Haywood 	obj.Buffer.Length = bufsize;
10047f606aceSMark Haywood 	obj.Buffer.Pointer = (void *)buffer;
10057f606aceSMark Haywood 
10067f606aceSMark Haywood 	/*
100700f97612SMark Haywood 	 * Fetch the ??? (if present) for the CPU node.
10087f606aceSMark Haywood 	 */
100900f97612SMark Haywood 	astatus = AcpiEvaluateObject(handle->cs_handle, "_PDC", &list, NULL);
101000f97612SMark Haywood 	if (ACPI_FAILURE(astatus)) {
101100f97612SMark Haywood 		if (astatus == AE_NOT_FOUND) {
101200f97612SMark Haywood 			DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
101300f97612SMark Haywood 			    int, PDC_OBJ, int, astatus);
101400f97612SMark Haywood 			ret = 1;
101500f97612SMark Haywood 		} else {
101600f97612SMark Haywood 			cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating _PDC "
101700f97612SMark Haywood 			    "package for CPU %d.", astatus, handle->cs_id);
101800f97612SMark Haywood 			ret = -1;
101900f97612SMark Haywood 		}
10207f606aceSMark Haywood 	}
10217f606aceSMark Haywood 
10227f606aceSMark Haywood 	kmem_free(buffer, bufsize);
102300f97612SMark Haywood 	return (ret);
10247f606aceSMark Haywood }
10257f606aceSMark Haywood 
10267f606aceSMark Haywood /*
10277f606aceSMark Haywood  * Write to system IO port.
10287f606aceSMark Haywood  */
10297f606aceSMark Haywood int
cpu_acpi_write_port(ACPI_IO_ADDRESS address,uint32_t value,uint32_t width)10307f606aceSMark Haywood cpu_acpi_write_port(ACPI_IO_ADDRESS address, uint32_t value, uint32_t width)
10317f606aceSMark Haywood {
10327f606aceSMark Haywood 	if (ACPI_FAILURE(AcpiOsWritePort(address, value, width))) {
103300f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: error writing system IO port "
10347f606aceSMark Haywood 		    "%lx.", (long)address);
10357f606aceSMark Haywood 		return (-1);
10367f606aceSMark Haywood 	}
10377f606aceSMark Haywood 	return (0);
10387f606aceSMark Haywood }
10397f606aceSMark Haywood 
10407f606aceSMark Haywood /*
10417f606aceSMark Haywood  * Read from a system IO port.
10427f606aceSMark Haywood  */
10437f606aceSMark Haywood int
cpu_acpi_read_port(ACPI_IO_ADDRESS address,uint32_t * value,uint32_t width)10447f606aceSMark Haywood cpu_acpi_read_port(ACPI_IO_ADDRESS address, uint32_t *value, uint32_t width)
10457f606aceSMark Haywood {
10467f606aceSMark Haywood 	if (ACPI_FAILURE(AcpiOsReadPort(address, value, width))) {
104700f97612SMark Haywood 		cmn_err(CE_NOTE, "!cpu_acpi: error reading system IO port "
10487f606aceSMark Haywood 		    "%lx.", (long)address);
10497f606aceSMark Haywood 		return (-1);
10507f606aceSMark Haywood 	}
10517f606aceSMark Haywood 	return (0);
10527f606aceSMark Haywood }
10537f606aceSMark Haywood 
10547f606aceSMark Haywood /*
10557f606aceSMark Haywood  * Return supported frequencies.
10567f606aceSMark Haywood  */
10577f606aceSMark Haywood uint_t
cpu_acpi_get_speeds(cpu_acpi_handle_t handle,int ** speeds)10587f606aceSMark Haywood cpu_acpi_get_speeds(cpu_acpi_handle_t handle, int **speeds)
10597f606aceSMark Haywood {
10607f606aceSMark Haywood 	cpu_acpi_pstate_t *pstate;
10617f606aceSMark Haywood 	int *hspeeds;
10627f606aceSMark Haywood 	uint_t nspeeds;
10637f606aceSMark Haywood 	int i;
10647f606aceSMark Haywood 
10657f606aceSMark Haywood 	nspeeds = CPU_ACPI_PSTATES_COUNT(handle);
10667f606aceSMark Haywood 	pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
10677f606aceSMark Haywood 	hspeeds = kmem_zalloc(nspeeds * sizeof (int), KM_SLEEP);
10687f606aceSMark Haywood 	for (i = 0; i < nspeeds; i++) {
10697f606aceSMark Haywood 		hspeeds[i] = CPU_ACPI_FREQ(pstate);
10707f606aceSMark Haywood 		pstate++;
10717f606aceSMark Haywood 	}
10727f606aceSMark Haywood 	*speeds = hspeeds;
10737f606aceSMark Haywood 	return (nspeeds);
10747f606aceSMark Haywood }
10757f606aceSMark Haywood 
10767f606aceSMark Haywood /*
10777f606aceSMark Haywood  * Free resources allocated by cpu_acpi_get_speeds().
10787f606aceSMark Haywood  */
10797f606aceSMark Haywood void
cpu_acpi_free_speeds(int * speeds,uint_t nspeeds)10807f606aceSMark Haywood cpu_acpi_free_speeds(int *speeds, uint_t nspeeds)
10817f606aceSMark Haywood {
10827f606aceSMark Haywood 	kmem_free(speeds, nspeeds * sizeof (int));
10837f606aceSMark Haywood }
10847f606aceSMark Haywood 
10850e751525SEric Saxe uint_t
cpu_acpi_get_max_cstates(cpu_acpi_handle_t handle)10860e751525SEric Saxe cpu_acpi_get_max_cstates(cpu_acpi_handle_t handle)
10870e751525SEric Saxe {
10880e751525SEric Saxe 	if (CPU_ACPI_CSTATES(handle))
10890e751525SEric Saxe 		return (CPU_ACPI_CSTATES_COUNT(handle));
10900e751525SEric Saxe 	else
10910e751525SEric Saxe 		return (1);
10920e751525SEric Saxe }
10930e751525SEric Saxe 
10940e751525SEric Saxe void
cpu_acpi_set_register(uint32_t bitreg,uint32_t value)10950e751525SEric Saxe cpu_acpi_set_register(uint32_t bitreg, uint32_t value)
10960e751525SEric Saxe {
1097444f66e7SMark Haywood 	(void) AcpiWriteBitRegister(bitreg, value);
10980e751525SEric Saxe }
10990e751525SEric Saxe 
11000e751525SEric Saxe void
cpu_acpi_get_register(uint32_t bitreg,uint32_t * value)11010e751525SEric Saxe cpu_acpi_get_register(uint32_t bitreg, uint32_t *value)
11020e751525SEric Saxe {
1103444f66e7SMark Haywood 	(void) AcpiReadBitRegister(bitreg, value);
11040e751525SEric Saxe }
11050e751525SEric Saxe 
11067f606aceSMark Haywood /*
11077f606aceSMark Haywood  * Map the dip to an ACPI handle for the device.
11087f606aceSMark Haywood  */
11097f606aceSMark Haywood cpu_acpi_handle_t
cpu_acpi_init(cpu_t * cp)11100e751525SEric Saxe cpu_acpi_init(cpu_t *cp)
11117f606aceSMark Haywood {
11127f606aceSMark Haywood 	cpu_acpi_handle_t handle;
11137f606aceSMark Haywood 
11147f606aceSMark Haywood 	handle = kmem_zalloc(sizeof (cpu_acpi_state_t), KM_SLEEP);
11157f606aceSMark Haywood 
11160e751525SEric Saxe 	if (ACPI_FAILURE(acpica_get_handle_cpu(cp->cpu_id,
11170e751525SEric Saxe 	    &handle->cs_handle))) {
11187f606aceSMark Haywood 		kmem_free(handle, sizeof (cpu_acpi_state_t));
11197f606aceSMark Haywood 		return (NULL);
11207f606aceSMark Haywood 	}
11210e751525SEric Saxe 	handle->cs_id = cp->cpu_id;
11227f606aceSMark Haywood 	return (handle);
11237f606aceSMark Haywood }
11247f606aceSMark Haywood 
11257f606aceSMark Haywood /*
11267f606aceSMark Haywood  * Free any resources.
11277f606aceSMark Haywood  */
11287f606aceSMark Haywood void
cpu_acpi_fini(cpu_acpi_handle_t handle)11297f606aceSMark Haywood cpu_acpi_fini(cpu_acpi_handle_t handle)
11307f606aceSMark Haywood {
11317f606aceSMark Haywood 	if (handle)
11327f606aceSMark Haywood 		kmem_free(handle, sizeof (cpu_acpi_state_t));
11337f606aceSMark Haywood }
1134