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