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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/kmem.h> 31 #include <sys/async.h> 32 #include <sys/sysmacros.h> 33 #include <sys/sunddi.h> 34 #include <sys/sunndi.h> 35 #include <sys/ddi_impldefs.h> 36 #include <sys/ddi_implfuncs.h> 37 #include <sys/pci/pci_obj.h> 38 #include <sys/pci/pci_pwr.h> 39 #include <sys/pci.h> 40 41 static void pci_pwr_update_comp(pci_pwr_t *pwr_p, pci_pwr_chld_t *p, int comp, 42 int lvl); 43 44 #ifdef DEBUG 45 static char *pci_pwr_bus_label[] = {"PM_LEVEL_B3", "PM_LEVEL_B2", \ 46 "PM_LEVEL_B1", "PM_LEVEL_B0"}; 47 #endif 48 49 /*LINTLIBRARY*/ 50 51 /* 52 * Retreive the pci_pwr_chld_t structure for a given devinfo node. 53 */ 54 pci_pwr_chld_t * 55 pci_pwr_get_info(pci_pwr_t *pwr_p, dev_info_t *dip) 56 { 57 pci_pwr_chld_t *p; 58 59 ASSERT(PM_CAPABLE(pwr_p)); 60 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex)); 61 62 for (p = pwr_p->pwr_info; p != NULL; p = p->next) { 63 if (p->dip == dip) { 64 65 return (p); 66 } 67 } 68 69 cmn_err(CE_PANIC, "unable to find pwr info data for %s@%s", 70 ddi_node_name(dip), ddi_get_name_addr(dip)); 71 72 /*NOTREACHED*/ 73 } 74 75 /* 76 * Create a pci_pwr_chld_t structure for a given devinfo node. 77 */ 78 void 79 pci_pwr_create_info(pci_pwr_t *pwr_p, dev_info_t *dip) 80 { 81 pci_pwr_chld_t *p; 82 83 ASSERT(PM_CAPABLE(pwr_p)); 84 85 DEBUG2(DBG_PWR, ddi_get_parent(dip), "ADDING NEW PWR_INFO %s@%s\n", 86 ddi_node_name(dip), ddi_get_name_addr(dip)); 87 88 p = kmem_zalloc(sizeof (struct pci_pwr_chld), KM_SLEEP); 89 p->dip = dip; 90 91 mutex_enter(&pwr_p->pwr_mutex); 92 93 /* 94 * Until components are created for this device, bus 95 * should be at full power since power of child device 96 * is unknown. Increment # children requiring "full power" 97 */ 98 p->flags |= PWR_FP_HOLD; 99 pwr_p->pwr_fp++; 100 101 p->next = pwr_p->pwr_info; 102 pwr_p->pwr_info = p; 103 104 pci_pwr_change(pwr_p, pwr_p->current_lvl, pci_pwr_new_lvl(pwr_p)); 105 106 mutex_exit(&pwr_p->pwr_mutex); 107 } 108 109 void 110 pci_pwr_rm_info(pci_pwr_t *pwr_p, dev_info_t *cdip) 111 { 112 pci_pwr_chld_t **prev_infop; 113 pci_pwr_chld_t *infop = NULL; 114 int i; 115 116 ASSERT(PM_CAPABLE(pwr_p)); 117 118 mutex_enter(&pwr_p->pwr_mutex); 119 120 for (prev_infop = &pwr_p->pwr_info; *prev_infop != NULL; 121 prev_infop = &((*prev_infop)->next)) { 122 if ((*prev_infop)->dip == cdip) { 123 infop = *prev_infop; 124 break; 125 } 126 } 127 128 if (infop == NULL) { 129 130 mutex_exit(&pwr_p->pwr_mutex); 131 return; 132 } 133 134 *prev_infop = infop->next; 135 136 /* 137 * Remove any reference counts for this child. 138 */ 139 if (infop->comp_pwr != NULL) { 140 for (i = 0; i < infop->num_comps; i++) { 141 pci_pwr_update_comp(pwr_p, infop, i, PM_LEVEL_NOLEVEL); 142 } 143 144 kmem_free(infop->comp_pwr, sizeof (int) * infop->num_comps); 145 } 146 147 if (infop->flags & PWR_FP_HOLD) { 148 pwr_p->pwr_fp--; 149 } 150 151 pci_pwr_change(pwr_p, pwr_p->current_lvl, pci_pwr_new_lvl(pwr_p)); 152 mutex_exit(&pwr_p->pwr_mutex); 153 kmem_free(infop, sizeof (struct pci_pwr_chld)); 154 } 155 156 /* 157 * Allocate space for component state information in pci_pwr_chld_t 158 */ 159 void 160 pci_pwr_add_components(pci_pwr_t *pwr_p, dev_info_t *cdip, pci_pwr_chld_t *p) 161 { 162 int num_comps = PM_NUMCMPTS(cdip); 163 int i; 164 165 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex)); 166 /* 167 * Assume the power level of a component is UNKNOWN until 168 * notified otherwise. 169 */ 170 if (num_comps > 0) { 171 p->comp_pwr = 172 kmem_alloc(sizeof (int) * num_comps, KM_SLEEP); 173 p->num_comps = num_comps; 174 175 DEBUG3(DBG_PWR, ddi_get_parent(cdip), 176 "ADDING %d COMPONENTS FOR %s@%s\n", num_comps, 177 ddi_node_name(cdip), ddi_get_name_addr(cdip)); 178 } else { 179 cmn_err(CE_WARN, "%s%d device has %d components", 180 ddi_driver_name(cdip), ddi_get_instance(cdip), 181 num_comps); 182 183 return; 184 } 185 186 /* 187 * Release the fp hold that was made when the device 188 * was created. 189 */ 190 ASSERT((p->flags & PWR_FP_HOLD) == PWR_FP_HOLD); 191 p->flags &= ~PWR_FP_HOLD; 192 pwr_p->pwr_fp--; 193 194 for (i = 0; i < num_comps; i++) { 195 /* 196 * Initialize the component lvl so that the 197 * state reference counts will be updated correctly. 198 */ 199 p->comp_pwr[i] = PM_LEVEL_NOLEVEL; 200 pci_pwr_update_comp(pwr_p, p, i, PM_LEVEL_UNKNOWN); 201 } 202 } 203 204 /* 205 * Update the current power level for component. Then adjust the 206 * bus reference counter for given state. 207 */ 208 static void 209 pci_pwr_update_comp(pci_pwr_t *pwr_p, pci_pwr_chld_t *p, int comp, 210 int lvl) 211 { 212 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex)); 213 214 /* 215 * Remove old pwr state count for old PM level. 216 */ 217 switch (p->comp_pwr[comp]) { 218 case PM_LEVEL_UNKNOWN: 219 pwr_p->pwr_uk--; 220 p->u01--; 221 ASSERT(pwr_p->pwr_uk >= 0); 222 break; 223 case PM_LEVEL_D0: 224 pwr_p->pwr_d0--; 225 p->u01--; 226 ASSERT(pwr_p->pwr_d0 >= 0); 227 break; 228 case PM_LEVEL_D1: 229 pwr_p->pwr_d1--; 230 p->u01--; 231 ASSERT(pwr_p->pwr_d1 >= 0); 232 break; 233 case PM_LEVEL_D2: 234 pwr_p->pwr_d2--; 235 ASSERT(pwr_p->pwr_d2 >= 0); 236 break; 237 case PM_LEVEL_D3: 238 pwr_p->pwr_d3--; 239 ASSERT(pwr_p->pwr_d3 >= 0); 240 break; 241 default: 242 break; 243 } 244 245 p->comp_pwr[comp] = lvl; 246 /* 247 * Add new pwr state count for the new PM level. 248 */ 249 switch (lvl) { 250 case PM_LEVEL_UNKNOWN: 251 pwr_p->pwr_uk++; 252 p->u01++; 253 break; 254 case PM_LEVEL_D0: 255 pwr_p->pwr_d0++; 256 p->u01++; 257 break; 258 case PM_LEVEL_D1: 259 pwr_p->pwr_d1++; 260 p->u01++; 261 break; 262 case PM_LEVEL_D2: 263 pwr_p->pwr_d2++; 264 break; 265 case PM_LEVEL_D3: 266 pwr_p->pwr_d3++; 267 break; 268 default: 269 break; 270 } 271 272 } 273 274 /* 275 * Knowing the current state of all devices on the bus, return the 276 * appropriate supported bus speed. 277 */ 278 int 279 pci_pwr_new_lvl(pci_pwr_t *pwr_p) 280 { 281 int b_lvl; 282 283 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex)); 284 285 if (pwr_p->pwr_fp > 0) { 286 DEBUG1(DBG_PWR, pwr_p->pwr_dip, "new_lvl: " 287 "returning PM_LEVEL_B0 pwr_fp = %d\n", pwr_p->pwr_fp); 288 289 return (PM_LEVEL_B0); 290 } 291 292 /* 293 * If any components are at unknown power levels, the 294 * highest power level has to be assumed for the device (D0). 295 */ 296 if (pwr_p->pwr_uk > 0) { 297 DEBUG1(DBG_PWR, pwr_p->pwr_dip, "new_lvl: unknown " 298 "count is %d. returning PM_LEVEL_B0\n", pwr_p->pwr_uk); 299 300 return (PM_LEVEL_B0); 301 } 302 303 /* 304 * Find the lowest theoretical level 305 * the bus can operate at. 306 */ 307 if (pwr_p->pwr_d0 > 0) { 308 b_lvl = PM_LEVEL_B0; 309 DEBUG1(DBG_PWR, pwr_p->pwr_dip, 310 "new_lvl: PM_LEVEL_B0 d0 count = %d\n", 311 pwr_p->pwr_d0); 312 } else if (pwr_p->pwr_d1 > 0) { 313 b_lvl = PM_LEVEL_B1; 314 DEBUG1(DBG_PWR, pwr_p->pwr_dip, 315 "new_lvl: PM_LEVEL_B1 d1 count = %d\n", 316 pwr_p->pwr_d1); 317 } else if (pwr_p->pwr_d2 > 0) { 318 b_lvl = PM_LEVEL_B2; 319 DEBUG1(DBG_PWR, pwr_p->pwr_dip, 320 "new_lvl: PM_LEVEL_B2 d2 count = %d\n", 321 pwr_p->pwr_d2); 322 } else if (pwr_p->pwr_d3 > 0) { 323 b_lvl = PM_LEVEL_B3; 324 DEBUG1(DBG_PWR, pwr_p->pwr_dip, 325 "new_lvl: PM_LEVEL_B3 d3 count = %d\n", 326 pwr_p->pwr_d3); 327 } else { 328 DEBUG0(DBG_PWR, pwr_p->pwr_dip, 329 "new_lvl: PM_LEVEL_B3: all counts are 0\n"); 330 b_lvl = PM_LEVEL_B3; 331 } 332 333 /* 334 * Now find the closest supported level available. 335 * If the level isn't available, have to find the 336 * next highest power level (or lowest in B# terms). 337 */ 338 switch (b_lvl) { 339 case PM_LEVEL_B3: 340 if (pwr_p->pwr_flags & PCI_PWR_B3_CAPABLE) { 341 break; 342 } 343 /*FALLTHROUGH*/ 344 case PM_LEVEL_B2: 345 if (pwr_p->pwr_flags & PCI_PWR_B2_CAPABLE) { 346 b_lvl = PM_LEVEL_B2; 347 break; 348 } 349 /*FALLTHROUGH*/ 350 case PM_LEVEL_B1: 351 if (pwr_p->pwr_flags & PCI_PWR_B1_CAPABLE) { 352 b_lvl = PM_LEVEL_B1; 353 break; 354 } 355 /*FALLTHROUGH*/ 356 case PM_LEVEL_B0: 357 /* 358 * This level always supported 359 */ 360 b_lvl = PM_LEVEL_B0; 361 break; 362 } 363 DEBUG1(DBG_PWR, pwr_p->pwr_dip, 364 "new_lvl: Adjusted Level is %s\n", 365 pci_pwr_bus_label[b_lvl]); 366 367 return (b_lvl); 368 369 } 370 371 int 372 pci_raise_power(pci_pwr_t *pwr_p, int current, int new, void *impl_arg, 373 pm_bp_nexus_pwrup_t bpn) 374 { 375 int ret = DDI_SUCCESS, pwrup_res; 376 377 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex)); 378 379 pci_pwr_component_busy(pwr_p); 380 mutex_exit(&pwr_p->pwr_mutex); 381 ret = pm_busop_bus_power(pwr_p->pwr_dip, impl_arg, 382 BUS_POWER_NEXUS_PWRUP, (void *) &bpn, 383 (void *) &pwrup_res); 384 if (ret != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) { 385 mutex_enter(&pwr_p->pwr_mutex); 386 pci_pwr_component_idle(pwr_p); 387 mutex_exit(&pwr_p->pwr_mutex); 388 cmn_err(CE_WARN, "%s%d pci_raise_power failed", 389 ddi_driver_name(pwr_p->pwr_dip), 390 ddi_get_instance(pwr_p->pwr_dip)); 391 } 392 393 return (ret); 394 } 395 396 int 397 pci_pwr_ops(pci_pwr_t *pwr_p, dev_info_t *dip, void *impl_arg, 398 pm_bus_power_op_t op, void *arg, void *result) 399 { 400 pci_pwr_chld_t *p_chld; 401 pm_bp_nexus_pwrup_t bpn; 402 pm_bp_child_pwrchg_t *bpc = (pm_bp_child_pwrchg_t *)arg; 403 dev_info_t *rdip = bpc->bpc_dip; 404 int new_level, *res = (int *)result, ret = DDI_SUCCESS; 405 406 mutex_enter(&pwr_p->pwr_mutex); 407 switch (op) { 408 case BUS_POWER_HAS_CHANGED: 409 p_chld = pci_pwr_get_info(pwr_p, rdip); 410 DEBUG5(DBG_PWR, dip, "%s@%s CHANGED_POWER cmp = %d " 411 "old = %d new = %d\n", 412 ddi_node_name(rdip), ddi_get_name_addr(rdip), 413 bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel); 414 415 if (*res == DDI_FAILURE) { 416 DEBUG0(DBG_PWR, rdip, "changed_power_req FAILED\n"); 417 break; 418 } else { 419 420 /* 421 * pci_pwr_add_components must be called here if 422 * comp_pwr hasn't been set up yet. It has to be done 423 * here rather than in post-attach, since it is possible 424 * for power() of child to get called before attach 425 * completes. 426 */ 427 if (p_chld->comp_pwr == NULL) 428 pci_pwr_add_components(pwr_p, rdip, p_chld); 429 430 pci_pwr_update_comp(pwr_p, p_chld, 431 bpc->bpc_comp, bpc->bpc_nlevel); 432 } 433 434 new_level = pci_pwr_new_lvl(pwr_p); 435 bpn.bpn_dip = pwr_p->pwr_dip; 436 bpn.bpn_comp = PCI_PM_COMP_0; 437 bpn.bpn_level = new_level; 438 bpn.bpn_private = bpc->bpc_private; 439 440 if (new_level > pwr_p->current_lvl) 441 return (pci_raise_power(pwr_p, pwr_p->current_lvl, 442 new_level, impl_arg, bpn)); 443 else 444 pci_pwr_change(pwr_p, pwr_p->current_lvl, 445 new_level); 446 break; 447 448 case BUS_POWER_PRE_NOTIFICATION: 449 DEBUG5(DBG_PWR, dip, "PRE %s@%s cmp = %d old = %d " 450 "new = %d. TEMP FULL POWER\n", 451 ddi_node_name(rdip), ddi_get_name_addr(rdip), 452 bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel); 453 454 /* 455 * Any state changes require that the bus be at full 456 * power (B0) so that the device configuration 457 * registers can be accessed. Make a fp hold here 458 * so device remains at full power during power 459 * configuration. 460 */ 461 462 pwr_p->pwr_fp++; 463 DEBUG1(DBG_PWR, pwr_p->pwr_dip, 464 "incremented fp is %d in PRE_NOTE\n\n", pwr_p->pwr_fp); 465 466 bpn.bpn_dip = pwr_p->pwr_dip; 467 bpn.bpn_comp = PCI_PM_COMP_0; 468 bpn.bpn_level = PM_LEVEL_B0; 469 bpn.bpn_private = bpc->bpc_private; 470 471 if (PM_LEVEL_B0 > pwr_p->current_lvl) 472 return (pci_raise_power(pwr_p, pwr_p->current_lvl, 473 PM_LEVEL_B0, impl_arg, bpn)); 474 475 break; 476 477 case BUS_POWER_POST_NOTIFICATION: 478 p_chld = pci_pwr_get_info(pwr_p, rdip); 479 DEBUG5(DBG_PWR, dip, "POST %s@%s cmp = %d old = %d new = %d\n", 480 ddi_node_name(rdip), ddi_get_name_addr(rdip), 481 bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel); 482 483 if (*res == DDI_FAILURE) { 484 DEBUG0(DBG_PWR, rdip, "child's power routine FAILED\n"); 485 } else { 486 487 /* 488 * pci_pwr_add_components must be called here if 489 * comp_pwr hasen't been set up yet. It has to be done 490 * here rather than in post-attach, since it is possible 491 * for power() of child to get called before attach 492 * completes. 493 */ 494 if (p_chld->comp_pwr == NULL) 495 pci_pwr_add_components(pwr_p, rdip, p_chld); 496 497 pci_pwr_update_comp(pwr_p, p_chld, 498 bpc->bpc_comp, bpc->bpc_nlevel); 499 500 } 501 502 pwr_p->pwr_fp--; 503 DEBUG1(DBG_PWR, pwr_p->pwr_dip, 504 "decremented fp is %d in POST_NOTE\n\n", pwr_p->pwr_fp); 505 506 new_level = pci_pwr_new_lvl(pwr_p); 507 bpn.bpn_dip = pwr_p->pwr_dip; 508 bpn.bpn_comp = PCI_PM_COMP_0; 509 bpn.bpn_level = new_level; 510 bpn.bpn_private = bpc->bpc_private; 511 512 if (new_level > pwr_p->current_lvl) 513 return (pci_raise_power(pwr_p, pwr_p->current_lvl, 514 new_level, impl_arg, bpn)); 515 else 516 pci_pwr_change(pwr_p, pwr_p->current_lvl, 517 new_level); 518 519 break; 520 default: 521 mutex_exit(&pwr_p->pwr_mutex); 522 return (pm_busop_bus_power(dip, impl_arg, op, arg, result)); 523 } 524 525 mutex_exit(&pwr_p->pwr_mutex); 526 527 return (ret); 528 } 529 530 void 531 pci_pwr_resume(dev_info_t *dip, pci_pwr_t *pwr_p) 532 { 533 dev_info_t *cdip; 534 535 /* 536 * Inform the PM framework of the current state of the device. 537 * (it is unknown to PM framework at this point). 538 */ 539 if (PM_CAPABLE(pwr_p)) { 540 pwr_p->current_lvl = pci_pwr_current_lvl(pwr_p); 541 pm_power_has_changed(dip, PCI_PM_COMP_0, 542 pwr_p->current_lvl); 543 } 544 545 /* 546 * Restore config registers for children that did not save 547 * their own registers. Children pwr states are UNKNOWN after 548 * a resume since it is possible for the PM framework to call 549 * resume without an actual power cycle. (ie if suspend fails). 550 */ 551 for (cdip = ddi_get_child(dip); cdip != NULL; 552 cdip = ddi_get_next_sibling(cdip)) { 553 554 /* 555 * Not interested in children who are not already 556 * init'ed. They will be set up by init_child(). 557 */ 558 if (i_ddi_node_state(cdip) < DS_INITIALIZED) { 559 DEBUG2(DBG_DETACH, dip, 560 "DDI_RESUME: skipping %s%d not in CF1\n", 561 ddi_driver_name(cdip), ddi_get_instance(cdip)); 562 563 continue; 564 } 565 566 /* 567 * Only restore config registers if saved by nexus. 568 */ 569 if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 570 NEXUS_SAVED) == 1) { 571 (void) pci_restore_config_regs(cdip); 572 573 DEBUG2(DBG_PWR, dip, 574 "DDI_RESUME: nexus restoring %s%d config regs\n", 575 ddi_driver_name(cdip), ddi_get_instance(cdip)); 576 577 578 if (ndi_prop_remove(DDI_DEV_T_NONE, cdip, 579 NEXUS_SAVED) != DDI_PROP_SUCCESS) { 580 cmn_err(CE_WARN, "%s%d can't remove prop %s", 581 ddi_driver_name(cdip), 582 ddi_get_instance(cdip), 583 NEXUS_SAVED); 584 } 585 } 586 } 587 } 588 589 void 590 pci_pwr_suspend(dev_info_t *dip, pci_pwr_t *pwr_p) 591 { 592 dev_info_t *cdip; 593 594 /* 595 * Save the state of the configuration headers of child 596 * nodes. 597 */ 598 599 for (cdip = ddi_get_child(dip); cdip != NULL; 600 cdip = ddi_get_next_sibling(cdip)) { 601 pci_pwr_chld_t *p; 602 int i; 603 int num_comps; 604 int ret; 605 /* 606 * Not interested in children who are not already 607 * init'ed. They will be set up in init_child(). 608 */ 609 if (i_ddi_node_state(cdip) < DS_INITIALIZED) { 610 DEBUG2(DBG_DETACH, dip, "DDI_SUSPEND: skipping " 611 "%s%d not in CF1\n", ddi_driver_name(cdip), 612 ddi_get_instance(cdip)); 613 614 continue; 615 } 616 617 /* 618 * Only save config registers if not already saved by child. 619 */ 620 if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 621 SAVED_CONFIG_REGS) == 1) { 622 623 continue; 624 } 625 626 /* 627 * The nexus needs to save config registers. Create a property 628 * so it knows to restore on resume. 629 */ 630 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, 631 NEXUS_SAVED); 632 633 if (ret != DDI_PROP_SUCCESS) { 634 cmn_err(CE_WARN, "%s%d can't update prop %s", 635 ddi_driver_name(cdip), ddi_get_instance(cdip), 636 NEXUS_SAVED); 637 } 638 639 if (!PM_CAPABLE(pwr_p)) { 640 (void) pci_save_config_regs(cdip); 641 642 continue; 643 } 644 645 mutex_enter(&pwr_p->pwr_mutex); 646 p = pci_pwr_get_info(pwr_p, cdip); 647 num_comps = p->num_comps; 648 649 /* 650 * If a device has components, reset the power level 651 * to unknown. This will ensure that the bus is full 652 * power so that saving register won't panic (if 653 * the device is already powered off, the child should 654 * have already done the save, but an incorrect driver 655 * may have forgotten). If resetting power levels 656 * to unknown isn't done here, it would have to be done 657 * in resume since pci driver has no way of knowing 658 * actual state of HW (power cycle may not have 659 * occurred, and it was decided that poking into a 660 * child's config space should be avoided unless 661 * absolutely necessary). 662 */ 663 if (p->comp_pwr == NULL) { 664 (void) pci_save_config_regs(cdip); 665 } else { 666 667 for (i = 0; i < num_comps; i++) { 668 pci_pwr_update_comp(pwr_p, p, i, 669 PM_LEVEL_UNKNOWN); 670 } 671 /* 672 * ensure bus power is on before saving 673 * config regs. 674 */ 675 pci_pwr_change(pwr_p, pwr_p->current_lvl, 676 pci_pwr_new_lvl(pwr_p)); 677 678 (void) pci_save_config_regs(cdip); 679 } 680 mutex_exit(&pwr_p->pwr_mutex); 681 } 682 } 683 684 void 685 pci_pwr_component_busy(pci_pwr_t *p) 686 { 687 ASSERT(MUTEX_HELD(&p->pwr_mutex)); 688 if ((p->pwr_flags & PCI_PWR_COMP_BUSY) == 0) { 689 if (pm_busy_component(p->pwr_dip, PCI_PM_COMP_0) == 690 DDI_FAILURE) { 691 cmn_err(CE_WARN, 692 "%s%d pm_busy_component failed", 693 ddi_driver_name(p->pwr_dip), 694 ddi_get_instance(p->pwr_dip)); 695 } else { 696 DEBUG0(DBG_PWR, p->pwr_dip, 697 "called PM_BUSY_COMPONENT(). BUSY BIT SET\n"); 698 p->pwr_flags |= PCI_PWR_COMP_BUSY; 699 } 700 } else { 701 DEBUG0(DBG_PWR, p->pwr_dip, "BUSY BIT ALREADY SET\n"); 702 } 703 } 704 705 void 706 pci_pwr_component_idle(pci_pwr_t *p) 707 { 708 ASSERT(MUTEX_HELD(&p->pwr_mutex)); 709 if (p->pwr_flags & PCI_PWR_COMP_BUSY) { 710 if (pm_idle_component(p->pwr_dip, PCI_PM_COMP_0) == 711 DDI_FAILURE) { 712 cmn_err(CE_WARN, 713 "%s%d pm_idle_component failed", 714 ddi_driver_name(p->pwr_dip), 715 ddi_get_instance(p->pwr_dip)); 716 } else { 717 DEBUG0(DBG_PWR, p->pwr_dip, 718 "called PM_IDLE_COMPONENT() BUSY BIT CLEARED\n"); 719 p->pwr_flags &= ~PCI_PWR_COMP_BUSY; 720 } 721 } else { 722 DEBUG0(DBG_PWR, p->pwr_dip, "BUSY BIT ALREADY CLEARED\n"); 723 } 724 } 725 726 void 727 pci_pwr_change(pci_pwr_t *pwr_p, int current, int new) 728 { 729 ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex)); 730 if (current == new) { 731 DEBUG2(DBG_PWR, pwr_p->pwr_dip, 732 "No change in power required. Should be " 733 "busy. (current=%d) == (new=%d)\n", 734 current, new); 735 pci_pwr_component_busy(pwr_p); 736 737 return; 738 } 739 740 if (new < current) { 741 DEBUG2(DBG_PWR, pwr_p->pwr_dip, 742 "should be idle (new=%d) < (current=%d)\n", 743 new, current); 744 pci_pwr_component_idle(pwr_p); 745 746 return; 747 } 748 749 if (new > current) { 750 DEBUG2(DBG_PWR, pwr_p->pwr_dip, "pwr_change: " 751 "pm_raise_power() and should be busy. " 752 "(new=%d) > (current=%d)\n", new, current); 753 pci_pwr_component_busy(pwr_p); 754 mutex_exit(&pwr_p->pwr_mutex); 755 if (pm_raise_power(pwr_p->pwr_dip, PCI_PM_COMP_0, 756 new) == DDI_FAILURE) { 757 cmn_err(CE_WARN, "%s%d pm_raise_power failed", 758 ddi_driver_name(pwr_p->pwr_dip), 759 ddi_get_instance(pwr_p->pwr_dip)); 760 } 761 mutex_enter(&pwr_p->pwr_mutex); 762 763 return; 764 } 765 } 766