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 }