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