1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/x86_archext.h> 27 #include <sys/machsystm.h> 28 #include <sys/x_call.h> 29 #include <sys/acpi/acpi.h> 30 #include <sys/acpica.h> 31 #include <sys/speedstep.h> 32 #include <sys/cpu_acpi.h> 33 #include <sys/cpupm.h> 34 #include <sys/dtrace.h> 35 #include <sys/sdt.h> 36 37 static int speedstep_init(cpu_t *); 38 static void speedstep_fini(cpu_t *); 39 static void speedstep_power(cpuset_t, uint32_t); 40 41 /* 42 * Interfaces for modules implementing Intel's Enhanced SpeedStep. 43 */ 44 cpupm_state_ops_t speedstep_ops = { 45 "Enhanced SpeedStep Technology", 46 speedstep_init, 47 speedstep_fini, 48 speedstep_power 49 }; 50 51 /* 52 * Error returns 53 */ 54 #define ESS_RET_SUCCESS 0x00 55 #define ESS_RET_NO_PM 0x01 56 #define ESS_RET_UNSUP_STATE 0x02 57 58 /* 59 * MSR registers for changing and reading processor power state. 60 */ 61 #define IA32_PERF_STAT_MSR 0x198 62 #define IA32_PERF_CTL_MSR 0x199 63 64 #define IA32_CPUID_TSC_CONSTANT 0xF30 65 #define IA32_MISC_ENABLE_MSR 0x1A0 66 #define IA32_MISC_ENABLE_EST (1<<16) 67 #define IA32_MISC_ENABLE_CXE (1<<25) 68 /* 69 * Debugging support 70 */ 71 #ifdef DEBUG 72 volatile int ess_debug = 0; 73 #define ESSDEBUG(arglist) if (ess_debug) printf arglist; 74 #else 75 #define ESSDEBUG(arglist) 76 #endif 77 78 /* 79 * Write the ctrl register. How it is written, depends upon the _PCT 80 * APCI object value. 81 */ 82 static void 83 write_ctrl(cpu_acpi_handle_t handle, uint32_t ctrl) 84 { 85 cpu_acpi_pct_t *pct_ctrl; 86 uint64_t reg; 87 88 pct_ctrl = CPU_ACPI_PCT_CTRL(handle); 89 90 switch (pct_ctrl->cr_addrspace_id) { 91 case ACPI_ADR_SPACE_FIXED_HARDWARE: 92 /* 93 * Read current power state because reserved bits must be 94 * preserved, compose new value, and write it. 95 */ 96 reg = rdmsr(IA32_PERF_CTL_MSR); 97 reg &= ~((uint64_t)0xFFFF); 98 reg |= ctrl; 99 wrmsr(IA32_PERF_CTL_MSR, reg); 100 break; 101 102 case ACPI_ADR_SPACE_SYSTEM_IO: 103 (void) cpu_acpi_write_port(pct_ctrl->cr_address, ctrl, 104 pct_ctrl->cr_width); 105 break; 106 107 default: 108 DTRACE_PROBE1(ess_ctrl_unsupported_type, uint8_t, 109 pct_ctrl->cr_addrspace_id); 110 return; 111 } 112 113 DTRACE_PROBE1(ess_ctrl_write, uint32_t, ctrl); 114 } 115 116 /* 117 * Transition the current processor to the requested state. 118 */ 119 void 120 speedstep_pstate_transition(uint32_t req_state) 121 { 122 cpupm_mach_state_t *mach_state = 123 (cpupm_mach_state_t *)CPU->cpu_m.mcpu_pm_mach_state; 124 cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; 125 cpu_acpi_pstate_t *req_pstate; 126 uint32_t ctrl; 127 128 req_pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle); 129 req_pstate += req_state; 130 131 DTRACE_PROBE1(ess_transition, uint32_t, CPU_ACPI_FREQ(req_pstate)); 132 133 /* 134 * Initiate the processor p-state change. 135 */ 136 ctrl = CPU_ACPI_PSTATE_CTRL(req_pstate); 137 write_ctrl(handle, ctrl); 138 139 mach_state->ms_pstate.cma_state.pstate = req_state; 140 cpu_set_curr_clock(((uint64_t)CPU_ACPI_FREQ(req_pstate) * 1000000)); 141 } 142 143 static void 144 speedstep_power(cpuset_t set, uint32_t req_state) 145 { 146 /* 147 * If thread is already running on target CPU then just 148 * make the transition request. Otherwise, we'll need to 149 * make a cross-call. 150 */ 151 kpreempt_disable(); 152 if (CPU_IN_SET(set, CPU->cpu_id)) { 153 speedstep_pstate_transition(req_state); 154 CPUSET_DEL(set, CPU->cpu_id); 155 } 156 if (!CPUSET_ISNULL(set)) { 157 xc_call((xc_arg_t)req_state, NULL, NULL, X_CALL_HIPRI, set, 158 (xc_func_t)speedstep_pstate_transition); 159 } 160 kpreempt_enable(); 161 } 162 163 /* 164 * Validate that this processor supports Speedstep and if so, 165 * get the P-state data from ACPI and cache it. 166 */ 167 static int 168 speedstep_init(cpu_t *cp) 169 { 170 cpupm_mach_state_t *mach_state = 171 (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 172 cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; 173 cpu_acpi_pct_t *pct_stat; 174 175 ESSDEBUG(("speedstep_init: processor %d\n", cp->cpu_id)); 176 177 /* 178 * Cache the P-state specific ACPI data. 179 */ 180 if (cpu_acpi_cache_pstate_data(handle) != 0) { 181 ESSDEBUG(("Failed to cache ACPI data\n")); 182 speedstep_fini(cp); 183 return (ESS_RET_NO_PM); 184 } 185 186 pct_stat = CPU_ACPI_PCT_STATUS(handle); 187 switch (pct_stat->cr_addrspace_id) { 188 case ACPI_ADR_SPACE_FIXED_HARDWARE: 189 ESSDEBUG(("Transitions will use fixed hardware\n")); 190 break; 191 case ACPI_ADR_SPACE_SYSTEM_IO: 192 ESSDEBUG(("Transitions will use system IO\n")); 193 break; 194 default: 195 cmn_err(CE_WARN, "!_PCT conifgured for unsupported " 196 "addrspace = %d.", pct_stat->cr_addrspace_id); 197 cmn_err(CE_NOTE, "!CPU power management will not function."); 198 speedstep_fini(cp); 199 return (ESS_RET_NO_PM); 200 } 201 202 cpupm_alloc_domains(cp, CPUPM_P_STATES); 203 204 ESSDEBUG(("Processor %d succeeded.\n", cp->cpu_id)) 205 return (ESS_RET_SUCCESS); 206 } 207 208 /* 209 * Free resources allocated by speedstep_init(). 210 */ 211 static void 212 speedstep_fini(cpu_t *cp) 213 { 214 cpupm_mach_state_t *mach_state = 215 (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state); 216 cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; 217 218 cpupm_free_domains(&cpupm_pstate_domains); 219 cpu_acpi_free_pstate_data(handle); 220 } 221 222 boolean_t 223 speedstep_supported(uint_t family, uint_t model) 224 { 225 struct cpuid_regs cpu_regs; 226 227 /* Required features */ 228 if (!(x86_feature & X86_CPUID) || 229 !(x86_feature & X86_MSR)) { 230 return (B_FALSE); 231 } 232 233 /* 234 * We only support family/model combinations which 235 * are P-state TSC invariant. 236 */ 237 if (!((family == 0xf && model >= 0x3) || 238 (family == 0x6 && model >= 0xe))) { 239 return (B_FALSE); 240 } 241 242 /* 243 * Enhanced SpeedStep supported? 244 */ 245 cpu_regs.cp_eax = 0x1; 246 (void) __cpuid_insn(&cpu_regs); 247 if (!(cpu_regs.cp_ecx & CPUID_INTC_ECX_EST)) { 248 return (B_FALSE); 249 } 250 251 return (B_TRUE); 252 } 253