Print this page
XXXX cpudrv attach is racy
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/cpudrv.c
+++ new/usr/src/uts/common/io/cpudrv.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25 /*
26 26 * Copyright (c) 2009, Intel Corporation.
27 27 * All Rights Reserved.
28 28 */
29 29
30 30 /*
31 31 * CPU Device driver. The driver is not DDI-compliant.
32 32 *
33 33 * The driver supports following features:
34 34 * - Power management.
35 35 */
36 36
37 37 #include <sys/types.h>
38 38 #include <sys/param.h>
39 39 #include <sys/errno.h>
40 40 #include <sys/modctl.h>
41 41 #include <sys/kmem.h>
42 42 #include <sys/conf.h>
43 43 #include <sys/cmn_err.h>
44 44 #include <sys/stat.h>
45 45 #include <sys/debug.h>
46 46 #include <sys/systm.h>
47 47 #include <sys/ddi.h>
48 48 #include <sys/sunddi.h>
49 49 #include <sys/sdt.h>
50 50 #include <sys/epm.h>
51 51 #include <sys/machsystm.h>
52 52 #include <sys/x_call.h>
53 53 #include <sys/cpudrv_mach.h>
54 54 #include <sys/msacct.h>
55 55
56 56 /*
57 57 * CPU power management
58 58 *
59 59 * The supported power saving model is to slow down the CPU (on SPARC by
60 60 * dividing the CPU clock and on x86 by dropping down a P-state).
61 61 * Periodically we determine the amount of time the CPU is running
62 62 * idle thread and threads in user mode during the last quantum. If the idle
63 63 * thread was running less than its low water mark for current speed for
64 64 * number of consecutive sampling periods, or number of running threads in
65 65 * user mode are above its high water mark, we arrange to go to the higher
66 66 * speed. If the idle thread was running more than its high water mark without
67 67 * dropping a number of consecutive times below the mark, and number of threads
68 68 * running in user mode are below its low water mark, we arrange to go to the
69 69 * next lower speed. While going down, we go through all the speeds. While
70 70 * going up we go to the maximum speed to minimize impact on the user, but have
71 71 * provisions in the driver to go to other speeds.
72 72 *
73 73 * The driver does not have knowledge of a particular implementation of this
74 74 * scheme and will work with all CPUs supporting this model. On SPARC, the
75 75 * driver determines supported speeds by looking at 'clock-divisors' property
76 76 * created by OBP. On x86, the driver retrieves the supported speeds from
77 77 * ACPI.
78 78 */
79 79
80 80 /*
81 81 * Configuration function prototypes and data structures
82 82 */
83 83 static int cpudrv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
84 84 static int cpudrv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
85 85 static int cpudrv_power(dev_info_t *dip, int comp, int level);
86 86
87 87 struct dev_ops cpudrv_ops = {
88 88 DEVO_REV, /* rev */
89 89 0, /* refcnt */
90 90 nodev, /* getinfo */
91 91 nulldev, /* identify */
92 92 nulldev, /* probe */
93 93 cpudrv_attach, /* attach */
94 94 cpudrv_detach, /* detach */
95 95 nodev, /* reset */
96 96 (struct cb_ops *)NULL, /* cb_ops */
97 97 (struct bus_ops *)NULL, /* bus_ops */
98 98 cpudrv_power, /* power */
99 99 ddi_quiesce_not_needed, /* quiesce */
100 100 };
101 101
102 102 static struct modldrv modldrv = {
103 103 &mod_driverops, /* modops */
104 104 "CPU Driver", /* linkinfo */
105 105 &cpudrv_ops, /* dev_ops */
106 106 };
107 107
108 108 static struct modlinkage modlinkage = {
109 109 MODREV_1, /* rev */
110 110 &modldrv, /* linkage */
111 111 NULL
112 112 };
113 113
114 114 /*
115 115 * Function prototypes
116 116 */
117 117 static int cpudrv_init(cpudrv_devstate_t *cpudsp);
118 118 static void cpudrv_free(cpudrv_devstate_t *cpudsp);
119 119 static int cpudrv_comp_create(cpudrv_devstate_t *cpudsp);
120 120 static void cpudrv_monitor_disp(void *arg);
121 121 static void cpudrv_monitor(void *arg);
122 122
123 123 /*
124 124 * Driver global variables
125 125 */
126 126 uint_t cpudrv_debug = 0;
127 127 void *cpudrv_state;
128 128 static uint_t cpudrv_idle_hwm = CPUDRV_IDLE_HWM;
129 129 static uint_t cpudrv_idle_lwm = CPUDRV_IDLE_LWM;
130 130 static uint_t cpudrv_idle_buf_zone = CPUDRV_IDLE_BUF_ZONE;
131 131 static uint_t cpudrv_idle_bhwm_cnt_max = CPUDRV_IDLE_BHWM_CNT_MAX;
132 132 static uint_t cpudrv_idle_blwm_cnt_max = CPUDRV_IDLE_BLWM_CNT_MAX;
133 133 static uint_t cpudrv_user_hwm = CPUDRV_USER_HWM;
134 134
135 135 boolean_t cpudrv_enabled = B_TRUE;
136 136
137 137 /*
138 138 * cpudrv_direct_pm allows user applications to directly control the
139 139 * power state transitions (direct pm) without following the normal
140 140 * direct pm protocol. This is needed because the normal protocol
141 141 * requires that a device only be lowered when it is idle, and be
142 142 * brought up when it request to do so by calling pm_raise_power().
143 143 * Ignoring this protocol is harmless for CPU (other than speed).
144 144 * Moreover it might be the case that CPU is never idle or wants
145 145 * to be at higher speed because of the addition CPU cycles required
146 146 * to run the user application.
147 147 *
148 148 * The driver will still report idle/busy status to the framework. Although
149 149 * framework will ignore this information for direct pm devices and not
150 150 * try to bring them down when idle, user applications can still use this
151 151 * information if they wants.
152 152 *
153 153 * In the future, provide an ioctl to control setting of this mode. In
154 154 * that case, this variable should move to the state structure and
155 155 * be protected by the lock in the state structure.
156 156 */
157 157 int cpudrv_direct_pm = 0;
158 158
159 159 /*
160 160 * Arranges for the handler function to be called at the interval suitable
161 161 * for current speed.
162 162 */
163 163 #define CPUDRV_MONITOR_INIT(cpudsp) { \
164 164 if (cpudrv_is_enabled(cpudsp)) { \
165 165 ASSERT(mutex_owned(&(cpudsp)->lock)); \
166 166 (cpudsp)->cpudrv_pm.timeout_id = \
167 167 timeout(cpudrv_monitor_disp, \
168 168 (cpudsp), (((cpudsp)->cpudrv_pm.cur_spd == NULL) ? \
169 169 CPUDRV_QUANT_CNT_OTHR : \
170 170 (cpudsp)->cpudrv_pm.cur_spd->quant_cnt)); \
171 171 } \
172 172 }
173 173
174 174 /*
175 175 * Arranges for the handler function not to be called back.
176 176 */
177 177 #define CPUDRV_MONITOR_FINI(cpudsp) { \
178 178 timeout_id_t tmp_tid; \
179 179 ASSERT(mutex_owned(&(cpudsp)->lock)); \
180 180 tmp_tid = (cpudsp)->cpudrv_pm.timeout_id; \
181 181 (cpudsp)->cpudrv_pm.timeout_id = 0; \
182 182 mutex_exit(&(cpudsp)->lock); \
183 183 if (tmp_tid != 0) { \
184 184 (void) untimeout(tmp_tid); \
185 185 mutex_enter(&(cpudsp)->cpudrv_pm.timeout_lock); \
186 186 while ((cpudsp)->cpudrv_pm.timeout_count != 0) \
187 187 cv_wait(&(cpudsp)->cpudrv_pm.timeout_cv, \
188 188 &(cpudsp)->cpudrv_pm.timeout_lock); \
189 189 mutex_exit(&(cpudsp)->cpudrv_pm.timeout_lock); \
190 190 } \
191 191 mutex_enter(&(cpudsp)->lock); \
192 192 }
193 193
194 194 int
195 195 _init(void)
196 196 {
197 197 int error;
198 198
199 199 DPRINTF(D_INIT, (" _init: function called\n"));
200 200 if ((error = ddi_soft_state_init(&cpudrv_state,
201 201 sizeof (cpudrv_devstate_t), 0)) != 0) {
202 202 return (error);
203 203 }
204 204
205 205 if ((error = mod_install(&modlinkage)) != 0) {
206 206 ddi_soft_state_fini(&cpudrv_state);
207 207 }
208 208
209 209 /*
210 210 * Callbacks used by the PPM driver.
211 211 */
212 212 CPUDRV_SET_PPM_CALLBACKS();
213 213 return (error);
214 214 }
215 215
216 216 int
217 217 _fini(void)
218 218 {
219 219 int error;
220 220
221 221 DPRINTF(D_FINI, (" _fini: function called\n"));
222 222 if ((error = mod_remove(&modlinkage)) == 0) {
223 223 ddi_soft_state_fini(&cpudrv_state);
224 224 }
225 225
226 226 return (error);
227 227 }
228 228
229 229 int
230 230 _info(struct modinfo *modinfop)
231 231 {
232 232 return (mod_info(&modlinkage, modinfop));
233 233 }
234 234
235 235 /*
236 236 * Driver attach(9e) entry point.
237 237 */
238 238 static int
239 239 cpudrv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
240 240 {
241 241 int instance;
242 242 cpudrv_devstate_t *cpudsp;
243 243
244 244 instance = ddi_get_instance(dip);
245 245
246 246 switch (cmd) {
247 247 case DDI_ATTACH:
248 248 DPRINTF(D_ATTACH, ("cpudrv_attach: instance %d: "
249 249 "DDI_ATTACH called\n", instance));
250 250 if (!cpudrv_is_enabled(NULL))
251 251 return (DDI_FAILURE);
252 252 if (ddi_soft_state_zalloc(cpudrv_state, instance) !=
253 253 DDI_SUCCESS) {
254 254 cmn_err(CE_WARN, "cpudrv_attach: instance %d: "
255 255 "can't allocate state", instance);
256 256 cpudrv_enabled = B_FALSE;
257 257 return (DDI_FAILURE);
258 258 }
259 259 if ((cpudsp = ddi_get_soft_state(cpudrv_state, instance)) ==
260 260 NULL) {
261 261 cmn_err(CE_WARN, "cpudrv_attach: instance %d: "
262 262 "can't get state", instance);
263 263 ddi_soft_state_free(cpudrv_state, instance);
264 264 cpudrv_enabled = B_FALSE;
265 265 return (DDI_FAILURE);
266 266 }
267 267 cpudsp->dip = dip;
268 268
269 269 /*
↓ open down ↓ |
269 lines elided |
↑ open up ↑ |
270 270 * Find CPU number for this dev_info node.
271 271 */
272 272 if (!cpudrv_get_cpu_id(dip, &(cpudsp->cpu_id))) {
273 273 cmn_err(CE_WARN, "cpudrv_attach: instance %d: "
274 274 "can't convert dip to cpu_id", instance);
275 275 ddi_soft_state_free(cpudrv_state, instance);
276 276 cpudrv_enabled = B_FALSE;
277 277 return (DDI_FAILURE);
278 278 }
279 279
280 - mutex_init(&cpudsp->lock, NULL, MUTEX_DRIVER, NULL);
281 - if (cpudrv_is_enabled(cpudsp)) {
282 - if (cpudrv_init(cpudsp) != DDI_SUCCESS) {
283 - cpudrv_enabled = B_FALSE;
284 - cpudrv_free(cpudsp);
285 - ddi_soft_state_free(cpudrv_state, instance);
286 - return (DDI_FAILURE);
287 - }
288 - if (cpudrv_comp_create(cpudsp) != DDI_SUCCESS) {
289 - cpudrv_enabled = B_FALSE;
290 - cpudrv_free(cpudsp);
291 - ddi_soft_state_free(cpudrv_state, instance);
292 - return (DDI_FAILURE);
293 - }
294 - if (ddi_prop_update_string(DDI_DEV_T_NONE,
295 - dip, "pm-class", "CPU") != DDI_PROP_SUCCESS) {
296 - cpudrv_enabled = B_FALSE;
297 - cpudrv_free(cpudsp);
298 - ddi_soft_state_free(cpudrv_state, instance);
299 - return (DDI_FAILURE);
300 - }
280 + if (!cpudrv_is_enabled(cpudsp)) {
281 + cmn_err(CE_WARN, "cpudrv_attach: instance %d: "
282 + "not supported or it got disabled on us",
283 + instance);
284 + cpudrv_enabled = B_FALSE;
285 + ddi_soft_state_free(cpudrv_state, instance);
286 + return (DDI_FAILURE);
287 + }
301 288
302 - /*
303 - * Taskq is used to dispatch routine to monitor CPU
304 - * activities.
305 - */
306 - cpudsp->cpudrv_pm.tq = ddi_taskq_create(dip,
307 - "cpudrv_monitor", CPUDRV_TASKQ_THREADS,
308 - TASKQ_DEFAULTPRI, 0);
289 + mutex_init(&cpudsp->lock, NULL, MUTEX_DRIVER, NULL);
290 + if (cpudrv_init(cpudsp) != DDI_SUCCESS) {
291 + cpudrv_enabled = B_FALSE;
292 + cpudrv_free(cpudsp);
293 + ddi_soft_state_free(cpudrv_state, instance);
294 + return (DDI_FAILURE);
295 + }
296 + if (cpudrv_comp_create(cpudsp) != DDI_SUCCESS) {
297 + cpudrv_enabled = B_FALSE;
298 + cpudrv_free(cpudsp);
299 + ddi_soft_state_free(cpudrv_state, instance);
300 + return (DDI_FAILURE);
301 + }
302 + if (ddi_prop_update_string(DDI_DEV_T_NONE,
303 + dip, "pm-class", "CPU") != DDI_PROP_SUCCESS) {
304 + cpudrv_enabled = B_FALSE;
305 + cpudrv_free(cpudsp);
306 + ddi_soft_state_free(cpudrv_state, instance);
307 + return (DDI_FAILURE);
308 + }
309 309
310 - mutex_init(&cpudsp->cpudrv_pm.timeout_lock, NULL,
311 - MUTEX_DRIVER, NULL);
312 - cv_init(&cpudsp->cpudrv_pm.timeout_cv, NULL,
313 - CV_DEFAULT, NULL);
310 + /*
311 + * Taskq is used to dispatch routine to monitor CPU
312 + * activities.
313 + */
314 + cpudsp->cpudrv_pm.tq = ddi_taskq_create(dip,
315 + "cpudrv_monitor", CPUDRV_TASKQ_THREADS,
316 + TASKQ_DEFAULTPRI, 0);
314 317
315 - /*
316 - * Driver needs to assume that CPU is running at
317 - * unknown speed at DDI_ATTACH and switch it to the
318 - * needed speed. We assume that initial needed speed
319 - * is full speed for us.
320 - */
321 - /*
322 - * We need to take the lock because cpudrv_monitor()
323 - * will start running in parallel with attach().
324 - */
325 - mutex_enter(&cpudsp->lock);
326 - cpudsp->cpudrv_pm.cur_spd = NULL;
327 - cpudsp->cpudrv_pm.pm_started = B_FALSE;
328 - /*
329 - * We don't call pm_raise_power() directly from attach
330 - * because driver attach for a slave CPU node can
331 - * happen before the CPU is even initialized. We just
332 - * start the monitoring system which understands
333 - * unknown speed and moves CPU to top speed when it
334 - * has been initialized.
335 - */
336 - CPUDRV_MONITOR_INIT(cpudsp);
337 - mutex_exit(&cpudsp->lock);
318 + mutex_init(&cpudsp->cpudrv_pm.timeout_lock, NULL,
319 + MUTEX_DRIVER, NULL);
320 + cv_init(&cpudsp->cpudrv_pm.timeout_cv, NULL,
321 + CV_DEFAULT, NULL);
338 322
339 - }
323 + /*
324 + * Driver needs to assume that CPU is running at
325 + * unknown speed at DDI_ATTACH and switch it to the
326 + * needed speed. We assume that initial needed speed
327 + * is full speed for us.
328 + */
329 + /*
330 + * We need to take the lock because cpudrv_monitor()
331 + * will start running in parallel with attach().
332 + */
333 + mutex_enter(&cpudsp->lock);
334 + cpudsp->cpudrv_pm.cur_spd = NULL;
335 + cpudsp->cpudrv_pm.pm_started = B_FALSE;
336 + /*
337 + * We don't call pm_raise_power() directly from attach
338 + * because driver attach for a slave CPU node can
339 + * happen before the CPU is even initialized. We just
340 + * start the monitoring system which understands
341 + * unknown speed and moves CPU to top speed when it
342 + * has been initialized.
343 + */
344 + CPUDRV_MONITOR_INIT(cpudsp);
345 + mutex_exit(&cpudsp->lock);
340 346
341 347 if (!cpudrv_mach_init(cpudsp)) {
342 348 cmn_err(CE_WARN, "cpudrv_attach: instance %d: "
343 349 "cpudrv_mach_init failed", instance);
344 350 cpudrv_enabled = B_FALSE;
345 351 cpudrv_free(cpudsp);
346 352 ddi_soft_state_free(cpudrv_state, instance);
347 353 return (DDI_FAILURE);
348 354 }
349 355
350 356 CPUDRV_INSTALL_MAX_CHANGE_HANDLER(cpudsp);
351 357
352 358 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
353 359 DDI_NO_AUTODETACH, 1);
354 360 ddi_report_dev(dip);
355 361 return (DDI_SUCCESS);
356 362
357 363 case DDI_RESUME:
358 364 DPRINTF(D_ATTACH, ("cpudrv_attach: instance %d: "
359 365 "DDI_RESUME called\n", instance));
360 366
361 367 cpudsp = ddi_get_soft_state(cpudrv_state, instance);
362 368 ASSERT(cpudsp != NULL);
363 369
364 370 /*
365 371 * Nothing to do for resume, if not doing active PM.
366 372 */
367 373 if (!cpudrv_is_enabled(cpudsp))
368 374 return (DDI_SUCCESS);
369 375
370 376 mutex_enter(&cpudsp->lock);
371 377 /*
372 378 * Driver needs to assume that CPU is running at unknown speed
373 379 * at DDI_RESUME and switch it to the needed speed. We assume
374 380 * that the needed speed is full speed for us.
375 381 */
376 382 cpudsp->cpudrv_pm.cur_spd = NULL;
377 383 CPUDRV_MONITOR_INIT(cpudsp);
378 384 mutex_exit(&cpudsp->lock);
379 385 CPUDRV_REDEFINE_TOPSPEED(dip);
380 386 return (DDI_SUCCESS);
381 387
382 388 default:
383 389 return (DDI_FAILURE);
384 390 }
385 391 }
386 392
387 393 /*
388 394 * Driver detach(9e) entry point.
389 395 */
390 396 static int
391 397 cpudrv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
392 398 {
393 399 int instance;
394 400 cpudrv_devstate_t *cpudsp;
395 401 cpudrv_pm_t *cpupm;
396 402
397 403 instance = ddi_get_instance(dip);
398 404
399 405 switch (cmd) {
400 406 case DDI_DETACH:
401 407 DPRINTF(D_DETACH, ("cpudrv_detach: instance %d: "
402 408 "DDI_DETACH called\n", instance));
403 409
404 410 #if defined(__x86)
405 411 cpudsp = ddi_get_soft_state(cpudrv_state, instance);
406 412 ASSERT(cpudsp != NULL);
407 413
408 414 /*
409 415 * Nothing to do for detach, if no doing active PM.
410 416 */
411 417 if (!cpudrv_is_enabled(cpudsp))
412 418 return (DDI_SUCCESS);
413 419
414 420 /*
415 421 * uninstall PPC/_TPC change notification handler
416 422 */
417 423 CPUDRV_UNINSTALL_MAX_CHANGE_HANDLER(cpudsp);
418 424
419 425 /*
420 426 * destruct platform specific resource
421 427 */
422 428 if (!cpudrv_mach_fini(cpudsp))
423 429 return (DDI_FAILURE);
424 430
425 431 mutex_enter(&cpudsp->lock);
426 432 CPUDRV_MONITOR_FINI(cpudsp);
427 433 cv_destroy(&cpudsp->cpudrv_pm.timeout_cv);
428 434 mutex_destroy(&cpudsp->cpudrv_pm.timeout_lock);
429 435 ddi_taskq_destroy(cpudsp->cpudrv_pm.tq);
430 436 cpudrv_free(cpudsp);
431 437 mutex_exit(&cpudsp->lock);
432 438 mutex_destroy(&cpudsp->lock);
433 439 ddi_soft_state_free(cpudrv_state, instance);
434 440 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
435 441 DDI_NO_AUTODETACH, 0);
436 442 return (DDI_SUCCESS);
437 443
438 444 #else
439 445 /*
440 446 * If the only thing supported by the driver is power
441 447 * management, we can in future enhance the driver and
442 448 * framework that loads it to unload the driver when
443 449 * user has disabled CPU power management.
444 450 */
445 451 return (DDI_FAILURE);
446 452 #endif
447 453
448 454 case DDI_SUSPEND:
449 455 DPRINTF(D_DETACH, ("cpudrv_detach: instance %d: "
450 456 "DDI_SUSPEND called\n", instance));
451 457
452 458 cpudsp = ddi_get_soft_state(cpudrv_state, instance);
453 459 ASSERT(cpudsp != NULL);
454 460
455 461 /*
456 462 * Nothing to do for suspend, if not doing active PM.
457 463 */
458 464 if (!cpudrv_is_enabled(cpudsp))
459 465 return (DDI_SUCCESS);
460 466
461 467 /*
462 468 * During a checkpoint-resume sequence, framework will
463 469 * stop interrupts to quiesce kernel activity. This will
464 470 * leave our monitoring system ineffective. Handle this
465 471 * by stopping our monitoring system and bringing CPU
466 472 * to full speed. In case we are in special direct pm
467 473 * mode, we leave the CPU at whatever speed it is. This
468 474 * is harmless other than speed.
469 475 */
470 476 mutex_enter(&cpudsp->lock);
471 477 cpupm = &(cpudsp->cpudrv_pm);
472 478
473 479 DPRINTF(D_DETACH, ("cpudrv_detach: instance %d: DDI_SUSPEND - "
474 480 "cur_spd %d, topspeed %d\n", instance,
475 481 cpupm->cur_spd->pm_level,
476 482 CPUDRV_TOPSPEED(cpupm)->pm_level));
477 483
478 484 CPUDRV_MONITOR_FINI(cpudsp);
479 485
480 486 if (!cpudrv_direct_pm && (cpupm->cur_spd !=
481 487 CPUDRV_TOPSPEED(cpupm))) {
482 488 if (cpupm->pm_busycnt < 1) {
483 489 if ((pm_busy_component(dip, CPUDRV_COMP_NUM)
484 490 == DDI_SUCCESS)) {
485 491 cpupm->pm_busycnt++;
486 492 } else {
487 493 CPUDRV_MONITOR_INIT(cpudsp);
488 494 mutex_exit(&cpudsp->lock);
489 495 cmn_err(CE_WARN, "cpudrv_detach: "
490 496 "instance %d: can't busy CPU "
491 497 "component", instance);
492 498 return (DDI_FAILURE);
493 499 }
494 500 }
495 501 mutex_exit(&cpudsp->lock);
496 502 if (pm_raise_power(dip, CPUDRV_COMP_NUM,
497 503 CPUDRV_TOPSPEED(cpupm)->pm_level) !=
498 504 DDI_SUCCESS) {
499 505 mutex_enter(&cpudsp->lock);
500 506 CPUDRV_MONITOR_INIT(cpudsp);
501 507 mutex_exit(&cpudsp->lock);
502 508 cmn_err(CE_WARN, "cpudrv_detach: instance %d: "
503 509 "can't raise CPU power level to %d",
504 510 instance,
505 511 CPUDRV_TOPSPEED(cpupm)->pm_level);
506 512 return (DDI_FAILURE);
507 513 } else {
508 514 return (DDI_SUCCESS);
509 515 }
510 516 } else {
511 517 mutex_exit(&cpudsp->lock);
512 518 return (DDI_SUCCESS);
513 519 }
514 520
515 521 default:
516 522 return (DDI_FAILURE);
517 523 }
518 524 }
519 525
520 526 /*
521 527 * Driver power(9e) entry point.
522 528 *
523 529 * Driver's notion of current power is set *only* in power(9e) entry point
524 530 * after actual power change operation has been successfully completed.
525 531 */
526 532 /* ARGSUSED */
527 533 static int
528 534 cpudrv_power(dev_info_t *dip, int comp, int level)
529 535 {
530 536 int instance;
531 537 cpudrv_devstate_t *cpudsp;
532 538 cpudrv_pm_t *cpudrvpm;
533 539 cpudrv_pm_spd_t *new_spd;
534 540 boolean_t is_ready;
535 541 int ret;
536 542
537 543 instance = ddi_get_instance(dip);
538 544
539 545 DPRINTF(D_POWER, ("cpudrv_power: instance %d: level %d\n",
540 546 instance, level));
541 547
542 548 if ((cpudsp = ddi_get_soft_state(cpudrv_state, instance)) == NULL) {
543 549 cmn_err(CE_WARN, "cpudrv_power: instance %d: can't "
544 550 "get state", instance);
545 551 return (DDI_FAILURE);
546 552 }
547 553
548 554 /*
549 555 * We're not ready until we can get a cpu_t
550 556 */
551 557 is_ready = (cpudrv_get_cpu(cpudsp) == DDI_SUCCESS);
552 558
553 559 mutex_enter(&cpudsp->lock);
554 560 cpudrvpm = &(cpudsp->cpudrv_pm);
555 561
556 562 /*
557 563 * In normal operation, we fail if we are busy and request is
558 564 * to lower the power level. We let this go through if the driver
559 565 * is in special direct pm mode. On x86, we also let this through
560 566 * if the change is due to a request to govern the max speed.
561 567 */
562 568 if (!cpudrv_direct_pm && (cpudrvpm->pm_busycnt >= 1) &&
563 569 !cpudrv_is_governor_thread(cpudrvpm)) {
564 570 if ((cpudrvpm->cur_spd != NULL) &&
565 571 (level < cpudrvpm->cur_spd->pm_level)) {
566 572 mutex_exit(&cpudsp->lock);
567 573 return (DDI_FAILURE);
568 574 }
569 575 }
570 576
571 577 for (new_spd = cpudrvpm->head_spd; new_spd; new_spd =
572 578 new_spd->down_spd) {
573 579 if (new_spd->pm_level == level)
574 580 break;
575 581 }
576 582 if (!new_spd) {
577 583 CPUDRV_RESET_GOVERNOR_THREAD(cpudrvpm);
578 584 mutex_exit(&cpudsp->lock);
579 585 cmn_err(CE_WARN, "cpudrv_power: instance %d: "
580 586 "can't locate new CPU speed", instance);
581 587 return (DDI_FAILURE);
582 588 }
583 589
584 590 /*
585 591 * We currently refuse to power manage if the CPU is not ready to
586 592 * take cross calls (cross calls fail silently if CPU is not ready
587 593 * for it).
588 594 *
589 595 * Additionally, for x86 platforms we cannot power manage an instance,
590 596 * until it has been initialized.
591 597 */
592 598 if (is_ready) {
593 599 is_ready = CPUDRV_XCALL_IS_READY(cpudsp->cpu_id);
594 600 if (!is_ready) {
595 601 DPRINTF(D_POWER, ("cpudrv_power: instance %d: "
596 602 "CPU not ready for x-calls\n", instance));
597 603 } else if (!(is_ready = cpudrv_power_ready(cpudsp->cp))) {
598 604 DPRINTF(D_POWER, ("cpudrv_power: instance %d: "
599 605 "waiting for all CPUs to be power manageable\n",
600 606 instance));
601 607 }
602 608 }
603 609 if (!is_ready) {
604 610 CPUDRV_RESET_GOVERNOR_THREAD(cpudrvpm);
605 611 mutex_exit(&cpudsp->lock);
606 612 return (DDI_FAILURE);
607 613 }
608 614
609 615 /*
610 616 * Execute CPU specific routine on the requested CPU to
611 617 * change its speed to normal-speed/divisor.
612 618 */
613 619 if ((ret = cpudrv_change_speed(cpudsp, new_spd)) != DDI_SUCCESS) {
614 620 cmn_err(CE_WARN, "cpudrv_power: "
615 621 "cpudrv_change_speed() return = %d", ret);
616 622 mutex_exit(&cpudsp->lock);
617 623 return (DDI_FAILURE);
618 624 }
619 625
620 626 /*
621 627 * Reset idle threshold time for the new power level.
622 628 */
623 629 if ((cpudrvpm->cur_spd != NULL) && (level <
624 630 cpudrvpm->cur_spd->pm_level)) {
625 631 if (pm_idle_component(dip, CPUDRV_COMP_NUM) ==
626 632 DDI_SUCCESS) {
627 633 if (cpudrvpm->pm_busycnt >= 1)
628 634 cpudrvpm->pm_busycnt--;
629 635 } else {
630 636 cmn_err(CE_WARN, "cpudrv_power: instance %d: "
631 637 "can't idle CPU component",
632 638 ddi_get_instance(dip));
633 639 }
634 640 }
635 641 /*
636 642 * Reset various parameters because we are now running at new speed.
637 643 */
638 644 cpudrvpm->lastquan_mstate[CMS_IDLE] = 0;
639 645 cpudrvpm->lastquan_mstate[CMS_SYSTEM] = 0;
640 646 cpudrvpm->lastquan_mstate[CMS_USER] = 0;
641 647 cpudrvpm->lastquan_ticks = 0;
642 648 cpudrvpm->cur_spd = new_spd;
643 649 CPUDRV_RESET_GOVERNOR_THREAD(cpudrvpm);
644 650 mutex_exit(&cpudsp->lock);
645 651
646 652 return (DDI_SUCCESS);
647 653 }
648 654
649 655 /*
650 656 * Initialize power management data.
651 657 */
652 658 static int
653 659 cpudrv_init(cpudrv_devstate_t *cpudsp)
654 660 {
655 661 cpudrv_pm_t *cpupm = &(cpudsp->cpudrv_pm);
656 662 cpudrv_pm_spd_t *cur_spd;
657 663 cpudrv_pm_spd_t *prev_spd = NULL;
658 664 int *speeds;
659 665 uint_t nspeeds;
660 666 int idle_cnt_percent;
661 667 int user_cnt_percent;
662 668 int i;
663 669
664 670 CPUDRV_GET_SPEEDS(cpudsp, speeds, nspeeds);
665 671 if (nspeeds < 2) {
666 672 /* Need at least two speeds to power manage */
667 673 CPUDRV_FREE_SPEEDS(speeds, nspeeds);
668 674 return (DDI_FAILURE);
669 675 }
670 676 cpupm->num_spd = nspeeds;
671 677
672 678 /*
673 679 * Calculate the watermarks and other parameters based on the
674 680 * supplied speeds.
675 681 *
676 682 * One of the basic assumption is that for X amount of CPU work,
677 683 * if CPU is slowed down by a factor of N, the time it takes to
678 684 * do the same work will be N * X.
679 685 *
680 686 * The driver declares that a CPU is idle and ready for slowed down,
681 687 * if amount of idle thread is more than the current speed idle_hwm
682 688 * without dropping below idle_hwm a number of consecutive sampling
683 689 * intervals and number of running threads in user mode are below
684 690 * user_lwm. We want to set the current user_lwm such that if we
685 691 * just switched to the next slower speed with no change in real work
686 692 * load, the amount of user threads at the slower speed will be such
687 693 * that it falls below the slower speed's user_hwm. If we didn't do
688 694 * that then we will just come back to the higher speed as soon as we
689 695 * go down even with no change in work load.
690 696 * The user_hwm is a fixed precentage and not calculated dynamically.
691 697 *
692 698 * We bring the CPU up if idle thread at current speed is less than
693 699 * the current speed idle_lwm for a number of consecutive sampling
694 700 * intervals or user threads are above the user_hwm for the current
695 701 * speed.
696 702 */
697 703 for (i = 0; i < nspeeds; i++) {
698 704 cur_spd = kmem_zalloc(sizeof (cpudrv_pm_spd_t), KM_SLEEP);
699 705 cur_spd->speed = speeds[i];
700 706 if (i == 0) { /* normal speed */
701 707 cpupm->head_spd = cur_spd;
702 708 CPUDRV_TOPSPEED(cpupm) = cur_spd;
703 709 cur_spd->quant_cnt = CPUDRV_QUANT_CNT_NORMAL;
704 710 cur_spd->idle_hwm =
705 711 (cpudrv_idle_hwm * cur_spd->quant_cnt) / 100;
706 712 /* can't speed anymore */
707 713 cur_spd->idle_lwm = 0;
708 714 cur_spd->user_hwm = UINT_MAX;
709 715 } else {
710 716 cur_spd->quant_cnt = CPUDRV_QUANT_CNT_OTHR;
711 717 ASSERT(prev_spd != NULL);
712 718 prev_spd->down_spd = cur_spd;
713 719 cur_spd->up_spd = cpupm->head_spd;
714 720
715 721 /*
716 722 * Let's assume CPU is considered idle at full speed
717 723 * when it is spending I% of time in running the idle
718 724 * thread. At full speed, CPU will be busy (100 - I) %
719 725 * of times. This % of busyness increases by factor of
720 726 * N as CPU slows down. CPU that is idle I% of times
721 727 * in full speed, it is idle (100 - ((100 - I) * N)) %
722 728 * of times in N speed. The idle_lwm is a fixed
723 729 * percentage. A large value of N may result in
724 730 * idle_hwm to go below idle_lwm. We need to make sure
725 731 * that there is at least a buffer zone seperation
726 732 * between the idle_lwm and idle_hwm values.
727 733 */
728 734 idle_cnt_percent = CPUDRV_IDLE_CNT_PERCENT(
729 735 cpudrv_idle_hwm, speeds, i);
730 736 idle_cnt_percent = max(idle_cnt_percent,
731 737 (cpudrv_idle_lwm + cpudrv_idle_buf_zone));
732 738 cur_spd->idle_hwm =
733 739 (idle_cnt_percent * cur_spd->quant_cnt) / 100;
734 740 cur_spd->idle_lwm =
735 741 (cpudrv_idle_lwm * cur_spd->quant_cnt) / 100;
736 742
737 743 /*
738 744 * The lwm for user threads are determined such that
739 745 * if CPU slows down, the load of work in the
740 746 * new speed would still keep the CPU at or below the
741 747 * user_hwm in the new speed. This is to prevent
742 748 * the quick jump back up to higher speed.
743 749 */
744 750 cur_spd->user_hwm = (cpudrv_user_hwm *
745 751 cur_spd->quant_cnt) / 100;
746 752 user_cnt_percent = CPUDRV_USER_CNT_PERCENT(
747 753 cpudrv_user_hwm, speeds, i);
748 754 prev_spd->user_lwm =
749 755 (user_cnt_percent * prev_spd->quant_cnt) / 100;
750 756 }
751 757 prev_spd = cur_spd;
752 758 }
753 759 /* Slowest speed. Can't slow down anymore */
754 760 cur_spd->idle_hwm = UINT_MAX;
755 761 cur_spd->user_lwm = -1;
756 762 #ifdef DEBUG
757 763 DPRINTF(D_PM_INIT, ("cpudrv_init: instance %d: head_spd spd %d, "
758 764 "num_spd %d\n", ddi_get_instance(cpudsp->dip),
759 765 cpupm->head_spd->speed, cpupm->num_spd));
760 766 for (cur_spd = cpupm->head_spd; cur_spd; cur_spd = cur_spd->down_spd) {
761 767 DPRINTF(D_PM_INIT, ("cpudrv_init: instance %d: speed %d, "
762 768 "down_spd spd %d, idle_hwm %d, user_lwm %d, "
763 769 "up_spd spd %d, idle_lwm %d, user_hwm %d, "
764 770 "quant_cnt %d\n", ddi_get_instance(cpudsp->dip),
765 771 cur_spd->speed,
766 772 (cur_spd->down_spd ? cur_spd->down_spd->speed : 0),
767 773 cur_spd->idle_hwm, cur_spd->user_lwm,
768 774 (cur_spd->up_spd ? cur_spd->up_spd->speed : 0),
769 775 cur_spd->idle_lwm, cur_spd->user_hwm,
770 776 cur_spd->quant_cnt));
771 777 }
772 778 #endif /* DEBUG */
773 779 CPUDRV_FREE_SPEEDS(speeds, nspeeds);
774 780 return (DDI_SUCCESS);
775 781 }
776 782
777 783 /*
778 784 * Free CPU power management data.
779 785 */
780 786 static void
781 787 cpudrv_free(cpudrv_devstate_t *cpudsp)
782 788 {
783 789 cpudrv_pm_t *cpupm = &(cpudsp->cpudrv_pm);
784 790 cpudrv_pm_spd_t *cur_spd, *next_spd;
785 791
786 792 cur_spd = cpupm->head_spd;
787 793 while (cur_spd) {
788 794 next_spd = cur_spd->down_spd;
789 795 kmem_free(cur_spd, sizeof (cpudrv_pm_spd_t));
790 796 cur_spd = next_spd;
791 797 }
792 798 bzero(cpupm, sizeof (cpudrv_pm_t));
793 799 }
794 800
795 801 /*
796 802 * Create pm-components property.
797 803 */
798 804 static int
799 805 cpudrv_comp_create(cpudrv_devstate_t *cpudsp)
800 806 {
801 807 cpudrv_pm_t *cpupm = &(cpudsp->cpudrv_pm);
802 808 cpudrv_pm_spd_t *cur_spd;
803 809 char **pmc;
804 810 int size;
805 811 char name[] = "NAME=CPU Speed";
806 812 int i, j;
807 813 uint_t comp_spd;
808 814 int result = DDI_FAILURE;
809 815
810 816 pmc = kmem_zalloc((cpupm->num_spd + 1) * sizeof (char *), KM_SLEEP);
811 817 size = CPUDRV_COMP_SIZE();
812 818 if (cpupm->num_spd > CPUDRV_COMP_MAX_VAL) {
813 819 cmn_err(CE_WARN, "cpudrv_comp_create: instance %d: "
814 820 "number of speeds exceeded limits",
815 821 ddi_get_instance(cpudsp->dip));
816 822 kmem_free(pmc, (cpupm->num_spd + 1) * sizeof (char *));
817 823 return (result);
818 824 }
819 825
820 826 for (i = cpupm->num_spd, cur_spd = cpupm->head_spd; i > 0;
821 827 i--, cur_spd = cur_spd->down_spd) {
822 828 cur_spd->pm_level = i;
823 829 pmc[i] = kmem_zalloc((size * sizeof (char)), KM_SLEEP);
824 830 comp_spd = CPUDRV_COMP_SPEED(cpupm, cur_spd);
825 831 if (comp_spd > CPUDRV_COMP_MAX_VAL) {
826 832 cmn_err(CE_WARN, "cpudrv_comp_create: "
827 833 "instance %d: speed exceeded limits",
828 834 ddi_get_instance(cpudsp->dip));
829 835 for (j = cpupm->num_spd; j >= i; j--) {
830 836 kmem_free(pmc[j], size * sizeof (char));
831 837 }
832 838 kmem_free(pmc, (cpupm->num_spd + 1) *
833 839 sizeof (char *));
834 840 return (result);
835 841 }
836 842 CPUDRV_COMP_SPRINT(pmc[i], cpupm, cur_spd, comp_spd)
837 843 DPRINTF(D_PM_COMP_CREATE, ("cpudrv_comp_create: "
838 844 "instance %d: pm-components power level %d string '%s'\n",
839 845 ddi_get_instance(cpudsp->dip), i, pmc[i]));
840 846 }
841 847 pmc[0] = kmem_zalloc(sizeof (name), KM_SLEEP);
842 848 (void) strcat(pmc[0], name);
843 849 DPRINTF(D_PM_COMP_CREATE, ("cpudrv_comp_create: instance %d: "
844 850 "pm-components component name '%s'\n",
845 851 ddi_get_instance(cpudsp->dip), pmc[0]));
846 852
847 853 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, cpudsp->dip,
848 854 "pm-components", pmc, cpupm->num_spd + 1) == DDI_PROP_SUCCESS) {
849 855 result = DDI_SUCCESS;
850 856 } else {
851 857 cmn_err(CE_WARN, "cpudrv_comp_create: instance %d: "
852 858 "can't create pm-components property",
853 859 ddi_get_instance(cpudsp->dip));
854 860 }
855 861
856 862 for (i = cpupm->num_spd; i > 0; i--) {
857 863 kmem_free(pmc[i], size * sizeof (char));
858 864 }
859 865 kmem_free(pmc[0], sizeof (name));
860 866 kmem_free(pmc, (cpupm->num_spd + 1) * sizeof (char *));
861 867 return (result);
862 868 }
863 869
864 870 /*
865 871 * Mark a component idle.
866 872 */
867 873 #define CPUDRV_MONITOR_PM_IDLE_COMP(dip, cpupm) { \
868 874 if ((cpupm)->pm_busycnt >= 1) { \
869 875 if (pm_idle_component((dip), CPUDRV_COMP_NUM) == \
870 876 DDI_SUCCESS) { \
871 877 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: " \
872 878 "instance %d: pm_idle_component called\n", \
873 879 ddi_get_instance((dip)))); \
874 880 (cpupm)->pm_busycnt--; \
875 881 } else { \
876 882 cmn_err(CE_WARN, "cpudrv_monitor: instance %d: " \
877 883 "can't idle CPU component", \
878 884 ddi_get_instance((dip))); \
879 885 } \
880 886 } \
881 887 }
882 888
883 889 /*
884 890 * Marks a component busy in both PM framework and driver state structure.
885 891 */
886 892 #define CPUDRV_MONITOR_PM_BUSY_COMP(dip, cpupm) { \
887 893 if ((cpupm)->pm_busycnt < 1) { \
888 894 if (pm_busy_component((dip), CPUDRV_COMP_NUM) == \
889 895 DDI_SUCCESS) { \
890 896 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: " \
891 897 "instance %d: pm_busy_component called\n", \
892 898 ddi_get_instance((dip)))); \
893 899 (cpupm)->pm_busycnt++; \
894 900 } else { \
895 901 cmn_err(CE_WARN, "cpudrv_monitor: instance %d: " \
896 902 "can't busy CPU component", \
897 903 ddi_get_instance((dip))); \
898 904 } \
899 905 } \
900 906 }
901 907
902 908 /*
903 909 * Marks a component busy and calls pm_raise_power().
904 910 */
905 911 #define CPUDRV_MONITOR_PM_BUSY_AND_RAISE(dip, cpudsp, cpupm, new_spd) { \
906 912 int ret; \
907 913 /* \
908 914 * Mark driver and PM framework busy first so framework doesn't try \
909 915 * to bring CPU to lower speed when we need to be at higher speed. \
910 916 */ \
911 917 CPUDRV_MONITOR_PM_BUSY_COMP((dip), (cpupm)); \
912 918 mutex_exit(&(cpudsp)->lock); \
913 919 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: " \
914 920 "pm_raise_power called to %d\n", ddi_get_instance((dip)), \
915 921 (new_spd->pm_level))); \
916 922 ret = pm_raise_power((dip), CPUDRV_COMP_NUM, (new_spd->pm_level)); \
917 923 if (ret != DDI_SUCCESS) { \
918 924 cmn_err(CE_WARN, "cpudrv_monitor: instance %d: can't " \
919 925 "raise CPU power level", ddi_get_instance((dip))); \
920 926 } \
921 927 mutex_enter(&(cpudsp)->lock); \
922 928 if (ret == DDI_SUCCESS && cpudsp->cpudrv_pm.cur_spd == NULL) { \
923 929 cpudsp->cpudrv_pm.cur_spd = new_spd; \
924 930 } \
925 931 }
926 932
927 933 /*
928 934 * In order to monitor a CPU, we need to hold cpu_lock to access CPU
929 935 * statistics. Holding cpu_lock is not allowed from a callout routine.
930 936 * We dispatch a taskq to do that job.
931 937 */
932 938 static void
933 939 cpudrv_monitor_disp(void *arg)
934 940 {
935 941 cpudrv_devstate_t *cpudsp = (cpudrv_devstate_t *)arg;
936 942
937 943 /*
938 944 * We are here because the last task has scheduled a timeout.
939 945 * The queue should be empty at this time.
940 946 */
941 947 mutex_enter(&cpudsp->cpudrv_pm.timeout_lock);
942 948 if ((ddi_taskq_dispatch(cpudsp->cpudrv_pm.tq, cpudrv_monitor, arg,
943 949 DDI_NOSLEEP)) != DDI_SUCCESS) {
944 950 mutex_exit(&cpudsp->cpudrv_pm.timeout_lock);
945 951 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor_disp: failed to "
946 952 "dispatch the cpudrv_monitor taskq\n"));
947 953 mutex_enter(&cpudsp->lock);
948 954 CPUDRV_MONITOR_INIT(cpudsp);
949 955 mutex_exit(&cpudsp->lock);
950 956 return;
951 957 }
952 958 cpudsp->cpudrv_pm.timeout_count++;
953 959 mutex_exit(&cpudsp->cpudrv_pm.timeout_lock);
954 960 }
955 961
956 962 /*
957 963 * Monitors each CPU for the amount of time idle thread was running in the
958 964 * last quantum and arranges for the CPU to go to the lower or higher speed.
959 965 * Called at the time interval appropriate for the current speed. The
960 966 * time interval for normal speed is CPUDRV_QUANT_CNT_NORMAL. The time
961 967 * interval for other speeds (including unknown speed) is
962 968 * CPUDRV_QUANT_CNT_OTHR.
963 969 */
964 970 static void
965 971 cpudrv_monitor(void *arg)
966 972 {
967 973 cpudrv_devstate_t *cpudsp = (cpudrv_devstate_t *)arg;
968 974 cpudrv_pm_t *cpupm;
969 975 cpudrv_pm_spd_t *cur_spd, *new_spd;
970 976 dev_info_t *dip;
971 977 uint_t idle_cnt, user_cnt, system_cnt;
972 978 clock_t ticks;
973 979 uint_t tick_cnt;
974 980 hrtime_t msnsecs[NCMSTATES];
975 981 boolean_t is_ready;
976 982
977 983 #define GET_CPU_MSTATE_CNT(state, cnt) \
978 984 msnsecs[state] = NSEC_TO_TICK(msnsecs[state]); \
979 985 if (cpupm->lastquan_mstate[state] > msnsecs[state]) \
980 986 msnsecs[state] = cpupm->lastquan_mstate[state]; \
981 987 cnt = msnsecs[state] - cpupm->lastquan_mstate[state]; \
982 988 cpupm->lastquan_mstate[state] = msnsecs[state]
983 989
984 990 /*
985 991 * We're not ready until we can get a cpu_t
986 992 */
987 993 is_ready = (cpudrv_get_cpu(cpudsp) == DDI_SUCCESS);
988 994
989 995 mutex_enter(&cpudsp->lock);
990 996 cpupm = &(cpudsp->cpudrv_pm);
991 997 if (cpupm->timeout_id == 0) {
992 998 mutex_exit(&cpudsp->lock);
993 999 goto do_return;
994 1000 }
995 1001 cur_spd = cpupm->cur_spd;
996 1002 dip = cpudsp->dip;
997 1003
998 1004 /*
999 1005 * We assume that a CPU is initialized and has a valid cpu_t
1000 1006 * structure, if it is ready for cross calls. If this changes,
1001 1007 * additional checks might be needed.
1002 1008 *
1003 1009 * Additionally, for x86 platforms we cannot power manage an
1004 1010 * instance, until it has been initialized.
1005 1011 */
1006 1012 if (is_ready) {
1007 1013 is_ready = CPUDRV_XCALL_IS_READY(cpudsp->cpu_id);
1008 1014 if (!is_ready) {
1009 1015 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
1010 1016 "CPU not ready for x-calls\n",
1011 1017 ddi_get_instance(dip)));
1012 1018 } else if (!(is_ready = cpudrv_power_ready(cpudsp->cp))) {
1013 1019 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
1014 1020 "waiting for all CPUs to be power manageable\n",
1015 1021 ddi_get_instance(dip)));
1016 1022 }
1017 1023 }
1018 1024 if (!is_ready) {
1019 1025 /*
1020 1026 * Make sure that we are busy so that framework doesn't
1021 1027 * try to bring us down in this situation.
1022 1028 */
1023 1029 CPUDRV_MONITOR_PM_BUSY_COMP(dip, cpupm);
1024 1030 CPUDRV_MONITOR_INIT(cpudsp);
1025 1031 mutex_exit(&cpudsp->lock);
1026 1032 goto do_return;
1027 1033 }
1028 1034
1029 1035 /*
1030 1036 * Make sure that we are still not at unknown power level.
1031 1037 */
1032 1038 if (cur_spd == NULL) {
1033 1039 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
1034 1040 "cur_spd is unknown\n", ddi_get_instance(dip)));
1035 1041 CPUDRV_MONITOR_PM_BUSY_AND_RAISE(dip, cpudsp, cpupm,
1036 1042 CPUDRV_TOPSPEED(cpupm));
1037 1043 /*
1038 1044 * We just changed the speed. Wait till at least next
1039 1045 * call to this routine before proceeding ahead.
1040 1046 */
1041 1047 CPUDRV_MONITOR_INIT(cpudsp);
1042 1048 mutex_exit(&cpudsp->lock);
1043 1049 goto do_return;
1044 1050 }
1045 1051
1046 1052 if (!cpupm->pm_started) {
1047 1053 cpupm->pm_started = B_TRUE;
1048 1054 cpudrv_set_supp_freqs(cpudsp);
1049 1055 }
1050 1056
1051 1057 get_cpu_mstate(cpudsp->cp, msnsecs);
1052 1058 GET_CPU_MSTATE_CNT(CMS_IDLE, idle_cnt);
1053 1059 GET_CPU_MSTATE_CNT(CMS_USER, user_cnt);
1054 1060 GET_CPU_MSTATE_CNT(CMS_SYSTEM, system_cnt);
1055 1061
1056 1062 /*
1057 1063 * We can't do anything when we have just switched to a state
1058 1064 * because there is no valid timestamp.
1059 1065 */
1060 1066 if (cpupm->lastquan_ticks == 0) {
1061 1067 cpupm->lastquan_ticks = NSEC_TO_TICK(gethrtime());
1062 1068 CPUDRV_MONITOR_INIT(cpudsp);
1063 1069 mutex_exit(&cpudsp->lock);
1064 1070 goto do_return;
1065 1071 }
1066 1072
1067 1073 /*
1068 1074 * Various watermarks are based on this routine being called back
1069 1075 * exactly at the requested period. This is not guaranteed
1070 1076 * because this routine is called from a taskq that is dispatched
1071 1077 * from a timeout routine. Handle this by finding out how many
1072 1078 * ticks have elapsed since the last call and adjusting
1073 1079 * the idle_cnt based on the delay added to the requested period
1074 1080 * by timeout and taskq.
1075 1081 */
1076 1082 ticks = NSEC_TO_TICK(gethrtime());
1077 1083 tick_cnt = ticks - cpupm->lastquan_ticks;
1078 1084 ASSERT(tick_cnt != 0);
1079 1085 cpupm->lastquan_ticks = ticks;
1080 1086
1081 1087 /*
1082 1088 * Time taken between recording the current counts and
1083 1089 * arranging the next call of this routine is an error in our
1084 1090 * calculation. We minimize the error by calling
1085 1091 * CPUDRV_MONITOR_INIT() here instead of end of this routine.
1086 1092 */
1087 1093 CPUDRV_MONITOR_INIT(cpudsp);
1088 1094 DPRINTF(D_PM_MONITOR_VERBOSE, ("cpudrv_monitor: instance %d: "
1089 1095 "idle count %d, user count %d, system count %d, pm_level %d, "
1090 1096 "pm_busycnt %d\n", ddi_get_instance(dip), idle_cnt, user_cnt,
1091 1097 system_cnt, cur_spd->pm_level, cpupm->pm_busycnt));
1092 1098
1093 1099 #ifdef DEBUG
1094 1100 /*
1095 1101 * Notify that timeout and taskq has caused delays and we need to
1096 1102 * scale our parameters accordingly.
1097 1103 *
1098 1104 * To get accurate result, don't turn on other DPRINTFs with
1099 1105 * the following DPRINTF. PROM calls generated by other
1100 1106 * DPRINTFs changes the timing.
1101 1107 */
1102 1108 if (tick_cnt > cur_spd->quant_cnt) {
1103 1109 DPRINTF(D_PM_MONITOR_DELAY, ("cpudrv_monitor: instance %d: "
1104 1110 "tick count %d > quantum_count %u\n",
1105 1111 ddi_get_instance(dip), tick_cnt, cur_spd->quant_cnt));
1106 1112 }
1107 1113 #endif /* DEBUG */
1108 1114
1109 1115 /*
1110 1116 * Adjust counts based on the delay added by timeout and taskq.
1111 1117 */
1112 1118 idle_cnt = (idle_cnt * cur_spd->quant_cnt) / tick_cnt;
1113 1119 user_cnt = (user_cnt * cur_spd->quant_cnt) / tick_cnt;
1114 1120
1115 1121 if ((user_cnt > cur_spd->user_hwm) || (idle_cnt < cur_spd->idle_lwm &&
1116 1122 cur_spd->idle_blwm_cnt >= cpudrv_idle_blwm_cnt_max)) {
1117 1123 cur_spd->idle_blwm_cnt = 0;
1118 1124 cur_spd->idle_bhwm_cnt = 0;
1119 1125 /*
1120 1126 * In normal situation, arrange to go to next higher speed.
1121 1127 * If we are running in special direct pm mode, we just stay
1122 1128 * at the current speed.
1123 1129 */
1124 1130 if (cur_spd == cur_spd->up_spd || cpudrv_direct_pm) {
1125 1131 CPUDRV_MONITOR_PM_BUSY_COMP(dip, cpupm);
1126 1132 } else {
1127 1133 new_spd = cur_spd->up_spd;
1128 1134 CPUDRV_MONITOR_PM_BUSY_AND_RAISE(dip, cpudsp, cpupm,
1129 1135 new_spd);
1130 1136 }
1131 1137 } else if ((user_cnt <= cur_spd->user_lwm) &&
1132 1138 (idle_cnt >= cur_spd->idle_hwm) || !CPU_ACTIVE(cpudsp->cp)) {
1133 1139 cur_spd->idle_blwm_cnt = 0;
1134 1140 cur_spd->idle_bhwm_cnt = 0;
1135 1141 /*
1136 1142 * Arrange to go to next lower speed by informing our idle
1137 1143 * status to the power management framework.
1138 1144 */
1139 1145 CPUDRV_MONITOR_PM_IDLE_COMP(dip, cpupm);
1140 1146 } else {
1141 1147 /*
1142 1148 * If we are between the idle water marks and have not
1143 1149 * been here enough consecutive times to be considered
1144 1150 * busy, just increment the count and return.
1145 1151 */
1146 1152 if ((idle_cnt < cur_spd->idle_hwm) &&
1147 1153 (idle_cnt >= cur_spd->idle_lwm) &&
1148 1154 (cur_spd->idle_bhwm_cnt < cpudrv_idle_bhwm_cnt_max)) {
1149 1155 cur_spd->idle_blwm_cnt = 0;
1150 1156 cur_spd->idle_bhwm_cnt++;
1151 1157 mutex_exit(&cpudsp->lock);
1152 1158 goto do_return;
1153 1159 }
1154 1160 if (idle_cnt < cur_spd->idle_lwm) {
1155 1161 cur_spd->idle_blwm_cnt++;
1156 1162 cur_spd->idle_bhwm_cnt = 0;
1157 1163 }
1158 1164 /*
1159 1165 * Arranges to stay at the current speed.
1160 1166 */
1161 1167 CPUDRV_MONITOR_PM_BUSY_COMP(dip, cpupm);
1162 1168 }
1163 1169 mutex_exit(&cpudsp->lock);
1164 1170 do_return:
1165 1171 mutex_enter(&cpupm->timeout_lock);
1166 1172 ASSERT(cpupm->timeout_count > 0);
1167 1173 cpupm->timeout_count--;
1168 1174 cv_signal(&cpupm->timeout_cv);
1169 1175 mutex_exit(&cpupm->timeout_lock);
1170 1176 }
1171 1177
1172 1178 /*
1173 1179 * get cpu_t structure for cpudrv_devstate_t
1174 1180 */
1175 1181 int
1176 1182 cpudrv_get_cpu(cpudrv_devstate_t *cpudsp)
1177 1183 {
1178 1184 ASSERT(cpudsp != NULL);
1179 1185
1180 1186 /*
1181 1187 * return DDI_SUCCESS if cpudrv_devstate_t
1182 1188 * already contains cpu_t structure
1183 1189 */
1184 1190 if (cpudsp->cp != NULL)
1185 1191 return (DDI_SUCCESS);
1186 1192
1187 1193 if (MUTEX_HELD(&cpu_lock)) {
1188 1194 cpudsp->cp = cpu_get(cpudsp->cpu_id);
1189 1195 } else {
1190 1196 mutex_enter(&cpu_lock);
1191 1197 cpudsp->cp = cpu_get(cpudsp->cpu_id);
1192 1198 mutex_exit(&cpu_lock);
1193 1199 }
1194 1200
1195 1201 if (cpudsp->cp == NULL)
1196 1202 return (DDI_FAILURE);
1197 1203
1198 1204 return (DDI_SUCCESS);
1199 1205 }
↓ open down ↓ |
850 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX