xref: /onnv-gate/usr/src/uts/sun4u/io/pci/pci_pwr.c (revision 946:5fb89afc576e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*946Smathue  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/kmem.h>
310Sstevel@tonic-gate #include <sys/async.h>
320Sstevel@tonic-gate #include <sys/sysmacros.h>
330Sstevel@tonic-gate #include <sys/sunddi.h>
340Sstevel@tonic-gate #include <sys/sunndi.h>
350Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
360Sstevel@tonic-gate #include <sys/ddi_implfuncs.h>
370Sstevel@tonic-gate #include <sys/pci/pci_obj.h>
380Sstevel@tonic-gate #include <sys/pci/pci_pwr.h>
390Sstevel@tonic-gate #include <sys/pci.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate static void pci_pwr_update_comp(pci_pwr_t *pwr_p, pci_pwr_chld_t *p, int comp,
420Sstevel@tonic-gate 	int lvl);
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #ifdef DEBUG
450Sstevel@tonic-gate static char *pci_pwr_bus_label[] = {"PM_LEVEL_B3", "PM_LEVEL_B2", \
460Sstevel@tonic-gate 	"PM_LEVEL_B1", "PM_LEVEL_B0"};
470Sstevel@tonic-gate #endif
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*LINTLIBRARY*/
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate  * Retreive the pci_pwr_chld_t structure for a given devinfo node.
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate pci_pwr_chld_t *
pci_pwr_get_info(pci_pwr_t * pwr_p,dev_info_t * dip)550Sstevel@tonic-gate pci_pwr_get_info(pci_pwr_t *pwr_p, dev_info_t *dip)
560Sstevel@tonic-gate {
570Sstevel@tonic-gate 	pci_pwr_chld_t *p;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	ASSERT(PM_CAPABLE(pwr_p));
600Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	for (p = pwr_p->pwr_info; p != NULL; p = p->next) {
630Sstevel@tonic-gate 		if (p->dip == dip) {
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 			return (p);
660Sstevel@tonic-gate 		}
670Sstevel@tonic-gate 	}
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	cmn_err(CE_PANIC, "unable to find pwr info data for %s@%s",
700Sstevel@tonic-gate 	    ddi_node_name(dip), ddi_get_name_addr(dip));
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	/*NOTREACHED*/
73*946Smathue 	return (NULL);
740Sstevel@tonic-gate }
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate  * Create a pci_pwr_chld_t structure for a given devinfo node.
780Sstevel@tonic-gate  */
790Sstevel@tonic-gate void
pci_pwr_create_info(pci_pwr_t * pwr_p,dev_info_t * dip)800Sstevel@tonic-gate pci_pwr_create_info(pci_pwr_t *pwr_p, dev_info_t *dip)
810Sstevel@tonic-gate {
820Sstevel@tonic-gate 	pci_pwr_chld_t *p;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	ASSERT(PM_CAPABLE(pwr_p));
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	DEBUG2(DBG_PWR, ddi_get_parent(dip), "ADDING NEW PWR_INFO %s@%s\n",
870Sstevel@tonic-gate 	    ddi_node_name(dip), ddi_get_name_addr(dip));
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	p = kmem_zalloc(sizeof (struct pci_pwr_chld), KM_SLEEP);
900Sstevel@tonic-gate 	p->dip = dip;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	mutex_enter(&pwr_p->pwr_mutex);
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	/*
950Sstevel@tonic-gate 	 * Until components are created for this device, bus
960Sstevel@tonic-gate 	 * should be at full power since power of child device
970Sstevel@tonic-gate 	 * is unknown.  Increment # children requiring "full power"
980Sstevel@tonic-gate 	 */
990Sstevel@tonic-gate 	p->flags |= PWR_FP_HOLD;
1000Sstevel@tonic-gate 	pwr_p->pwr_fp++;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	p->next =  pwr_p->pwr_info;
1030Sstevel@tonic-gate 	pwr_p->pwr_info = p;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	pci_pwr_change(pwr_p, pwr_p->current_lvl, pci_pwr_new_lvl(pwr_p));
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	mutex_exit(&pwr_p->pwr_mutex);
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate void
pci_pwr_rm_info(pci_pwr_t * pwr_p,dev_info_t * cdip)1110Sstevel@tonic-gate pci_pwr_rm_info(pci_pwr_t *pwr_p, dev_info_t *cdip)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	pci_pwr_chld_t **prev_infop;
1140Sstevel@tonic-gate 	pci_pwr_chld_t *infop = NULL;
1150Sstevel@tonic-gate 	int i;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	ASSERT(PM_CAPABLE(pwr_p));
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	mutex_enter(&pwr_p->pwr_mutex);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	for (prev_infop = &pwr_p->pwr_info; *prev_infop != NULL;
1220Sstevel@tonic-gate 	    prev_infop = &((*prev_infop)->next)) {
1230Sstevel@tonic-gate 		if ((*prev_infop)->dip == cdip) {
1240Sstevel@tonic-gate 			infop = *prev_infop;
1250Sstevel@tonic-gate 			break;
1260Sstevel@tonic-gate 		}
1270Sstevel@tonic-gate 	}
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	if (infop == NULL) {
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 		mutex_exit(&pwr_p->pwr_mutex);
1320Sstevel@tonic-gate 		return;
1330Sstevel@tonic-gate 	}
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	*prev_infop =  infop->next;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	/*
1380Sstevel@tonic-gate 	 * Remove any reference counts for this child.
1390Sstevel@tonic-gate 	 */
1400Sstevel@tonic-gate 	if (infop->comp_pwr != NULL) {
1410Sstevel@tonic-gate 		for (i = 0; i < infop->num_comps; i++) {
1420Sstevel@tonic-gate 			pci_pwr_update_comp(pwr_p, infop, i, PM_LEVEL_NOLEVEL);
1430Sstevel@tonic-gate 		}
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 		kmem_free(infop->comp_pwr, sizeof (int) * infop->num_comps);
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	if (infop->flags & PWR_FP_HOLD) {
1490Sstevel@tonic-gate 		pwr_p->pwr_fp--;
1500Sstevel@tonic-gate 	}
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	pci_pwr_change(pwr_p, pwr_p->current_lvl, pci_pwr_new_lvl(pwr_p));
1530Sstevel@tonic-gate 	mutex_exit(&pwr_p->pwr_mutex);
1540Sstevel@tonic-gate 	kmem_free(infop, sizeof (struct pci_pwr_chld));
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate  * Allocate space for component state information in pci_pwr_chld_t
1590Sstevel@tonic-gate  */
1600Sstevel@tonic-gate void
pci_pwr_add_components(pci_pwr_t * pwr_p,dev_info_t * cdip,pci_pwr_chld_t * p)1610Sstevel@tonic-gate pci_pwr_add_components(pci_pwr_t *pwr_p, dev_info_t *cdip, pci_pwr_chld_t *p)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate 	int num_comps = PM_NUMCMPTS(cdip);
1640Sstevel@tonic-gate 	int i;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
1670Sstevel@tonic-gate 	/*
1680Sstevel@tonic-gate 	 * Assume the power level of a component is UNKNOWN until
1690Sstevel@tonic-gate 	 * notified otherwise.
1700Sstevel@tonic-gate 	 */
1710Sstevel@tonic-gate 	if (num_comps > 0) {
1720Sstevel@tonic-gate 		p->comp_pwr =
1730Sstevel@tonic-gate 		    kmem_alloc(sizeof (int) * num_comps, KM_SLEEP);
1740Sstevel@tonic-gate 		p->num_comps = num_comps;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 		DEBUG3(DBG_PWR, ddi_get_parent(cdip),
1770Sstevel@tonic-gate 		    "ADDING %d COMPONENTS FOR %s@%s\n", num_comps,
1780Sstevel@tonic-gate 		    ddi_node_name(cdip), ddi_get_name_addr(cdip));
1790Sstevel@tonic-gate 	} else {
1800Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d device has %d components",
1810Sstevel@tonic-gate 		    ddi_driver_name(cdip), ddi_get_instance(cdip),
1820Sstevel@tonic-gate 		    num_comps);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 		return;
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	/*
1880Sstevel@tonic-gate 	 * Release the fp hold that was made when the device
1890Sstevel@tonic-gate 	 * was created.
1900Sstevel@tonic-gate 	 */
1910Sstevel@tonic-gate 	ASSERT((p->flags & PWR_FP_HOLD) == PWR_FP_HOLD);
1920Sstevel@tonic-gate 	p->flags &= ~PWR_FP_HOLD;
1930Sstevel@tonic-gate 	pwr_p->pwr_fp--;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	for (i = 0; i < num_comps; i++) {
1960Sstevel@tonic-gate 		/*
1970Sstevel@tonic-gate 		 * Initialize the component lvl so that the
1980Sstevel@tonic-gate 		 * state reference counts will be updated correctly.
1990Sstevel@tonic-gate 		 */
2000Sstevel@tonic-gate 		p->comp_pwr[i] = PM_LEVEL_NOLEVEL;
2010Sstevel@tonic-gate 		pci_pwr_update_comp(pwr_p, p, i, PM_LEVEL_UNKNOWN);
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate  * Update the current power level for component.  Then adjust the
2070Sstevel@tonic-gate  * bus reference counter for given state.
2080Sstevel@tonic-gate  */
2090Sstevel@tonic-gate static void
pci_pwr_update_comp(pci_pwr_t * pwr_p,pci_pwr_chld_t * p,int comp,int lvl)2100Sstevel@tonic-gate pci_pwr_update_comp(pci_pwr_t *pwr_p, pci_pwr_chld_t *p, int comp,
2110Sstevel@tonic-gate 			int lvl)
2120Sstevel@tonic-gate {
2130Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	/*
2160Sstevel@tonic-gate 	 * Remove old pwr state count for old PM level.
2170Sstevel@tonic-gate 	 */
2180Sstevel@tonic-gate 	switch (p->comp_pwr[comp]) {
2190Sstevel@tonic-gate 	case PM_LEVEL_UNKNOWN:
2200Sstevel@tonic-gate 		pwr_p->pwr_uk--;
2210Sstevel@tonic-gate 		p->u01--;
2220Sstevel@tonic-gate 		ASSERT(pwr_p->pwr_uk >= 0);
2230Sstevel@tonic-gate 		break;
2240Sstevel@tonic-gate 	case PM_LEVEL_D0:
2250Sstevel@tonic-gate 		pwr_p->pwr_d0--;
2260Sstevel@tonic-gate 		p->u01--;
2270Sstevel@tonic-gate 		ASSERT(pwr_p->pwr_d0 >= 0);
2280Sstevel@tonic-gate 		break;
2290Sstevel@tonic-gate 	case PM_LEVEL_D1:
2300Sstevel@tonic-gate 		pwr_p->pwr_d1--;
2310Sstevel@tonic-gate 		p->u01--;
2320Sstevel@tonic-gate 		ASSERT(pwr_p->pwr_d1 >= 0);
2330Sstevel@tonic-gate 		break;
2340Sstevel@tonic-gate 	case PM_LEVEL_D2:
2350Sstevel@tonic-gate 		pwr_p->pwr_d2--;
2360Sstevel@tonic-gate 		ASSERT(pwr_p->pwr_d2 >= 0);
2370Sstevel@tonic-gate 		break;
2380Sstevel@tonic-gate 	case PM_LEVEL_D3:
2390Sstevel@tonic-gate 		pwr_p->pwr_d3--;
2400Sstevel@tonic-gate 		ASSERT(pwr_p->pwr_d3 >= 0);
2410Sstevel@tonic-gate 		break;
2420Sstevel@tonic-gate 	default:
2430Sstevel@tonic-gate 		break;
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	p->comp_pwr[comp] = lvl;
2470Sstevel@tonic-gate 	/*
2480Sstevel@tonic-gate 	 * Add new pwr state count for the new PM level.
2490Sstevel@tonic-gate 	 */
2500Sstevel@tonic-gate 	switch (lvl) {
2510Sstevel@tonic-gate 	case PM_LEVEL_UNKNOWN:
2520Sstevel@tonic-gate 		pwr_p->pwr_uk++;
2530Sstevel@tonic-gate 		p->u01++;
2540Sstevel@tonic-gate 		break;
2550Sstevel@tonic-gate 	case PM_LEVEL_D0:
2560Sstevel@tonic-gate 		pwr_p->pwr_d0++;
2570Sstevel@tonic-gate 		p->u01++;
2580Sstevel@tonic-gate 		break;
2590Sstevel@tonic-gate 	case PM_LEVEL_D1:
2600Sstevel@tonic-gate 		pwr_p->pwr_d1++;
2610Sstevel@tonic-gate 		p->u01++;
2620Sstevel@tonic-gate 		break;
2630Sstevel@tonic-gate 	case PM_LEVEL_D2:
2640Sstevel@tonic-gate 		pwr_p->pwr_d2++;
2650Sstevel@tonic-gate 		break;
2660Sstevel@tonic-gate 	case PM_LEVEL_D3:
2670Sstevel@tonic-gate 		pwr_p->pwr_d3++;
2680Sstevel@tonic-gate 		break;
2690Sstevel@tonic-gate 	default:
2700Sstevel@tonic-gate 		break;
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate  * Knowing the current state of all devices on the bus, return the
2770Sstevel@tonic-gate  * appropriate supported bus speed.
2780Sstevel@tonic-gate  */
2790Sstevel@tonic-gate int
pci_pwr_new_lvl(pci_pwr_t * pwr_p)2800Sstevel@tonic-gate pci_pwr_new_lvl(pci_pwr_t *pwr_p)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	int b_lvl;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	if (pwr_p->pwr_fp > 0) {
2870Sstevel@tonic-gate 		DEBUG1(DBG_PWR, pwr_p->pwr_dip, "new_lvl: "
2880Sstevel@tonic-gate 		    "returning PM_LEVEL_B0 pwr_fp = %d\n", pwr_p->pwr_fp);
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 		return (PM_LEVEL_B0);
2910Sstevel@tonic-gate 	}
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	/*
2940Sstevel@tonic-gate 	 * If any components are at unknown power levels, the
2950Sstevel@tonic-gate 	 * highest power level has to be assumed for the device (D0).
2960Sstevel@tonic-gate 	 */
2970Sstevel@tonic-gate 	if (pwr_p->pwr_uk > 0) {
2980Sstevel@tonic-gate 		DEBUG1(DBG_PWR, pwr_p->pwr_dip, "new_lvl: unknown "
2990Sstevel@tonic-gate 		    "count is %d. returning PM_LEVEL_B0\n", pwr_p->pwr_uk);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 		return (PM_LEVEL_B0);
3020Sstevel@tonic-gate 	}
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	/*
3050Sstevel@tonic-gate 	 * Find the lowest theoretical level
3060Sstevel@tonic-gate 	 * the bus can operate at.
3070Sstevel@tonic-gate 	 */
3080Sstevel@tonic-gate 	if (pwr_p->pwr_d0 > 0) {
3090Sstevel@tonic-gate 		b_lvl = PM_LEVEL_B0;
3100Sstevel@tonic-gate 		DEBUG1(DBG_PWR, pwr_p->pwr_dip,
3110Sstevel@tonic-gate 		    "new_lvl: PM_LEVEL_B0 d0 count = %d\n",
3120Sstevel@tonic-gate 		    pwr_p->pwr_d0);
3130Sstevel@tonic-gate 	} else if (pwr_p->pwr_d1 > 0) {
3140Sstevel@tonic-gate 		b_lvl = PM_LEVEL_B1;
3150Sstevel@tonic-gate 		DEBUG1(DBG_PWR, pwr_p->pwr_dip,
3160Sstevel@tonic-gate 		    "new_lvl: PM_LEVEL_B1 d1 count = %d\n",
3170Sstevel@tonic-gate 		    pwr_p->pwr_d1);
3180Sstevel@tonic-gate 	} else if (pwr_p->pwr_d2 > 0) {
3190Sstevel@tonic-gate 		b_lvl = PM_LEVEL_B2;
3200Sstevel@tonic-gate 		DEBUG1(DBG_PWR, pwr_p->pwr_dip,
3210Sstevel@tonic-gate 		    "new_lvl: PM_LEVEL_B2 d2 count = %d\n",
3220Sstevel@tonic-gate 		    pwr_p->pwr_d2);
3230Sstevel@tonic-gate 	} else if (pwr_p->pwr_d3 > 0) {
3240Sstevel@tonic-gate 		b_lvl = PM_LEVEL_B3;
3250Sstevel@tonic-gate 		DEBUG1(DBG_PWR, pwr_p->pwr_dip,
3260Sstevel@tonic-gate 		    "new_lvl: PM_LEVEL_B3 d3 count = %d\n",
3270Sstevel@tonic-gate 		    pwr_p->pwr_d3);
3280Sstevel@tonic-gate 	} else {
3290Sstevel@tonic-gate 		DEBUG0(DBG_PWR, pwr_p->pwr_dip,
3300Sstevel@tonic-gate 		    "new_lvl: PM_LEVEL_B3: all counts are 0\n");
3310Sstevel@tonic-gate 		b_lvl = PM_LEVEL_B3;
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/*
3350Sstevel@tonic-gate 	 * Now find the closest supported level available.
3360Sstevel@tonic-gate 	 * If the level isn't available, have to find the
3370Sstevel@tonic-gate 	 * next highest power level (or lowest in B# terms).
3380Sstevel@tonic-gate 	 */
3390Sstevel@tonic-gate 	switch (b_lvl) {
3400Sstevel@tonic-gate 	case PM_LEVEL_B3:
3410Sstevel@tonic-gate 		if (pwr_p->pwr_flags & PCI_PWR_B3_CAPABLE) {
3420Sstevel@tonic-gate 			break;
3430Sstevel@tonic-gate 		}
3440Sstevel@tonic-gate 		/*FALLTHROUGH*/
3450Sstevel@tonic-gate 	case PM_LEVEL_B2:
3460Sstevel@tonic-gate 		if (pwr_p->pwr_flags & PCI_PWR_B2_CAPABLE) {
3470Sstevel@tonic-gate 			b_lvl = PM_LEVEL_B2;
3480Sstevel@tonic-gate 			break;
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 		/*FALLTHROUGH*/
3510Sstevel@tonic-gate 	case PM_LEVEL_B1:
3520Sstevel@tonic-gate 		if (pwr_p->pwr_flags & PCI_PWR_B1_CAPABLE) {
3530Sstevel@tonic-gate 			b_lvl = PM_LEVEL_B1;
3540Sstevel@tonic-gate 			break;
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 		/*FALLTHROUGH*/
3570Sstevel@tonic-gate 	case PM_LEVEL_B0:
3580Sstevel@tonic-gate 		/*
3590Sstevel@tonic-gate 		 * This level always supported
3600Sstevel@tonic-gate 		 */
3610Sstevel@tonic-gate 		b_lvl = PM_LEVEL_B0;
3620Sstevel@tonic-gate 		break;
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate 	DEBUG1(DBG_PWR, pwr_p->pwr_dip,
3650Sstevel@tonic-gate 	    "new_lvl: Adjusted Level is %s\n",
3660Sstevel@tonic-gate 	    pci_pwr_bus_label[b_lvl]);
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	return (b_lvl);
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate int
pci_raise_power(pci_pwr_t * pwr_p,int current,int new,void * impl_arg,pm_bp_nexus_pwrup_t bpn)3730Sstevel@tonic-gate pci_raise_power(pci_pwr_t *pwr_p, int current, int new, void *impl_arg,
3740Sstevel@tonic-gate     pm_bp_nexus_pwrup_t bpn)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	int ret = DDI_SUCCESS, pwrup_res;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	pci_pwr_component_busy(pwr_p);
3810Sstevel@tonic-gate 	mutex_exit(&pwr_p->pwr_mutex);
3820Sstevel@tonic-gate 	ret = pm_busop_bus_power(pwr_p->pwr_dip, impl_arg,
3830Sstevel@tonic-gate 	    BUS_POWER_NEXUS_PWRUP, (void *) &bpn,
3840Sstevel@tonic-gate 	    (void *) &pwrup_res);
3850Sstevel@tonic-gate 	if (ret != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) {
3860Sstevel@tonic-gate 		mutex_enter(&pwr_p->pwr_mutex);
3870Sstevel@tonic-gate 		pci_pwr_component_idle(pwr_p);
3880Sstevel@tonic-gate 		mutex_exit(&pwr_p->pwr_mutex);
3890Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d pci_raise_power failed",
3900Sstevel@tonic-gate 		    ddi_driver_name(pwr_p->pwr_dip),
3910Sstevel@tonic-gate 		    ddi_get_instance(pwr_p->pwr_dip));
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	return (ret);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate int
pci_pwr_ops(pci_pwr_t * pwr_p,dev_info_t * dip,void * impl_arg,pm_bus_power_op_t op,void * arg,void * result)3980Sstevel@tonic-gate pci_pwr_ops(pci_pwr_t *pwr_p, dev_info_t *dip, void *impl_arg,
3990Sstevel@tonic-gate     pm_bus_power_op_t op, void *arg, void *result)
4000Sstevel@tonic-gate {
4010Sstevel@tonic-gate 	pci_pwr_chld_t *p_chld;
4020Sstevel@tonic-gate 	pm_bp_nexus_pwrup_t bpn;
4030Sstevel@tonic-gate 	pm_bp_child_pwrchg_t *bpc = (pm_bp_child_pwrchg_t *)arg;
4040Sstevel@tonic-gate 	dev_info_t *rdip = bpc->bpc_dip;
4050Sstevel@tonic-gate 	int new_level, *res = (int *)result, ret = DDI_SUCCESS;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	mutex_enter(&pwr_p->pwr_mutex);
4080Sstevel@tonic-gate 	switch (op) {
4090Sstevel@tonic-gate 	case BUS_POWER_HAS_CHANGED:
4100Sstevel@tonic-gate 		p_chld = pci_pwr_get_info(pwr_p, rdip);
4110Sstevel@tonic-gate 		DEBUG5(DBG_PWR, dip, "%s@%s CHANGED_POWER cmp = %d "
4120Sstevel@tonic-gate 		    "old = %d new = %d\n",
4130Sstevel@tonic-gate 			ddi_node_name(rdip), ddi_get_name_addr(rdip),
4140Sstevel@tonic-gate 		    bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 		if (*res == DDI_FAILURE) {
4170Sstevel@tonic-gate 			DEBUG0(DBG_PWR, rdip, "changed_power_req FAILED\n");
4180Sstevel@tonic-gate 			break;
4190Sstevel@tonic-gate 		} else {
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 			/*
4220Sstevel@tonic-gate 			 * pci_pwr_add_components must be called here if
4230Sstevel@tonic-gate 			 * comp_pwr hasn't been set up yet.  It has to be done
4240Sstevel@tonic-gate 			 * here rather than in post-attach, since it is possible
4250Sstevel@tonic-gate 			 * for power() of child to get called before attach
4260Sstevel@tonic-gate 			 * completes.
4270Sstevel@tonic-gate 			 */
4280Sstevel@tonic-gate 			if (p_chld->comp_pwr == NULL)
4290Sstevel@tonic-gate 				pci_pwr_add_components(pwr_p, rdip, p_chld);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 			pci_pwr_update_comp(pwr_p, p_chld,
4320Sstevel@tonic-gate 			    bpc->bpc_comp, bpc->bpc_nlevel);
4330Sstevel@tonic-gate 		}
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 		new_level = pci_pwr_new_lvl(pwr_p);
4360Sstevel@tonic-gate 		bpn.bpn_dip = pwr_p->pwr_dip;
4370Sstevel@tonic-gate 		bpn.bpn_comp = PCI_PM_COMP_0;
4380Sstevel@tonic-gate 		bpn.bpn_level = new_level;
4390Sstevel@tonic-gate 		bpn.bpn_private = bpc->bpc_private;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 		if (new_level > pwr_p->current_lvl)
4420Sstevel@tonic-gate 			return (pci_raise_power(pwr_p, pwr_p->current_lvl,
4430Sstevel@tonic-gate 			    new_level, impl_arg, bpn));
4440Sstevel@tonic-gate 		else
4450Sstevel@tonic-gate 			pci_pwr_change(pwr_p, pwr_p->current_lvl,
4460Sstevel@tonic-gate 			    new_level);
4470Sstevel@tonic-gate 		break;
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	case BUS_POWER_PRE_NOTIFICATION:
4500Sstevel@tonic-gate 		DEBUG5(DBG_PWR, dip, "PRE %s@%s cmp = %d old = %d "
4510Sstevel@tonic-gate 		    "new = %d. TEMP FULL POWER\n",
4520Sstevel@tonic-gate 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
4530Sstevel@tonic-gate 		    bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		/*
4560Sstevel@tonic-gate 		 * Any state changes require that the bus be at full
4570Sstevel@tonic-gate 		 * power (B0) so that the device configuration
4580Sstevel@tonic-gate 		 * registers can be accessed.  Make a fp hold here
4590Sstevel@tonic-gate 		 * so device remains at full power during power
4600Sstevel@tonic-gate 		 * configuration.
4610Sstevel@tonic-gate 		 */
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		pwr_p->pwr_fp++;
4640Sstevel@tonic-gate 		DEBUG1(DBG_PWR, pwr_p->pwr_dip,
4650Sstevel@tonic-gate 		    "incremented fp is %d in PRE_NOTE\n\n", pwr_p->pwr_fp);
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		bpn.bpn_dip = pwr_p->pwr_dip;
4680Sstevel@tonic-gate 		bpn.bpn_comp = PCI_PM_COMP_0;
4690Sstevel@tonic-gate 		bpn.bpn_level = PM_LEVEL_B0;
4700Sstevel@tonic-gate 		bpn.bpn_private = bpc->bpc_private;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 		if (PM_LEVEL_B0 > pwr_p->current_lvl)
4730Sstevel@tonic-gate 			return (pci_raise_power(pwr_p, pwr_p->current_lvl,
4740Sstevel@tonic-gate 			    PM_LEVEL_B0, impl_arg, bpn));
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 		break;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	case BUS_POWER_POST_NOTIFICATION:
4790Sstevel@tonic-gate 		p_chld = pci_pwr_get_info(pwr_p, rdip);
4800Sstevel@tonic-gate 		DEBUG5(DBG_PWR, dip, "POST %s@%s cmp = %d old = %d new = %d\n",
4810Sstevel@tonic-gate 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
4820Sstevel@tonic-gate 		    bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 		if (*res == DDI_FAILURE) {
4850Sstevel@tonic-gate 			DEBUG0(DBG_PWR, rdip, "child's power routine FAILED\n");
4860Sstevel@tonic-gate 		} else {
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 			/*
4890Sstevel@tonic-gate 			 * pci_pwr_add_components must be called here if
4900Sstevel@tonic-gate 			 * comp_pwr hasen't been set up yet.  It has to be done
4910Sstevel@tonic-gate 			 * here rather than in post-attach, since it is possible
4920Sstevel@tonic-gate 			 * for power() of child to get called before attach
4930Sstevel@tonic-gate 			 * completes.
4940Sstevel@tonic-gate 			 */
4950Sstevel@tonic-gate 			if (p_chld->comp_pwr == NULL)
4960Sstevel@tonic-gate 				pci_pwr_add_components(pwr_p, rdip, p_chld);
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 			pci_pwr_update_comp(pwr_p, p_chld,
4990Sstevel@tonic-gate 			    bpc->bpc_comp, bpc->bpc_nlevel);
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 		}
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 		pwr_p->pwr_fp--;
5040Sstevel@tonic-gate 		DEBUG1(DBG_PWR, pwr_p->pwr_dip,
5050Sstevel@tonic-gate 		    "decremented fp is %d in POST_NOTE\n\n", pwr_p->pwr_fp);
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 		new_level = pci_pwr_new_lvl(pwr_p);
5080Sstevel@tonic-gate 		bpn.bpn_dip = pwr_p->pwr_dip;
5090Sstevel@tonic-gate 		bpn.bpn_comp = PCI_PM_COMP_0;
5100Sstevel@tonic-gate 		bpn.bpn_level = new_level;
5110Sstevel@tonic-gate 		bpn.bpn_private = bpc->bpc_private;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		if (new_level > pwr_p->current_lvl)
5140Sstevel@tonic-gate 			return (pci_raise_power(pwr_p, pwr_p->current_lvl,
5150Sstevel@tonic-gate 			    new_level, impl_arg, bpn));
5160Sstevel@tonic-gate 		else
5170Sstevel@tonic-gate 			pci_pwr_change(pwr_p, pwr_p->current_lvl,
5180Sstevel@tonic-gate 			    new_level);
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 		break;
5210Sstevel@tonic-gate 	default:
5220Sstevel@tonic-gate 		mutex_exit(&pwr_p->pwr_mutex);
5230Sstevel@tonic-gate 		return (pm_busop_bus_power(dip, impl_arg, op, arg, result));
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	mutex_exit(&pwr_p->pwr_mutex);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	return (ret);
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate void
pci_pwr_resume(dev_info_t * dip,pci_pwr_t * pwr_p)5320Sstevel@tonic-gate pci_pwr_resume(dev_info_t *dip, pci_pwr_t *pwr_p)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate 	dev_info_t *cdip;
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	/*
5370Sstevel@tonic-gate 	 * Inform the PM framework of the current state of the device.
5380Sstevel@tonic-gate 	 * (it is unknown to PM framework at this point).
5390Sstevel@tonic-gate 	 */
5400Sstevel@tonic-gate 	if (PM_CAPABLE(pwr_p)) {
5410Sstevel@tonic-gate 		pwr_p->current_lvl = pci_pwr_current_lvl(pwr_p);
5420Sstevel@tonic-gate 		pm_power_has_changed(dip, PCI_PM_COMP_0,
5430Sstevel@tonic-gate 		    pwr_p->current_lvl);
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	/*
5470Sstevel@tonic-gate 	 * Restore config registers for children that did not save
5480Sstevel@tonic-gate 	 * their own registers.  Children pwr states are UNKNOWN after
5490Sstevel@tonic-gate 	 * a resume since it is possible for the PM framework to call
5500Sstevel@tonic-gate 	 * resume without an actual power cycle. (ie if suspend fails).
5510Sstevel@tonic-gate 	 */
5520Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip != NULL;
5530Sstevel@tonic-gate 		cdip = ddi_get_next_sibling(cdip)) {
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 		/*
5560Sstevel@tonic-gate 		 * Not interested in children who are not already
5570Sstevel@tonic-gate 		 * init'ed.  They will be set up by init_child().
5580Sstevel@tonic-gate 		 */
5590Sstevel@tonic-gate 		if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
5600Sstevel@tonic-gate 			DEBUG2(DBG_DETACH, dip,
5610Sstevel@tonic-gate 			    "DDI_RESUME: skipping %s%d not in CF1\n",
5620Sstevel@tonic-gate 			    ddi_driver_name(cdip), ddi_get_instance(cdip));
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 			continue;
5650Sstevel@tonic-gate 		}
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 		/*
5680Sstevel@tonic-gate 		 * Only restore config registers if saved by nexus.
5690Sstevel@tonic-gate 		 */
5700Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
5710Sstevel@tonic-gate 		    NEXUS_SAVED) == 1) {
5720Sstevel@tonic-gate 			(void) pci_restore_config_regs(cdip);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 			DEBUG2(DBG_PWR, dip,
5750Sstevel@tonic-gate 			    "DDI_RESUME: nexus restoring %s%d config regs\n",
5760Sstevel@tonic-gate 			    ddi_driver_name(cdip), ddi_get_instance(cdip));
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 			if (ndi_prop_remove(DDI_DEV_T_NONE, cdip,
5800Sstevel@tonic-gate 			    NEXUS_SAVED) != DDI_PROP_SUCCESS) {
5810Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d can't remove prop %s",
5820Sstevel@tonic-gate 				    ddi_driver_name(cdip),
5830Sstevel@tonic-gate 				    ddi_get_instance(cdip),
5840Sstevel@tonic-gate 				    NEXUS_SAVED);
5850Sstevel@tonic-gate 			}
5860Sstevel@tonic-gate 		}
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate void
pci_pwr_suspend(dev_info_t * dip,pci_pwr_t * pwr_p)5910Sstevel@tonic-gate pci_pwr_suspend(dev_info_t *dip, pci_pwr_t *pwr_p)
5920Sstevel@tonic-gate {
5930Sstevel@tonic-gate 	dev_info_t *cdip;
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	/*
5960Sstevel@tonic-gate 	 * Save the state of the configuration headers of child
5970Sstevel@tonic-gate 	 * nodes.
5980Sstevel@tonic-gate 	 */
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip != NULL;
6010Sstevel@tonic-gate 	    cdip = ddi_get_next_sibling(cdip)) {
6020Sstevel@tonic-gate 		pci_pwr_chld_t *p;
6030Sstevel@tonic-gate 		int i;
6040Sstevel@tonic-gate 		int num_comps;
6050Sstevel@tonic-gate 		int ret;
6060Sstevel@tonic-gate 		/*
6070Sstevel@tonic-gate 		 * Not interested in children who are not already
6080Sstevel@tonic-gate 		 * init'ed.  They will be set up in init_child().
6090Sstevel@tonic-gate 		 */
6100Sstevel@tonic-gate 		if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
6110Sstevel@tonic-gate 			DEBUG2(DBG_DETACH, dip, "DDI_SUSPEND: skipping "
6120Sstevel@tonic-gate 			    "%s%d not in CF1\n", ddi_driver_name(cdip),
6130Sstevel@tonic-gate 			    ddi_get_instance(cdip));
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 			continue;
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 		/*
6190Sstevel@tonic-gate 		 * Only save config registers if not already saved by child.
6200Sstevel@tonic-gate 		 */
6210Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
6220Sstevel@tonic-gate 		    SAVED_CONFIG_REGS) == 1) {
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 			continue;
6250Sstevel@tonic-gate 		}
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 		/*
6280Sstevel@tonic-gate 		 * The nexus needs to save config registers.  Create a property
6290Sstevel@tonic-gate 		 * so it knows to restore on resume.
6300Sstevel@tonic-gate 		 */
6310Sstevel@tonic-gate 		ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
6320Sstevel@tonic-gate 		    NEXUS_SAVED);
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 		if (ret != DDI_PROP_SUCCESS) {
6350Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d can't update prop %s",
6360Sstevel@tonic-gate 			    ddi_driver_name(cdip), ddi_get_instance(cdip),
6370Sstevel@tonic-gate 			    NEXUS_SAVED);
6380Sstevel@tonic-gate 		}
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 		if (!PM_CAPABLE(pwr_p)) {
6410Sstevel@tonic-gate 			(void) pci_save_config_regs(cdip);
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 			continue;
6440Sstevel@tonic-gate 		}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 		mutex_enter(&pwr_p->pwr_mutex);
6470Sstevel@tonic-gate 		p = pci_pwr_get_info(pwr_p, cdip);
6480Sstevel@tonic-gate 		num_comps = p->num_comps;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		/*
6510Sstevel@tonic-gate 		 * If a device has components, reset the power level
6520Sstevel@tonic-gate 		 * to unknown.  This will ensure that the bus is full
6530Sstevel@tonic-gate 		 * power so that saving register won't panic (if
6540Sstevel@tonic-gate 		 * the device is already powered off, the child should
6550Sstevel@tonic-gate 		 * have already done the save, but an incorrect driver
6560Sstevel@tonic-gate 		 * may have forgotten).  If resetting power levels
6570Sstevel@tonic-gate 		 * to unknown isn't done here, it would have to be done
6580Sstevel@tonic-gate 		 * in resume since pci driver has no way of knowing
6590Sstevel@tonic-gate 		 * actual state of HW (power cycle may not have
6600Sstevel@tonic-gate 		 * occurred, and it was decided that poking into a
6610Sstevel@tonic-gate 		 * child's config space should be avoided unless
6620Sstevel@tonic-gate 		 * absolutely necessary).
6630Sstevel@tonic-gate 		 */
6640Sstevel@tonic-gate 		if (p->comp_pwr == NULL) {
6650Sstevel@tonic-gate 			(void) pci_save_config_regs(cdip);
6660Sstevel@tonic-gate 		} else {
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 			for (i = 0; i < num_comps; i++) {
6690Sstevel@tonic-gate 				pci_pwr_update_comp(pwr_p, p, i,
6700Sstevel@tonic-gate 				    PM_LEVEL_UNKNOWN);
6710Sstevel@tonic-gate 			}
6720Sstevel@tonic-gate 			/*
6730Sstevel@tonic-gate 			 * ensure bus power is on before saving
6740Sstevel@tonic-gate 			 * config regs.
6750Sstevel@tonic-gate 			 */
6760Sstevel@tonic-gate 			pci_pwr_change(pwr_p, pwr_p->current_lvl,
6770Sstevel@tonic-gate 			    pci_pwr_new_lvl(pwr_p));
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 			(void) pci_save_config_regs(cdip);
6800Sstevel@tonic-gate 		}
6810Sstevel@tonic-gate 		mutex_exit(&pwr_p->pwr_mutex);
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate void
pci_pwr_component_busy(pci_pwr_t * p)6860Sstevel@tonic-gate pci_pwr_component_busy(pci_pwr_t *p)
6870Sstevel@tonic-gate {
6880Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->pwr_mutex));
6890Sstevel@tonic-gate 	if ((p->pwr_flags & PCI_PWR_COMP_BUSY) == 0) {
6900Sstevel@tonic-gate 		if (pm_busy_component(p->pwr_dip, PCI_PM_COMP_0) ==
6910Sstevel@tonic-gate 		    DDI_FAILURE) {
6920Sstevel@tonic-gate 			cmn_err(CE_WARN,
6930Sstevel@tonic-gate 			    "%s%d pm_busy_component failed",
6940Sstevel@tonic-gate 			    ddi_driver_name(p->pwr_dip),
6950Sstevel@tonic-gate 			    ddi_get_instance(p->pwr_dip));
6960Sstevel@tonic-gate 		} else {
6970Sstevel@tonic-gate 			DEBUG0(DBG_PWR, p->pwr_dip,
6980Sstevel@tonic-gate 			    "called PM_BUSY_COMPONENT().  BUSY BIT SET\n");
6990Sstevel@tonic-gate 			p->pwr_flags |= PCI_PWR_COMP_BUSY;
7000Sstevel@tonic-gate 		}
7010Sstevel@tonic-gate 	} else {
7020Sstevel@tonic-gate 		DEBUG0(DBG_PWR, p->pwr_dip, "BUSY BIT ALREADY SET\n");
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate void
pci_pwr_component_idle(pci_pwr_t * p)7070Sstevel@tonic-gate pci_pwr_component_idle(pci_pwr_t *p)
7080Sstevel@tonic-gate {
7090Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->pwr_mutex));
7100Sstevel@tonic-gate 	if (p->pwr_flags & PCI_PWR_COMP_BUSY) {
7110Sstevel@tonic-gate 		if (pm_idle_component(p->pwr_dip, PCI_PM_COMP_0) ==
7120Sstevel@tonic-gate 		    DDI_FAILURE) {
7130Sstevel@tonic-gate 			cmn_err(CE_WARN,
7140Sstevel@tonic-gate 			    "%s%d pm_idle_component failed",
7150Sstevel@tonic-gate 			    ddi_driver_name(p->pwr_dip),
7160Sstevel@tonic-gate 			    ddi_get_instance(p->pwr_dip));
7170Sstevel@tonic-gate 		} else {
7180Sstevel@tonic-gate 			DEBUG0(DBG_PWR, p->pwr_dip,
7190Sstevel@tonic-gate 			    "called PM_IDLE_COMPONENT() BUSY BIT CLEARED\n");
7200Sstevel@tonic-gate 			p->pwr_flags &= ~PCI_PWR_COMP_BUSY;
7210Sstevel@tonic-gate 		}
7220Sstevel@tonic-gate 	} else {
7230Sstevel@tonic-gate 		DEBUG0(DBG_PWR, p->pwr_dip, "BUSY BIT ALREADY CLEARED\n");
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate }
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate void
pci_pwr_change(pci_pwr_t * pwr_p,int current,int new)7280Sstevel@tonic-gate pci_pwr_change(pci_pwr_t *pwr_p, int current, int new)
7290Sstevel@tonic-gate {
7300Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
7310Sstevel@tonic-gate 	if (current == new) {
7320Sstevel@tonic-gate 		DEBUG2(DBG_PWR, pwr_p->pwr_dip,
7330Sstevel@tonic-gate 		    "No change in power required. Should be "
7340Sstevel@tonic-gate 		    "busy. (current=%d) == (new=%d)\n",
7350Sstevel@tonic-gate 		    current, new);
7360Sstevel@tonic-gate 		pci_pwr_component_busy(pwr_p);
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 		return;
7390Sstevel@tonic-gate 	}
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	if (new < current) {
7420Sstevel@tonic-gate 		DEBUG2(DBG_PWR, pwr_p->pwr_dip,
7430Sstevel@tonic-gate 		    "should be idle (new=%d) < (current=%d)\n",
7440Sstevel@tonic-gate 		    new, current);
7450Sstevel@tonic-gate 		pci_pwr_component_idle(pwr_p);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 		return;
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	if (new > current) {
7510Sstevel@tonic-gate 		DEBUG2(DBG_PWR, pwr_p->pwr_dip, "pwr_change: "
7520Sstevel@tonic-gate 		    "pm_raise_power() and should be busy. "
7530Sstevel@tonic-gate 		    "(new=%d) > (current=%d)\n", new, current);
7540Sstevel@tonic-gate 		pci_pwr_component_busy(pwr_p);
7550Sstevel@tonic-gate 		mutex_exit(&pwr_p->pwr_mutex);
7560Sstevel@tonic-gate 		if (pm_raise_power(pwr_p->pwr_dip, PCI_PM_COMP_0,
7570Sstevel@tonic-gate 		    new) == DDI_FAILURE) {
7580Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d pm_raise_power failed",
7590Sstevel@tonic-gate 			    ddi_driver_name(pwr_p->pwr_dip),
7600Sstevel@tonic-gate 			    ddi_get_instance(pwr_p->pwr_dip));
7610Sstevel@tonic-gate 		}
7620Sstevel@tonic-gate 		mutex_enter(&pwr_p->pwr_mutex);
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 		return;
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate }
767