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 * Copyright (c) 2009, Intel Corporation. 27 * All Rights Reserved. 28 */ 29 30 /* 31 * CPU power management driver support for i86pc. 32 */ 33 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/cpupm.h> 37 #include <sys/cpudrv_mach.h> 38 #include <sys/machsystm.h> 39 #include <sys/cpu_pm.h> 40 #include <sys/cpuvar.h> 41 #include <sys/sdt.h> 42 #include <sys/cpu_idle.h> 43 44 /* 45 * Note that our driver numbers the power levels from lowest to 46 * highest starting at 1 (i.e., the lowest power level is 1 and 47 * the highest power level is cpupm->num_spd). The x86 modules get 48 * their power levels from ACPI which numbers power levels from 49 * highest to lowest starting at 0 (i.e., the lowest power level 50 * is (cpupm->num_spd - 1) and the highest power level is 0). So to 51 * map one of our driver power levels to one understood by ACPI we 52 * simply subtract our driver power level from cpupm->num_spd. Likewise, 53 * to map an ACPI power level to the proper driver power level, we 54 * subtract the ACPI power level from cpupm->num_spd. 55 */ 56 #define PM_2_PLAT_LEVEL(cpupm, pm_level) (cpupm->num_spd - pm_level) 57 #define PLAT_2_PM_LEVEL(cpupm, plat_level) (cpupm->num_spd - plat_level) 58 59 /* 60 * Change CPU speed using interface provided by module. 61 */ 62 int 63 cpudrv_change_speed(cpudrv_devstate_t *cpudsp, cpudrv_pm_spd_t *new_spd) 64 { 65 cpu_t *cp = cpudsp->cp; 66 cpupm_mach_state_t *mach_state = 67 (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 68 cpudrv_pm_t *cpupm; 69 cpuset_t set; 70 uint32_t plat_level; 71 72 if (!(mach_state->ms_caps & CPUPM_P_STATES)) 73 return (DDI_FAILURE); 74 ASSERT(mach_state->ms_pstate.cma_ops != NULL); 75 cpupm = &(cpudsp->cpudrv_pm); 76 plat_level = PM_2_PLAT_LEVEL(cpupm, new_spd->pm_level); 77 CPUSET_ONLY(set, cp->cpu_id); 78 mach_state->ms_pstate.cma_ops->cpus_change(set, plat_level); 79 80 return (DDI_SUCCESS); 81 } 82 83 /* 84 * Determine the cpu_id for the CPU device. 85 */ 86 boolean_t 87 cpudrv_get_cpu_id(dev_info_t *dip, processorid_t *cpu_id) 88 { 89 return ((*cpu_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 90 DDI_PROP_DONTPASS, "reg", -1)) != -1); 91 92 } 93 94 boolean_t 95 cpudrv_is_enabled(cpudrv_devstate_t *cpudsp) 96 { 97 cpupm_mach_state_t *mach_state; 98 99 if (!cpupm_is_enabled(CPUPM_P_STATES) || !cpudrv_enabled) 100 return (B_FALSE); 101 102 /* 103 * Only check the instance specific setting it exists. 104 */ 105 if (cpudsp != NULL && cpudsp->cp != NULL && 106 cpudsp->cp->cpu_m.mcpu_pm_mach_state != NULL) { 107 mach_state = 108 (cpupm_mach_state_t *)cpudsp->cp->cpu_m.mcpu_pm_mach_state; 109 return (mach_state->ms_caps & CPUPM_P_STATES); 110 } 111 112 return (B_TRUE); 113 } 114 115 /* 116 * Is the current thread the thread that is handling the 117 * PPC change notification? 118 */ 119 boolean_t 120 cpudrv_is_governor_thread(cpudrv_pm_t *cpupm) 121 { 122 return (curthread == cpupm->pm_governor_thread); 123 } 124 125 /* 126 * This routine changes the top speed to which the CPUs can transition by: 127 * 128 * - Resetting the up_spd for all speeds lower than the new top speed 129 * to point to the new top speed. 130 * - Updating the framework with a new "normal" (maximum power) for this 131 * device. 132 */ 133 void 134 cpudrv_set_topspeed(void *ctx, int plat_level) 135 { 136 cpudrv_devstate_t *cpudsp; 137 cpudrv_pm_t *cpupm; 138 cpudrv_pm_spd_t *spd; 139 cpudrv_pm_spd_t *top_spd; 140 dev_info_t *dip; 141 int pm_level; 142 int instance; 143 int i; 144 145 dip = ctx; 146 instance = ddi_get_instance(dip); 147 cpudsp = ddi_get_soft_state(cpudrv_state, instance); 148 ASSERT(cpudsp != NULL); 149 150 mutex_enter(&cpudsp->lock); 151 cpupm = &(cpudsp->cpudrv_pm); 152 pm_level = PLAT_2_PM_LEVEL(cpupm, plat_level); 153 for (i = 0, spd = cpupm->head_spd; spd; i++, spd = spd->down_spd) { 154 /* 155 * Don't mess with speeds that are higher than the new 156 * top speed. They should be out of range anyway. 157 */ 158 if (spd->pm_level > pm_level) 159 continue; 160 /* 161 * This is the new top speed. 162 */ 163 if (spd->pm_level == pm_level) 164 top_spd = spd; 165 166 spd->up_spd = top_spd; 167 } 168 cpupm->top_spd = top_spd; 169 170 cpupm->pm_governor_thread = curthread; 171 172 mutex_exit(&cpudsp->lock); 173 174 (void) pm_update_maxpower(dip, 0, top_spd->pm_level); 175 } 176 177 /* 178 * This routine reads the ACPI _PPC object. It's accessed as a callback 179 * by the ppm driver whenever a _PPC change notification is received. 180 */ 181 int 182 cpudrv_get_topspeed(void *ctx) 183 { 184 cpu_t *cp; 185 cpudrv_devstate_t *cpudsp; 186 dev_info_t *dip; 187 int instance; 188 int plat_level; 189 190 dip = ctx; 191 instance = ddi_get_instance(dip); 192 cpudsp = ddi_get_soft_state(cpudrv_state, instance); 193 ASSERT(cpudsp != NULL); 194 cp = cpudsp->cp; 195 plat_level = cpupm_get_top_speed(cp); 196 197 return (plat_level); 198 } 199 200 201 /* 202 * This notification handler is called whenever the ACPI _PPC 203 * object changes. The _PPC is a sort of governor on power levels. 204 * It sets an upper threshold on which, _PSS defined, power levels 205 * are usuable. The _PPC value is dynamic and may change as properties 206 * (i.e., thermal or AC source) of the system change. 207 */ 208 /* ARGSUSED */ 209 static void 210 cpudrv_notify_handler(ACPI_HANDLE obj, UINT32 val, void *ctx) 211 { 212 cpu_t *cp; 213 cpupm_mach_state_t *mach_state; 214 cpudrv_devstate_t *cpudsp; 215 dev_info_t *dip; 216 int instance; 217 extern pm_cpupm_t cpupm; 218 219 dip = ctx; 220 instance = ddi_get_instance(dip); 221 cpudsp = ddi_get_soft_state(cpudrv_state, instance); 222 if (cpudsp == NULL) 223 return; 224 cp = cpudsp->cp; 225 mach_state = (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 226 if (mach_state == NULL) 227 return; 228 229 /* 230 * We only handle _PPC change notifications. 231 */ 232 if (!PM_EVENT_CPUPM && val == CPUPM_PPC_CHANGE_NOTIFICATION && 233 mach_state->ms_caps & CPUPM_P_STATES) 234 cpudrv_redefine_topspeed(ctx); 235 } 236 237 void 238 cpudrv_install_notify_handler(cpudrv_devstate_t *cpudsp) 239 { 240 cpu_t *cp = cpudsp->cp; 241 cpupm_add_notify_handler(cp, cpudrv_notify_handler, 242 cpudsp->dip); 243 } 244 245 void 246 cpudrv_uninstall_notify_handler(cpudrv_devstate_t *cpudsp) 247 { 248 cpu_t *cp = cpudsp->cp; 249 cpupm_notification_t *entry, **next; 250 251 ASSERT(cp != NULL); 252 cpupm_mach_state_t *mach_state = 253 (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 254 255 mutex_enter(&mach_state->ms_lock); 256 if (mach_state->ms_handlers == NULL) { 257 mutex_exit(&mach_state->ms_lock); 258 return; 259 } 260 261 for (next = &mach_state->ms_handlers; (entry = *next) != NULL; ) { 262 if (entry->nq_handler != cpudrv_notify_handler) { 263 next = &entry->nq_next; 264 continue; 265 } 266 *next = entry->nq_next; 267 kmem_free(entry, sizeof (cpupm_notification_t)); 268 } 269 mutex_exit(&mach_state->ms_lock); 270 } 271 272 void 273 cpudrv_redefine_topspeed(void *ctx) 274 { 275 /* 276 * This should never happen, unless ppm does not get loaded. 277 */ 278 if (cpupm_redefine_topspeed == NULL) { 279 cmn_err(CE_WARN, "cpudrv_redefine_topspeed: " 280 "cpupm_redefine_topspeed has not been initialized - " 281 "ignoring notification"); 282 return; 283 } 284 285 /* 286 * ppm callback needs to handle redefinition for all CPUs in 287 * the domain. 288 */ 289 (*cpupm_redefine_topspeed)(ctx); 290 } 291 292 boolean_t 293 cpudrv_mach_init(cpudrv_devstate_t *cpudsp) 294 { 295 cpupm_mach_state_t *mach_state; 296 int topspeed; 297 298 ASSERT(cpudsp->cp); 299 300 mach_state = (cpupm_mach_state_t *) 301 (cpudsp->cp->cpu_m.mcpu_pm_mach_state); 302 mach_state->ms_dip = cpudsp->dip; 303 /* 304 * allocate ppm CPU domain and initialize the topspeed 305 * only if P-states are enabled. 306 */ 307 if (cpudrv_power_ready(cpudsp->cp)) { 308 (*cpupm_ppm_alloc_pstate_domains)(cpudsp->cp); 309 topspeed = cpudrv_get_topspeed(cpudsp->dip); 310 cpudrv_set_topspeed(cpudsp->dip, topspeed); 311 } 312 313 return (B_TRUE); 314 } 315 316 boolean_t 317 cpudrv_mach_fini(cpudrv_devstate_t *cpudsp) 318 { 319 /* 320 * return TRUE if cpu pointer is NULL 321 */ 322 if (cpudsp->cp == NULL) 323 return (B_TRUE); 324 /* 325 * free ppm cpu pstate domains only if 326 * P-states are enabled 327 */ 328 if (cpudrv_power_ready(cpudsp->cp)) { 329 (*cpupm_ppm_free_pstate_domains)(cpudsp->cp); 330 } 331 332 return (B_TRUE); 333 } 334 335 uint_t 336 cpudrv_get_speeds(cpudrv_devstate_t *cpudsp, int **speeds) 337 { 338 /* 339 * return nspeeds = 0 if can't get cpu_t 340 */ 341 if (cpudrv_get_cpu(cpudsp) != DDI_SUCCESS) 342 return (0); 343 344 return (cpupm_get_speeds(cpudsp->cp, speeds)); 345 } 346 347 void 348 cpudrv_free_speeds(int *speeds, uint_t nspeeds) 349 { 350 cpupm_free_speeds(speeds, nspeeds); 351 } 352 353 boolean_t 354 cpudrv_power_ready(cpu_t *cp) 355 { 356 return (cpupm_power_ready(cp)); 357 } 358 359 /* ARGSUSED */ 360 void 361 cpudrv_set_supp_freqs(cpudrv_devstate_t *cpudsp) 362 { 363 } 364