Print this page
XXXX cpudrv attach error handling is leaky
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 /*
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 280 if (!cpudrv_is_enabled(cpudsp)) {
281 281 cmn_err(CE_WARN, "cpudrv_attach: instance %d: "
282 282 "not supported or it got disabled on us",
283 283 instance);
284 284 cpudrv_enabled = B_FALSE;
285 285 ddi_soft_state_free(cpudrv_state, instance);
286 286 return (DDI_FAILURE);
287 287 }
288 288
289 289 mutex_init(&cpudsp->lock, NULL, MUTEX_DRIVER, NULL);
290 290 if (cpudrv_init(cpudsp) != DDI_SUCCESS) {
291 291 cpudrv_enabled = B_FALSE;
292 292 cpudrv_free(cpudsp);
293 293 ddi_soft_state_free(cpudrv_state, instance);
294 294 return (DDI_FAILURE);
295 295 }
296 296 if (cpudrv_comp_create(cpudsp) != DDI_SUCCESS) {
297 297 cpudrv_enabled = B_FALSE;
298 298 cpudrv_free(cpudsp);
299 299 ddi_soft_state_free(cpudrv_state, instance);
300 300 return (DDI_FAILURE);
301 301 }
302 302 if (ddi_prop_update_string(DDI_DEV_T_NONE,
303 303 dip, "pm-class", "CPU") != DDI_PROP_SUCCESS) {
304 304 cpudrv_enabled = B_FALSE;
305 305 cpudrv_free(cpudsp);
306 306 ddi_soft_state_free(cpudrv_state, instance);
↓ open down ↓ |
306 lines elided |
↑ open up ↑ |
307 307 return (DDI_FAILURE);
308 308 }
309 309
310 310 /*
311 311 * Taskq is used to dispatch routine to monitor CPU
312 312 * activities.
313 313 */
314 314 cpudsp->cpudrv_pm.tq = ddi_taskq_create(dip,
315 315 "cpudrv_monitor", CPUDRV_TASKQ_THREADS,
316 316 TASKQ_DEFAULTPRI, 0);
317 + if (cpudsp->cpudrv_pm.tq == NULL) {
318 + cpudrv_enabled = B_FALSE;
319 + cpudrv_free(cpudsp);
320 + ddi_soft_state_free(cpudrv_state, instance);
321 + return (DDI_FAILURE);
322 + }
317 323
318 324 mutex_init(&cpudsp->cpudrv_pm.timeout_lock, NULL,
319 325 MUTEX_DRIVER, NULL);
320 326 cv_init(&cpudsp->cpudrv_pm.timeout_cv, NULL,
321 327 CV_DEFAULT, NULL);
322 328
323 329 /*
324 330 * Driver needs to assume that CPU is running at
325 331 * unknown speed at DDI_ATTACH and switch it to the
326 332 * needed speed. We assume that initial needed speed
327 333 * is full speed for us.
328 334 */
329 335 /*
330 336 * We need to take the lock because cpudrv_monitor()
331 337 * will start running in parallel with attach().
332 338 */
333 339 mutex_enter(&cpudsp->lock);
334 340 cpudsp->cpudrv_pm.cur_spd = NULL;
335 341 cpudsp->cpudrv_pm.pm_started = B_FALSE;
336 342 /*
337 343 * We don't call pm_raise_power() directly from attach
338 344 * because driver attach for a slave CPU node can
339 345 * happen before the CPU is even initialized. We just
340 346 * start the monitoring system which understands
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
341 347 * unknown speed and moves CPU to top speed when it
342 348 * has been initialized.
343 349 */
344 350 CPUDRV_MONITOR_INIT(cpudsp);
345 351 mutex_exit(&cpudsp->lock);
346 352
347 353 if (!cpudrv_mach_init(cpudsp)) {
348 354 cmn_err(CE_WARN, "cpudrv_attach: instance %d: "
349 355 "cpudrv_mach_init failed", instance);
350 356 cpudrv_enabled = B_FALSE;
357 + ddi_taskq_destroy(cpudsp->cpudrv_pm.tq);
351 358 cpudrv_free(cpudsp);
352 359 ddi_soft_state_free(cpudrv_state, instance);
353 360 return (DDI_FAILURE);
354 361 }
355 362
356 363 CPUDRV_INSTALL_MAX_CHANGE_HANDLER(cpudsp);
357 364
358 365 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
359 366 DDI_NO_AUTODETACH, 1);
360 367 ddi_report_dev(dip);
361 368 return (DDI_SUCCESS);
362 369
363 370 case DDI_RESUME:
364 371 DPRINTF(D_ATTACH, ("cpudrv_attach: instance %d: "
365 372 "DDI_RESUME called\n", instance));
366 373
367 374 cpudsp = ddi_get_soft_state(cpudrv_state, instance);
368 375 ASSERT(cpudsp != NULL);
369 376
370 377 /*
371 378 * Nothing to do for resume, if not doing active PM.
372 379 */
373 380 if (!cpudrv_is_enabled(cpudsp))
374 381 return (DDI_SUCCESS);
375 382
376 383 mutex_enter(&cpudsp->lock);
377 384 /*
378 385 * Driver needs to assume that CPU is running at unknown speed
379 386 * at DDI_RESUME and switch it to the needed speed. We assume
380 387 * that the needed speed is full speed for us.
381 388 */
382 389 cpudsp->cpudrv_pm.cur_spd = NULL;
383 390 CPUDRV_MONITOR_INIT(cpudsp);
384 391 mutex_exit(&cpudsp->lock);
385 392 CPUDRV_REDEFINE_TOPSPEED(dip);
386 393 return (DDI_SUCCESS);
387 394
388 395 default:
389 396 return (DDI_FAILURE);
390 397 }
391 398 }
392 399
393 400 /*
394 401 * Driver detach(9e) entry point.
395 402 */
396 403 static int
397 404 cpudrv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
398 405 {
399 406 int instance;
400 407 cpudrv_devstate_t *cpudsp;
401 408 cpudrv_pm_t *cpupm;
402 409
403 410 instance = ddi_get_instance(dip);
404 411
405 412 switch (cmd) {
406 413 case DDI_DETACH:
407 414 DPRINTF(D_DETACH, ("cpudrv_detach: instance %d: "
408 415 "DDI_DETACH called\n", instance));
409 416
410 417 #if defined(__x86)
411 418 cpudsp = ddi_get_soft_state(cpudrv_state, instance);
412 419 ASSERT(cpudsp != NULL);
413 420
414 421 /*
415 422 * Nothing to do for detach, if no doing active PM.
416 423 */
417 424 if (!cpudrv_is_enabled(cpudsp))
418 425 return (DDI_SUCCESS);
419 426
420 427 /*
421 428 * uninstall PPC/_TPC change notification handler
422 429 */
423 430 CPUDRV_UNINSTALL_MAX_CHANGE_HANDLER(cpudsp);
424 431
425 432 /*
426 433 * destruct platform specific resource
427 434 */
428 435 if (!cpudrv_mach_fini(cpudsp))
429 436 return (DDI_FAILURE);
430 437
431 438 mutex_enter(&cpudsp->lock);
432 439 CPUDRV_MONITOR_FINI(cpudsp);
433 440 cv_destroy(&cpudsp->cpudrv_pm.timeout_cv);
434 441 mutex_destroy(&cpudsp->cpudrv_pm.timeout_lock);
435 442 ddi_taskq_destroy(cpudsp->cpudrv_pm.tq);
436 443 cpudrv_free(cpudsp);
437 444 mutex_exit(&cpudsp->lock);
438 445 mutex_destroy(&cpudsp->lock);
439 446 ddi_soft_state_free(cpudrv_state, instance);
440 447 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
441 448 DDI_NO_AUTODETACH, 0);
442 449 return (DDI_SUCCESS);
443 450
444 451 #else
445 452 /*
446 453 * If the only thing supported by the driver is power
447 454 * management, we can in future enhance the driver and
448 455 * framework that loads it to unload the driver when
449 456 * user has disabled CPU power management.
450 457 */
451 458 return (DDI_FAILURE);
452 459 #endif
453 460
454 461 case DDI_SUSPEND:
455 462 DPRINTF(D_DETACH, ("cpudrv_detach: instance %d: "
456 463 "DDI_SUSPEND called\n", instance));
457 464
458 465 cpudsp = ddi_get_soft_state(cpudrv_state, instance);
459 466 ASSERT(cpudsp != NULL);
460 467
461 468 /*
462 469 * Nothing to do for suspend, if not doing active PM.
463 470 */
464 471 if (!cpudrv_is_enabled(cpudsp))
465 472 return (DDI_SUCCESS);
466 473
467 474 /*
468 475 * During a checkpoint-resume sequence, framework will
469 476 * stop interrupts to quiesce kernel activity. This will
470 477 * leave our monitoring system ineffective. Handle this
471 478 * by stopping our monitoring system and bringing CPU
472 479 * to full speed. In case we are in special direct pm
473 480 * mode, we leave the CPU at whatever speed it is. This
474 481 * is harmless other than speed.
475 482 */
476 483 mutex_enter(&cpudsp->lock);
477 484 cpupm = &(cpudsp->cpudrv_pm);
478 485
479 486 DPRINTF(D_DETACH, ("cpudrv_detach: instance %d: DDI_SUSPEND - "
480 487 "cur_spd %d, topspeed %d\n", instance,
481 488 cpupm->cur_spd->pm_level,
482 489 CPUDRV_TOPSPEED(cpupm)->pm_level));
483 490
484 491 CPUDRV_MONITOR_FINI(cpudsp);
485 492
486 493 if (!cpudrv_direct_pm && (cpupm->cur_spd !=
487 494 CPUDRV_TOPSPEED(cpupm))) {
488 495 if (cpupm->pm_busycnt < 1) {
489 496 if ((pm_busy_component(dip, CPUDRV_COMP_NUM)
490 497 == DDI_SUCCESS)) {
491 498 cpupm->pm_busycnt++;
492 499 } else {
493 500 CPUDRV_MONITOR_INIT(cpudsp);
494 501 mutex_exit(&cpudsp->lock);
495 502 cmn_err(CE_WARN, "cpudrv_detach: "
496 503 "instance %d: can't busy CPU "
497 504 "component", instance);
498 505 return (DDI_FAILURE);
499 506 }
500 507 }
501 508 mutex_exit(&cpudsp->lock);
502 509 if (pm_raise_power(dip, CPUDRV_COMP_NUM,
503 510 CPUDRV_TOPSPEED(cpupm)->pm_level) !=
504 511 DDI_SUCCESS) {
505 512 mutex_enter(&cpudsp->lock);
506 513 CPUDRV_MONITOR_INIT(cpudsp);
507 514 mutex_exit(&cpudsp->lock);
508 515 cmn_err(CE_WARN, "cpudrv_detach: instance %d: "
509 516 "can't raise CPU power level to %d",
510 517 instance,
511 518 CPUDRV_TOPSPEED(cpupm)->pm_level);
512 519 return (DDI_FAILURE);
513 520 } else {
514 521 return (DDI_SUCCESS);
515 522 }
516 523 } else {
517 524 mutex_exit(&cpudsp->lock);
518 525 return (DDI_SUCCESS);
519 526 }
520 527
521 528 default:
522 529 return (DDI_FAILURE);
523 530 }
524 531 }
525 532
526 533 /*
527 534 * Driver power(9e) entry point.
528 535 *
529 536 * Driver's notion of current power is set *only* in power(9e) entry point
530 537 * after actual power change operation has been successfully completed.
531 538 */
532 539 /* ARGSUSED */
533 540 static int
534 541 cpudrv_power(dev_info_t *dip, int comp, int level)
535 542 {
536 543 int instance;
537 544 cpudrv_devstate_t *cpudsp;
538 545 cpudrv_pm_t *cpudrvpm;
539 546 cpudrv_pm_spd_t *new_spd;
540 547 boolean_t is_ready;
541 548 int ret;
542 549
543 550 instance = ddi_get_instance(dip);
544 551
545 552 DPRINTF(D_POWER, ("cpudrv_power: instance %d: level %d\n",
546 553 instance, level));
547 554
548 555 if ((cpudsp = ddi_get_soft_state(cpudrv_state, instance)) == NULL) {
549 556 cmn_err(CE_WARN, "cpudrv_power: instance %d: can't "
550 557 "get state", instance);
551 558 return (DDI_FAILURE);
552 559 }
553 560
554 561 /*
555 562 * We're not ready until we can get a cpu_t
556 563 */
557 564 is_ready = (cpudrv_get_cpu(cpudsp) == DDI_SUCCESS);
558 565
559 566 mutex_enter(&cpudsp->lock);
560 567 cpudrvpm = &(cpudsp->cpudrv_pm);
561 568
562 569 /*
563 570 * In normal operation, we fail if we are busy and request is
564 571 * to lower the power level. We let this go through if the driver
565 572 * is in special direct pm mode. On x86, we also let this through
566 573 * if the change is due to a request to govern the max speed.
567 574 */
568 575 if (!cpudrv_direct_pm && (cpudrvpm->pm_busycnt >= 1) &&
569 576 !cpudrv_is_governor_thread(cpudrvpm)) {
570 577 if ((cpudrvpm->cur_spd != NULL) &&
571 578 (level < cpudrvpm->cur_spd->pm_level)) {
572 579 mutex_exit(&cpudsp->lock);
573 580 return (DDI_FAILURE);
574 581 }
575 582 }
576 583
577 584 for (new_spd = cpudrvpm->head_spd; new_spd; new_spd =
578 585 new_spd->down_spd) {
579 586 if (new_spd->pm_level == level)
580 587 break;
581 588 }
582 589 if (!new_spd) {
583 590 CPUDRV_RESET_GOVERNOR_THREAD(cpudrvpm);
584 591 mutex_exit(&cpudsp->lock);
585 592 cmn_err(CE_WARN, "cpudrv_power: instance %d: "
586 593 "can't locate new CPU speed", instance);
587 594 return (DDI_FAILURE);
588 595 }
589 596
590 597 /*
591 598 * We currently refuse to power manage if the CPU is not ready to
592 599 * take cross calls (cross calls fail silently if CPU is not ready
593 600 * for it).
594 601 *
595 602 * Additionally, for x86 platforms we cannot power manage an instance,
596 603 * until it has been initialized.
597 604 */
598 605 if (is_ready) {
599 606 is_ready = CPUDRV_XCALL_IS_READY(cpudsp->cpu_id);
600 607 if (!is_ready) {
601 608 DPRINTF(D_POWER, ("cpudrv_power: instance %d: "
602 609 "CPU not ready for x-calls\n", instance));
603 610 } else if (!(is_ready = cpudrv_power_ready(cpudsp->cp))) {
604 611 DPRINTF(D_POWER, ("cpudrv_power: instance %d: "
605 612 "waiting for all CPUs to be power manageable\n",
606 613 instance));
607 614 }
608 615 }
609 616 if (!is_ready) {
610 617 CPUDRV_RESET_GOVERNOR_THREAD(cpudrvpm);
611 618 mutex_exit(&cpudsp->lock);
612 619 return (DDI_FAILURE);
613 620 }
614 621
615 622 /*
616 623 * Execute CPU specific routine on the requested CPU to
617 624 * change its speed to normal-speed/divisor.
618 625 */
619 626 if ((ret = cpudrv_change_speed(cpudsp, new_spd)) != DDI_SUCCESS) {
620 627 cmn_err(CE_WARN, "cpudrv_power: "
621 628 "cpudrv_change_speed() return = %d", ret);
622 629 mutex_exit(&cpudsp->lock);
623 630 return (DDI_FAILURE);
624 631 }
625 632
626 633 /*
627 634 * Reset idle threshold time for the new power level.
628 635 */
629 636 if ((cpudrvpm->cur_spd != NULL) && (level <
630 637 cpudrvpm->cur_spd->pm_level)) {
631 638 if (pm_idle_component(dip, CPUDRV_COMP_NUM) ==
632 639 DDI_SUCCESS) {
633 640 if (cpudrvpm->pm_busycnt >= 1)
634 641 cpudrvpm->pm_busycnt--;
635 642 } else {
636 643 cmn_err(CE_WARN, "cpudrv_power: instance %d: "
637 644 "can't idle CPU component",
638 645 ddi_get_instance(dip));
639 646 }
640 647 }
641 648 /*
642 649 * Reset various parameters because we are now running at new speed.
643 650 */
644 651 cpudrvpm->lastquan_mstate[CMS_IDLE] = 0;
645 652 cpudrvpm->lastquan_mstate[CMS_SYSTEM] = 0;
646 653 cpudrvpm->lastquan_mstate[CMS_USER] = 0;
647 654 cpudrvpm->lastquan_ticks = 0;
648 655 cpudrvpm->cur_spd = new_spd;
649 656 CPUDRV_RESET_GOVERNOR_THREAD(cpudrvpm);
650 657 mutex_exit(&cpudsp->lock);
651 658
652 659 return (DDI_SUCCESS);
653 660 }
654 661
655 662 /*
656 663 * Initialize power management data.
657 664 */
658 665 static int
659 666 cpudrv_init(cpudrv_devstate_t *cpudsp)
660 667 {
661 668 cpudrv_pm_t *cpupm = &(cpudsp->cpudrv_pm);
662 669 cpudrv_pm_spd_t *cur_spd;
663 670 cpudrv_pm_spd_t *prev_spd = NULL;
664 671 int *speeds;
665 672 uint_t nspeeds;
666 673 int idle_cnt_percent;
667 674 int user_cnt_percent;
668 675 int i;
669 676
670 677 CPUDRV_GET_SPEEDS(cpudsp, speeds, nspeeds);
671 678 if (nspeeds < 2) {
672 679 /* Need at least two speeds to power manage */
673 680 CPUDRV_FREE_SPEEDS(speeds, nspeeds);
674 681 return (DDI_FAILURE);
675 682 }
676 683 cpupm->num_spd = nspeeds;
677 684
678 685 /*
679 686 * Calculate the watermarks and other parameters based on the
680 687 * supplied speeds.
681 688 *
682 689 * One of the basic assumption is that for X amount of CPU work,
683 690 * if CPU is slowed down by a factor of N, the time it takes to
684 691 * do the same work will be N * X.
685 692 *
686 693 * The driver declares that a CPU is idle and ready for slowed down,
687 694 * if amount of idle thread is more than the current speed idle_hwm
688 695 * without dropping below idle_hwm a number of consecutive sampling
689 696 * intervals and number of running threads in user mode are below
690 697 * user_lwm. We want to set the current user_lwm such that if we
691 698 * just switched to the next slower speed with no change in real work
692 699 * load, the amount of user threads at the slower speed will be such
693 700 * that it falls below the slower speed's user_hwm. If we didn't do
694 701 * that then we will just come back to the higher speed as soon as we
695 702 * go down even with no change in work load.
696 703 * The user_hwm is a fixed precentage and not calculated dynamically.
697 704 *
698 705 * We bring the CPU up if idle thread at current speed is less than
699 706 * the current speed idle_lwm for a number of consecutive sampling
700 707 * intervals or user threads are above the user_hwm for the current
701 708 * speed.
702 709 */
703 710 for (i = 0; i < nspeeds; i++) {
704 711 cur_spd = kmem_zalloc(sizeof (cpudrv_pm_spd_t), KM_SLEEP);
705 712 cur_spd->speed = speeds[i];
706 713 if (i == 0) { /* normal speed */
707 714 cpupm->head_spd = cur_spd;
708 715 CPUDRV_TOPSPEED(cpupm) = cur_spd;
709 716 cur_spd->quant_cnt = CPUDRV_QUANT_CNT_NORMAL;
710 717 cur_spd->idle_hwm =
711 718 (cpudrv_idle_hwm * cur_spd->quant_cnt) / 100;
712 719 /* can't speed anymore */
713 720 cur_spd->idle_lwm = 0;
714 721 cur_spd->user_hwm = UINT_MAX;
715 722 } else {
716 723 cur_spd->quant_cnt = CPUDRV_QUANT_CNT_OTHR;
717 724 ASSERT(prev_spd != NULL);
718 725 prev_spd->down_spd = cur_spd;
719 726 cur_spd->up_spd = cpupm->head_spd;
720 727
721 728 /*
722 729 * Let's assume CPU is considered idle at full speed
723 730 * when it is spending I% of time in running the idle
724 731 * thread. At full speed, CPU will be busy (100 - I) %
725 732 * of times. This % of busyness increases by factor of
726 733 * N as CPU slows down. CPU that is idle I% of times
727 734 * in full speed, it is idle (100 - ((100 - I) * N)) %
728 735 * of times in N speed. The idle_lwm is a fixed
729 736 * percentage. A large value of N may result in
730 737 * idle_hwm to go below idle_lwm. We need to make sure
731 738 * that there is at least a buffer zone seperation
732 739 * between the idle_lwm and idle_hwm values.
733 740 */
734 741 idle_cnt_percent = CPUDRV_IDLE_CNT_PERCENT(
735 742 cpudrv_idle_hwm, speeds, i);
736 743 idle_cnt_percent = max(idle_cnt_percent,
737 744 (cpudrv_idle_lwm + cpudrv_idle_buf_zone));
738 745 cur_spd->idle_hwm =
739 746 (idle_cnt_percent * cur_spd->quant_cnt) / 100;
740 747 cur_spd->idle_lwm =
741 748 (cpudrv_idle_lwm * cur_spd->quant_cnt) / 100;
742 749
743 750 /*
744 751 * The lwm for user threads are determined such that
745 752 * if CPU slows down, the load of work in the
746 753 * new speed would still keep the CPU at or below the
747 754 * user_hwm in the new speed. This is to prevent
748 755 * the quick jump back up to higher speed.
749 756 */
750 757 cur_spd->user_hwm = (cpudrv_user_hwm *
751 758 cur_spd->quant_cnt) / 100;
752 759 user_cnt_percent = CPUDRV_USER_CNT_PERCENT(
753 760 cpudrv_user_hwm, speeds, i);
754 761 prev_spd->user_lwm =
755 762 (user_cnt_percent * prev_spd->quant_cnt) / 100;
756 763 }
757 764 prev_spd = cur_spd;
758 765 }
759 766 /* Slowest speed. Can't slow down anymore */
760 767 cur_spd->idle_hwm = UINT_MAX;
761 768 cur_spd->user_lwm = -1;
762 769 #ifdef DEBUG
763 770 DPRINTF(D_PM_INIT, ("cpudrv_init: instance %d: head_spd spd %d, "
764 771 "num_spd %d\n", ddi_get_instance(cpudsp->dip),
765 772 cpupm->head_spd->speed, cpupm->num_spd));
766 773 for (cur_spd = cpupm->head_spd; cur_spd; cur_spd = cur_spd->down_spd) {
767 774 DPRINTF(D_PM_INIT, ("cpudrv_init: instance %d: speed %d, "
768 775 "down_spd spd %d, idle_hwm %d, user_lwm %d, "
769 776 "up_spd spd %d, idle_lwm %d, user_hwm %d, "
770 777 "quant_cnt %d\n", ddi_get_instance(cpudsp->dip),
771 778 cur_spd->speed,
772 779 (cur_spd->down_spd ? cur_spd->down_spd->speed : 0),
773 780 cur_spd->idle_hwm, cur_spd->user_lwm,
774 781 (cur_spd->up_spd ? cur_spd->up_spd->speed : 0),
775 782 cur_spd->idle_lwm, cur_spd->user_hwm,
776 783 cur_spd->quant_cnt));
777 784 }
778 785 #endif /* DEBUG */
779 786 CPUDRV_FREE_SPEEDS(speeds, nspeeds);
780 787 return (DDI_SUCCESS);
781 788 }
782 789
783 790 /*
784 791 * Free CPU power management data.
785 792 */
786 793 static void
787 794 cpudrv_free(cpudrv_devstate_t *cpudsp)
788 795 {
789 796 cpudrv_pm_t *cpupm = &(cpudsp->cpudrv_pm);
790 797 cpudrv_pm_spd_t *cur_spd, *next_spd;
791 798
792 799 cur_spd = cpupm->head_spd;
793 800 while (cur_spd) {
794 801 next_spd = cur_spd->down_spd;
795 802 kmem_free(cur_spd, sizeof (cpudrv_pm_spd_t));
796 803 cur_spd = next_spd;
797 804 }
798 805 bzero(cpupm, sizeof (cpudrv_pm_t));
799 806 }
800 807
801 808 /*
802 809 * Create pm-components property.
803 810 */
804 811 static int
805 812 cpudrv_comp_create(cpudrv_devstate_t *cpudsp)
806 813 {
807 814 cpudrv_pm_t *cpupm = &(cpudsp->cpudrv_pm);
808 815 cpudrv_pm_spd_t *cur_spd;
809 816 char **pmc;
810 817 int size;
811 818 char name[] = "NAME=CPU Speed";
812 819 int i, j;
813 820 uint_t comp_spd;
814 821 int result = DDI_FAILURE;
815 822
816 823 pmc = kmem_zalloc((cpupm->num_spd + 1) * sizeof (char *), KM_SLEEP);
817 824 size = CPUDRV_COMP_SIZE();
818 825 if (cpupm->num_spd > CPUDRV_COMP_MAX_VAL) {
819 826 cmn_err(CE_WARN, "cpudrv_comp_create: instance %d: "
820 827 "number of speeds exceeded limits",
821 828 ddi_get_instance(cpudsp->dip));
822 829 kmem_free(pmc, (cpupm->num_spd + 1) * sizeof (char *));
823 830 return (result);
824 831 }
825 832
826 833 for (i = cpupm->num_spd, cur_spd = cpupm->head_spd; i > 0;
827 834 i--, cur_spd = cur_spd->down_spd) {
828 835 cur_spd->pm_level = i;
829 836 pmc[i] = kmem_zalloc((size * sizeof (char)), KM_SLEEP);
830 837 comp_spd = CPUDRV_COMP_SPEED(cpupm, cur_spd);
831 838 if (comp_spd > CPUDRV_COMP_MAX_VAL) {
832 839 cmn_err(CE_WARN, "cpudrv_comp_create: "
833 840 "instance %d: speed exceeded limits",
834 841 ddi_get_instance(cpudsp->dip));
835 842 for (j = cpupm->num_spd; j >= i; j--) {
836 843 kmem_free(pmc[j], size * sizeof (char));
837 844 }
838 845 kmem_free(pmc, (cpupm->num_spd + 1) *
839 846 sizeof (char *));
840 847 return (result);
841 848 }
842 849 CPUDRV_COMP_SPRINT(pmc[i], cpupm, cur_spd, comp_spd)
843 850 DPRINTF(D_PM_COMP_CREATE, ("cpudrv_comp_create: "
844 851 "instance %d: pm-components power level %d string '%s'\n",
845 852 ddi_get_instance(cpudsp->dip), i, pmc[i]));
846 853 }
847 854 pmc[0] = kmem_zalloc(sizeof (name), KM_SLEEP);
848 855 (void) strcat(pmc[0], name);
849 856 DPRINTF(D_PM_COMP_CREATE, ("cpudrv_comp_create: instance %d: "
850 857 "pm-components component name '%s'\n",
851 858 ddi_get_instance(cpudsp->dip), pmc[0]));
852 859
853 860 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, cpudsp->dip,
854 861 "pm-components", pmc, cpupm->num_spd + 1) == DDI_PROP_SUCCESS) {
855 862 result = DDI_SUCCESS;
856 863 } else {
857 864 cmn_err(CE_WARN, "cpudrv_comp_create: instance %d: "
858 865 "can't create pm-components property",
859 866 ddi_get_instance(cpudsp->dip));
860 867 }
861 868
862 869 for (i = cpupm->num_spd; i > 0; i--) {
863 870 kmem_free(pmc[i], size * sizeof (char));
864 871 }
865 872 kmem_free(pmc[0], sizeof (name));
866 873 kmem_free(pmc, (cpupm->num_spd + 1) * sizeof (char *));
867 874 return (result);
868 875 }
869 876
870 877 /*
871 878 * Mark a component idle.
872 879 */
873 880 #define CPUDRV_MONITOR_PM_IDLE_COMP(dip, cpupm) { \
874 881 if ((cpupm)->pm_busycnt >= 1) { \
875 882 if (pm_idle_component((dip), CPUDRV_COMP_NUM) == \
876 883 DDI_SUCCESS) { \
877 884 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: " \
878 885 "instance %d: pm_idle_component called\n", \
879 886 ddi_get_instance((dip)))); \
880 887 (cpupm)->pm_busycnt--; \
881 888 } else { \
882 889 cmn_err(CE_WARN, "cpudrv_monitor: instance %d: " \
883 890 "can't idle CPU component", \
884 891 ddi_get_instance((dip))); \
885 892 } \
886 893 } \
887 894 }
888 895
889 896 /*
890 897 * Marks a component busy in both PM framework and driver state structure.
891 898 */
892 899 #define CPUDRV_MONITOR_PM_BUSY_COMP(dip, cpupm) { \
893 900 if ((cpupm)->pm_busycnt < 1) { \
894 901 if (pm_busy_component((dip), CPUDRV_COMP_NUM) == \
895 902 DDI_SUCCESS) { \
896 903 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: " \
897 904 "instance %d: pm_busy_component called\n", \
898 905 ddi_get_instance((dip)))); \
899 906 (cpupm)->pm_busycnt++; \
900 907 } else { \
901 908 cmn_err(CE_WARN, "cpudrv_monitor: instance %d: " \
902 909 "can't busy CPU component", \
903 910 ddi_get_instance((dip))); \
904 911 } \
905 912 } \
906 913 }
907 914
908 915 /*
909 916 * Marks a component busy and calls pm_raise_power().
910 917 */
911 918 #define CPUDRV_MONITOR_PM_BUSY_AND_RAISE(dip, cpudsp, cpupm, new_spd) { \
912 919 int ret; \
913 920 /* \
914 921 * Mark driver and PM framework busy first so framework doesn't try \
915 922 * to bring CPU to lower speed when we need to be at higher speed. \
916 923 */ \
917 924 CPUDRV_MONITOR_PM_BUSY_COMP((dip), (cpupm)); \
918 925 mutex_exit(&(cpudsp)->lock); \
919 926 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: " \
920 927 "pm_raise_power called to %d\n", ddi_get_instance((dip)), \
921 928 (new_spd->pm_level))); \
922 929 ret = pm_raise_power((dip), CPUDRV_COMP_NUM, (new_spd->pm_level)); \
923 930 if (ret != DDI_SUCCESS) { \
924 931 cmn_err(CE_WARN, "cpudrv_monitor: instance %d: can't " \
925 932 "raise CPU power level", ddi_get_instance((dip))); \
926 933 } \
927 934 mutex_enter(&(cpudsp)->lock); \
928 935 if (ret == DDI_SUCCESS && cpudsp->cpudrv_pm.cur_spd == NULL) { \
929 936 cpudsp->cpudrv_pm.cur_spd = new_spd; \
930 937 } \
931 938 }
932 939
933 940 /*
934 941 * In order to monitor a CPU, we need to hold cpu_lock to access CPU
935 942 * statistics. Holding cpu_lock is not allowed from a callout routine.
936 943 * We dispatch a taskq to do that job.
937 944 */
938 945 static void
939 946 cpudrv_monitor_disp(void *arg)
940 947 {
941 948 cpudrv_devstate_t *cpudsp = (cpudrv_devstate_t *)arg;
942 949
943 950 /*
944 951 * We are here because the last task has scheduled a timeout.
945 952 * The queue should be empty at this time.
946 953 */
947 954 mutex_enter(&cpudsp->cpudrv_pm.timeout_lock);
948 955 if ((ddi_taskq_dispatch(cpudsp->cpudrv_pm.tq, cpudrv_monitor, arg,
949 956 DDI_NOSLEEP)) != DDI_SUCCESS) {
950 957 mutex_exit(&cpudsp->cpudrv_pm.timeout_lock);
951 958 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor_disp: failed to "
952 959 "dispatch the cpudrv_monitor taskq\n"));
953 960 mutex_enter(&cpudsp->lock);
954 961 CPUDRV_MONITOR_INIT(cpudsp);
955 962 mutex_exit(&cpudsp->lock);
956 963 return;
957 964 }
958 965 cpudsp->cpudrv_pm.timeout_count++;
959 966 mutex_exit(&cpudsp->cpudrv_pm.timeout_lock);
960 967 }
961 968
962 969 /*
963 970 * Monitors each CPU for the amount of time idle thread was running in the
964 971 * last quantum and arranges for the CPU to go to the lower or higher speed.
965 972 * Called at the time interval appropriate for the current speed. The
966 973 * time interval for normal speed is CPUDRV_QUANT_CNT_NORMAL. The time
967 974 * interval for other speeds (including unknown speed) is
968 975 * CPUDRV_QUANT_CNT_OTHR.
969 976 */
970 977 static void
971 978 cpudrv_monitor(void *arg)
972 979 {
973 980 cpudrv_devstate_t *cpudsp = (cpudrv_devstate_t *)arg;
974 981 cpudrv_pm_t *cpupm;
975 982 cpudrv_pm_spd_t *cur_spd, *new_spd;
976 983 dev_info_t *dip;
977 984 uint_t idle_cnt, user_cnt, system_cnt;
978 985 clock_t ticks;
979 986 uint_t tick_cnt;
980 987 hrtime_t msnsecs[NCMSTATES];
981 988 boolean_t is_ready;
982 989
983 990 #define GET_CPU_MSTATE_CNT(state, cnt) \
984 991 msnsecs[state] = NSEC_TO_TICK(msnsecs[state]); \
985 992 if (cpupm->lastquan_mstate[state] > msnsecs[state]) \
986 993 msnsecs[state] = cpupm->lastquan_mstate[state]; \
987 994 cnt = msnsecs[state] - cpupm->lastquan_mstate[state]; \
988 995 cpupm->lastquan_mstate[state] = msnsecs[state]
989 996
990 997 /*
991 998 * We're not ready until we can get a cpu_t
992 999 */
993 1000 is_ready = (cpudrv_get_cpu(cpudsp) == DDI_SUCCESS);
994 1001
995 1002 mutex_enter(&cpudsp->lock);
996 1003 cpupm = &(cpudsp->cpudrv_pm);
997 1004 if (cpupm->timeout_id == 0) {
998 1005 mutex_exit(&cpudsp->lock);
999 1006 goto do_return;
1000 1007 }
1001 1008 cur_spd = cpupm->cur_spd;
1002 1009 dip = cpudsp->dip;
1003 1010
1004 1011 /*
1005 1012 * We assume that a CPU is initialized and has a valid cpu_t
1006 1013 * structure, if it is ready for cross calls. If this changes,
1007 1014 * additional checks might be needed.
1008 1015 *
1009 1016 * Additionally, for x86 platforms we cannot power manage an
1010 1017 * instance, until it has been initialized.
1011 1018 */
1012 1019 if (is_ready) {
1013 1020 is_ready = CPUDRV_XCALL_IS_READY(cpudsp->cpu_id);
1014 1021 if (!is_ready) {
1015 1022 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
1016 1023 "CPU not ready for x-calls\n",
1017 1024 ddi_get_instance(dip)));
1018 1025 } else if (!(is_ready = cpudrv_power_ready(cpudsp->cp))) {
1019 1026 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
1020 1027 "waiting for all CPUs to be power manageable\n",
1021 1028 ddi_get_instance(dip)));
1022 1029 }
1023 1030 }
1024 1031 if (!is_ready) {
1025 1032 /*
1026 1033 * Make sure that we are busy so that framework doesn't
1027 1034 * try to bring us down in this situation.
1028 1035 */
1029 1036 CPUDRV_MONITOR_PM_BUSY_COMP(dip, cpupm);
1030 1037 CPUDRV_MONITOR_INIT(cpudsp);
1031 1038 mutex_exit(&cpudsp->lock);
1032 1039 goto do_return;
1033 1040 }
1034 1041
1035 1042 /*
1036 1043 * Make sure that we are still not at unknown power level.
1037 1044 */
1038 1045 if (cur_spd == NULL) {
1039 1046 DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
1040 1047 "cur_spd is unknown\n", ddi_get_instance(dip)));
1041 1048 CPUDRV_MONITOR_PM_BUSY_AND_RAISE(dip, cpudsp, cpupm,
1042 1049 CPUDRV_TOPSPEED(cpupm));
1043 1050 /*
1044 1051 * We just changed the speed. Wait till at least next
1045 1052 * call to this routine before proceeding ahead.
1046 1053 */
1047 1054 CPUDRV_MONITOR_INIT(cpudsp);
1048 1055 mutex_exit(&cpudsp->lock);
1049 1056 goto do_return;
1050 1057 }
1051 1058
1052 1059 if (!cpupm->pm_started) {
1053 1060 cpupm->pm_started = B_TRUE;
1054 1061 cpudrv_set_supp_freqs(cpudsp);
1055 1062 }
1056 1063
1057 1064 get_cpu_mstate(cpudsp->cp, msnsecs);
1058 1065 GET_CPU_MSTATE_CNT(CMS_IDLE, idle_cnt);
1059 1066 GET_CPU_MSTATE_CNT(CMS_USER, user_cnt);
1060 1067 GET_CPU_MSTATE_CNT(CMS_SYSTEM, system_cnt);
1061 1068
1062 1069 /*
1063 1070 * We can't do anything when we have just switched to a state
1064 1071 * because there is no valid timestamp.
1065 1072 */
1066 1073 if (cpupm->lastquan_ticks == 0) {
1067 1074 cpupm->lastquan_ticks = NSEC_TO_TICK(gethrtime());
1068 1075 CPUDRV_MONITOR_INIT(cpudsp);
1069 1076 mutex_exit(&cpudsp->lock);
1070 1077 goto do_return;
1071 1078 }
1072 1079
1073 1080 /*
1074 1081 * Various watermarks are based on this routine being called back
1075 1082 * exactly at the requested period. This is not guaranteed
1076 1083 * because this routine is called from a taskq that is dispatched
1077 1084 * from a timeout routine. Handle this by finding out how many
1078 1085 * ticks have elapsed since the last call and adjusting
1079 1086 * the idle_cnt based on the delay added to the requested period
1080 1087 * by timeout and taskq.
1081 1088 */
1082 1089 ticks = NSEC_TO_TICK(gethrtime());
1083 1090 tick_cnt = ticks - cpupm->lastquan_ticks;
1084 1091 ASSERT(tick_cnt != 0);
1085 1092 cpupm->lastquan_ticks = ticks;
1086 1093
1087 1094 /*
1088 1095 * Time taken between recording the current counts and
1089 1096 * arranging the next call of this routine is an error in our
1090 1097 * calculation. We minimize the error by calling
1091 1098 * CPUDRV_MONITOR_INIT() here instead of end of this routine.
1092 1099 */
1093 1100 CPUDRV_MONITOR_INIT(cpudsp);
1094 1101 DPRINTF(D_PM_MONITOR_VERBOSE, ("cpudrv_monitor: instance %d: "
1095 1102 "idle count %d, user count %d, system count %d, pm_level %d, "
1096 1103 "pm_busycnt %d\n", ddi_get_instance(dip), idle_cnt, user_cnt,
1097 1104 system_cnt, cur_spd->pm_level, cpupm->pm_busycnt));
1098 1105
1099 1106 #ifdef DEBUG
1100 1107 /*
1101 1108 * Notify that timeout and taskq has caused delays and we need to
1102 1109 * scale our parameters accordingly.
1103 1110 *
1104 1111 * To get accurate result, don't turn on other DPRINTFs with
1105 1112 * the following DPRINTF. PROM calls generated by other
1106 1113 * DPRINTFs changes the timing.
1107 1114 */
1108 1115 if (tick_cnt > cur_spd->quant_cnt) {
1109 1116 DPRINTF(D_PM_MONITOR_DELAY, ("cpudrv_monitor: instance %d: "
1110 1117 "tick count %d > quantum_count %u\n",
1111 1118 ddi_get_instance(dip), tick_cnt, cur_spd->quant_cnt));
1112 1119 }
1113 1120 #endif /* DEBUG */
1114 1121
1115 1122 /*
1116 1123 * Adjust counts based on the delay added by timeout and taskq.
1117 1124 */
1118 1125 idle_cnt = (idle_cnt * cur_spd->quant_cnt) / tick_cnt;
1119 1126 user_cnt = (user_cnt * cur_spd->quant_cnt) / tick_cnt;
1120 1127
1121 1128 if ((user_cnt > cur_spd->user_hwm) || (idle_cnt < cur_spd->idle_lwm &&
1122 1129 cur_spd->idle_blwm_cnt >= cpudrv_idle_blwm_cnt_max)) {
1123 1130 cur_spd->idle_blwm_cnt = 0;
1124 1131 cur_spd->idle_bhwm_cnt = 0;
1125 1132 /*
1126 1133 * In normal situation, arrange to go to next higher speed.
1127 1134 * If we are running in special direct pm mode, we just stay
1128 1135 * at the current speed.
1129 1136 */
1130 1137 if (cur_spd == cur_spd->up_spd || cpudrv_direct_pm) {
1131 1138 CPUDRV_MONITOR_PM_BUSY_COMP(dip, cpupm);
1132 1139 } else {
1133 1140 new_spd = cur_spd->up_spd;
1134 1141 CPUDRV_MONITOR_PM_BUSY_AND_RAISE(dip, cpudsp, cpupm,
1135 1142 new_spd);
1136 1143 }
1137 1144 } else if ((user_cnt <= cur_spd->user_lwm) &&
1138 1145 (idle_cnt >= cur_spd->idle_hwm) || !CPU_ACTIVE(cpudsp->cp)) {
1139 1146 cur_spd->idle_blwm_cnt = 0;
1140 1147 cur_spd->idle_bhwm_cnt = 0;
1141 1148 /*
1142 1149 * Arrange to go to next lower speed by informing our idle
1143 1150 * status to the power management framework.
1144 1151 */
1145 1152 CPUDRV_MONITOR_PM_IDLE_COMP(dip, cpupm);
1146 1153 } else {
1147 1154 /*
1148 1155 * If we are between the idle water marks and have not
1149 1156 * been here enough consecutive times to be considered
1150 1157 * busy, just increment the count and return.
1151 1158 */
1152 1159 if ((idle_cnt < cur_spd->idle_hwm) &&
1153 1160 (idle_cnt >= cur_spd->idle_lwm) &&
1154 1161 (cur_spd->idle_bhwm_cnt < cpudrv_idle_bhwm_cnt_max)) {
1155 1162 cur_spd->idle_blwm_cnt = 0;
1156 1163 cur_spd->idle_bhwm_cnt++;
1157 1164 mutex_exit(&cpudsp->lock);
1158 1165 goto do_return;
1159 1166 }
1160 1167 if (idle_cnt < cur_spd->idle_lwm) {
1161 1168 cur_spd->idle_blwm_cnt++;
1162 1169 cur_spd->idle_bhwm_cnt = 0;
1163 1170 }
1164 1171 /*
1165 1172 * Arranges to stay at the current speed.
1166 1173 */
1167 1174 CPUDRV_MONITOR_PM_BUSY_COMP(dip, cpupm);
1168 1175 }
1169 1176 mutex_exit(&cpudsp->lock);
1170 1177 do_return:
1171 1178 mutex_enter(&cpupm->timeout_lock);
1172 1179 ASSERT(cpupm->timeout_count > 0);
1173 1180 cpupm->timeout_count--;
1174 1181 cv_signal(&cpupm->timeout_cv);
1175 1182 mutex_exit(&cpupm->timeout_lock);
1176 1183 }
1177 1184
1178 1185 /*
1179 1186 * get cpu_t structure for cpudrv_devstate_t
1180 1187 */
1181 1188 int
1182 1189 cpudrv_get_cpu(cpudrv_devstate_t *cpudsp)
1183 1190 {
1184 1191 ASSERT(cpudsp != NULL);
1185 1192
1186 1193 /*
1187 1194 * return DDI_SUCCESS if cpudrv_devstate_t
1188 1195 * already contains cpu_t structure
1189 1196 */
1190 1197 if (cpudsp->cp != NULL)
1191 1198 return (DDI_SUCCESS);
1192 1199
1193 1200 if (MUTEX_HELD(&cpu_lock)) {
1194 1201 cpudsp->cp = cpu_get(cpudsp->cpu_id);
1195 1202 } else {
1196 1203 mutex_enter(&cpu_lock);
1197 1204 cpudsp->cp = cpu_get(cpudsp->cpu_id);
1198 1205 mutex_exit(&cpu_lock);
1199 1206 }
1200 1207
1201 1208 if (cpudsp->cp == NULL)
1202 1209 return (DDI_FAILURE);
1203 1210
1204 1211 return (DDI_SUCCESS);
1205 1212 }
↓ open down ↓ |
845 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX