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
cpudrv_change_speed(cpudrv_devstate_t * cpudsp,cpudrv_pm_spd_t * new_spd)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
cpudrv_get_cpu_id(dev_info_t * dip,processorid_t * cpu_id)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
cpudrv_is_enabled(cpudrv_devstate_t * cpudsp)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
cpudrv_is_governor_thread(cpudrv_pm_t * cpupm)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
cpudrv_set_topspeed(void * ctx,int plat_level)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
cpudrv_get_topspeed(void * ctx)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
cpudrv_notify_handler(ACPI_HANDLE obj,UINT32 val,void * ctx)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
cpudrv_install_notify_handler(cpudrv_devstate_t * cpudsp)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
cpudrv_uninstall_notify_handler(cpudrv_devstate_t * cpudsp)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
cpudrv_redefine_topspeed(void * ctx)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
cpudrv_mach_init(cpudrv_devstate_t * cpudsp)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
cpudrv_mach_fini(cpudrv_devstate_t * cpudsp)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
cpudrv_get_speeds(cpudrv_devstate_t * cpudsp,int ** speeds)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
cpudrv_free_speeds(int * speeds,uint_t nspeeds)349 cpudrv_free_speeds(int *speeds, uint_t nspeeds)
350 {
351 cpupm_free_speeds(speeds, nspeeds);
352 }
353
354 boolean_t
cpudrv_power_ready(cpu_t * cp)355 cpudrv_power_ready(cpu_t *cp)
356 {
357 return (cpupm_power_ready(cp));
358 }
359
360 /* ARGSUSED */
361 void
cpudrv_set_supp_freqs(cpudrv_devstate_t * cpudsp)362 cpudrv_set_supp_freqs(cpudrv_devstate_t *cpudsp)
363 {
364 }
365