xref: /illumos-gate/usr/src/uts/i86pc/io/cpudrv_mach.c (revision 0e7515250c8395f368aa45fb9acae7c4f8f8b786)
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