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