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