xref: /onnv-gate/usr/src/uts/i86pc/io/cpudrv_mach.c (revision 10961:76b611950d1e)
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  */
2510488SMark.Haywood@Sun.COM /*
2610488SMark.Haywood@Sun.COM  * Copyright (c) 2009,  Intel Corporation.
2710488SMark.Haywood@Sun.COM  * All Rights Reserved.
2810488SMark.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
cpudrv_change_speed(cpudrv_devstate_t * cpudsp,cpudrv_pm_spd_t * new_spd)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
cpudrv_get_cpu_id(dev_info_t * dip,processorid_t * cpu_id)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
cpudrv_is_enabled(cpudrv_devstate_t * cpudsp)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
cpudrv_is_governor_thread(cpudrv_pm_t * cpupm)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
cpudrv_set_topspeed(void * ctx,int plat_level)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
cpudrv_get_topspeed(void * ctx)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
cpudrv_notify_handler(ACPI_HANDLE obj,UINT32 val,void * ctx)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
cpudrv_install_notify_handler(cpudrv_devstate_t * cpudsp)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
cpudrv_uninstall_notify_handler(cpudrv_devstate_t * cpudsp)24610488SMark.Haywood@Sun.COM cpudrv_uninstall_notify_handler(cpudrv_devstate_t *cpudsp)
24710488SMark.Haywood@Sun.COM {
24810488SMark.Haywood@Sun.COM 	cpu_t *cp = cpudsp->cp;
24910488SMark.Haywood@Sun.COM 	cpupm_notification_t *entry, **next;
25010488SMark.Haywood@Sun.COM 
25110488SMark.Haywood@Sun.COM 	ASSERT(cp != NULL);
25210488SMark.Haywood@Sun.COM 	cpupm_mach_state_t *mach_state =
25310488SMark.Haywood@Sun.COM 	    (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state;
25410488SMark.Haywood@Sun.COM 
25510488SMark.Haywood@Sun.COM 	mutex_enter(&mach_state->ms_lock);
25610488SMark.Haywood@Sun.COM 	if (mach_state->ms_handlers == NULL) {
25710488SMark.Haywood@Sun.COM 		mutex_exit(&mach_state->ms_lock);
25810488SMark.Haywood@Sun.COM 		return;
25910488SMark.Haywood@Sun.COM 	}
26010488SMark.Haywood@Sun.COM 
26110488SMark.Haywood@Sun.COM 	for (next = &mach_state->ms_handlers; (entry = *next) != NULL; ) {
26210488SMark.Haywood@Sun.COM 		if (entry->nq_handler != cpudrv_notify_handler) {
26310488SMark.Haywood@Sun.COM 			next = &entry->nq_next;
26410488SMark.Haywood@Sun.COM 			continue;
26510488SMark.Haywood@Sun.COM 		}
26610488SMark.Haywood@Sun.COM 		*next = entry->nq_next;
26710488SMark.Haywood@Sun.COM 		kmem_free(entry, sizeof (cpupm_notification_t));
26810488SMark.Haywood@Sun.COM 	}
26910488SMark.Haywood@Sun.COM 	mutex_exit(&mach_state->ms_lock);
27010488SMark.Haywood@Sun.COM }
27110488SMark.Haywood@Sun.COM 
27210488SMark.Haywood@Sun.COM void
cpudrv_redefine_topspeed(void * ctx)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
cpudrv_mach_init(cpudrv_devstate_t * cpudsp)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;
29610488SMark.Haywood@Sun.COM 	int topspeed;
2978906SEric.Saxe@Sun.COM 
29810488SMark.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;
30310488SMark.Haywood@Sun.COM 	/*
30410488SMark.Haywood@Sun.COM 	 * allocate ppm CPU domain and initialize the topspeed
30510488SMark.Haywood@Sun.COM 	 * only if P-states are enabled.
30610488SMark.Haywood@Sun.COM 	 */
30710488SMark.Haywood@Sun.COM 	if (cpudrv_power_ready(cpudsp->cp)) {
30810488SMark.Haywood@Sun.COM 		(*cpupm_ppm_alloc_pstate_domains)(cpudsp->cp);
30910488SMark.Haywood@Sun.COM 		topspeed = cpudrv_get_topspeed(cpudsp->dip);
31010488SMark.Haywood@Sun.COM 		cpudrv_set_topspeed(cpudsp->dip, topspeed);
31110488SMark.Haywood@Sun.COM 	}
31210488SMark.Haywood@Sun.COM 
31310488SMark.Haywood@Sun.COM 	return (B_TRUE);
31410488SMark.Haywood@Sun.COM }
31510488SMark.Haywood@Sun.COM 
31610488SMark.Haywood@Sun.COM boolean_t
cpudrv_mach_fini(cpudrv_devstate_t * cpudsp)31710488SMark.Haywood@Sun.COM cpudrv_mach_fini(cpudrv_devstate_t *cpudsp)
31810488SMark.Haywood@Sun.COM {
31910488SMark.Haywood@Sun.COM 	/*
32010488SMark.Haywood@Sun.COM 	 * return TRUE if cpu pointer is NULL
32110488SMark.Haywood@Sun.COM 	 */
32210488SMark.Haywood@Sun.COM 	if (cpudsp->cp == NULL)
32310488SMark.Haywood@Sun.COM 		return (B_TRUE);
32410488SMark.Haywood@Sun.COM 	/*
32510488SMark.Haywood@Sun.COM 	 * free ppm cpu pstate domains only if
32610488SMark.Haywood@Sun.COM 	 * P-states are enabled
32710488SMark.Haywood@Sun.COM 	 */
32810488SMark.Haywood@Sun.COM 	if (cpudrv_power_ready(cpudsp->cp)) {
32910488SMark.Haywood@Sun.COM 		(*cpupm_ppm_free_pstate_domains)(cpudsp->cp);
33010488SMark.Haywood@Sun.COM 	}
33110488SMark.Haywood@Sun.COM 
3328906SEric.Saxe@Sun.COM 	return (B_TRUE);
3338906SEric.Saxe@Sun.COM }
3348906SEric.Saxe@Sun.COM 
3358906SEric.Saxe@Sun.COM uint_t
cpudrv_get_speeds(cpudrv_devstate_t * cpudsp,int ** speeds)3368906SEric.Saxe@Sun.COM cpudrv_get_speeds(cpudrv_devstate_t *cpudsp, int **speeds)
3378906SEric.Saxe@Sun.COM {
338*10961Saubrey.li@intel.com 	/*
339*10961Saubrey.li@intel.com 	 * return nspeeds = 0 if can't get cpu_t
340*10961Saubrey.li@intel.com 	 */
341*10961Saubrey.li@intel.com 	if (cpudrv_get_cpu(cpudsp) != DDI_SUCCESS)
342*10961Saubrey.li@intel.com 		return (0);
343*10961Saubrey.li@intel.com 
3448906SEric.Saxe@Sun.COM 	return (cpupm_get_speeds(cpudsp->cp, speeds));
3458906SEric.Saxe@Sun.COM }
3468906SEric.Saxe@Sun.COM 
3478906SEric.Saxe@Sun.COM void
cpudrv_free_speeds(int * speeds,uint_t nspeeds)3488906SEric.Saxe@Sun.COM cpudrv_free_speeds(int *speeds, uint_t nspeeds)
3498906SEric.Saxe@Sun.COM {
3508906SEric.Saxe@Sun.COM 	cpupm_free_speeds(speeds, nspeeds);
3518906SEric.Saxe@Sun.COM }
3528906SEric.Saxe@Sun.COM 
3538906SEric.Saxe@Sun.COM boolean_t
cpudrv_power_ready(cpu_t * cp)35410488SMark.Haywood@Sun.COM cpudrv_power_ready(cpu_t *cp)
3558906SEric.Saxe@Sun.COM {
35610488SMark.Haywood@Sun.COM 	return (cpupm_power_ready(cp));
3578906SEric.Saxe@Sun.COM }
3588906SEric.Saxe@Sun.COM 
3598906SEric.Saxe@Sun.COM /* ARGSUSED */
3608906SEric.Saxe@Sun.COM void
cpudrv_set_supp_freqs(cpudrv_devstate_t * cpudsp)3618906SEric.Saxe@Sun.COM cpudrv_set_supp_freqs(cpudrv_devstate_t *cpudsp)
3628906SEric.Saxe@Sun.COM {
3638906SEric.Saxe@Sun.COM }
364