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 */ 25*10488SMark.Haywood@Sun.COM /* 26*10488SMark.Haywood@Sun.COM * Copyright (c) 2009, Intel Corporation. 27*10488SMark.Haywood@Sun.COM * All Rights Reserved. 28*10488SMark.Haywood@Sun.COM */ 298906SEric.Saxe@Sun.COM 308906SEric.Saxe@Sun.COM /* 318906SEric.Saxe@Sun.COM * CPU power management driver support for i86pc. 328906SEric.Saxe@Sun.COM */ 338906SEric.Saxe@Sun.COM 348906SEric.Saxe@Sun.COM #include <sys/ddi.h> 358906SEric.Saxe@Sun.COM #include <sys/sunddi.h> 368906SEric.Saxe@Sun.COM #include <sys/cpupm.h> 378906SEric.Saxe@Sun.COM #include <sys/cpudrv_mach.h> 388906SEric.Saxe@Sun.COM #include <sys/machsystm.h> 398906SEric.Saxe@Sun.COM #include <sys/cpu_pm.h> 408906SEric.Saxe@Sun.COM #include <sys/cpuvar.h> 418906SEric.Saxe@Sun.COM #include <sys/sdt.h> 428906SEric.Saxe@Sun.COM #include <sys/cpu_idle.h> 438906SEric.Saxe@Sun.COM 448906SEric.Saxe@Sun.COM /* 458906SEric.Saxe@Sun.COM * Note that our driver numbers the power levels from lowest to 468906SEric.Saxe@Sun.COM * highest starting at 1 (i.e., the lowest power level is 1 and 478906SEric.Saxe@Sun.COM * the highest power level is cpupm->num_spd). The x86 modules get 488906SEric.Saxe@Sun.COM * their power levels from ACPI which numbers power levels from 498906SEric.Saxe@Sun.COM * highest to lowest starting at 0 (i.e., the lowest power level 508906SEric.Saxe@Sun.COM * is (cpupm->num_spd - 1) and the highest power level is 0). So to 518906SEric.Saxe@Sun.COM * map one of our driver power levels to one understood by ACPI we 528906SEric.Saxe@Sun.COM * simply subtract our driver power level from cpupm->num_spd. Likewise, 538906SEric.Saxe@Sun.COM * to map an ACPI power level to the proper driver power level, we 548906SEric.Saxe@Sun.COM * subtract the ACPI power level from cpupm->num_spd. 558906SEric.Saxe@Sun.COM */ 568906SEric.Saxe@Sun.COM #define PM_2_PLAT_LEVEL(cpupm, pm_level) (cpupm->num_spd - pm_level) 578906SEric.Saxe@Sun.COM #define PLAT_2_PM_LEVEL(cpupm, plat_level) (cpupm->num_spd - plat_level) 588906SEric.Saxe@Sun.COM 598906SEric.Saxe@Sun.COM /* 608906SEric.Saxe@Sun.COM * Change CPU speed using interface provided by module. 618906SEric.Saxe@Sun.COM */ 628906SEric.Saxe@Sun.COM int 638906SEric.Saxe@Sun.COM cpudrv_change_speed(cpudrv_devstate_t *cpudsp, cpudrv_pm_spd_t *new_spd) 648906SEric.Saxe@Sun.COM { 658906SEric.Saxe@Sun.COM cpu_t *cp = cpudsp->cp; 668906SEric.Saxe@Sun.COM cpupm_mach_state_t *mach_state = 678906SEric.Saxe@Sun.COM (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 688906SEric.Saxe@Sun.COM cpudrv_pm_t *cpupm; 698906SEric.Saxe@Sun.COM cpuset_t set; 708906SEric.Saxe@Sun.COM uint32_t plat_level; 718906SEric.Saxe@Sun.COM 728906SEric.Saxe@Sun.COM if (!(mach_state->ms_caps & CPUPM_P_STATES)) 738906SEric.Saxe@Sun.COM return (DDI_FAILURE); 748906SEric.Saxe@Sun.COM ASSERT(mach_state->ms_pstate.cma_ops != NULL); 758906SEric.Saxe@Sun.COM cpupm = &(cpudsp->cpudrv_pm); 768906SEric.Saxe@Sun.COM plat_level = PM_2_PLAT_LEVEL(cpupm, new_spd->pm_level); 778906SEric.Saxe@Sun.COM CPUSET_ONLY(set, cp->cpu_id); 788906SEric.Saxe@Sun.COM mach_state->ms_pstate.cma_ops->cpus_change(set, plat_level); 798906SEric.Saxe@Sun.COM 808906SEric.Saxe@Sun.COM return (DDI_SUCCESS); 818906SEric.Saxe@Sun.COM } 828906SEric.Saxe@Sun.COM 838906SEric.Saxe@Sun.COM /* 848906SEric.Saxe@Sun.COM * Determine the cpu_id for the CPU device. 858906SEric.Saxe@Sun.COM */ 868906SEric.Saxe@Sun.COM boolean_t 878906SEric.Saxe@Sun.COM cpudrv_get_cpu_id(dev_info_t *dip, processorid_t *cpu_id) 888906SEric.Saxe@Sun.COM { 898906SEric.Saxe@Sun.COM return ((*cpu_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 908906SEric.Saxe@Sun.COM DDI_PROP_DONTPASS, "reg", -1)) != -1); 918906SEric.Saxe@Sun.COM 928906SEric.Saxe@Sun.COM } 938906SEric.Saxe@Sun.COM 948906SEric.Saxe@Sun.COM boolean_t 958906SEric.Saxe@Sun.COM cpudrv_is_enabled(cpudrv_devstate_t *cpudsp) 968906SEric.Saxe@Sun.COM { 978906SEric.Saxe@Sun.COM cpupm_mach_state_t *mach_state; 988906SEric.Saxe@Sun.COM 998906SEric.Saxe@Sun.COM if (!cpupm_is_enabled(CPUPM_P_STATES) || !cpudrv_enabled) 1008906SEric.Saxe@Sun.COM return (B_FALSE); 1018906SEric.Saxe@Sun.COM 1028906SEric.Saxe@Sun.COM /* 1038906SEric.Saxe@Sun.COM * Only check the instance specific setting it exists. 1048906SEric.Saxe@Sun.COM */ 1058906SEric.Saxe@Sun.COM if (cpudsp != NULL && cpudsp->cp != NULL && 1068906SEric.Saxe@Sun.COM cpudsp->cp->cpu_m.mcpu_pm_mach_state != NULL) { 1078906SEric.Saxe@Sun.COM mach_state = 1088906SEric.Saxe@Sun.COM (cpupm_mach_state_t *)cpudsp->cp->cpu_m.mcpu_pm_mach_state; 1098906SEric.Saxe@Sun.COM return (mach_state->ms_caps & CPUPM_P_STATES); 1108906SEric.Saxe@Sun.COM } 1118906SEric.Saxe@Sun.COM 1128906SEric.Saxe@Sun.COM return (B_TRUE); 1138906SEric.Saxe@Sun.COM } 1148906SEric.Saxe@Sun.COM 1158906SEric.Saxe@Sun.COM /* 1168906SEric.Saxe@Sun.COM * Is the current thread the thread that is handling the 1178906SEric.Saxe@Sun.COM * PPC change notification? 1188906SEric.Saxe@Sun.COM */ 1198906SEric.Saxe@Sun.COM boolean_t 1208906SEric.Saxe@Sun.COM cpudrv_is_governor_thread(cpudrv_pm_t *cpupm) 1218906SEric.Saxe@Sun.COM { 1228906SEric.Saxe@Sun.COM return (curthread == cpupm->pm_governor_thread); 1238906SEric.Saxe@Sun.COM } 1248906SEric.Saxe@Sun.COM 1258906SEric.Saxe@Sun.COM /* 1268906SEric.Saxe@Sun.COM * This routine changes the top speed to which the CPUs can transition by: 1278906SEric.Saxe@Sun.COM * 1288906SEric.Saxe@Sun.COM * - Resetting the up_spd for all speeds lower than the new top speed 1298906SEric.Saxe@Sun.COM * to point to the new top speed. 1308906SEric.Saxe@Sun.COM * - Updating the framework with a new "normal" (maximum power) for this 1318906SEric.Saxe@Sun.COM * device. 1328906SEric.Saxe@Sun.COM */ 1338906SEric.Saxe@Sun.COM void 1348906SEric.Saxe@Sun.COM cpudrv_set_topspeed(void *ctx, int plat_level) 1358906SEric.Saxe@Sun.COM { 1368906SEric.Saxe@Sun.COM cpudrv_devstate_t *cpudsp; 1378906SEric.Saxe@Sun.COM cpudrv_pm_t *cpupm; 1388906SEric.Saxe@Sun.COM cpudrv_pm_spd_t *spd; 1398906SEric.Saxe@Sun.COM cpudrv_pm_spd_t *top_spd; 1408906SEric.Saxe@Sun.COM dev_info_t *dip; 1418906SEric.Saxe@Sun.COM int pm_level; 1428906SEric.Saxe@Sun.COM int instance; 1438906SEric.Saxe@Sun.COM int i; 1448906SEric.Saxe@Sun.COM 1458906SEric.Saxe@Sun.COM dip = ctx; 1468906SEric.Saxe@Sun.COM instance = ddi_get_instance(dip); 1478906SEric.Saxe@Sun.COM cpudsp = ddi_get_soft_state(cpudrv_state, instance); 1488906SEric.Saxe@Sun.COM ASSERT(cpudsp != NULL); 1498906SEric.Saxe@Sun.COM 1508906SEric.Saxe@Sun.COM mutex_enter(&cpudsp->lock); 1518906SEric.Saxe@Sun.COM cpupm = &(cpudsp->cpudrv_pm); 1528906SEric.Saxe@Sun.COM pm_level = PLAT_2_PM_LEVEL(cpupm, plat_level); 1538906SEric.Saxe@Sun.COM for (i = 0, spd = cpupm->head_spd; spd; i++, spd = spd->down_spd) { 1548906SEric.Saxe@Sun.COM /* 1558906SEric.Saxe@Sun.COM * Don't mess with speeds that are higher than the new 1568906SEric.Saxe@Sun.COM * top speed. They should be out of range anyway. 1578906SEric.Saxe@Sun.COM */ 1588906SEric.Saxe@Sun.COM if (spd->pm_level > pm_level) 1598906SEric.Saxe@Sun.COM continue; 1608906SEric.Saxe@Sun.COM /* 1618906SEric.Saxe@Sun.COM * This is the new top speed. 1628906SEric.Saxe@Sun.COM */ 1638906SEric.Saxe@Sun.COM if (spd->pm_level == pm_level) 1648906SEric.Saxe@Sun.COM top_spd = spd; 1658906SEric.Saxe@Sun.COM 1668906SEric.Saxe@Sun.COM spd->up_spd = top_spd; 1678906SEric.Saxe@Sun.COM } 1688906SEric.Saxe@Sun.COM cpupm->top_spd = top_spd; 1698906SEric.Saxe@Sun.COM 1708906SEric.Saxe@Sun.COM cpupm->pm_governor_thread = curthread; 1718906SEric.Saxe@Sun.COM 1728906SEric.Saxe@Sun.COM mutex_exit(&cpudsp->lock); 1738906SEric.Saxe@Sun.COM 1748906SEric.Saxe@Sun.COM (void) pm_update_maxpower(dip, 0, top_spd->pm_level); 1758906SEric.Saxe@Sun.COM } 1768906SEric.Saxe@Sun.COM 1778906SEric.Saxe@Sun.COM /* 1788906SEric.Saxe@Sun.COM * This routine reads the ACPI _PPC object. It's accessed as a callback 1798906SEric.Saxe@Sun.COM * by the ppm driver whenever a _PPC change notification is received. 1808906SEric.Saxe@Sun.COM */ 1818906SEric.Saxe@Sun.COM int 1828906SEric.Saxe@Sun.COM cpudrv_get_topspeed(void *ctx) 1838906SEric.Saxe@Sun.COM { 1848906SEric.Saxe@Sun.COM cpu_t *cp; 1858906SEric.Saxe@Sun.COM cpudrv_devstate_t *cpudsp; 1868906SEric.Saxe@Sun.COM dev_info_t *dip; 1878906SEric.Saxe@Sun.COM int instance; 1888906SEric.Saxe@Sun.COM int plat_level; 1898906SEric.Saxe@Sun.COM 1908906SEric.Saxe@Sun.COM dip = ctx; 1918906SEric.Saxe@Sun.COM instance = ddi_get_instance(dip); 1928906SEric.Saxe@Sun.COM cpudsp = ddi_get_soft_state(cpudrv_state, instance); 1938906SEric.Saxe@Sun.COM ASSERT(cpudsp != NULL); 1948906SEric.Saxe@Sun.COM cp = cpudsp->cp; 1958906SEric.Saxe@Sun.COM plat_level = cpupm_get_top_speed(cp); 1968906SEric.Saxe@Sun.COM 1978906SEric.Saxe@Sun.COM return (plat_level); 1988906SEric.Saxe@Sun.COM } 1998906SEric.Saxe@Sun.COM 2008906SEric.Saxe@Sun.COM 2018906SEric.Saxe@Sun.COM /* 2028906SEric.Saxe@Sun.COM * This notification handler is called whenever the ACPI _PPC 2038906SEric.Saxe@Sun.COM * object changes. The _PPC is a sort of governor on power levels. 2048906SEric.Saxe@Sun.COM * It sets an upper threshold on which, _PSS defined, power levels 2058906SEric.Saxe@Sun.COM * are usuable. The _PPC value is dynamic and may change as properties 2068906SEric.Saxe@Sun.COM * (i.e., thermal or AC source) of the system change. 2078906SEric.Saxe@Sun.COM */ 2088906SEric.Saxe@Sun.COM /* ARGSUSED */ 2098906SEric.Saxe@Sun.COM static void 2108906SEric.Saxe@Sun.COM cpudrv_notify_handler(ACPI_HANDLE obj, UINT32 val, void *ctx) 2118906SEric.Saxe@Sun.COM { 2129040SMark.Haywood@Sun.COM cpu_t *cp; 2139040SMark.Haywood@Sun.COM cpupm_mach_state_t *mach_state; 2149040SMark.Haywood@Sun.COM cpudrv_devstate_t *cpudsp; 2159040SMark.Haywood@Sun.COM dev_info_t *dip; 2169040SMark.Haywood@Sun.COM int instance; 2179040SMark.Haywood@Sun.COM extern pm_cpupm_t cpupm; 2189040SMark.Haywood@Sun.COM 2199040SMark.Haywood@Sun.COM dip = ctx; 2209040SMark.Haywood@Sun.COM instance = ddi_get_instance(dip); 2219040SMark.Haywood@Sun.COM cpudsp = ddi_get_soft_state(cpudrv_state, instance); 2229040SMark.Haywood@Sun.COM if (cpudsp == NULL) 2239040SMark.Haywood@Sun.COM return; 2249040SMark.Haywood@Sun.COM cp = cpudsp->cp; 2259040SMark.Haywood@Sun.COM mach_state = (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 2269040SMark.Haywood@Sun.COM if (mach_state == NULL) 2279040SMark.Haywood@Sun.COM return; 2288906SEric.Saxe@Sun.COM 2298906SEric.Saxe@Sun.COM /* 2308906SEric.Saxe@Sun.COM * We only handle _PPC change notifications. 2318906SEric.Saxe@Sun.COM */ 2329040SMark.Haywood@Sun.COM if (!PM_EVENT_CPUPM && val == CPUPM_PPC_CHANGE_NOTIFICATION && 2339040SMark.Haywood@Sun.COM mach_state->ms_caps & CPUPM_P_STATES) 2348906SEric.Saxe@Sun.COM cpudrv_redefine_topspeed(ctx); 2358906SEric.Saxe@Sun.COM } 2368906SEric.Saxe@Sun.COM 2378906SEric.Saxe@Sun.COM void 2388906SEric.Saxe@Sun.COM cpudrv_install_notify_handler(cpudrv_devstate_t *cpudsp) 2398906SEric.Saxe@Sun.COM { 2408906SEric.Saxe@Sun.COM cpu_t *cp = cpudsp->cp; 2418906SEric.Saxe@Sun.COM cpupm_add_notify_handler(cp, cpudrv_notify_handler, 2428906SEric.Saxe@Sun.COM cpudsp->dip); 2438906SEric.Saxe@Sun.COM } 2448906SEric.Saxe@Sun.COM 2458906SEric.Saxe@Sun.COM void 246*10488SMark.Haywood@Sun.COM cpudrv_uninstall_notify_handler(cpudrv_devstate_t *cpudsp) 247*10488SMark.Haywood@Sun.COM { 248*10488SMark.Haywood@Sun.COM cpu_t *cp = cpudsp->cp; 249*10488SMark.Haywood@Sun.COM cpupm_notification_t *entry, **next; 250*10488SMark.Haywood@Sun.COM 251*10488SMark.Haywood@Sun.COM ASSERT(cp != NULL); 252*10488SMark.Haywood@Sun.COM cpupm_mach_state_t *mach_state = 253*10488SMark.Haywood@Sun.COM (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; 254*10488SMark.Haywood@Sun.COM 255*10488SMark.Haywood@Sun.COM mutex_enter(&mach_state->ms_lock); 256*10488SMark.Haywood@Sun.COM if (mach_state->ms_handlers == NULL) { 257*10488SMark.Haywood@Sun.COM mutex_exit(&mach_state->ms_lock); 258*10488SMark.Haywood@Sun.COM return; 259*10488SMark.Haywood@Sun.COM } 260*10488SMark.Haywood@Sun.COM 261*10488SMark.Haywood@Sun.COM for (next = &mach_state->ms_handlers; (entry = *next) != NULL; ) { 262*10488SMark.Haywood@Sun.COM if (entry->nq_handler != cpudrv_notify_handler) { 263*10488SMark.Haywood@Sun.COM next = &entry->nq_next; 264*10488SMark.Haywood@Sun.COM continue; 265*10488SMark.Haywood@Sun.COM } 266*10488SMark.Haywood@Sun.COM *next = entry->nq_next; 267*10488SMark.Haywood@Sun.COM kmem_free(entry, sizeof (cpupm_notification_t)); 268*10488SMark.Haywood@Sun.COM } 269*10488SMark.Haywood@Sun.COM mutex_exit(&mach_state->ms_lock); 270*10488SMark.Haywood@Sun.COM } 271*10488SMark.Haywood@Sun.COM 272*10488SMark.Haywood@Sun.COM void 2738906SEric.Saxe@Sun.COM cpudrv_redefine_topspeed(void *ctx) 2748906SEric.Saxe@Sun.COM { 2758906SEric.Saxe@Sun.COM /* 2768906SEric.Saxe@Sun.COM * This should never happen, unless ppm does not get loaded. 2778906SEric.Saxe@Sun.COM */ 2788906SEric.Saxe@Sun.COM if (cpupm_redefine_topspeed == NULL) { 2798906SEric.Saxe@Sun.COM cmn_err(CE_WARN, "cpudrv_redefine_topspeed: " 2808906SEric.Saxe@Sun.COM "cpupm_redefine_topspeed has not been initialized - " 2818906SEric.Saxe@Sun.COM "ignoring notification"); 2828906SEric.Saxe@Sun.COM return; 2838906SEric.Saxe@Sun.COM } 2848906SEric.Saxe@Sun.COM 2858906SEric.Saxe@Sun.COM /* 2868906SEric.Saxe@Sun.COM * ppm callback needs to handle redefinition for all CPUs in 2878906SEric.Saxe@Sun.COM * the domain. 2888906SEric.Saxe@Sun.COM */ 2898906SEric.Saxe@Sun.COM (*cpupm_redefine_topspeed)(ctx); 2908906SEric.Saxe@Sun.COM } 2918906SEric.Saxe@Sun.COM 2928906SEric.Saxe@Sun.COM boolean_t 2938906SEric.Saxe@Sun.COM cpudrv_mach_init(cpudrv_devstate_t *cpudsp) 2948906SEric.Saxe@Sun.COM { 2958906SEric.Saxe@Sun.COM cpupm_mach_state_t *mach_state; 296*10488SMark.Haywood@Sun.COM int topspeed; 2978906SEric.Saxe@Sun.COM 298*10488SMark.Haywood@Sun.COM ASSERT(cpudsp->cp); 2998906SEric.Saxe@Sun.COM 3008906SEric.Saxe@Sun.COM mach_state = (cpupm_mach_state_t *) 3018906SEric.Saxe@Sun.COM (cpudsp->cp->cpu_m.mcpu_pm_mach_state); 3028906SEric.Saxe@Sun.COM mach_state->ms_dip = cpudsp->dip; 303*10488SMark.Haywood@Sun.COM /* 304*10488SMark.Haywood@Sun.COM * allocate ppm CPU domain and initialize the topspeed 305*10488SMark.Haywood@Sun.COM * only if P-states are enabled. 306*10488SMark.Haywood@Sun.COM */ 307*10488SMark.Haywood@Sun.COM if (cpudrv_power_ready(cpudsp->cp)) { 308*10488SMark.Haywood@Sun.COM (*cpupm_ppm_alloc_pstate_domains)(cpudsp->cp); 309*10488SMark.Haywood@Sun.COM topspeed = cpudrv_get_topspeed(cpudsp->dip); 310*10488SMark.Haywood@Sun.COM cpudrv_set_topspeed(cpudsp->dip, topspeed); 311*10488SMark.Haywood@Sun.COM } 312*10488SMark.Haywood@Sun.COM 313*10488SMark.Haywood@Sun.COM return (B_TRUE); 314*10488SMark.Haywood@Sun.COM } 315*10488SMark.Haywood@Sun.COM 316*10488SMark.Haywood@Sun.COM boolean_t 317*10488SMark.Haywood@Sun.COM cpudrv_mach_fini(cpudrv_devstate_t *cpudsp) 318*10488SMark.Haywood@Sun.COM { 319*10488SMark.Haywood@Sun.COM /* 320*10488SMark.Haywood@Sun.COM * return TRUE if cpu pointer is NULL 321*10488SMark.Haywood@Sun.COM */ 322*10488SMark.Haywood@Sun.COM if (cpudsp->cp == NULL) 323*10488SMark.Haywood@Sun.COM return (B_TRUE); 324*10488SMark.Haywood@Sun.COM /* 325*10488SMark.Haywood@Sun.COM * free ppm cpu pstate domains only if 326*10488SMark.Haywood@Sun.COM * P-states are enabled 327*10488SMark.Haywood@Sun.COM */ 328*10488SMark.Haywood@Sun.COM if (cpudrv_power_ready(cpudsp->cp)) { 329*10488SMark.Haywood@Sun.COM (*cpupm_ppm_free_pstate_domains)(cpudsp->cp); 330*10488SMark.Haywood@Sun.COM } 331*10488SMark.Haywood@Sun.COM 3328906SEric.Saxe@Sun.COM return (B_TRUE); 3338906SEric.Saxe@Sun.COM } 3348906SEric.Saxe@Sun.COM 3358906SEric.Saxe@Sun.COM uint_t 3368906SEric.Saxe@Sun.COM cpudrv_get_speeds(cpudrv_devstate_t *cpudsp, int **speeds) 3378906SEric.Saxe@Sun.COM { 3388906SEric.Saxe@Sun.COM return (cpupm_get_speeds(cpudsp->cp, speeds)); 3398906SEric.Saxe@Sun.COM } 3408906SEric.Saxe@Sun.COM 3418906SEric.Saxe@Sun.COM void 3428906SEric.Saxe@Sun.COM cpudrv_free_speeds(int *speeds, uint_t nspeeds) 3438906SEric.Saxe@Sun.COM { 3448906SEric.Saxe@Sun.COM cpupm_free_speeds(speeds, nspeeds); 3458906SEric.Saxe@Sun.COM } 3468906SEric.Saxe@Sun.COM 3478906SEric.Saxe@Sun.COM boolean_t 348*10488SMark.Haywood@Sun.COM cpudrv_power_ready(cpu_t *cp) 3498906SEric.Saxe@Sun.COM { 350*10488SMark.Haywood@Sun.COM return (cpupm_power_ready(cp)); 3518906SEric.Saxe@Sun.COM } 3528906SEric.Saxe@Sun.COM 3538906SEric.Saxe@Sun.COM /* ARGSUSED */ 3548906SEric.Saxe@Sun.COM void 3558906SEric.Saxe@Sun.COM cpudrv_set_supp_freqs(cpudrv_devstate_t *cpudsp) 3568906SEric.Saxe@Sun.COM { 3578906SEric.Saxe@Sun.COM } 358