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 /*
22*12511Sjiang.liu@intel.com * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
238906SEric.Saxe@Sun.COM */
248906SEric.Saxe@Sun.COM
258906SEric.Saxe@Sun.COM #include <sys/cpu_acpi.h>
268983SBill.Holler@Sun.COM #include <sys/cpu_idle.h>
279004SNapanda.Pemmaiah@Sun.COM #include <sys/dtrace.h>
289004SNapanda.Pemmaiah@Sun.COM #include <sys/sdt.h>
298906SEric.Saxe@Sun.COM
308906SEric.Saxe@Sun.COM /*
318906SEric.Saxe@Sun.COM * List of the processor ACPI object types that are being used.
328906SEric.Saxe@Sun.COM */
338906SEric.Saxe@Sun.COM typedef enum cpu_acpi_obj {
348906SEric.Saxe@Sun.COM PDC_OBJ = 0,
358906SEric.Saxe@Sun.COM PCT_OBJ,
368906SEric.Saxe@Sun.COM PSS_OBJ,
378906SEric.Saxe@Sun.COM PSD_OBJ,
388906SEric.Saxe@Sun.COM PPC_OBJ,
398906SEric.Saxe@Sun.COM PTC_OBJ,
408906SEric.Saxe@Sun.COM TSS_OBJ,
418906SEric.Saxe@Sun.COM TSD_OBJ,
428906SEric.Saxe@Sun.COM TPC_OBJ,
4310075SMark.Haywood@Sun.COM CST_OBJ,
448906SEric.Saxe@Sun.COM CSD_OBJ,
458906SEric.Saxe@Sun.COM } cpu_acpi_obj_t;
468906SEric.Saxe@Sun.COM
478906SEric.Saxe@Sun.COM /*
488906SEric.Saxe@Sun.COM * Container to store object name.
498906SEric.Saxe@Sun.COM * Other attributes can be added in the future as necessary.
508906SEric.Saxe@Sun.COM */
518906SEric.Saxe@Sun.COM typedef struct cpu_acpi_obj_attr {
528906SEric.Saxe@Sun.COM char *name;
538906SEric.Saxe@Sun.COM } cpu_acpi_obj_attr_t;
548906SEric.Saxe@Sun.COM
558906SEric.Saxe@Sun.COM /*
568906SEric.Saxe@Sun.COM * List of object attributes.
578906SEric.Saxe@Sun.COM * NOTE: Please keep the ordering of the list as same as cpu_acpi_obj_t.
588906SEric.Saxe@Sun.COM */
598906SEric.Saxe@Sun.COM static cpu_acpi_obj_attr_t cpu_acpi_obj_attrs[] = {
608906SEric.Saxe@Sun.COM {"_PDC"},
618906SEric.Saxe@Sun.COM {"_PCT"},
628906SEric.Saxe@Sun.COM {"_PSS"},
638906SEric.Saxe@Sun.COM {"_PSD"},
648906SEric.Saxe@Sun.COM {"_PPC"},
658906SEric.Saxe@Sun.COM {"_PTC"},
668906SEric.Saxe@Sun.COM {"_TSS"},
678906SEric.Saxe@Sun.COM {"_TSD"},
688906SEric.Saxe@Sun.COM {"_TPC"},
6910075SMark.Haywood@Sun.COM {"_CST"},
708906SEric.Saxe@Sun.COM {"_CSD"}
718906SEric.Saxe@Sun.COM };
728906SEric.Saxe@Sun.COM
738906SEric.Saxe@Sun.COM /*
748906SEric.Saxe@Sun.COM * Cache the ACPI CPU control data objects.
758906SEric.Saxe@Sun.COM */
768906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_ctrl_regs(cpu_acpi_handle_t handle,cpu_acpi_obj_t objtype,cpu_acpi_ctrl_regs_t * regs)778906SEric.Saxe@Sun.COM cpu_acpi_cache_ctrl_regs(cpu_acpi_handle_t handle, cpu_acpi_obj_t objtype,
788906SEric.Saxe@Sun.COM cpu_acpi_ctrl_regs_t *regs)
798906SEric.Saxe@Sun.COM {
8010075SMark.Haywood@Sun.COM ACPI_STATUS astatus;
818906SEric.Saxe@Sun.COM ACPI_BUFFER abuf;
828906SEric.Saxe@Sun.COM ACPI_OBJECT *obj;
838906SEric.Saxe@Sun.COM AML_RESOURCE_GENERIC_REGISTER *greg;
848906SEric.Saxe@Sun.COM int ret = -1;
858906SEric.Saxe@Sun.COM int i;
868906SEric.Saxe@Sun.COM
878906SEric.Saxe@Sun.COM /*
888906SEric.Saxe@Sun.COM * Fetch the control registers (if present) for the CPU node.
898906SEric.Saxe@Sun.COM * Since they are optional, non-existence is not a failure
908906SEric.Saxe@Sun.COM * (we just consider it a fixed hardware case).
918906SEric.Saxe@Sun.COM */
928906SEric.Saxe@Sun.COM abuf.Length = ACPI_ALLOCATE_BUFFER;
938906SEric.Saxe@Sun.COM abuf.Pointer = NULL;
9410075SMark.Haywood@Sun.COM astatus = AcpiEvaluateObjectTyped(handle->cs_handle,
9510075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name, NULL, &abuf, ACPI_TYPE_PACKAGE);
9610075SMark.Haywood@Sun.COM if (ACPI_FAILURE(astatus)) {
9710075SMark.Haywood@Sun.COM if (astatus == AE_NOT_FOUND) {
9810075SMark.Haywood@Sun.COM DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
9910075SMark.Haywood@Sun.COM int, objtype, int, astatus);
10010075SMark.Haywood@Sun.COM regs[0].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
10110075SMark.Haywood@Sun.COM regs[1].cr_addrspace_id = ACPI_ADR_SPACE_FIXED_HARDWARE;
10210075SMark.Haywood@Sun.COM return (1);
10310075SMark.Haywood@Sun.COM }
10410075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s package "
10510075SMark.Haywood@Sun.COM "for CPU %d.", astatus, cpu_acpi_obj_attrs[objtype].name,
10610075SMark.Haywood@Sun.COM handle->cs_id);
10710075SMark.Haywood@Sun.COM goto out;
1088906SEric.Saxe@Sun.COM }
1098906SEric.Saxe@Sun.COM
1108906SEric.Saxe@Sun.COM obj = abuf.Pointer;
1118906SEric.Saxe@Sun.COM if (obj->Package.Count != 2) {
11210075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: %s package bad count %d for "
11310075SMark.Haywood@Sun.COM "CPU %d.", cpu_acpi_obj_attrs[objtype].name,
11410075SMark.Haywood@Sun.COM obj->Package.Count, handle->cs_id);
1158906SEric.Saxe@Sun.COM goto out;
1168906SEric.Saxe@Sun.COM }
1178906SEric.Saxe@Sun.COM
1188906SEric.Saxe@Sun.COM /*
1198906SEric.Saxe@Sun.COM * Does the package look coherent?
1208906SEric.Saxe@Sun.COM */
1218906SEric.Saxe@Sun.COM for (i = 0; i < obj->Package.Count; i++) {
1228906SEric.Saxe@Sun.COM if (obj->Package.Elements[i].Type != ACPI_TYPE_BUFFER) {
12310075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in "
12410075SMark.Haywood@Sun.COM "%s package for CPU %d.",
12510075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name,
12610075SMark.Haywood@Sun.COM handle->cs_id);
1278906SEric.Saxe@Sun.COM goto out;
1288906SEric.Saxe@Sun.COM }
1298906SEric.Saxe@Sun.COM
1308906SEric.Saxe@Sun.COM greg = (AML_RESOURCE_GENERIC_REGISTER *)
1318906SEric.Saxe@Sun.COM obj->Package.Elements[i].Buffer.Pointer;
1328906SEric.Saxe@Sun.COM if (greg->DescriptorType !=
1338906SEric.Saxe@Sun.COM ACPI_RESOURCE_NAME_GENERIC_REGISTER) {
13410075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: %s package has format "
13510075SMark.Haywood@Sun.COM "error for CPU %d.",
13610075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name,
13710075SMark.Haywood@Sun.COM handle->cs_id);
1388906SEric.Saxe@Sun.COM goto out;
1398906SEric.Saxe@Sun.COM }
1408906SEric.Saxe@Sun.COM if (greg->ResourceLength !=
1418906SEric.Saxe@Sun.COM ACPI_AML_SIZE_LARGE(AML_RESOURCE_GENERIC_REGISTER)) {
14210075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: %s package not right "
14310075SMark.Haywood@Sun.COM "size for CPU %d.",
14410075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name,
14510075SMark.Haywood@Sun.COM handle->cs_id);
1468906SEric.Saxe@Sun.COM goto out;
1478906SEric.Saxe@Sun.COM }
1488906SEric.Saxe@Sun.COM if (greg->AddressSpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE &&
1498906SEric.Saxe@Sun.COM greg->AddressSpaceId != ACPI_ADR_SPACE_SYSTEM_IO) {
15010075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_apci: %s contains unsupported "
15110075SMark.Haywood@Sun.COM "address space type %x for CPU %d.",
1528906SEric.Saxe@Sun.COM cpu_acpi_obj_attrs[objtype].name,
15310075SMark.Haywood@Sun.COM greg->AddressSpaceId,
15410075SMark.Haywood@Sun.COM handle->cs_id);
1558906SEric.Saxe@Sun.COM goto out;
1568906SEric.Saxe@Sun.COM }
1578906SEric.Saxe@Sun.COM }
1588906SEric.Saxe@Sun.COM
1598906SEric.Saxe@Sun.COM /*
1608906SEric.Saxe@Sun.COM * Looks good!
1618906SEric.Saxe@Sun.COM */
1628906SEric.Saxe@Sun.COM for (i = 0; i < obj->Package.Count; i++) {
1638906SEric.Saxe@Sun.COM greg = (AML_RESOURCE_GENERIC_REGISTER *)
1648906SEric.Saxe@Sun.COM obj->Package.Elements[i].Buffer.Pointer;
1658906SEric.Saxe@Sun.COM regs[i].cr_addrspace_id = greg->AddressSpaceId;
1668906SEric.Saxe@Sun.COM regs[i].cr_width = greg->BitWidth;
1678906SEric.Saxe@Sun.COM regs[i].cr_offset = greg->BitOffset;
1688906SEric.Saxe@Sun.COM regs[i].cr_asize = greg->AccessSize;
1698906SEric.Saxe@Sun.COM regs[i].cr_address = greg->Address;
1708906SEric.Saxe@Sun.COM }
1718906SEric.Saxe@Sun.COM ret = 0;
1728906SEric.Saxe@Sun.COM out:
17310075SMark.Haywood@Sun.COM if (abuf.Pointer != NULL)
17410075SMark.Haywood@Sun.COM AcpiOsFree(abuf.Pointer);
1758906SEric.Saxe@Sun.COM return (ret);
1768906SEric.Saxe@Sun.COM }
1778906SEric.Saxe@Sun.COM
1788906SEric.Saxe@Sun.COM /*
1798906SEric.Saxe@Sun.COM * Cache the ACPI _PCT data. The _PCT data defines the interface to use
1808906SEric.Saxe@Sun.COM * when making power level transitions (i.e., system IO ports, fixed
1818906SEric.Saxe@Sun.COM * hardware port, etc).
1828906SEric.Saxe@Sun.COM */
1838906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_pct(cpu_acpi_handle_t handle)1848906SEric.Saxe@Sun.COM cpu_acpi_cache_pct(cpu_acpi_handle_t handle)
1858906SEric.Saxe@Sun.COM {
1868906SEric.Saxe@Sun.COM cpu_acpi_pct_t *pct;
1878906SEric.Saxe@Sun.COM int ret;
1888906SEric.Saxe@Sun.COM
1898906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PCT_CACHED);
1908906SEric.Saxe@Sun.COM pct = &CPU_ACPI_PCT(handle)[0];
1918906SEric.Saxe@Sun.COM if ((ret = cpu_acpi_cache_ctrl_regs(handle, PCT_OBJ, pct)) == 0)
1928906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PCT_CACHED);
1938906SEric.Saxe@Sun.COM return (ret);
1948906SEric.Saxe@Sun.COM }
1958906SEric.Saxe@Sun.COM
1968906SEric.Saxe@Sun.COM /*
1978906SEric.Saxe@Sun.COM * Cache the ACPI _PTC data. The _PTC data defines the interface to use
1988906SEric.Saxe@Sun.COM * when making T-state transitions (i.e., system IO ports, fixed
1998906SEric.Saxe@Sun.COM * hardware port, etc).
2008906SEric.Saxe@Sun.COM */
2018906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_ptc(cpu_acpi_handle_t handle)2028906SEric.Saxe@Sun.COM cpu_acpi_cache_ptc(cpu_acpi_handle_t handle)
2038906SEric.Saxe@Sun.COM {
2048906SEric.Saxe@Sun.COM cpu_acpi_ptc_t *ptc;
2058906SEric.Saxe@Sun.COM int ret;
2068906SEric.Saxe@Sun.COM
2078906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PTC_CACHED);
2088906SEric.Saxe@Sun.COM ptc = &CPU_ACPI_PTC(handle)[0];
2098906SEric.Saxe@Sun.COM if ((ret = cpu_acpi_cache_ctrl_regs(handle, PTC_OBJ, ptc)) == 0)
2108906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PTC_CACHED);
2118906SEric.Saxe@Sun.COM return (ret);
2128906SEric.Saxe@Sun.COM }
2138906SEric.Saxe@Sun.COM
2148906SEric.Saxe@Sun.COM /*
2158906SEric.Saxe@Sun.COM * Cache the ACPI CPU state dependency data objects.
2168906SEric.Saxe@Sun.COM */
2178906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_state_dependencies(cpu_acpi_handle_t handle,cpu_acpi_obj_t objtype,cpu_acpi_state_dependency_t * sd)2188906SEric.Saxe@Sun.COM cpu_acpi_cache_state_dependencies(cpu_acpi_handle_t handle,
2198906SEric.Saxe@Sun.COM cpu_acpi_obj_t objtype, cpu_acpi_state_dependency_t *sd)
2208906SEric.Saxe@Sun.COM {
22110075SMark.Haywood@Sun.COM ACPI_STATUS astatus;
2228906SEric.Saxe@Sun.COM ACPI_BUFFER abuf;
2238906SEric.Saxe@Sun.COM ACPI_OBJECT *pkg, *elements;
2248906SEric.Saxe@Sun.COM int number;
2258906SEric.Saxe@Sun.COM int ret = -1;
2268906SEric.Saxe@Sun.COM
2278906SEric.Saxe@Sun.COM if (objtype == CSD_OBJ) {
2288906SEric.Saxe@Sun.COM number = 6;
2298906SEric.Saxe@Sun.COM } else {
2308906SEric.Saxe@Sun.COM number = 5;
2318906SEric.Saxe@Sun.COM }
2328906SEric.Saxe@Sun.COM /*
2338906SEric.Saxe@Sun.COM * Fetch the dependencies (if present) for the CPU node.
2348906SEric.Saxe@Sun.COM * Since they are optional, non-existence is not a failure
2358906SEric.Saxe@Sun.COM * (it's up to the caller to determine how to handle non-existence).
2368906SEric.Saxe@Sun.COM */
2378906SEric.Saxe@Sun.COM abuf.Length = ACPI_ALLOCATE_BUFFER;
2388906SEric.Saxe@Sun.COM abuf.Pointer = NULL;
23910075SMark.Haywood@Sun.COM astatus = AcpiEvaluateObjectTyped(handle->cs_handle,
24010075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name, NULL, &abuf, ACPI_TYPE_PACKAGE);
24110075SMark.Haywood@Sun.COM if (ACPI_FAILURE(astatus)) {
24210075SMark.Haywood@Sun.COM if (astatus == AE_NOT_FOUND) {
24310075SMark.Haywood@Sun.COM DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
24410075SMark.Haywood@Sun.COM int, objtype, int, astatus);
24510075SMark.Haywood@Sun.COM return (1);
24610075SMark.Haywood@Sun.COM }
24710075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s package "
24810075SMark.Haywood@Sun.COM "for CPU %d.", astatus, cpu_acpi_obj_attrs[objtype].name,
24910075SMark.Haywood@Sun.COM handle->cs_id);
25010075SMark.Haywood@Sun.COM goto out;
2518906SEric.Saxe@Sun.COM }
2528906SEric.Saxe@Sun.COM
2538906SEric.Saxe@Sun.COM pkg = abuf.Pointer;
2548906SEric.Saxe@Sun.COM
2558906SEric.Saxe@Sun.COM if (((objtype != CSD_OBJ) && (pkg->Package.Count != 1)) ||
2568906SEric.Saxe@Sun.COM ((objtype == CSD_OBJ) && (pkg->Package.Count != 1) &&
2578906SEric.Saxe@Sun.COM (pkg->Package.Count != 2))) {
25810075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: %s unsupported package count %d "
25910075SMark.Haywood@Sun.COM "for CPU %d.", cpu_acpi_obj_attrs[objtype].name,
26010075SMark.Haywood@Sun.COM pkg->Package.Count, handle->cs_id);
2618906SEric.Saxe@Sun.COM goto out;
2628906SEric.Saxe@Sun.COM }
2638906SEric.Saxe@Sun.COM
2648906SEric.Saxe@Sun.COM /*
2658906SEric.Saxe@Sun.COM * For C-state domain, we assume C2 and C3 have the same
2668906SEric.Saxe@Sun.COM * domain information
2678906SEric.Saxe@Sun.COM */
2688906SEric.Saxe@Sun.COM if (pkg->Package.Elements[0].Type != ACPI_TYPE_PACKAGE ||
2698906SEric.Saxe@Sun.COM pkg->Package.Elements[0].Package.Count != number) {
27010075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in %s package "
27110075SMark.Haywood@Sun.COM "for CPU %d.", cpu_acpi_obj_attrs[objtype].name,
27210075SMark.Haywood@Sun.COM handle->cs_id);
2738906SEric.Saxe@Sun.COM goto out;
2748906SEric.Saxe@Sun.COM }
2758906SEric.Saxe@Sun.COM elements = pkg->Package.Elements[0].Package.Elements;
2768906SEric.Saxe@Sun.COM if (elements[0].Integer.Value != number ||
2778906SEric.Saxe@Sun.COM elements[1].Integer.Value != 0) {
27810075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: Unexpected %s revision for "
27910075SMark.Haywood@Sun.COM "CPU %d.", cpu_acpi_obj_attrs[objtype].name,
28010075SMark.Haywood@Sun.COM handle->cs_id);
2818906SEric.Saxe@Sun.COM goto out;
2828906SEric.Saxe@Sun.COM }
2838906SEric.Saxe@Sun.COM
2848906SEric.Saxe@Sun.COM sd->sd_entries = elements[0].Integer.Value;
2858906SEric.Saxe@Sun.COM sd->sd_revision = elements[1].Integer.Value;
2868906SEric.Saxe@Sun.COM sd->sd_domain = elements[2].Integer.Value;
2878906SEric.Saxe@Sun.COM sd->sd_type = elements[3].Integer.Value;
2888906SEric.Saxe@Sun.COM sd->sd_num = elements[4].Integer.Value;
2898906SEric.Saxe@Sun.COM if (objtype == CSD_OBJ) {
2908906SEric.Saxe@Sun.COM sd->sd_index = elements[5].Integer.Value;
2918906SEric.Saxe@Sun.COM }
2928906SEric.Saxe@Sun.COM
2938906SEric.Saxe@Sun.COM ret = 0;
2948906SEric.Saxe@Sun.COM out:
29510075SMark.Haywood@Sun.COM if (abuf.Pointer != NULL)
29610075SMark.Haywood@Sun.COM AcpiOsFree(abuf.Pointer);
2978906SEric.Saxe@Sun.COM return (ret);
2988906SEric.Saxe@Sun.COM }
2998906SEric.Saxe@Sun.COM
3008906SEric.Saxe@Sun.COM /*
3018906SEric.Saxe@Sun.COM * Cache the ACPI _PSD data. The _PSD data defines P-state CPU dependencies
3028906SEric.Saxe@Sun.COM * (think CPU domains).
3038906SEric.Saxe@Sun.COM */
3048906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_psd(cpu_acpi_handle_t handle)3058906SEric.Saxe@Sun.COM cpu_acpi_cache_psd(cpu_acpi_handle_t handle)
3068906SEric.Saxe@Sun.COM {
3078906SEric.Saxe@Sun.COM cpu_acpi_psd_t *psd;
3088906SEric.Saxe@Sun.COM int ret;
3098906SEric.Saxe@Sun.COM
3108906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSD_CACHED);
3118906SEric.Saxe@Sun.COM psd = &CPU_ACPI_PSD(handle);
3128906SEric.Saxe@Sun.COM ret = cpu_acpi_cache_state_dependencies(handle, PSD_OBJ, psd);
3138906SEric.Saxe@Sun.COM if (ret == 0)
3148906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSD_CACHED);
3158906SEric.Saxe@Sun.COM return (ret);
3168906SEric.Saxe@Sun.COM
3178906SEric.Saxe@Sun.COM }
3188906SEric.Saxe@Sun.COM
3198906SEric.Saxe@Sun.COM /*
3208906SEric.Saxe@Sun.COM * Cache the ACPI _TSD data. The _TSD data defines T-state CPU dependencies
3218906SEric.Saxe@Sun.COM * (think CPU domains).
3228906SEric.Saxe@Sun.COM */
3238906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_tsd(cpu_acpi_handle_t handle)3248906SEric.Saxe@Sun.COM cpu_acpi_cache_tsd(cpu_acpi_handle_t handle)
3258906SEric.Saxe@Sun.COM {
3268906SEric.Saxe@Sun.COM cpu_acpi_tsd_t *tsd;
3278906SEric.Saxe@Sun.COM int ret;
3288906SEric.Saxe@Sun.COM
3298906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSD_CACHED);
3308906SEric.Saxe@Sun.COM tsd = &CPU_ACPI_TSD(handle);
3318906SEric.Saxe@Sun.COM ret = cpu_acpi_cache_state_dependencies(handle, TSD_OBJ, tsd);
3328906SEric.Saxe@Sun.COM if (ret == 0)
3338906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSD_CACHED);
3348906SEric.Saxe@Sun.COM return (ret);
3358906SEric.Saxe@Sun.COM
3368906SEric.Saxe@Sun.COM }
3378906SEric.Saxe@Sun.COM
3388906SEric.Saxe@Sun.COM /*
3398906SEric.Saxe@Sun.COM * Cache the ACPI _CSD data. The _CSD data defines C-state CPU dependencies
3408906SEric.Saxe@Sun.COM * (think CPU domains).
3418906SEric.Saxe@Sun.COM */
3428906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_csd(cpu_acpi_handle_t handle)3438906SEric.Saxe@Sun.COM cpu_acpi_cache_csd(cpu_acpi_handle_t handle)
3448906SEric.Saxe@Sun.COM {
3458906SEric.Saxe@Sun.COM cpu_acpi_csd_t *csd;
3468906SEric.Saxe@Sun.COM int ret;
3478906SEric.Saxe@Sun.COM
3488906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CSD_CACHED);
3498906SEric.Saxe@Sun.COM csd = &CPU_ACPI_CSD(handle);
3508906SEric.Saxe@Sun.COM ret = cpu_acpi_cache_state_dependencies(handle, CSD_OBJ, csd);
3518906SEric.Saxe@Sun.COM if (ret == 0)
3528906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CSD_CACHED);
3538906SEric.Saxe@Sun.COM return (ret);
3548906SEric.Saxe@Sun.COM
3558906SEric.Saxe@Sun.COM }
3568906SEric.Saxe@Sun.COM
3578906SEric.Saxe@Sun.COM static void
cpu_acpi_cache_pstate(cpu_acpi_handle_t handle,ACPI_OBJECT * obj,int cnt)3588906SEric.Saxe@Sun.COM cpu_acpi_cache_pstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
3598906SEric.Saxe@Sun.COM {
3608906SEric.Saxe@Sun.COM cpu_acpi_pstate_t *pstate;
3618906SEric.Saxe@Sun.COM ACPI_OBJECT *q, *l;
3628906SEric.Saxe@Sun.COM int i, j;
3638906SEric.Saxe@Sun.COM
3648906SEric.Saxe@Sun.COM CPU_ACPI_PSTATES_COUNT(handle) = cnt;
3658906SEric.Saxe@Sun.COM CPU_ACPI_PSTATES(handle) = kmem_zalloc(CPU_ACPI_PSTATES_SIZE(cnt),
3668906SEric.Saxe@Sun.COM KM_SLEEP);
3678906SEric.Saxe@Sun.COM pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
3688906SEric.Saxe@Sun.COM for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
3698906SEric.Saxe@Sun.COM uint32_t *up;
3708906SEric.Saxe@Sun.COM
3718906SEric.Saxe@Sun.COM q = obj->Package.Elements[i].Package.Elements;
3728906SEric.Saxe@Sun.COM
3738906SEric.Saxe@Sun.COM /*
3748906SEric.Saxe@Sun.COM * Skip duplicate entries.
3758906SEric.Saxe@Sun.COM */
3768906SEric.Saxe@Sun.COM if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
3778906SEric.Saxe@Sun.COM continue;
3788906SEric.Saxe@Sun.COM
3798906SEric.Saxe@Sun.COM up = (uint32_t *)pstate;
3808906SEric.Saxe@Sun.COM for (j = 0; j < CPU_ACPI_PSS_CNT; j++)
3818906SEric.Saxe@Sun.COM up[j] = q[j].Integer.Value;
3828906SEric.Saxe@Sun.COM pstate++;
3838906SEric.Saxe@Sun.COM cnt--;
3848906SEric.Saxe@Sun.COM }
3858906SEric.Saxe@Sun.COM }
3868906SEric.Saxe@Sun.COM
3878906SEric.Saxe@Sun.COM static void
cpu_acpi_cache_tstate(cpu_acpi_handle_t handle,ACPI_OBJECT * obj,int cnt)3888906SEric.Saxe@Sun.COM cpu_acpi_cache_tstate(cpu_acpi_handle_t handle, ACPI_OBJECT *obj, int cnt)
3898906SEric.Saxe@Sun.COM {
3908906SEric.Saxe@Sun.COM cpu_acpi_tstate_t *tstate;
3918906SEric.Saxe@Sun.COM ACPI_OBJECT *q, *l;
3928906SEric.Saxe@Sun.COM int i, j;
3938906SEric.Saxe@Sun.COM
3948906SEric.Saxe@Sun.COM CPU_ACPI_TSTATES_COUNT(handle) = cnt;
3958906SEric.Saxe@Sun.COM CPU_ACPI_TSTATES(handle) = kmem_zalloc(CPU_ACPI_TSTATES_SIZE(cnt),
3968906SEric.Saxe@Sun.COM KM_SLEEP);
3978906SEric.Saxe@Sun.COM tstate = (cpu_acpi_tstate_t *)CPU_ACPI_TSTATES(handle);
3988906SEric.Saxe@Sun.COM for (i = 0, l = NULL; i < obj->Package.Count && cnt > 0; i++, l = q) {
3998906SEric.Saxe@Sun.COM uint32_t *up;
4008906SEric.Saxe@Sun.COM
4018906SEric.Saxe@Sun.COM q = obj->Package.Elements[i].Package.Elements;
4028906SEric.Saxe@Sun.COM
4038906SEric.Saxe@Sun.COM /*
4048906SEric.Saxe@Sun.COM * Skip duplicate entries.
4058906SEric.Saxe@Sun.COM */
4068906SEric.Saxe@Sun.COM if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
4078906SEric.Saxe@Sun.COM continue;
4088906SEric.Saxe@Sun.COM
4098906SEric.Saxe@Sun.COM up = (uint32_t *)tstate;
4108906SEric.Saxe@Sun.COM for (j = 0; j < CPU_ACPI_TSS_CNT; j++)
4118906SEric.Saxe@Sun.COM up[j] = q[j].Integer.Value;
4128906SEric.Saxe@Sun.COM tstate++;
4138906SEric.Saxe@Sun.COM cnt--;
4148906SEric.Saxe@Sun.COM }
4158906SEric.Saxe@Sun.COM }
4168906SEric.Saxe@Sun.COM
4178906SEric.Saxe@Sun.COM /*
4188906SEric.Saxe@Sun.COM * Cache the _PSS or _TSS data.
4198906SEric.Saxe@Sun.COM */
4208906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_supported_states(cpu_acpi_handle_t handle,cpu_acpi_obj_t objtype,int fcnt)4218906SEric.Saxe@Sun.COM cpu_acpi_cache_supported_states(cpu_acpi_handle_t handle,
4228906SEric.Saxe@Sun.COM cpu_acpi_obj_t objtype, int fcnt)
4238906SEric.Saxe@Sun.COM {
42410075SMark.Haywood@Sun.COM ACPI_STATUS astatus;
4258906SEric.Saxe@Sun.COM ACPI_BUFFER abuf;
4268906SEric.Saxe@Sun.COM ACPI_OBJECT *obj, *q, *l;
4278906SEric.Saxe@Sun.COM boolean_t eot = B_FALSE;
4288906SEric.Saxe@Sun.COM int ret = -1;
4298906SEric.Saxe@Sun.COM int cnt;
4308906SEric.Saxe@Sun.COM int i, j;
4318906SEric.Saxe@Sun.COM
4328906SEric.Saxe@Sun.COM /*
43310075SMark.Haywood@Sun.COM * Fetch the state data (if present) for the CPU node.
4348906SEric.Saxe@Sun.COM */
4358906SEric.Saxe@Sun.COM abuf.Length = ACPI_ALLOCATE_BUFFER;
4368906SEric.Saxe@Sun.COM abuf.Pointer = NULL;
43710075SMark.Haywood@Sun.COM astatus = AcpiEvaluateObjectTyped(handle->cs_handle,
4388906SEric.Saxe@Sun.COM cpu_acpi_obj_attrs[objtype].name, NULL, &abuf,
43910075SMark.Haywood@Sun.COM ACPI_TYPE_PACKAGE);
44010075SMark.Haywood@Sun.COM if (ACPI_FAILURE(astatus)) {
44110075SMark.Haywood@Sun.COM if (astatus == AE_NOT_FOUND) {
44210075SMark.Haywood@Sun.COM DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
44310075SMark.Haywood@Sun.COM int, objtype, int, astatus);
44410075SMark.Haywood@Sun.COM if (objtype == PSS_OBJ)
44510075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: _PSS package "
44610075SMark.Haywood@Sun.COM "evaluation failed for with status %d for "
44710075SMark.Haywood@Sun.COM "CPU %d.", astatus, handle->cs_id);
44810075SMark.Haywood@Sun.COM return (1);
44910075SMark.Haywood@Sun.COM }
45010075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s package "
45110075SMark.Haywood@Sun.COM "for CPU %d.", astatus, cpu_acpi_obj_attrs[objtype].name,
45210075SMark.Haywood@Sun.COM handle->cs_id);
45310075SMark.Haywood@Sun.COM goto out;
4548906SEric.Saxe@Sun.COM }
4558906SEric.Saxe@Sun.COM obj = abuf.Pointer;
4568906SEric.Saxe@Sun.COM if (obj->Package.Count < 2) {
45710075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: %s package bad count %d for "
45810075SMark.Haywood@Sun.COM "CPU %d.", cpu_acpi_obj_attrs[objtype].name,
45910075SMark.Haywood@Sun.COM obj->Package.Count, handle->cs_id);
4608906SEric.Saxe@Sun.COM goto out;
4618906SEric.Saxe@Sun.COM }
4628906SEric.Saxe@Sun.COM
4638906SEric.Saxe@Sun.COM /*
4648906SEric.Saxe@Sun.COM * Does the package look coherent?
4658906SEric.Saxe@Sun.COM */
4668906SEric.Saxe@Sun.COM cnt = 0;
4678906SEric.Saxe@Sun.COM for (i = 0, l = NULL; i < obj->Package.Count; i++, l = q) {
4688906SEric.Saxe@Sun.COM if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE ||
4698906SEric.Saxe@Sun.COM obj->Package.Elements[i].Package.Count != fcnt) {
47010075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in "
47110075SMark.Haywood@Sun.COM "%s package for CPU %d.",
47210075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name,
47310075SMark.Haywood@Sun.COM handle->cs_id);
4748906SEric.Saxe@Sun.COM goto out;
4758906SEric.Saxe@Sun.COM }
4768906SEric.Saxe@Sun.COM
4778906SEric.Saxe@Sun.COM q = obj->Package.Elements[i].Package.Elements;
4788906SEric.Saxe@Sun.COM for (j = 0; j < fcnt; j++) {
4798906SEric.Saxe@Sun.COM if (q[j].Type != ACPI_TYPE_INTEGER) {
48010075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: %s element "
48110075SMark.Haywood@Sun.COM "invalid (type) for CPU %d.",
48210075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name,
48310075SMark.Haywood@Sun.COM handle->cs_id);
4848906SEric.Saxe@Sun.COM goto out;
4858906SEric.Saxe@Sun.COM }
4868906SEric.Saxe@Sun.COM }
4878906SEric.Saxe@Sun.COM
4888906SEric.Saxe@Sun.COM /*
4898906SEric.Saxe@Sun.COM * Ignore duplicate entries.
4908906SEric.Saxe@Sun.COM */
4918906SEric.Saxe@Sun.COM if (l != NULL && l[0].Integer.Value == q[0].Integer.Value)
4928906SEric.Saxe@Sun.COM continue;
4938906SEric.Saxe@Sun.COM
4948906SEric.Saxe@Sun.COM /*
4958906SEric.Saxe@Sun.COM * Some supported state tables are larger than required
4968906SEric.Saxe@Sun.COM * and unused elements are filled with patterns
4978906SEric.Saxe@Sun.COM * of 0xff. Simply check here for frequency = 0xffff
4988906SEric.Saxe@Sun.COM * and stop counting if found.
4998906SEric.Saxe@Sun.COM */
5008906SEric.Saxe@Sun.COM if (q[0].Integer.Value == 0xffff) {
5018906SEric.Saxe@Sun.COM eot = B_TRUE;
5028906SEric.Saxe@Sun.COM continue;
5038906SEric.Saxe@Sun.COM }
5048906SEric.Saxe@Sun.COM
5058906SEric.Saxe@Sun.COM /*
5068906SEric.Saxe@Sun.COM * We should never find a valid entry after we've hit
5078906SEric.Saxe@Sun.COM * an the end-of-table entry.
5088906SEric.Saxe@Sun.COM */
5098906SEric.Saxe@Sun.COM if (eot) {
51010075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: Unexpected data in %s "
51110075SMark.Haywood@Sun.COM "package after eot for CPU %d.",
51210075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name,
51310075SMark.Haywood@Sun.COM handle->cs_id);
5148906SEric.Saxe@Sun.COM goto out;
5158906SEric.Saxe@Sun.COM }
5168906SEric.Saxe@Sun.COM
5178906SEric.Saxe@Sun.COM /*
5188906SEric.Saxe@Sun.COM * states must be defined in order from highest to lowest.
5198906SEric.Saxe@Sun.COM */
5208906SEric.Saxe@Sun.COM if (l != NULL && l[0].Integer.Value < q[0].Integer.Value) {
52110075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: %s package state "
52210075SMark.Haywood@Sun.COM "definitions out of order for CPU %d.",
52310075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name,
52410075SMark.Haywood@Sun.COM handle->cs_id);
5258906SEric.Saxe@Sun.COM goto out;
5268906SEric.Saxe@Sun.COM }
5278906SEric.Saxe@Sun.COM
5288906SEric.Saxe@Sun.COM /*
5298906SEric.Saxe@Sun.COM * This entry passes.
5308906SEric.Saxe@Sun.COM */
5318906SEric.Saxe@Sun.COM cnt++;
5328906SEric.Saxe@Sun.COM }
5338906SEric.Saxe@Sun.COM if (cnt == 0)
5348906SEric.Saxe@Sun.COM goto out;
5358906SEric.Saxe@Sun.COM
5368906SEric.Saxe@Sun.COM /*
5378906SEric.Saxe@Sun.COM * Yes, fill in the structure.
5388906SEric.Saxe@Sun.COM */
5398906SEric.Saxe@Sun.COM ASSERT(objtype == PSS_OBJ || objtype == TSS_OBJ);
5408906SEric.Saxe@Sun.COM (objtype == PSS_OBJ) ? cpu_acpi_cache_pstate(handle, obj, cnt) :
5418906SEric.Saxe@Sun.COM cpu_acpi_cache_tstate(handle, obj, cnt);
5428906SEric.Saxe@Sun.COM
5438906SEric.Saxe@Sun.COM ret = 0;
5448906SEric.Saxe@Sun.COM out:
54510075SMark.Haywood@Sun.COM if (abuf.Pointer != NULL)
54610075SMark.Haywood@Sun.COM AcpiOsFree(abuf.Pointer);
5478906SEric.Saxe@Sun.COM return (ret);
5488906SEric.Saxe@Sun.COM }
5498906SEric.Saxe@Sun.COM
5508906SEric.Saxe@Sun.COM /*
5518906SEric.Saxe@Sun.COM * Cache the _PSS data. The _PSS data defines the different power levels
5528906SEric.Saxe@Sun.COM * supported by the CPU and the attributes associated with each power level
5538906SEric.Saxe@Sun.COM * (i.e., frequency, voltage, etc.). The power levels are number from
5548906SEric.Saxe@Sun.COM * highest to lowest. That is, the highest power level is _PSS entry 0
5558906SEric.Saxe@Sun.COM * and the lowest power level is the last _PSS entry.
5568906SEric.Saxe@Sun.COM */
5578906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_pstates(cpu_acpi_handle_t handle)5588906SEric.Saxe@Sun.COM cpu_acpi_cache_pstates(cpu_acpi_handle_t handle)
5598906SEric.Saxe@Sun.COM {
5608906SEric.Saxe@Sun.COM int ret;
5618906SEric.Saxe@Sun.COM
5628906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PSS_CACHED);
5638906SEric.Saxe@Sun.COM ret = cpu_acpi_cache_supported_states(handle, PSS_OBJ,
5648906SEric.Saxe@Sun.COM CPU_ACPI_PSS_CNT);
5658906SEric.Saxe@Sun.COM if (ret == 0)
5668906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PSS_CACHED);
5678906SEric.Saxe@Sun.COM return (ret);
5688906SEric.Saxe@Sun.COM }
5698906SEric.Saxe@Sun.COM
5708906SEric.Saxe@Sun.COM /*
5718906SEric.Saxe@Sun.COM * Cache the _TSS data. The _TSS data defines the different freq throttle
5728906SEric.Saxe@Sun.COM * levels supported by the CPU and the attributes associated with each
5738906SEric.Saxe@Sun.COM * throttle level (i.e., frequency throttle percentage, voltage, etc.).
5748906SEric.Saxe@Sun.COM * The throttle levels are number from highest to lowest.
5758906SEric.Saxe@Sun.COM */
5768906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_tstates(cpu_acpi_handle_t handle)5778906SEric.Saxe@Sun.COM cpu_acpi_cache_tstates(cpu_acpi_handle_t handle)
5788906SEric.Saxe@Sun.COM {
5798906SEric.Saxe@Sun.COM int ret;
5808906SEric.Saxe@Sun.COM
5818906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TSS_CACHED);
5828906SEric.Saxe@Sun.COM ret = cpu_acpi_cache_supported_states(handle, TSS_OBJ,
5838906SEric.Saxe@Sun.COM CPU_ACPI_TSS_CNT);
5848906SEric.Saxe@Sun.COM if (ret == 0)
5858906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TSS_CACHED);
5868906SEric.Saxe@Sun.COM return (ret);
5878906SEric.Saxe@Sun.COM }
5888906SEric.Saxe@Sun.COM
5898906SEric.Saxe@Sun.COM /*
5908906SEric.Saxe@Sun.COM * Cache the ACPI CPU present capabilities data objects.
5918906SEric.Saxe@Sun.COM */
5928906SEric.Saxe@Sun.COM static int
cpu_acpi_cache_present_capabilities(cpu_acpi_handle_t handle,cpu_acpi_obj_t objtype,cpu_acpi_present_capabilities_t * pc)5938906SEric.Saxe@Sun.COM cpu_acpi_cache_present_capabilities(cpu_acpi_handle_t handle,
5948906SEric.Saxe@Sun.COM cpu_acpi_obj_t objtype, cpu_acpi_present_capabilities_t *pc)
5958906SEric.Saxe@Sun.COM
5968906SEric.Saxe@Sun.COM {
59710075SMark.Haywood@Sun.COM ACPI_STATUS astatus;
5988906SEric.Saxe@Sun.COM ACPI_BUFFER abuf;
5998906SEric.Saxe@Sun.COM ACPI_OBJECT *obj;
60010075SMark.Haywood@Sun.COM int ret = -1;
6018906SEric.Saxe@Sun.COM
6028906SEric.Saxe@Sun.COM /*
6038906SEric.Saxe@Sun.COM * Fetch the present capabilites object (if present) for the CPU node.
6048906SEric.Saxe@Sun.COM */
6058906SEric.Saxe@Sun.COM abuf.Length = ACPI_ALLOCATE_BUFFER;
6068906SEric.Saxe@Sun.COM abuf.Pointer = NULL;
60710075SMark.Haywood@Sun.COM astatus = AcpiEvaluateObject(handle->cs_handle,
60810075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name, NULL, &abuf);
60910075SMark.Haywood@Sun.COM if (ACPI_FAILURE(astatus) && astatus != AE_NOT_FOUND) {
61010075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating %s "
61110075SMark.Haywood@Sun.COM "package for CPU %d.", astatus,
61210075SMark.Haywood@Sun.COM cpu_acpi_obj_attrs[objtype].name, handle->cs_id);
61310075SMark.Haywood@Sun.COM goto out;
61410075SMark.Haywood@Sun.COM }
61510075SMark.Haywood@Sun.COM if (astatus == AE_NOT_FOUND || abuf.Length == 0) {
6168906SEric.Saxe@Sun.COM *pc = 0;
6178906SEric.Saxe@Sun.COM return (1);
6188906SEric.Saxe@Sun.COM }
6198906SEric.Saxe@Sun.COM
6208906SEric.Saxe@Sun.COM obj = (ACPI_OBJECT *)abuf.Pointer;
6218906SEric.Saxe@Sun.COM *pc = obj->Integer.Value;
62210075SMark.Haywood@Sun.COM
62310075SMark.Haywood@Sun.COM ret = 0;
62410075SMark.Haywood@Sun.COM out:
62510075SMark.Haywood@Sun.COM if (abuf.Pointer != NULL)
62610075SMark.Haywood@Sun.COM AcpiOsFree(abuf.Pointer);
62710075SMark.Haywood@Sun.COM return (ret);
6288906SEric.Saxe@Sun.COM }
6298906SEric.Saxe@Sun.COM
6308906SEric.Saxe@Sun.COM /*
6318906SEric.Saxe@Sun.COM * Cache the _PPC data. The _PPC simply contains an integer value which
6328906SEric.Saxe@Sun.COM * represents the highest power level that a CPU should transition to.
6338906SEric.Saxe@Sun.COM * That is, it's an index into the array of _PSS entries and will be
6348906SEric.Saxe@Sun.COM * greater than or equal to zero.
6358906SEric.Saxe@Sun.COM */
6368906SEric.Saxe@Sun.COM void
cpu_acpi_cache_ppc(cpu_acpi_handle_t handle)6378906SEric.Saxe@Sun.COM cpu_acpi_cache_ppc(cpu_acpi_handle_t handle)
6388906SEric.Saxe@Sun.COM {
6398906SEric.Saxe@Sun.COM cpu_acpi_ppc_t *ppc;
6408906SEric.Saxe@Sun.COM int ret;
6418906SEric.Saxe@Sun.COM
6428906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_PPC_CACHED);
6438906SEric.Saxe@Sun.COM ppc = &CPU_ACPI_PPC(handle);
6448906SEric.Saxe@Sun.COM ret = cpu_acpi_cache_present_capabilities(handle, PPC_OBJ, ppc);
6458906SEric.Saxe@Sun.COM if (ret == 0)
6468906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_PPC_CACHED);
6478906SEric.Saxe@Sun.COM }
6488906SEric.Saxe@Sun.COM
6498906SEric.Saxe@Sun.COM /*
6508906SEric.Saxe@Sun.COM * Cache the _TPC data. The _TPC simply contains an integer value which
6518906SEric.Saxe@Sun.COM * represents the throttle level that a CPU should transition to.
6528906SEric.Saxe@Sun.COM * That is, it's an index into the array of _TSS entries and will be
6538906SEric.Saxe@Sun.COM * greater than or equal to zero.
6548906SEric.Saxe@Sun.COM */
6558906SEric.Saxe@Sun.COM void
cpu_acpi_cache_tpc(cpu_acpi_handle_t handle)6568906SEric.Saxe@Sun.COM cpu_acpi_cache_tpc(cpu_acpi_handle_t handle)
6578906SEric.Saxe@Sun.COM {
6588906SEric.Saxe@Sun.COM cpu_acpi_tpc_t *tpc;
6598906SEric.Saxe@Sun.COM int ret;
6608906SEric.Saxe@Sun.COM
6618906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_TPC_CACHED);
6628906SEric.Saxe@Sun.COM tpc = &CPU_ACPI_TPC(handle);
6638906SEric.Saxe@Sun.COM ret = cpu_acpi_cache_present_capabilities(handle, TPC_OBJ, tpc);
6648906SEric.Saxe@Sun.COM if (ret == 0)
6658906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_TPC_CACHED);
6668906SEric.Saxe@Sun.COM }
6678906SEric.Saxe@Sun.COM
6688906SEric.Saxe@Sun.COM int
cpu_acpi_verify_cstate(cpu_acpi_cstate_t * cstate)6698906SEric.Saxe@Sun.COM cpu_acpi_verify_cstate(cpu_acpi_cstate_t *cstate)
6708906SEric.Saxe@Sun.COM {
6718906SEric.Saxe@Sun.COM uint32_t addrspaceid = cstate->cs_addrspace_id;
6728906SEric.Saxe@Sun.COM
6738906SEric.Saxe@Sun.COM if ((addrspaceid != ACPI_ADR_SPACE_FIXED_HARDWARE) &&
6748906SEric.Saxe@Sun.COM (addrspaceid != ACPI_ADR_SPACE_SYSTEM_IO)) {
67510075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: _CST unsupported address space id"
6768906SEric.Saxe@Sun.COM ":C%d, type: %d\n", cstate->cs_type, addrspaceid);
6778906SEric.Saxe@Sun.COM return (1);
6788906SEric.Saxe@Sun.COM }
6798906SEric.Saxe@Sun.COM return (0);
6808906SEric.Saxe@Sun.COM }
6818906SEric.Saxe@Sun.COM
6828906SEric.Saxe@Sun.COM int
cpu_acpi_cache_cst(cpu_acpi_handle_t handle)6838906SEric.Saxe@Sun.COM cpu_acpi_cache_cst(cpu_acpi_handle_t handle)
6848906SEric.Saxe@Sun.COM {
68510075SMark.Haywood@Sun.COM ACPI_STATUS astatus;
6868906SEric.Saxe@Sun.COM ACPI_BUFFER abuf;
6878906SEric.Saxe@Sun.COM ACPI_OBJECT *obj;
688*12511Sjiang.liu@intel.com ACPI_INTEGER cnt, old_cnt;
6898906SEric.Saxe@Sun.COM cpu_acpi_cstate_t *cstate, *p;
6909148SBill.Holler@Sun.COM size_t alloc_size;
6918906SEric.Saxe@Sun.COM int i, count;
69210075SMark.Haywood@Sun.COM int ret = 1;
6938906SEric.Saxe@Sun.COM
6948906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_NOT_CACHED(handle, CPU_ACPI_CST_CACHED);
6958906SEric.Saxe@Sun.COM
6968906SEric.Saxe@Sun.COM abuf.Length = ACPI_ALLOCATE_BUFFER;
6978906SEric.Saxe@Sun.COM abuf.Pointer = NULL;
6988906SEric.Saxe@Sun.COM
69910075SMark.Haywood@Sun.COM /*
70010075SMark.Haywood@Sun.COM * Fetch the C-state data (if present) for the CPU node.
70110075SMark.Haywood@Sun.COM */
70210075SMark.Haywood@Sun.COM astatus = AcpiEvaluateObjectTyped(handle->cs_handle, "_CST",
70310075SMark.Haywood@Sun.COM NULL, &abuf, ACPI_TYPE_PACKAGE);
70410075SMark.Haywood@Sun.COM if (ACPI_FAILURE(astatus)) {
70510075SMark.Haywood@Sun.COM if (astatus == AE_NOT_FOUND) {
70610075SMark.Haywood@Sun.COM DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
70710075SMark.Haywood@Sun.COM int, CST_OBJ, int, astatus);
70810075SMark.Haywood@Sun.COM return (1);
70910075SMark.Haywood@Sun.COM }
71010075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating _CST package "
71110075SMark.Haywood@Sun.COM "for CPU %d.", astatus, handle->cs_id);
71210075SMark.Haywood@Sun.COM goto out;
71310075SMark.Haywood@Sun.COM
7148906SEric.Saxe@Sun.COM }
7158906SEric.Saxe@Sun.COM obj = (ACPI_OBJECT *)abuf.Pointer;
7168906SEric.Saxe@Sun.COM if (obj->Package.Count < 2) {
71710075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: _CST unsupported package "
71810075SMark.Haywood@Sun.COM "count %d for CPU %d.", obj->Package.Count, handle->cs_id);
71910075SMark.Haywood@Sun.COM goto out;
7208906SEric.Saxe@Sun.COM }
7218906SEric.Saxe@Sun.COM
7228906SEric.Saxe@Sun.COM /*
7238906SEric.Saxe@Sun.COM * Does the package look coherent?
7248906SEric.Saxe@Sun.COM */
7258906SEric.Saxe@Sun.COM cnt = obj->Package.Elements[0].Integer.Value;
7268906SEric.Saxe@Sun.COM if (cnt < 1 || cnt != obj->Package.Count - 1) {
72710075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid element "
72810075SMark.Haywood@Sun.COM "count %d != Package count %d for CPU %d",
72910075SMark.Haywood@Sun.COM (int)cnt, (int)obj->Package.Count - 1, handle->cs_id);
73010075SMark.Haywood@Sun.COM goto out;
7318906SEric.Saxe@Sun.COM }
7328906SEric.Saxe@Sun.COM
733*12511Sjiang.liu@intel.com /*
734*12511Sjiang.liu@intel.com * Reuse the old buffer if the number of C states is the same.
735*12511Sjiang.liu@intel.com */
736*12511Sjiang.liu@intel.com if (CPU_ACPI_CSTATES(handle) &&
737*12511Sjiang.liu@intel.com (old_cnt = CPU_ACPI_CSTATES_COUNT(handle)) != cnt) {
738*12511Sjiang.liu@intel.com kmem_free(CPU_ACPI_CSTATES(handle),
739*12511Sjiang.liu@intel.com CPU_ACPI_CSTATES_SIZE(old_cnt));
740*12511Sjiang.liu@intel.com CPU_ACPI_CSTATES(handle) = NULL;
741*12511Sjiang.liu@intel.com }
742*12511Sjiang.liu@intel.com
7438906SEric.Saxe@Sun.COM CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)cnt;
7449148SBill.Holler@Sun.COM alloc_size = CPU_ACPI_CSTATES_SIZE(cnt);
74512004Sjiang.liu@intel.com if (CPU_ACPI_CSTATES(handle) == NULL)
74612004Sjiang.liu@intel.com CPU_ACPI_CSTATES(handle) = kmem_zalloc(alloc_size, KM_SLEEP);
7478906SEric.Saxe@Sun.COM cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
7488906SEric.Saxe@Sun.COM p = cstate;
7498906SEric.Saxe@Sun.COM
7508906SEric.Saxe@Sun.COM for (i = 1, count = 1; i <= cnt; i++) {
7518906SEric.Saxe@Sun.COM ACPI_OBJECT *pkg;
7528906SEric.Saxe@Sun.COM AML_RESOURCE_GENERIC_REGISTER *reg;
7538906SEric.Saxe@Sun.COM ACPI_OBJECT *element;
7548906SEric.Saxe@Sun.COM
7558906SEric.Saxe@Sun.COM pkg = &(obj->Package.Elements[i]);
7568906SEric.Saxe@Sun.COM reg = (AML_RESOURCE_GENERIC_REGISTER *)
7578906SEric.Saxe@Sun.COM pkg->Package.Elements[0].Buffer.Pointer;
7588906SEric.Saxe@Sun.COM cstate->cs_addrspace_id = reg->AddressSpaceId;
7598906SEric.Saxe@Sun.COM cstate->cs_address = reg->Address;
7608906SEric.Saxe@Sun.COM element = &(pkg->Package.Elements[1]);
7618906SEric.Saxe@Sun.COM cstate->cs_type = element->Integer.Value;
7628906SEric.Saxe@Sun.COM element = &(pkg->Package.Elements[2]);
7638906SEric.Saxe@Sun.COM cstate->cs_latency = element->Integer.Value;
7648906SEric.Saxe@Sun.COM element = &(pkg->Package.Elements[3]);
7658906SEric.Saxe@Sun.COM cstate->cs_power = element->Integer.Value;
7668906SEric.Saxe@Sun.COM
7678906SEric.Saxe@Sun.COM if (cpu_acpi_verify_cstate(cstate)) {
7688906SEric.Saxe@Sun.COM /*
7698906SEric.Saxe@Sun.COM * ignore this entry if it's not valid
7708906SEric.Saxe@Sun.COM */
7718906SEric.Saxe@Sun.COM continue;
7728906SEric.Saxe@Sun.COM }
7738906SEric.Saxe@Sun.COM if (cstate == p) {
7748906SEric.Saxe@Sun.COM cstate++;
7758906SEric.Saxe@Sun.COM } else if (p->cs_type == cstate->cs_type) {
7768906SEric.Saxe@Sun.COM /*
7778906SEric.Saxe@Sun.COM * if there are duplicate entries, we keep the
7788906SEric.Saxe@Sun.COM * last one. This fixes:
7798906SEric.Saxe@Sun.COM * 1) some buggy BIOS have total duplicate entries.
7808906SEric.Saxe@Sun.COM * 2) ACPI Spec allows the same cstate entry with
7818906SEric.Saxe@Sun.COM * different power and latency, we use the one
7828906SEric.Saxe@Sun.COM * with more power saving.
7838906SEric.Saxe@Sun.COM */
7848906SEric.Saxe@Sun.COM (void) memcpy(p, cstate, sizeof (cpu_acpi_cstate_t));
7858906SEric.Saxe@Sun.COM } else {
7868906SEric.Saxe@Sun.COM /*
7878906SEric.Saxe@Sun.COM * we got a valid entry, cache it to the
7888906SEric.Saxe@Sun.COM * cstate structure
7898906SEric.Saxe@Sun.COM */
7908906SEric.Saxe@Sun.COM p = cstate++;
7918906SEric.Saxe@Sun.COM count++;
7928906SEric.Saxe@Sun.COM }
7938906SEric.Saxe@Sun.COM }
7948906SEric.Saxe@Sun.COM
7958906SEric.Saxe@Sun.COM if (count < 2) {
79610075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: _CST invalid count %d < 2 for "
79710075SMark.Haywood@Sun.COM "CPU %d", count, handle->cs_id);
7989148SBill.Holler@Sun.COM kmem_free(CPU_ACPI_CSTATES(handle), alloc_size);
7999148SBill.Holler@Sun.COM CPU_ACPI_CSTATES(handle) = NULL;
8009148SBill.Holler@Sun.COM CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)0;
80110075SMark.Haywood@Sun.COM goto out;
8028906SEric.Saxe@Sun.COM }
8038983SBill.Holler@Sun.COM cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
8048983SBill.Holler@Sun.COM if (cstate[0].cs_type != CPU_ACPI_C1) {
80510075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: _CST first element type not "
80610075SMark.Haywood@Sun.COM "C1: %d for CPU %d", (int)cstate->cs_type, handle->cs_id);
8079148SBill.Holler@Sun.COM kmem_free(CPU_ACPI_CSTATES(handle), alloc_size);
8089148SBill.Holler@Sun.COM CPU_ACPI_CSTATES(handle) = NULL;
8099148SBill.Holler@Sun.COM CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)0;
81010075SMark.Haywood@Sun.COM goto out;
8118983SBill.Holler@Sun.COM }
8128906SEric.Saxe@Sun.COM
8139148SBill.Holler@Sun.COM if (count != cnt) {
8149148SBill.Holler@Sun.COM void *orig = CPU_ACPI_CSTATES(handle);
8159148SBill.Holler@Sun.COM
8168906SEric.Saxe@Sun.COM CPU_ACPI_CSTATES_COUNT(handle) = (uint32_t)count;
8179148SBill.Holler@Sun.COM CPU_ACPI_CSTATES(handle) = kmem_zalloc(
8189148SBill.Holler@Sun.COM CPU_ACPI_CSTATES_SIZE(count), KM_SLEEP);
8199148SBill.Holler@Sun.COM (void) memcpy(CPU_ACPI_CSTATES(handle), orig,
8209148SBill.Holler@Sun.COM CPU_ACPI_CSTATES_SIZE(count));
8219148SBill.Holler@Sun.COM kmem_free(orig, alloc_size);
8229148SBill.Holler@Sun.COM }
8238906SEric.Saxe@Sun.COM
8248906SEric.Saxe@Sun.COM CPU_ACPI_OBJ_IS_CACHED(handle, CPU_ACPI_CST_CACHED);
82510075SMark.Haywood@Sun.COM
82610075SMark.Haywood@Sun.COM ret = 0;
82710075SMark.Haywood@Sun.COM
82810075SMark.Haywood@Sun.COM out:
82910075SMark.Haywood@Sun.COM if (abuf.Pointer != NULL)
83010075SMark.Haywood@Sun.COM AcpiOsFree(abuf.Pointer);
83110075SMark.Haywood@Sun.COM return (ret);
8328906SEric.Saxe@Sun.COM }
8338906SEric.Saxe@Sun.COM
8348906SEric.Saxe@Sun.COM /*
8358906SEric.Saxe@Sun.COM * Cache the _PCT, _PSS, _PSD and _PPC data.
8368906SEric.Saxe@Sun.COM */
8378906SEric.Saxe@Sun.COM int
cpu_acpi_cache_pstate_data(cpu_acpi_handle_t handle)8388906SEric.Saxe@Sun.COM cpu_acpi_cache_pstate_data(cpu_acpi_handle_t handle)
8398906SEric.Saxe@Sun.COM {
8408906SEric.Saxe@Sun.COM if (cpu_acpi_cache_pct(handle) < 0) {
84110075SMark.Haywood@Sun.COM DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
84210075SMark.Haywood@Sun.COM int, PCT_OBJ);
84310075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error parsing _PCT for "
8448906SEric.Saxe@Sun.COM "CPU %d", handle->cs_id);
8458906SEric.Saxe@Sun.COM return (-1);
8468906SEric.Saxe@Sun.COM }
8478906SEric.Saxe@Sun.COM
8488906SEric.Saxe@Sun.COM if (cpu_acpi_cache_pstates(handle) != 0) {
84910075SMark.Haywood@Sun.COM DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
85010075SMark.Haywood@Sun.COM int, PSS_OBJ);
85110075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error parsing _PSS for "
8528906SEric.Saxe@Sun.COM "CPU %d", handle->cs_id);
8538906SEric.Saxe@Sun.COM return (-1);
8548906SEric.Saxe@Sun.COM }
8558906SEric.Saxe@Sun.COM
8568906SEric.Saxe@Sun.COM if (cpu_acpi_cache_psd(handle) < 0) {
85710075SMark.Haywood@Sun.COM DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
85810075SMark.Haywood@Sun.COM int, PSD_OBJ);
85910075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error parsing _PSD for "
8608906SEric.Saxe@Sun.COM "CPU %d", handle->cs_id);
8618906SEric.Saxe@Sun.COM return (-1);
8628906SEric.Saxe@Sun.COM }
8638906SEric.Saxe@Sun.COM
8648906SEric.Saxe@Sun.COM cpu_acpi_cache_ppc(handle);
8658906SEric.Saxe@Sun.COM
8668906SEric.Saxe@Sun.COM return (0);
8678906SEric.Saxe@Sun.COM }
8688906SEric.Saxe@Sun.COM
8698906SEric.Saxe@Sun.COM void
cpu_acpi_free_pstate_data(cpu_acpi_handle_t handle)8708906SEric.Saxe@Sun.COM cpu_acpi_free_pstate_data(cpu_acpi_handle_t handle)
8718906SEric.Saxe@Sun.COM {
8728906SEric.Saxe@Sun.COM if (handle != NULL) {
8738906SEric.Saxe@Sun.COM if (CPU_ACPI_PSTATES(handle)) {
8748906SEric.Saxe@Sun.COM kmem_free(CPU_ACPI_PSTATES(handle),
8758906SEric.Saxe@Sun.COM CPU_ACPI_PSTATES_SIZE(
8768906SEric.Saxe@Sun.COM CPU_ACPI_PSTATES_COUNT(handle)));
8778906SEric.Saxe@Sun.COM CPU_ACPI_PSTATES(handle) = NULL;
8788906SEric.Saxe@Sun.COM }
8798906SEric.Saxe@Sun.COM }
8808906SEric.Saxe@Sun.COM }
8818906SEric.Saxe@Sun.COM
8828906SEric.Saxe@Sun.COM /*
8838906SEric.Saxe@Sun.COM * Cache the _PTC, _TSS, _TSD and _TPC data.
8848906SEric.Saxe@Sun.COM */
8858906SEric.Saxe@Sun.COM int
cpu_acpi_cache_tstate_data(cpu_acpi_handle_t handle)8868906SEric.Saxe@Sun.COM cpu_acpi_cache_tstate_data(cpu_acpi_handle_t handle)
8878906SEric.Saxe@Sun.COM {
88810075SMark.Haywood@Sun.COM int ret;
8899004SNapanda.Pemmaiah@Sun.COM
8908906SEric.Saxe@Sun.COM if (cpu_acpi_cache_ptc(handle) < 0) {
89110075SMark.Haywood@Sun.COM DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
89210075SMark.Haywood@Sun.COM int, PTC_OBJ);
8938906SEric.Saxe@Sun.COM return (-1);
8948906SEric.Saxe@Sun.COM }
8958906SEric.Saxe@Sun.COM
89610075SMark.Haywood@Sun.COM if ((ret = cpu_acpi_cache_tstates(handle)) != 0) {
89710075SMark.Haywood@Sun.COM DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
89810075SMark.Haywood@Sun.COM int, TSS_OBJ);
89910075SMark.Haywood@Sun.COM return (ret);
9008906SEric.Saxe@Sun.COM }
9018906SEric.Saxe@Sun.COM
9028906SEric.Saxe@Sun.COM if (cpu_acpi_cache_tsd(handle) < 0) {
90310075SMark.Haywood@Sun.COM DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
90410075SMark.Haywood@Sun.COM int, TSD_OBJ);
9058906SEric.Saxe@Sun.COM return (-1);
9068906SEric.Saxe@Sun.COM }
9078906SEric.Saxe@Sun.COM
9088906SEric.Saxe@Sun.COM cpu_acpi_cache_tpc(handle);
9098906SEric.Saxe@Sun.COM
9108906SEric.Saxe@Sun.COM return (0);
9118906SEric.Saxe@Sun.COM }
9128906SEric.Saxe@Sun.COM
9138906SEric.Saxe@Sun.COM void
cpu_acpi_free_tstate_data(cpu_acpi_handle_t handle)9148906SEric.Saxe@Sun.COM cpu_acpi_free_tstate_data(cpu_acpi_handle_t handle)
9158906SEric.Saxe@Sun.COM {
9168906SEric.Saxe@Sun.COM if (handle != NULL) {
9178906SEric.Saxe@Sun.COM if (CPU_ACPI_TSTATES(handle)) {
9188906SEric.Saxe@Sun.COM kmem_free(CPU_ACPI_TSTATES(handle),
9198906SEric.Saxe@Sun.COM CPU_ACPI_TSTATES_SIZE(
9208906SEric.Saxe@Sun.COM CPU_ACPI_TSTATES_COUNT(handle)));
9218906SEric.Saxe@Sun.COM CPU_ACPI_TSTATES(handle) = NULL;
9228906SEric.Saxe@Sun.COM }
9238906SEric.Saxe@Sun.COM }
9248906SEric.Saxe@Sun.COM }
9258906SEric.Saxe@Sun.COM
9268906SEric.Saxe@Sun.COM /*
9278906SEric.Saxe@Sun.COM * Cache the _CST data.
9288906SEric.Saxe@Sun.COM */
9298906SEric.Saxe@Sun.COM int
cpu_acpi_cache_cstate_data(cpu_acpi_handle_t handle)9308906SEric.Saxe@Sun.COM cpu_acpi_cache_cstate_data(cpu_acpi_handle_t handle)
9318906SEric.Saxe@Sun.COM {
93210075SMark.Haywood@Sun.COM int ret;
93310075SMark.Haywood@Sun.COM
93410075SMark.Haywood@Sun.COM if ((ret = cpu_acpi_cache_cst(handle)) != 0) {
93510075SMark.Haywood@Sun.COM DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
93610075SMark.Haywood@Sun.COM int, CST_OBJ);
93710075SMark.Haywood@Sun.COM return (ret);
9388906SEric.Saxe@Sun.COM }
9398906SEric.Saxe@Sun.COM
9408906SEric.Saxe@Sun.COM if (cpu_acpi_cache_csd(handle) < 0) {
94110075SMark.Haywood@Sun.COM DTRACE_PROBE2(cpu_acpi__cache__err, int, handle->cs_id,
94210075SMark.Haywood@Sun.COM int, CSD_OBJ);
9438906SEric.Saxe@Sun.COM return (-1);
9448906SEric.Saxe@Sun.COM }
9458906SEric.Saxe@Sun.COM
9468906SEric.Saxe@Sun.COM return (0);
9478906SEric.Saxe@Sun.COM }
9488906SEric.Saxe@Sun.COM
9498906SEric.Saxe@Sun.COM void
cpu_acpi_free_cstate_data(cpu_acpi_handle_t handle)9508906SEric.Saxe@Sun.COM cpu_acpi_free_cstate_data(cpu_acpi_handle_t handle)
9518906SEric.Saxe@Sun.COM {
9528906SEric.Saxe@Sun.COM if (handle != NULL) {
9538906SEric.Saxe@Sun.COM if (CPU_ACPI_CSTATES(handle)) {
9548906SEric.Saxe@Sun.COM kmem_free(CPU_ACPI_CSTATES(handle),
9558906SEric.Saxe@Sun.COM CPU_ACPI_CSTATES_SIZE(
9568906SEric.Saxe@Sun.COM CPU_ACPI_CSTATES_COUNT(handle)));
9578906SEric.Saxe@Sun.COM CPU_ACPI_CSTATES(handle) = NULL;
9588906SEric.Saxe@Sun.COM }
9598906SEric.Saxe@Sun.COM }
9608906SEric.Saxe@Sun.COM }
9618906SEric.Saxe@Sun.COM
9628906SEric.Saxe@Sun.COM /*
9638906SEric.Saxe@Sun.COM * Register a handler for processor change notifications.
9648906SEric.Saxe@Sun.COM */
9658906SEric.Saxe@Sun.COM void
cpu_acpi_install_notify_handler(cpu_acpi_handle_t handle,ACPI_NOTIFY_HANDLER handler,void * ctx)9668906SEric.Saxe@Sun.COM cpu_acpi_install_notify_handler(cpu_acpi_handle_t handle,
9678906SEric.Saxe@Sun.COM ACPI_NOTIFY_HANDLER handler, void *ctx)
9688906SEric.Saxe@Sun.COM {
9698906SEric.Saxe@Sun.COM if (ACPI_FAILURE(AcpiInstallNotifyHandler(handle->cs_handle,
9708906SEric.Saxe@Sun.COM ACPI_DEVICE_NOTIFY, handler, ctx)))
9718906SEric.Saxe@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: Unable to register "
97210075SMark.Haywood@Sun.COM "notify handler for CPU %d.", handle->cs_id);
9738906SEric.Saxe@Sun.COM }
9748906SEric.Saxe@Sun.COM
9758906SEric.Saxe@Sun.COM /*
9768906SEric.Saxe@Sun.COM * Remove a handler for processor change notifications.
9778906SEric.Saxe@Sun.COM */
9788906SEric.Saxe@Sun.COM void
cpu_acpi_remove_notify_handler(cpu_acpi_handle_t handle,ACPI_NOTIFY_HANDLER handler)9798906SEric.Saxe@Sun.COM cpu_acpi_remove_notify_handler(cpu_acpi_handle_t handle,
9808906SEric.Saxe@Sun.COM ACPI_NOTIFY_HANDLER handler)
9818906SEric.Saxe@Sun.COM {
9828906SEric.Saxe@Sun.COM if (ACPI_FAILURE(AcpiRemoveNotifyHandler(handle->cs_handle,
9838906SEric.Saxe@Sun.COM ACPI_DEVICE_NOTIFY, handler)))
9848906SEric.Saxe@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: Unable to remove "
98510075SMark.Haywood@Sun.COM "notify handler for CPU %d.", handle->cs_id);
9868906SEric.Saxe@Sun.COM }
9878906SEric.Saxe@Sun.COM
9888906SEric.Saxe@Sun.COM /*
9898906SEric.Saxe@Sun.COM * Write _PDC.
9908906SEric.Saxe@Sun.COM */
9918906SEric.Saxe@Sun.COM int
cpu_acpi_write_pdc(cpu_acpi_handle_t handle,uint32_t revision,uint32_t count,uint32_t * capabilities)9928906SEric.Saxe@Sun.COM cpu_acpi_write_pdc(cpu_acpi_handle_t handle, uint32_t revision, uint32_t count,
9938906SEric.Saxe@Sun.COM uint32_t *capabilities)
9948906SEric.Saxe@Sun.COM {
99510075SMark.Haywood@Sun.COM ACPI_STATUS astatus;
9968906SEric.Saxe@Sun.COM ACPI_OBJECT obj;
9978906SEric.Saxe@Sun.COM ACPI_OBJECT_LIST list = { 1, &obj};
9988906SEric.Saxe@Sun.COM uint32_t *buffer;
9998906SEric.Saxe@Sun.COM uint32_t *bufptr;
10008906SEric.Saxe@Sun.COM uint32_t bufsize;
10018906SEric.Saxe@Sun.COM int i;
100210075SMark.Haywood@Sun.COM int ret = 0;
10038906SEric.Saxe@Sun.COM
10048906SEric.Saxe@Sun.COM bufsize = (count + 2) * sizeof (uint32_t);
10058906SEric.Saxe@Sun.COM buffer = kmem_zalloc(bufsize, KM_SLEEP);
10068906SEric.Saxe@Sun.COM buffer[0] = revision;
10078906SEric.Saxe@Sun.COM buffer[1] = count;
10088906SEric.Saxe@Sun.COM bufptr = &buffer[2];
10098906SEric.Saxe@Sun.COM for (i = 0; i < count; i++)
10108906SEric.Saxe@Sun.COM *bufptr++ = *capabilities++;
10118906SEric.Saxe@Sun.COM
10128906SEric.Saxe@Sun.COM obj.Type = ACPI_TYPE_BUFFER;
10138906SEric.Saxe@Sun.COM obj.Buffer.Length = bufsize;
10148906SEric.Saxe@Sun.COM obj.Buffer.Pointer = (void *)buffer;
10158906SEric.Saxe@Sun.COM
10168906SEric.Saxe@Sun.COM /*
101710075SMark.Haywood@Sun.COM * Fetch the ??? (if present) for the CPU node.
10188906SEric.Saxe@Sun.COM */
101910075SMark.Haywood@Sun.COM astatus = AcpiEvaluateObject(handle->cs_handle, "_PDC", &list, NULL);
102010075SMark.Haywood@Sun.COM if (ACPI_FAILURE(astatus)) {
102110075SMark.Haywood@Sun.COM if (astatus == AE_NOT_FOUND) {
102210075SMark.Haywood@Sun.COM DTRACE_PROBE3(cpu_acpi__eval__err, int, handle->cs_id,
102310075SMark.Haywood@Sun.COM int, PDC_OBJ, int, astatus);
102410075SMark.Haywood@Sun.COM ret = 1;
102510075SMark.Haywood@Sun.COM } else {
102610075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error %d evaluating _PDC "
102710075SMark.Haywood@Sun.COM "package for CPU %d.", astatus, handle->cs_id);
102810075SMark.Haywood@Sun.COM ret = -1;
102910075SMark.Haywood@Sun.COM }
10308906SEric.Saxe@Sun.COM }
10318906SEric.Saxe@Sun.COM
10328906SEric.Saxe@Sun.COM kmem_free(buffer, bufsize);
103310075SMark.Haywood@Sun.COM return (ret);
10348906SEric.Saxe@Sun.COM }
10358906SEric.Saxe@Sun.COM
10368906SEric.Saxe@Sun.COM /*
10378906SEric.Saxe@Sun.COM * Write to system IO port.
10388906SEric.Saxe@Sun.COM */
10398906SEric.Saxe@Sun.COM int
cpu_acpi_write_port(ACPI_IO_ADDRESS address,uint32_t value,uint32_t width)10408906SEric.Saxe@Sun.COM cpu_acpi_write_port(ACPI_IO_ADDRESS address, uint32_t value, uint32_t width)
10418906SEric.Saxe@Sun.COM {
10428906SEric.Saxe@Sun.COM if (ACPI_FAILURE(AcpiOsWritePort(address, value, width))) {
104310075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error writing system IO port "
10448906SEric.Saxe@Sun.COM "%lx.", (long)address);
10458906SEric.Saxe@Sun.COM return (-1);
10468906SEric.Saxe@Sun.COM }
10478906SEric.Saxe@Sun.COM return (0);
10488906SEric.Saxe@Sun.COM }
10498906SEric.Saxe@Sun.COM
10508906SEric.Saxe@Sun.COM /*
10518906SEric.Saxe@Sun.COM * Read from a system IO port.
10528906SEric.Saxe@Sun.COM */
10538906SEric.Saxe@Sun.COM int
cpu_acpi_read_port(ACPI_IO_ADDRESS address,uint32_t * value,uint32_t width)10548906SEric.Saxe@Sun.COM cpu_acpi_read_port(ACPI_IO_ADDRESS address, uint32_t *value, uint32_t width)
10558906SEric.Saxe@Sun.COM {
10568906SEric.Saxe@Sun.COM if (ACPI_FAILURE(AcpiOsReadPort(address, value, width))) {
105710075SMark.Haywood@Sun.COM cmn_err(CE_NOTE, "!cpu_acpi: error reading system IO port "
10588906SEric.Saxe@Sun.COM "%lx.", (long)address);
10598906SEric.Saxe@Sun.COM return (-1);
10608906SEric.Saxe@Sun.COM }
10618906SEric.Saxe@Sun.COM return (0);
10628906SEric.Saxe@Sun.COM }
10638906SEric.Saxe@Sun.COM
10648906SEric.Saxe@Sun.COM /*
10658906SEric.Saxe@Sun.COM * Return supported frequencies.
10668906SEric.Saxe@Sun.COM */
10678906SEric.Saxe@Sun.COM uint_t
cpu_acpi_get_speeds(cpu_acpi_handle_t handle,int ** speeds)10688906SEric.Saxe@Sun.COM cpu_acpi_get_speeds(cpu_acpi_handle_t handle, int **speeds)
10698906SEric.Saxe@Sun.COM {
10708906SEric.Saxe@Sun.COM cpu_acpi_pstate_t *pstate;
10718906SEric.Saxe@Sun.COM int *hspeeds;
10728906SEric.Saxe@Sun.COM uint_t nspeeds;
10738906SEric.Saxe@Sun.COM int i;
10748906SEric.Saxe@Sun.COM
10758906SEric.Saxe@Sun.COM nspeeds = CPU_ACPI_PSTATES_COUNT(handle);
10768906SEric.Saxe@Sun.COM pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle);
10778906SEric.Saxe@Sun.COM hspeeds = kmem_zalloc(nspeeds * sizeof (int), KM_SLEEP);
10788906SEric.Saxe@Sun.COM for (i = 0; i < nspeeds; i++) {
10798906SEric.Saxe@Sun.COM hspeeds[i] = CPU_ACPI_FREQ(pstate);
10808906SEric.Saxe@Sun.COM pstate++;
10818906SEric.Saxe@Sun.COM }
10828906SEric.Saxe@Sun.COM *speeds = hspeeds;
10838906SEric.Saxe@Sun.COM return (nspeeds);
10848906SEric.Saxe@Sun.COM }
10858906SEric.Saxe@Sun.COM
10868906SEric.Saxe@Sun.COM /*
10878906SEric.Saxe@Sun.COM * Free resources allocated by cpu_acpi_get_speeds().
10888906SEric.Saxe@Sun.COM */
10898906SEric.Saxe@Sun.COM void
cpu_acpi_free_speeds(int * speeds,uint_t nspeeds)10908906SEric.Saxe@Sun.COM cpu_acpi_free_speeds(int *speeds, uint_t nspeeds)
10918906SEric.Saxe@Sun.COM {
10928906SEric.Saxe@Sun.COM kmem_free(speeds, nspeeds * sizeof (int));
10938906SEric.Saxe@Sun.COM }
10948906SEric.Saxe@Sun.COM
10958906SEric.Saxe@Sun.COM uint_t
cpu_acpi_get_max_cstates(cpu_acpi_handle_t handle)10968906SEric.Saxe@Sun.COM cpu_acpi_get_max_cstates(cpu_acpi_handle_t handle)
10978906SEric.Saxe@Sun.COM {
10988906SEric.Saxe@Sun.COM if (CPU_ACPI_CSTATES(handle))
10998906SEric.Saxe@Sun.COM return (CPU_ACPI_CSTATES_COUNT(handle));
11008906SEric.Saxe@Sun.COM else
11018906SEric.Saxe@Sun.COM return (1);
11028906SEric.Saxe@Sun.COM }
11038906SEric.Saxe@Sun.COM
11048906SEric.Saxe@Sun.COM void
cpu_acpi_set_register(uint32_t bitreg,uint32_t value)11058906SEric.Saxe@Sun.COM cpu_acpi_set_register(uint32_t bitreg, uint32_t value)
11068906SEric.Saxe@Sun.COM {
110710488SMark.Haywood@Sun.COM (void) AcpiWriteBitRegister(bitreg, value);
11088906SEric.Saxe@Sun.COM }
11098906SEric.Saxe@Sun.COM
11108906SEric.Saxe@Sun.COM void
cpu_acpi_get_register(uint32_t bitreg,uint32_t * value)11118906SEric.Saxe@Sun.COM cpu_acpi_get_register(uint32_t bitreg, uint32_t *value)
11128906SEric.Saxe@Sun.COM {
111310488SMark.Haywood@Sun.COM (void) AcpiReadBitRegister(bitreg, value);
11148906SEric.Saxe@Sun.COM }
11158906SEric.Saxe@Sun.COM
11168906SEric.Saxe@Sun.COM /*
11178906SEric.Saxe@Sun.COM * Map the dip to an ACPI handle for the device.
11188906SEric.Saxe@Sun.COM */
11198906SEric.Saxe@Sun.COM cpu_acpi_handle_t
cpu_acpi_init(cpu_t * cp)11208906SEric.Saxe@Sun.COM cpu_acpi_init(cpu_t *cp)
11218906SEric.Saxe@Sun.COM {
11228906SEric.Saxe@Sun.COM cpu_acpi_handle_t handle;
11238906SEric.Saxe@Sun.COM
11248906SEric.Saxe@Sun.COM handle = kmem_zalloc(sizeof (cpu_acpi_state_t), KM_SLEEP);
11258906SEric.Saxe@Sun.COM
11268906SEric.Saxe@Sun.COM if (ACPI_FAILURE(acpica_get_handle_cpu(cp->cpu_id,
11278906SEric.Saxe@Sun.COM &handle->cs_handle))) {
11288906SEric.Saxe@Sun.COM kmem_free(handle, sizeof (cpu_acpi_state_t));
11298906SEric.Saxe@Sun.COM return (NULL);
11308906SEric.Saxe@Sun.COM }
11318906SEric.Saxe@Sun.COM handle->cs_id = cp->cpu_id;
11328906SEric.Saxe@Sun.COM return (handle);
11338906SEric.Saxe@Sun.COM }
11348906SEric.Saxe@Sun.COM
11358906SEric.Saxe@Sun.COM /*
11368906SEric.Saxe@Sun.COM * Free any resources.
11378906SEric.Saxe@Sun.COM */
11388906SEric.Saxe@Sun.COM void
cpu_acpi_fini(cpu_acpi_handle_t handle)11398906SEric.Saxe@Sun.COM cpu_acpi_fini(cpu_acpi_handle_t handle)
11408906SEric.Saxe@Sun.COM {
11418906SEric.Saxe@Sun.COM if (handle)
11428906SEric.Saxe@Sun.COM kmem_free(handle, sizeof (cpu_acpi_state_t));
11438906SEric.Saxe@Sun.COM }
1144