1*0e751525SEric Saxe /* 2*0e751525SEric Saxe * CDDL HEADER START 3*0e751525SEric Saxe * 4*0e751525SEric Saxe * The contents of this file are subject to the terms of the 5*0e751525SEric Saxe * Common Development and Distribution License (the "License"). 6*0e751525SEric Saxe * You may not use this file except in compliance with the License. 7*0e751525SEric Saxe * 8*0e751525SEric Saxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*0e751525SEric Saxe * or http://www.opensolaris.org/os/licensing. 10*0e751525SEric Saxe * See the License for the specific language governing permissions 11*0e751525SEric Saxe * and limitations under the License. 12*0e751525SEric Saxe * 13*0e751525SEric Saxe * When distributing Covered Code, include this CDDL HEADER in each 14*0e751525SEric Saxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*0e751525SEric Saxe * If applicable, add the following below this CDDL HEADER, with the 16*0e751525SEric Saxe * fields enclosed by brackets "[]" replaced with your own identifying 17*0e751525SEric Saxe * information: Portions Copyright [yyyy] [name of copyright owner] 18*0e751525SEric Saxe * 19*0e751525SEric Saxe * CDDL HEADER END 20*0e751525SEric Saxe */ 21*0e751525SEric Saxe /* 22*0e751525SEric Saxe * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*0e751525SEric Saxe * Use is subject to license terms. 24*0e751525SEric Saxe */ 25*0e751525SEric Saxe 26*0e751525SEric Saxe /* 27*0e751525SEric Saxe * CPU power management driver support for i86pc. 28*0e751525SEric Saxe */ 29*0e751525SEric Saxe 30*0e751525SEric Saxe #include <sys/ddi.h> 31*0e751525SEric Saxe #include <sys/sunddi.h> 32*0e751525SEric Saxe #include <sys/cpupm.h> 33*0e751525SEric Saxe #include <sys/cpudrv_mach.h> 34*0e751525SEric Saxe #include <sys/machsystm.h> 35*0e751525SEric Saxe #include <sys/cpu_pm.h> 36*0e751525SEric Saxe #include <sys/cpuvar.h> 37*0e751525SEric Saxe #include <sys/sdt.h> 38*0e751525SEric Saxe #include <sys/cpu_idle.h> 39*0e751525SEric Saxe 40*0e751525SEric Saxe /* 41*0e751525SEric Saxe * Note that our driver numbers the power levels from lowest to 42*0e751525SEric Saxe * highest starting at 1 (i.e., the lowest power level is 1 and 43*0e751525SEric Saxe * the highest power level is cpupm->num_spd). The x86 modules get 44*0e751525SEric Saxe * their power levels from ACPI which numbers power levels from 45*0e751525SEric Saxe * highest to lowest starting at 0 (i.e., the lowest power level 46*0e751525SEric Saxe * is (cpupm->num_spd - 1) and the highest power level is 0). So to 47*0e751525SEric Saxe * map one of our driver power levels to one understood by ACPI we 48*0e751525SEric Saxe * simply subtract our driver power level from cpupm->num_spd. Likewise, 49*0e751525SEric Saxe * to map an ACPI power level to the proper driver power level, we 50*0e751525SEric Saxe * subtract the ACPI power level from cpupm->num_spd. 51*0e751525SEric Saxe */ 52*0e751525SEric Saxe #define PM_2_PLAT_LEVEL(cpupm, pm_level) (cpupm->num_spd - pm_level) 53*0e751525SEric Saxe #define PLAT_2_PM_LEVEL(cpupm, plat_level) (cpupm->num_spd - plat_level) 54*0e751525SEric Saxe 55*0e751525SEric Saxe /* 56*0e751525SEric Saxe * Change CPU speed using interface provided by module. 57*0e751525SEric Saxe */ 58*0e751525SEric Saxe int 59*0e751525SEric Saxe cpudrv_change_speed(cpudrv_devstate_t *cpudsp, cpudrv_pm_spd_t *new_spd) 60*0e751525SEric Saxe { 61*0e751525SEric Saxe cpu_t *cp = cpudsp->cp; 62*0e751525SEric Saxe cpupm_mach_state_t *mach_state = 63*0e751525SEric Saxe (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 64*0e751525SEric Saxe cpudrv_pm_t *cpupm; 65*0e751525SEric Saxe cpuset_t set; 66*0e751525SEric Saxe uint32_t plat_level; 67*0e751525SEric Saxe 68*0e751525SEric Saxe if (!(mach_state->ms_caps & CPUPM_P_STATES)) 69*0e751525SEric Saxe return (DDI_FAILURE); 70*0e751525SEric Saxe ASSERT(mach_state->ms_pstate.cma_ops != NULL); 71*0e751525SEric Saxe cpupm = &(cpudsp->cpudrv_pm); 72*0e751525SEric Saxe plat_level = PM_2_PLAT_LEVEL(cpupm, new_spd->pm_level); 73*0e751525SEric Saxe CPUSET_ONLY(set, cp->cpu_id); 74*0e751525SEric Saxe mach_state->ms_pstate.cma_ops->cpus_change(set, plat_level); 75*0e751525SEric Saxe 76*0e751525SEric Saxe return (DDI_SUCCESS); 77*0e751525SEric Saxe } 78*0e751525SEric Saxe 79*0e751525SEric Saxe /* 80*0e751525SEric Saxe * Determine the cpu_id for the CPU device. 81*0e751525SEric Saxe */ 82*0e751525SEric Saxe boolean_t 83*0e751525SEric Saxe cpudrv_get_cpu_id(dev_info_t *dip, processorid_t *cpu_id) 84*0e751525SEric Saxe { 85*0e751525SEric Saxe return ((*cpu_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 86*0e751525SEric Saxe DDI_PROP_DONTPASS, "reg", -1)) != -1); 87*0e751525SEric Saxe 88*0e751525SEric Saxe } 89*0e751525SEric Saxe 90*0e751525SEric Saxe boolean_t 91*0e751525SEric Saxe cpudrv_is_enabled(cpudrv_devstate_t *cpudsp) 92*0e751525SEric Saxe { 93*0e751525SEric Saxe cpupm_mach_state_t *mach_state; 94*0e751525SEric Saxe 95*0e751525SEric Saxe if (!cpupm_is_enabled(CPUPM_P_STATES) || !cpudrv_enabled) 96*0e751525SEric Saxe return (B_FALSE); 97*0e751525SEric Saxe 98*0e751525SEric Saxe /* 99*0e751525SEric Saxe * Only check the instance specific setting it exists. 100*0e751525SEric Saxe */ 101*0e751525SEric Saxe if (cpudsp != NULL && cpudsp->cp != NULL && 102*0e751525SEric Saxe cpudsp->cp->cpu_m.mcpu_pm_mach_state != NULL) { 103*0e751525SEric Saxe mach_state = 104*0e751525SEric Saxe (cpupm_mach_state_t *)cpudsp->cp->cpu_m.mcpu_pm_mach_state; 105*0e751525SEric Saxe return (mach_state->ms_caps & CPUPM_P_STATES); 106*0e751525SEric Saxe } 107*0e751525SEric Saxe 108*0e751525SEric Saxe return (B_TRUE); 109*0e751525SEric Saxe } 110*0e751525SEric Saxe 111*0e751525SEric Saxe /* 112*0e751525SEric Saxe * Is the current thread the thread that is handling the 113*0e751525SEric Saxe * PPC change notification? 114*0e751525SEric Saxe */ 115*0e751525SEric Saxe boolean_t 116*0e751525SEric Saxe cpudrv_is_governor_thread(cpudrv_pm_t *cpupm) 117*0e751525SEric Saxe { 118*0e751525SEric Saxe return (curthread == cpupm->pm_governor_thread); 119*0e751525SEric Saxe } 120*0e751525SEric Saxe 121*0e751525SEric Saxe /* 122*0e751525SEric Saxe * This routine changes the top speed to which the CPUs can transition by: 123*0e751525SEric Saxe * 124*0e751525SEric Saxe * - Resetting the up_spd for all speeds lower than the new top speed 125*0e751525SEric Saxe * to point to the new top speed. 126*0e751525SEric Saxe * - Updating the framework with a new "normal" (maximum power) for this 127*0e751525SEric Saxe * device. 128*0e751525SEric Saxe */ 129*0e751525SEric Saxe void 130*0e751525SEric Saxe cpudrv_set_topspeed(void *ctx, int plat_level) 131*0e751525SEric Saxe { 132*0e751525SEric Saxe cpudrv_devstate_t *cpudsp; 133*0e751525SEric Saxe cpudrv_pm_t *cpupm; 134*0e751525SEric Saxe cpudrv_pm_spd_t *spd; 135*0e751525SEric Saxe cpudrv_pm_spd_t *top_spd; 136*0e751525SEric Saxe dev_info_t *dip; 137*0e751525SEric Saxe int pm_level; 138*0e751525SEric Saxe int instance; 139*0e751525SEric Saxe int i; 140*0e751525SEric Saxe 141*0e751525SEric Saxe dip = ctx; 142*0e751525SEric Saxe instance = ddi_get_instance(dip); 143*0e751525SEric Saxe cpudsp = ddi_get_soft_state(cpudrv_state, instance); 144*0e751525SEric Saxe ASSERT(cpudsp != NULL); 145*0e751525SEric Saxe 146*0e751525SEric Saxe mutex_enter(&cpudsp->lock); 147*0e751525SEric Saxe cpupm = &(cpudsp->cpudrv_pm); 148*0e751525SEric Saxe pm_level = PLAT_2_PM_LEVEL(cpupm, plat_level); 149*0e751525SEric Saxe for (i = 0, spd = cpupm->head_spd; spd; i++, spd = spd->down_spd) { 150*0e751525SEric Saxe /* 151*0e751525SEric Saxe * Don't mess with speeds that are higher than the new 152*0e751525SEric Saxe * top speed. They should be out of range anyway. 153*0e751525SEric Saxe */ 154*0e751525SEric Saxe if (spd->pm_level > pm_level) 155*0e751525SEric Saxe continue; 156*0e751525SEric Saxe /* 157*0e751525SEric Saxe * This is the new top speed. 158*0e751525SEric Saxe */ 159*0e751525SEric Saxe if (spd->pm_level == pm_level) 160*0e751525SEric Saxe top_spd = spd; 161*0e751525SEric Saxe 162*0e751525SEric Saxe spd->up_spd = top_spd; 163*0e751525SEric Saxe } 164*0e751525SEric Saxe cpupm->top_spd = top_spd; 165*0e751525SEric Saxe 166*0e751525SEric Saxe cpupm->pm_governor_thread = curthread; 167*0e751525SEric Saxe 168*0e751525SEric Saxe mutex_exit(&cpudsp->lock); 169*0e751525SEric Saxe 170*0e751525SEric Saxe (void) pm_update_maxpower(dip, 0, top_spd->pm_level); 171*0e751525SEric Saxe } 172*0e751525SEric Saxe 173*0e751525SEric Saxe /* 174*0e751525SEric Saxe * This routine reads the ACPI _PPC object. It's accessed as a callback 175*0e751525SEric Saxe * by the ppm driver whenever a _PPC change notification is received. 176*0e751525SEric Saxe */ 177*0e751525SEric Saxe int 178*0e751525SEric Saxe cpudrv_get_topspeed(void *ctx) 179*0e751525SEric Saxe { 180*0e751525SEric Saxe cpu_t *cp; 181*0e751525SEric Saxe cpudrv_devstate_t *cpudsp; 182*0e751525SEric Saxe dev_info_t *dip; 183*0e751525SEric Saxe int instance; 184*0e751525SEric Saxe int plat_level; 185*0e751525SEric Saxe 186*0e751525SEric Saxe dip = ctx; 187*0e751525SEric Saxe instance = ddi_get_instance(dip); 188*0e751525SEric Saxe cpudsp = ddi_get_soft_state(cpudrv_state, instance); 189*0e751525SEric Saxe ASSERT(cpudsp != NULL); 190*0e751525SEric Saxe cp = cpudsp->cp; 191*0e751525SEric Saxe plat_level = cpupm_get_top_speed(cp); 192*0e751525SEric Saxe 193*0e751525SEric Saxe return (plat_level); 194*0e751525SEric Saxe } 195*0e751525SEric Saxe 196*0e751525SEric Saxe 197*0e751525SEric Saxe /* 198*0e751525SEric Saxe * This notification handler is called whenever the ACPI _PPC 199*0e751525SEric Saxe * object changes. The _PPC is a sort of governor on power levels. 200*0e751525SEric Saxe * It sets an upper threshold on which, _PSS defined, power levels 201*0e751525SEric Saxe * are usuable. The _PPC value is dynamic and may change as properties 202*0e751525SEric Saxe * (i.e., thermal or AC source) of the system change. 203*0e751525SEric Saxe */ 204*0e751525SEric Saxe /* ARGSUSED */ 205*0e751525SEric Saxe static void 206*0e751525SEric Saxe cpudrv_notify_handler(ACPI_HANDLE obj, UINT32 val, void *ctx) 207*0e751525SEric Saxe { 208*0e751525SEric Saxe extern pm_cpupm_t cpupm; 209*0e751525SEric Saxe 210*0e751525SEric Saxe /* 211*0e751525SEric Saxe * We only handle _PPC change notifications. 212*0e751525SEric Saxe */ 213*0e751525SEric Saxe if (val == CPUPM_PPC_CHANGE_NOTIFICATION && !PM_EVENT_CPUPM) 214*0e751525SEric Saxe cpudrv_redefine_topspeed(ctx); 215*0e751525SEric Saxe } 216*0e751525SEric Saxe 217*0e751525SEric Saxe void 218*0e751525SEric Saxe cpudrv_install_notify_handler(cpudrv_devstate_t *cpudsp) 219*0e751525SEric Saxe { 220*0e751525SEric Saxe cpu_t *cp = cpudsp->cp; 221*0e751525SEric Saxe cpupm_add_notify_handler(cp, cpudrv_notify_handler, 222*0e751525SEric Saxe cpudsp->dip); 223*0e751525SEric Saxe } 224*0e751525SEric Saxe 225*0e751525SEric Saxe void 226*0e751525SEric Saxe cpudrv_redefine_topspeed(void *ctx) 227*0e751525SEric Saxe { 228*0e751525SEric Saxe /* 229*0e751525SEric Saxe * This should never happen, unless ppm does not get loaded. 230*0e751525SEric Saxe */ 231*0e751525SEric Saxe if (cpupm_redefine_topspeed == NULL) { 232*0e751525SEric Saxe cmn_err(CE_WARN, "cpudrv_redefine_topspeed: " 233*0e751525SEric Saxe "cpupm_redefine_topspeed has not been initialized - " 234*0e751525SEric Saxe "ignoring notification"); 235*0e751525SEric Saxe return; 236*0e751525SEric Saxe } 237*0e751525SEric Saxe 238*0e751525SEric Saxe /* 239*0e751525SEric Saxe * ppm callback needs to handle redefinition for all CPUs in 240*0e751525SEric Saxe * the domain. 241*0e751525SEric Saxe */ 242*0e751525SEric Saxe (*cpupm_redefine_topspeed)(ctx); 243*0e751525SEric Saxe } 244*0e751525SEric Saxe 245*0e751525SEric Saxe boolean_t 246*0e751525SEric Saxe cpudrv_mach_init(cpudrv_devstate_t *cpudsp) 247*0e751525SEric Saxe { 248*0e751525SEric Saxe cpupm_mach_state_t *mach_state; 249*0e751525SEric Saxe 250*0e751525SEric Saxe mutex_enter(&cpu_lock); 251*0e751525SEric Saxe cpudsp->cp = cpu_get(cpudsp->cpu_id); 252*0e751525SEric Saxe mutex_exit(&cpu_lock); 253*0e751525SEric Saxe if (cpudsp->cp == NULL) { 254*0e751525SEric Saxe cmn_err(CE_WARN, "cpudrv_mach_pm_init: instance %d: " 255*0e751525SEric Saxe "can't get cpu_t", ddi_get_instance(cpudsp->dip)); 256*0e751525SEric Saxe return (B_FALSE); 257*0e751525SEric Saxe } 258*0e751525SEric Saxe 259*0e751525SEric Saxe mach_state = (cpupm_mach_state_t *) 260*0e751525SEric Saxe (cpudsp->cp->cpu_m.mcpu_pm_mach_state); 261*0e751525SEric Saxe mach_state->ms_dip = cpudsp->dip; 262*0e751525SEric Saxe return (B_TRUE); 263*0e751525SEric Saxe } 264*0e751525SEric Saxe 265*0e751525SEric Saxe uint_t 266*0e751525SEric Saxe cpudrv_get_speeds(cpudrv_devstate_t *cpudsp, int **speeds) 267*0e751525SEric Saxe { 268*0e751525SEric Saxe return (cpupm_get_speeds(cpudsp->cp, speeds)); 269*0e751525SEric Saxe } 270*0e751525SEric Saxe 271*0e751525SEric Saxe void 272*0e751525SEric Saxe cpudrv_free_speeds(int *speeds, uint_t nspeeds) 273*0e751525SEric Saxe { 274*0e751525SEric Saxe cpupm_free_speeds(speeds, nspeeds); 275*0e751525SEric Saxe } 276*0e751525SEric Saxe 277*0e751525SEric Saxe boolean_t 278*0e751525SEric Saxe cpudrv_power_ready(void) 279*0e751525SEric Saxe { 280*0e751525SEric Saxe return (cpupm_power_ready()); 281*0e751525SEric Saxe } 282*0e751525SEric Saxe 283*0e751525SEric Saxe /* ARGSUSED */ 284*0e751525SEric Saxe void 285*0e751525SEric Saxe cpudrv_set_supp_freqs(cpudrv_devstate_t *cpudsp) 286*0e751525SEric Saxe { 287*0e751525SEric Saxe } 288