pci_pwr.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/async.h>
#include <sys/sysmacros.h>
#include <sys/sunddi.h>
#include <sys/sunndi.h>
#include <sys/ddi_impldefs.h>
#include <sys/ddi_implfuncs.h>
#include <sys/pci/pci_obj.h>
#include <sys/pci/pci_pwr.h>
#include <sys/pci.h>
static void pci_pwr_update_comp(pci_pwr_t *pwr_p, pci_pwr_chld_t *p, int comp,
int lvl);
#ifdef DEBUG
static char *pci_pwr_bus_label[] = {"PM_LEVEL_B3", "PM_LEVEL_B2", \
"PM_LEVEL_B1", "PM_LEVEL_B0"};
#endif
/*LINTLIBRARY*/
/*
* Retreive the pci_pwr_chld_t structure for a given devinfo node.
*/
pci_pwr_chld_t *
pci_pwr_get_info(pci_pwr_t *pwr_p, dev_info_t *dip)
{
pci_pwr_chld_t *p;
ASSERT(PM_CAPABLE(pwr_p));
ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
for (p = pwr_p->pwr_info; p != NULL; p = p->next) {
if (p->dip == dip) {
return (p);
}
}
cmn_err(CE_PANIC, "unable to find pwr info data for %s@%s",
ddi_node_name(dip), ddi_get_name_addr(dip));
/*NOTREACHED*/
}
/*
* Create a pci_pwr_chld_t structure for a given devinfo node.
*/
void
pci_pwr_create_info(pci_pwr_t *pwr_p, dev_info_t *dip)
{
pci_pwr_chld_t *p;
ASSERT(PM_CAPABLE(pwr_p));
DEBUG2(DBG_PWR, ddi_get_parent(dip), "ADDING NEW PWR_INFO %s@%s\n",
ddi_node_name(dip), ddi_get_name_addr(dip));
p = kmem_zalloc(sizeof (struct pci_pwr_chld), KM_SLEEP);
p->dip = dip;
mutex_enter(&pwr_p->pwr_mutex);
/*
* Until components are created for this device, bus
* should be at full power since power of child device
* is unknown. Increment # children requiring "full power"
*/
p->flags |= PWR_FP_HOLD;
pwr_p->pwr_fp++;
p->next = pwr_p->pwr_info;
pwr_p->pwr_info = p;
pci_pwr_change(pwr_p, pwr_p->current_lvl, pci_pwr_new_lvl(pwr_p));
mutex_exit(&pwr_p->pwr_mutex);
}
void
pci_pwr_rm_info(pci_pwr_t *pwr_p, dev_info_t *cdip)
{
pci_pwr_chld_t **prev_infop;
pci_pwr_chld_t *infop = NULL;
int i;
ASSERT(PM_CAPABLE(pwr_p));
mutex_enter(&pwr_p->pwr_mutex);
for (prev_infop = &pwr_p->pwr_info; *prev_infop != NULL;
prev_infop = &((*prev_infop)->next)) {
if ((*prev_infop)->dip == cdip) {
infop = *prev_infop;
break;
}
}
if (infop == NULL) {
mutex_exit(&pwr_p->pwr_mutex);
return;
}
*prev_infop = infop->next;
/*
* Remove any reference counts for this child.
*/
if (infop->comp_pwr != NULL) {
for (i = 0; i < infop->num_comps; i++) {
pci_pwr_update_comp(pwr_p, infop, i, PM_LEVEL_NOLEVEL);
}
kmem_free(infop->comp_pwr, sizeof (int) * infop->num_comps);
}
if (infop->flags & PWR_FP_HOLD) {
pwr_p->pwr_fp--;
}
pci_pwr_change(pwr_p, pwr_p->current_lvl, pci_pwr_new_lvl(pwr_p));
mutex_exit(&pwr_p->pwr_mutex);
kmem_free(infop, sizeof (struct pci_pwr_chld));
}
/*
* Allocate space for component state information in pci_pwr_chld_t
*/
void
pci_pwr_add_components(pci_pwr_t *pwr_p, dev_info_t *cdip, pci_pwr_chld_t *p)
{
int num_comps = PM_NUMCMPTS(cdip);
int i;
ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
/*
* Assume the power level of a component is UNKNOWN until
* notified otherwise.
*/
if (num_comps > 0) {
p->comp_pwr =
kmem_alloc(sizeof (int) * num_comps, KM_SLEEP);
p->num_comps = num_comps;
DEBUG3(DBG_PWR, ddi_get_parent(cdip),
"ADDING %d COMPONENTS FOR %s@%s\n", num_comps,
ddi_node_name(cdip), ddi_get_name_addr(cdip));
} else {
cmn_err(CE_WARN, "%s%d device has %d components",
ddi_driver_name(cdip), ddi_get_instance(cdip),
num_comps);
return;
}
/*
* Release the fp hold that was made when the device
* was created.
*/
ASSERT((p->flags & PWR_FP_HOLD) == PWR_FP_HOLD);
p->flags &= ~PWR_FP_HOLD;
pwr_p->pwr_fp--;
for (i = 0; i < num_comps; i++) {
/*
* Initialize the component lvl so that the
* state reference counts will be updated correctly.
*/
p->comp_pwr[i] = PM_LEVEL_NOLEVEL;
pci_pwr_update_comp(pwr_p, p, i, PM_LEVEL_UNKNOWN);
}
}
/*
* Update the current power level for component. Then adjust the
* bus reference counter for given state.
*/
static void
pci_pwr_update_comp(pci_pwr_t *pwr_p, pci_pwr_chld_t *p, int comp,
int lvl)
{
ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
/*
* Remove old pwr state count for old PM level.
*/
switch (p->comp_pwr[comp]) {
case PM_LEVEL_UNKNOWN:
pwr_p->pwr_uk--;
p->u01--;
ASSERT(pwr_p->pwr_uk >= 0);
break;
case PM_LEVEL_D0:
pwr_p->pwr_d0--;
p->u01--;
ASSERT(pwr_p->pwr_d0 >= 0);
break;
case PM_LEVEL_D1:
pwr_p->pwr_d1--;
p->u01--;
ASSERT(pwr_p->pwr_d1 >= 0);
break;
case PM_LEVEL_D2:
pwr_p->pwr_d2--;
ASSERT(pwr_p->pwr_d2 >= 0);
break;
case PM_LEVEL_D3:
pwr_p->pwr_d3--;
ASSERT(pwr_p->pwr_d3 >= 0);
break;
default:
break;
}
p->comp_pwr[comp] = lvl;
/*
* Add new pwr state count for the new PM level.
*/
switch (lvl) {
case PM_LEVEL_UNKNOWN:
pwr_p->pwr_uk++;
p->u01++;
break;
case PM_LEVEL_D0:
pwr_p->pwr_d0++;
p->u01++;
break;
case PM_LEVEL_D1:
pwr_p->pwr_d1++;
p->u01++;
break;
case PM_LEVEL_D2:
pwr_p->pwr_d2++;
break;
case PM_LEVEL_D3:
pwr_p->pwr_d3++;
break;
default:
break;
}
}
/*
* Knowing the current state of all devices on the bus, return the
* appropriate supported bus speed.
*/
int
pci_pwr_new_lvl(pci_pwr_t *pwr_p)
{
int b_lvl;
ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
if (pwr_p->pwr_fp > 0) {
DEBUG1(DBG_PWR, pwr_p->pwr_dip, "new_lvl: "
"returning PM_LEVEL_B0 pwr_fp = %d\n", pwr_p->pwr_fp);
return (PM_LEVEL_B0);
}
/*
* If any components are at unknown power levels, the
* highest power level has to be assumed for the device (D0).
*/
if (pwr_p->pwr_uk > 0) {
DEBUG1(DBG_PWR, pwr_p->pwr_dip, "new_lvl: unknown "
"count is %d. returning PM_LEVEL_B0\n", pwr_p->pwr_uk);
return (PM_LEVEL_B0);
}
/*
* Find the lowest theoretical level
* the bus can operate at.
*/
if (pwr_p->pwr_d0 > 0) {
b_lvl = PM_LEVEL_B0;
DEBUG1(DBG_PWR, pwr_p->pwr_dip,
"new_lvl: PM_LEVEL_B0 d0 count = %d\n",
pwr_p->pwr_d0);
} else if (pwr_p->pwr_d1 > 0) {
b_lvl = PM_LEVEL_B1;
DEBUG1(DBG_PWR, pwr_p->pwr_dip,
"new_lvl: PM_LEVEL_B1 d1 count = %d\n",
pwr_p->pwr_d1);
} else if (pwr_p->pwr_d2 > 0) {
b_lvl = PM_LEVEL_B2;
DEBUG1(DBG_PWR, pwr_p->pwr_dip,
"new_lvl: PM_LEVEL_B2 d2 count = %d\n",
pwr_p->pwr_d2);
} else if (pwr_p->pwr_d3 > 0) {
b_lvl = PM_LEVEL_B3;
DEBUG1(DBG_PWR, pwr_p->pwr_dip,
"new_lvl: PM_LEVEL_B3 d3 count = %d\n",
pwr_p->pwr_d3);
} else {
DEBUG0(DBG_PWR, pwr_p->pwr_dip,
"new_lvl: PM_LEVEL_B3: all counts are 0\n");
b_lvl = PM_LEVEL_B3;
}
/*
* Now find the closest supported level available.
* If the level isn't available, have to find the
* next highest power level (or lowest in B# terms).
*/
switch (b_lvl) {
case PM_LEVEL_B3:
if (pwr_p->pwr_flags & PCI_PWR_B3_CAPABLE) {
break;
}
/*FALLTHROUGH*/
case PM_LEVEL_B2:
if (pwr_p->pwr_flags & PCI_PWR_B2_CAPABLE) {
b_lvl = PM_LEVEL_B2;
break;
}
/*FALLTHROUGH*/
case PM_LEVEL_B1:
if (pwr_p->pwr_flags & PCI_PWR_B1_CAPABLE) {
b_lvl = PM_LEVEL_B1;
break;
}
/*FALLTHROUGH*/
case PM_LEVEL_B0:
/*
* This level always supported
*/
b_lvl = PM_LEVEL_B0;
break;
}
DEBUG1(DBG_PWR, pwr_p->pwr_dip,
"new_lvl: Adjusted Level is %s\n",
pci_pwr_bus_label[b_lvl]);
return (b_lvl);
}
int
pci_raise_power(pci_pwr_t *pwr_p, int current, int new, void *impl_arg,
pm_bp_nexus_pwrup_t bpn)
{
int ret = DDI_SUCCESS, pwrup_res;
ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
pci_pwr_component_busy(pwr_p);
mutex_exit(&pwr_p->pwr_mutex);
ret = pm_busop_bus_power(pwr_p->pwr_dip, impl_arg,
BUS_POWER_NEXUS_PWRUP, (void *) &bpn,
(void *) &pwrup_res);
if (ret != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) {
mutex_enter(&pwr_p->pwr_mutex);
pci_pwr_component_idle(pwr_p);
mutex_exit(&pwr_p->pwr_mutex);
cmn_err(CE_WARN, "%s%d pci_raise_power failed",
ddi_driver_name(pwr_p->pwr_dip),
ddi_get_instance(pwr_p->pwr_dip));
}
return (ret);
}
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)
{
pci_pwr_chld_t *p_chld;
pm_bp_nexus_pwrup_t bpn;
pm_bp_child_pwrchg_t *bpc = (pm_bp_child_pwrchg_t *)arg;
dev_info_t *rdip = bpc->bpc_dip;
int new_level, *res = (int *)result, ret = DDI_SUCCESS;
mutex_enter(&pwr_p->pwr_mutex);
switch (op) {
case BUS_POWER_HAS_CHANGED:
p_chld = pci_pwr_get_info(pwr_p, rdip);
DEBUG5(DBG_PWR, dip, "%s@%s CHANGED_POWER cmp = %d "
"old = %d new = %d\n",
ddi_node_name(rdip), ddi_get_name_addr(rdip),
bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel);
if (*res == DDI_FAILURE) {
DEBUG0(DBG_PWR, rdip, "changed_power_req FAILED\n");
break;
} else {
/*
* pci_pwr_add_components must be called here if
* comp_pwr hasn't been set up yet. It has to be done
* here rather than in post-attach, since it is possible
* for power() of child to get called before attach
* completes.
*/
if (p_chld->comp_pwr == NULL)
pci_pwr_add_components(pwr_p, rdip, p_chld);
pci_pwr_update_comp(pwr_p, p_chld,
bpc->bpc_comp, bpc->bpc_nlevel);
}
new_level = pci_pwr_new_lvl(pwr_p);
bpn.bpn_dip = pwr_p->pwr_dip;
bpn.bpn_comp = PCI_PM_COMP_0;
bpn.bpn_level = new_level;
bpn.bpn_private = bpc->bpc_private;
if (new_level > pwr_p->current_lvl)
return (pci_raise_power(pwr_p, pwr_p->current_lvl,
new_level, impl_arg, bpn));
else
pci_pwr_change(pwr_p, pwr_p->current_lvl,
new_level);
break;
case BUS_POWER_PRE_NOTIFICATION:
DEBUG5(DBG_PWR, dip, "PRE %s@%s cmp = %d old = %d "
"new = %d. TEMP FULL POWER\n",
ddi_node_name(rdip), ddi_get_name_addr(rdip),
bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel);
/*
* Any state changes require that the bus be at full
* power (B0) so that the device configuration
* registers can be accessed. Make a fp hold here
* so device remains at full power during power
* configuration.
*/
pwr_p->pwr_fp++;
DEBUG1(DBG_PWR, pwr_p->pwr_dip,
"incremented fp is %d in PRE_NOTE\n\n", pwr_p->pwr_fp);
bpn.bpn_dip = pwr_p->pwr_dip;
bpn.bpn_comp = PCI_PM_COMP_0;
bpn.bpn_level = PM_LEVEL_B0;
bpn.bpn_private = bpc->bpc_private;
if (PM_LEVEL_B0 > pwr_p->current_lvl)
return (pci_raise_power(pwr_p, pwr_p->current_lvl,
PM_LEVEL_B0, impl_arg, bpn));
break;
case BUS_POWER_POST_NOTIFICATION:
p_chld = pci_pwr_get_info(pwr_p, rdip);
DEBUG5(DBG_PWR, dip, "POST %s@%s cmp = %d old = %d new = %d\n",
ddi_node_name(rdip), ddi_get_name_addr(rdip),
bpc->bpc_comp, bpc->bpc_olevel, bpc->bpc_nlevel);
if (*res == DDI_FAILURE) {
DEBUG0(DBG_PWR, rdip, "child's power routine FAILED\n");
} else {
/*
* pci_pwr_add_components must be called here if
* comp_pwr hasen't been set up yet. It has to be done
* here rather than in post-attach, since it is possible
* for power() of child to get called before attach
* completes.
*/
if (p_chld->comp_pwr == NULL)
pci_pwr_add_components(pwr_p, rdip, p_chld);
pci_pwr_update_comp(pwr_p, p_chld,
bpc->bpc_comp, bpc->bpc_nlevel);
}
pwr_p->pwr_fp--;
DEBUG1(DBG_PWR, pwr_p->pwr_dip,
"decremented fp is %d in POST_NOTE\n\n", pwr_p->pwr_fp);
new_level = pci_pwr_new_lvl(pwr_p);
bpn.bpn_dip = pwr_p->pwr_dip;
bpn.bpn_comp = PCI_PM_COMP_0;
bpn.bpn_level = new_level;
bpn.bpn_private = bpc->bpc_private;
if (new_level > pwr_p->current_lvl)
return (pci_raise_power(pwr_p, pwr_p->current_lvl,
new_level, impl_arg, bpn));
else
pci_pwr_change(pwr_p, pwr_p->current_lvl,
new_level);
break;
default:
mutex_exit(&pwr_p->pwr_mutex);
return (pm_busop_bus_power(dip, impl_arg, op, arg, result));
}
mutex_exit(&pwr_p->pwr_mutex);
return (ret);
}
void
pci_pwr_resume(dev_info_t *dip, pci_pwr_t *pwr_p)
{
dev_info_t *cdip;
/*
* Inform the PM framework of the current state of the device.
* (it is unknown to PM framework at this point).
*/
if (PM_CAPABLE(pwr_p)) {
pwr_p->current_lvl = pci_pwr_current_lvl(pwr_p);
pm_power_has_changed(dip, PCI_PM_COMP_0,
pwr_p->current_lvl);
}
/*
* Restore config registers for children that did not save
* their own registers. Children pwr states are UNKNOWN after
* a resume since it is possible for the PM framework to call
* resume without an actual power cycle. (ie if suspend fails).
*/
for (cdip = ddi_get_child(dip); cdip != NULL;
cdip = ddi_get_next_sibling(cdip)) {
/*
* Not interested in children who are not already
* init'ed. They will be set up by init_child().
*/
if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
DEBUG2(DBG_DETACH, dip,
"DDI_RESUME: skipping %s%d not in CF1\n",
ddi_driver_name(cdip), ddi_get_instance(cdip));
continue;
}
/*
* Only restore config registers if saved by nexus.
*/
if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
NEXUS_SAVED) == 1) {
(void) pci_restore_config_regs(cdip);
DEBUG2(DBG_PWR, dip,
"DDI_RESUME: nexus restoring %s%d config regs\n",
ddi_driver_name(cdip), ddi_get_instance(cdip));
if (ndi_prop_remove(DDI_DEV_T_NONE, cdip,
NEXUS_SAVED) != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN, "%s%d can't remove prop %s",
ddi_driver_name(cdip),
ddi_get_instance(cdip),
NEXUS_SAVED);
}
}
}
}
void
pci_pwr_suspend(dev_info_t *dip, pci_pwr_t *pwr_p)
{
dev_info_t *cdip;
/*
* Save the state of the configuration headers of child
* nodes.
*/
for (cdip = ddi_get_child(dip); cdip != NULL;
cdip = ddi_get_next_sibling(cdip)) {
pci_pwr_chld_t *p;
int i;
int num_comps;
int ret;
/*
* Not interested in children who are not already
* init'ed. They will be set up in init_child().
*/
if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
DEBUG2(DBG_DETACH, dip, "DDI_SUSPEND: skipping "
"%s%d not in CF1\n", ddi_driver_name(cdip),
ddi_get_instance(cdip));
continue;
}
/*
* Only save config registers if not already saved by child.
*/
if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
SAVED_CONFIG_REGS) == 1) {
continue;
}
/*
* The nexus needs to save config registers. Create a property
* so it knows to restore on resume.
*/
ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
NEXUS_SAVED);
if (ret != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN, "%s%d can't update prop %s",
ddi_driver_name(cdip), ddi_get_instance(cdip),
NEXUS_SAVED);
}
if (!PM_CAPABLE(pwr_p)) {
(void) pci_save_config_regs(cdip);
continue;
}
mutex_enter(&pwr_p->pwr_mutex);
p = pci_pwr_get_info(pwr_p, cdip);
num_comps = p->num_comps;
/*
* If a device has components, reset the power level
* to unknown. This will ensure that the bus is full
* power so that saving register won't panic (if
* the device is already powered off, the child should
* have already done the save, but an incorrect driver
* may have forgotten). If resetting power levels
* to unknown isn't done here, it would have to be done
* in resume since pci driver has no way of knowing
* actual state of HW (power cycle may not have
* occurred, and it was decided that poking into a
* child's config space should be avoided unless
* absolutely necessary).
*/
if (p->comp_pwr == NULL) {
(void) pci_save_config_regs(cdip);
} else {
for (i = 0; i < num_comps; i++) {
pci_pwr_update_comp(pwr_p, p, i,
PM_LEVEL_UNKNOWN);
}
/*
* ensure bus power is on before saving
* config regs.
*/
pci_pwr_change(pwr_p, pwr_p->current_lvl,
pci_pwr_new_lvl(pwr_p));
(void) pci_save_config_regs(cdip);
}
mutex_exit(&pwr_p->pwr_mutex);
}
}
void
pci_pwr_component_busy(pci_pwr_t *p)
{
ASSERT(MUTEX_HELD(&p->pwr_mutex));
if ((p->pwr_flags & PCI_PWR_COMP_BUSY) == 0) {
if (pm_busy_component(p->pwr_dip, PCI_PM_COMP_0) ==
DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d pm_busy_component failed",
ddi_driver_name(p->pwr_dip),
ddi_get_instance(p->pwr_dip));
} else {
DEBUG0(DBG_PWR, p->pwr_dip,
"called PM_BUSY_COMPONENT(). BUSY BIT SET\n");
p->pwr_flags |= PCI_PWR_COMP_BUSY;
}
} else {
DEBUG0(DBG_PWR, p->pwr_dip, "BUSY BIT ALREADY SET\n");
}
}
void
pci_pwr_component_idle(pci_pwr_t *p)
{
ASSERT(MUTEX_HELD(&p->pwr_mutex));
if (p->pwr_flags & PCI_PWR_COMP_BUSY) {
if (pm_idle_component(p->pwr_dip, PCI_PM_COMP_0) ==
DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d pm_idle_component failed",
ddi_driver_name(p->pwr_dip),
ddi_get_instance(p->pwr_dip));
} else {
DEBUG0(DBG_PWR, p->pwr_dip,
"called PM_IDLE_COMPONENT() BUSY BIT CLEARED\n");
p->pwr_flags &= ~PCI_PWR_COMP_BUSY;
}
} else {
DEBUG0(DBG_PWR, p->pwr_dip, "BUSY BIT ALREADY CLEARED\n");
}
}
void
pci_pwr_change(pci_pwr_t *pwr_p, int current, int new)
{
ASSERT(MUTEX_HELD(&pwr_p->pwr_mutex));
if (current == new) {
DEBUG2(DBG_PWR, pwr_p->pwr_dip,
"No change in power required. Should be "
"busy. (current=%d) == (new=%d)\n",
current, new);
pci_pwr_component_busy(pwr_p);
return;
}
if (new < current) {
DEBUG2(DBG_PWR, pwr_p->pwr_dip,
"should be idle (new=%d) < (current=%d)\n",
new, current);
pci_pwr_component_idle(pwr_p);
return;
}
if (new > current) {
DEBUG2(DBG_PWR, pwr_p->pwr_dip, "pwr_change: "
"pm_raise_power() and should be busy. "
"(new=%d) > (current=%d)\n", new, current);
pci_pwr_component_busy(pwr_p);
mutex_exit(&pwr_p->pwr_mutex);
if (pm_raise_power(pwr_p->pwr_dip, PCI_PM_COMP_0,
new) == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d pm_raise_power failed",
ddi_driver_name(pwr_p->pwr_dip),
ddi_get_instance(pwr_p->pwr_dip));
}
mutex_enter(&pwr_p->pwr_mutex);
return;
}
}