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 top_spd = NULL; 146 dip = ctx; 147 instance = ddi_get_instance(dip); 148 cpudsp = ddi_get_soft_state(cpudrv_state, instance); 149 ASSERT(cpudsp != NULL); 150 151 mutex_enter(&cpudsp->lock); 152 cpupm = &(cpudsp->cpudrv_pm); 153 pm_level = PLAT_2_PM_LEVEL(cpupm, plat_level); 154 for (i = 0, spd = cpupm->head_spd; spd; i++, spd = spd->down_spd) { 155 /* 156 * Don't mess with speeds that are higher than the new 157 * top speed. They should be out of range anyway. 158 */ 159 if (spd->pm_level > pm_level) 160 continue; 161 /* 162 * This is the new top speed. 163 */ 164 if (spd->pm_level == pm_level) 165 top_spd = spd; 166 167 spd->up_spd = top_spd; 168 } 169 cpupm->top_spd = top_spd; 170 171 cpupm->pm_governor_thread = curthread; 172 173 mutex_exit(&cpudsp->lock); 174 175 (void) pm_update_maxpower(dip, 0, top_spd->pm_level); 176 } 177 178 /* 179 * This routine reads the ACPI _PPC object. It's accessed as a callback 180 * by the ppm driver whenever a _PPC change notification is received. 181 */ 182 int 183 cpudrv_get_topspeed(void *ctx) 184 { 185 cpu_t *cp; 186 cpudrv_devstate_t *cpudsp; 187 dev_info_t *dip; 188 int instance; 189 int plat_level; 190 191 dip = ctx; 192 instance = ddi_get_instance(dip); 193 cpudsp = ddi_get_soft_state(cpudrv_state, instance); 194 ASSERT(cpudsp != NULL); 195 cp = cpudsp->cp; 196 plat_level = cpupm_get_top_speed(cp); 197 198 return (plat_level); 199 } 200 201 202 /* 203 * This notification handler is called whenever the ACPI _PPC 204 * object changes. The _PPC is a sort of governor on power levels. 205 * It sets an upper threshold on which, _PSS defined, power levels 206 * are usuable. The _PPC value is dynamic and may change as properties 207 * (i.e., thermal or AC source) of the system change. 208 */ 209 /* ARGSUSED */ 210 static void 211 cpudrv_notify_handler(ACPI_HANDLE obj, UINT32 val, void *ctx) 212 { 213 cpu_t *cp; 214 cpupm_mach_state_t *mach_state; 215 cpudrv_devstate_t *cpudsp; 216 dev_info_t *dip; 217 int instance; 218 extern pm_cpupm_t cpupm; 219 220 dip = ctx; 221 instance = ddi_get_instance(dip); 222 cpudsp = ddi_get_soft_state(cpudrv_state, instance); 223 if (cpudsp == NULL) 224 return; 225 cp = cpudsp->cp; 226 mach_state = (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 227 if (mach_state == NULL) 228 return; 229 230 /* 231 * We only handle _PPC change notifications. 232 */ 233 if (!PM_EVENT_CPUPM && val == CPUPM_PPC_CHANGE_NOTIFICATION && 234 mach_state->ms_caps & CPUPM_P_STATES) 235 cpudrv_redefine_topspeed(ctx); 236 } 237 238 void 239 cpudrv_install_notify_handler(cpudrv_devstate_t *cpudsp) 240 { 241 cpu_t *cp = cpudsp->cp; 242 cpupm_add_notify_handler(cp, cpudrv_notify_handler, 243 cpudsp->dip); 244 } 245 246 void 247 cpudrv_uninstall_notify_handler(cpudrv_devstate_t *cpudsp) 248 { 249 cpu_t *cp = cpudsp->cp; 250 cpupm_notification_t *entry, **next; 251 252 ASSERT(cp != NULL); 253 cpupm_mach_state_t *mach_state = 254 (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 255 256 mutex_enter(&mach_state->ms_lock); 257 if (mach_state->ms_handlers == NULL) { 258 mutex_exit(&mach_state->ms_lock); 259 return; 260 } 261 262 for (next = &mach_state->ms_handlers; (entry = *next) != NULL; ) { 263 if (entry->nq_handler != cpudrv_notify_handler) { 264 next = &entry->nq_next; 265 continue; 266 } 267 *next = entry->nq_next; 268 kmem_free(entry, sizeof (cpupm_notification_t)); 269 } 270 mutex_exit(&mach_state->ms_lock); 271 } 272 273 void 274 cpudrv_redefine_topspeed(void *ctx) 275 { 276 /* 277 * This should never happen, unless ppm does not get loaded. 278 */ 279 if (cpupm_redefine_topspeed == NULL) { 280 cmn_err(CE_WARN, "cpudrv_redefine_topspeed: " 281 "cpupm_redefine_topspeed has not been initialized - " 282 "ignoring notification"); 283 return; 284 } 285 286 /* 287 * ppm callback needs to handle redefinition for all CPUs in 288 * the domain. 289 */ 290 (*cpupm_redefine_topspeed)(ctx); 291 } 292 293 boolean_t 294 cpudrv_mach_init(cpudrv_devstate_t *cpudsp) 295 { 296 cpupm_mach_state_t *mach_state; 297 int topspeed; 298 299 ASSERT(cpudsp->cp); 300 301 mach_state = (cpupm_mach_state_t *) 302 (cpudsp->cp->cpu_m.mcpu_pm_mach_state); 303 mach_state->ms_dip = cpudsp->dip; 304 /* 305 * allocate ppm CPU domain and initialize the topspeed 306 * only if P-states are enabled. 307 */ 308 if (cpudrv_power_ready(cpudsp->cp)) { 309 (*cpupm_ppm_alloc_pstate_domains)(cpudsp->cp); 310 topspeed = cpudrv_get_topspeed(cpudsp->dip); 311 cpudrv_set_topspeed(cpudsp->dip, topspeed); 312 } 313 314 return (B_TRUE); 315 } 316 317 boolean_t 318 cpudrv_mach_fini(cpudrv_devstate_t *cpudsp) 319 { 320 /* 321 * return TRUE if cpu pointer is NULL 322 */ 323 if (cpudsp->cp == NULL) 324 return (B_TRUE); 325 /* 326 * free ppm cpu pstate domains only if 327 * P-states are enabled 328 */ 329 if (cpudrv_power_ready(cpudsp->cp)) { 330 (*cpupm_ppm_free_pstate_domains)(cpudsp->cp); 331 } 332 333 return (B_TRUE); 334 } 335 336 uint_t 337 cpudrv_get_speeds(cpudrv_devstate_t *cpudsp, int **speeds) 338 { 339 /* 340 * return nspeeds = 0 if can't get cpu_t 341 */ 342 if (cpudrv_get_cpu(cpudsp) != DDI_SUCCESS) 343 return (0); 344 345 return (cpupm_get_speeds(cpudsp->cp, speeds)); 346 } 347 348 void 349 cpudrv_free_speeds(int *speeds, uint_t nspeeds) 350 { 351 cpupm_free_speeds(speeds, nspeeds); 352 } 353 354 boolean_t 355 cpudrv_power_ready(cpu_t *cp) 356 { 357 return (cpupm_power_ready(cp)); 358 } 359 360 /* ARGSUSED */ 361 void 362 cpudrv_set_supp_freqs(cpudrv_devstate_t *cpudsp) 363 { 364 } 365