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