static void usba_async_req_lower_power(void *arg) { usba_pm_req_t *pmrq = (usba_pm_req_t *)arg; int rval; /* * To eliminate race condition between the call to power entry * point and our call to lower power level, we call idle component * to push ahead the PM timestamp */ (void) pm_idle_component(pmrq->dip, pmrq->comp); rval = pm_lower_power(pmrq->dip, pmrq->comp, pmrq->level); pmrq->cb(pmrq->arg, rval); }
static void usba_async_req_raise_power(void *arg) { usba_pm_req_t *pmrq = (usba_pm_req_t *)arg; int rval; /* * To eliminate race condition between the call to power entry * point and our call to raise power level, we first mark the * component busy and later idle */ (void) pm_busy_component(pmrq->dip, pmrq->comp); rval = pm_raise_power(pmrq->dip, pmrq->comp, pmrq->level); (void) pm_idle_component(pmrq->dip, pmrq->comp); pmrq->cb(pmrq->arg, rval); /* We are done with pmrq. Free it now */ kmem_free(pmrq, sizeof (usba_pm_req_t)); }
/* * mark device idle */ static void uftdi_pm_set_idle(uftdi_state_t *uf) { uftdi_pm_t *pm = uf->uf_pm; dev_info_t *dip = uf->uf_dip; USB_DPRINTF_L4(DPRINT_PM, uf->uf_lh, "uftdi_pm_set_idle"); if (!pm) return; /* * if more ports use the device, do not mark as yet */ mutex_enter(&uf->uf_lock); if (--pm->pm_busy_cnt > 0) { mutex_exit(&uf->uf_lock); return; } (void) pm_idle_component(dip, 0); mutex_exit(&uf->uf_lock); }
static void wusb_df_pm_idle_component(wusb_df_state_t *wusb_dfp) { ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex)); mutex_enter(&wusb_dfp->wusb_df_mutex); if (wusb_dfp->wusb_df_pm == NULL) { mutex_exit(&wusb_dfp->wusb_df_mutex); return; } mutex_exit(&wusb_dfp->wusb_df_mutex); if (pm_idle_component(wusb_dfp->wusb_df_dip, 0) == DDI_SUCCESS) { mutex_enter(&wusb_dfp->wusb_df_mutex); ASSERT(wusb_dfp->wusb_df_pm->wusb_df_pm_busy > 0); wusb_dfp->wusb_df_pm->wusb_df_pm_busy--; USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl, "wusb_df_pm_idle_component: %d", wusb_dfp->wusb_df_pm->wusb_df_pm_busy); mutex_exit(&wusb_dfp->wusb_df_mutex); } }
/*ARGSUSED*/ static int gen_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) { struct dstate *dstatep; ddi_eventcookie_t cookie; int instance; int rval = 0; char *nodename; int i; struct devctl_iocdata *dcp; uint_t state; int ret; int level_tmp; instance = MINOR_TO_INST(getminor(dev)); dstatep = ddi_get_soft_state(dstates, instance); nodename = dstatep->nodename; if (dstatep == NULL) return (ENXIO); /* * read devctl ioctl data */ if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) return (EFAULT); switch (cmd) { case GENDRV_IOFAULT_SIMULATE: if (ddi_get_eventcookie(dstatep->dip, DDI_DEVI_FAULT_EVENT, &(cookie)) != NDI_SUCCESS) return (DDI_FAILURE); return (ndi_post_event(dstatep->dip, dstatep->dip, cookie, NULL)); case GENDRV_NDI_EVENT_TEST: if (ddi_get_eventcookie(dstatep->dip, "pshot_dev_offline", &cookie) == NDI_SUCCESS) { (void) ndi_post_event(dstatep->dip, dstatep->dip, cookie, NULL); } if (ddi_get_eventcookie(dstatep->dip, "pshot_dev_reset", &cookie) == NDI_SUCCESS) { (void) ndi_post_event(dstatep->dip, dstatep->dip, cookie, NULL); } if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_reset", &cookie) == NDI_SUCCESS) { (void) ndi_post_event(dstatep->dip, dstatep->dip, cookie, NULL); } if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_quiesce", &cookie) == NDI_SUCCESS) { (void) ndi_post_event(dstatep->dip, dstatep->dip, cookie, NULL); } if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_unquiesce", &cookie) == NDI_SUCCESS) { (void) ndi_post_event(dstatep->dip, dstatep->dip, cookie, NULL); } if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_test_post", &cookie) == NDI_SUCCESS) { (void) ndi_post_event(dstatep->dip, dstatep->dip, cookie, NULL); } break; case DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME: /* * Issue pm_power_has_changed() call on DDI_RESUME */ mutex_enter(&dstatep->lock); dstatep->flag |= PWR_HAS_CHANGED_ON_RESUME_FLAG; mutex_exit(&dstatep->lock); GEN_DEBUG((CE_CONT, "%s%d:" " DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME", nodename, instance)); break; case DEVCTL_PM_FAIL_SUSPEND: /* * Fail the suspend attempt in DDI_SUSPEND */ mutex_enter(&dstatep->lock); dstatep->flag |= FAIL_SUSPEND_FLAG; mutex_exit(&dstatep->lock); GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_FAIL_SUSPEND", nodename, instance)); break; case DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED: /* * Use pm_power_has_changed() to power up comp 0 when * enforcing the comp 0 vs comp-not 0 dependency: * Power up comp 0 first, if request for comp-not-0 * comes in. * Else, default to pm_raise_power(). */ mutex_enter(&dstatep->lock); dstatep->flag |= PUP_WITH_PWR_HAS_CHANGED_FLAG; mutex_exit(&dstatep->lock); GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED", nodename, instance)); break; case DEVCTL_PM_BUSY_COMP: /* * mark component 0 busy via a pm_busy_component() call. * update the busy[] array. */ mutex_enter(&dstatep->lock); ++dstatep->busy[0]; GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_BUSY_COMP: comp 0:" " busy=%d", nodename, instance, dstatep->busy[0])); mutex_exit(&dstatep->lock); ret = pm_busy_component(dstatep->dip, 0); ASSERT(ret == DDI_SUCCESS); break; case DEVCTL_PM_BUSY_COMP_TEST: /* * test busy state on component 0 */ mutex_enter(&dstatep->lock); state = dstatep->busy[0]; if (copyout(&state, dcp->cpyout_buf, sizeof (uint_t)) != 0) { cmn_err(CE_WARN, "%s%d:" " DEVCTL_PM_BUSY_COMP_TEST: copyout failed\n", nodename, instance); rval = EINVAL; } GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_BUSY_COMP_TEST:" " comp 0 busy %d", nodename, instance, state)); mutex_exit(&dstatep->lock); break; case DEVCTL_PM_IDLE_COMP: /* * mark component 0 idle via a pm_idle_component() call. * NOP if dstatep->busy[0] == 0. */ mutex_enter(&dstatep->lock); if (dstatep->busy[0] > 0) { --dstatep->busy[0]; GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_IDLE_COMP:" " comp 0: busy=%d", nodename, instance, dstatep->busy[0])); mutex_exit(&dstatep->lock); ret = pm_idle_component(dstatep->dip, 0); ASSERT(ret == DDI_SUCCESS); } else { mutex_exit(&dstatep->lock); } break; case DEVCTL_PM_PROM_PRINTF: (void) prom_printf("%s%d: PROM_PRINTF FROM GEN_DRV\n", nodename, instance); break; case DEVCTL_PM_RAISE_PWR: /* * power up both components to MAXPWR via * pm_raise_power() calls. this ioctl() cmd * assumes that the current level is 0 */ for (i = 0; i < COMPONENTS; i++) { GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_RAISE_PWR:" " comp %d old 0 new %d", nodename, instance, i, maxpwr[i])); if (pm_raise_power(dstatep->dip, 0, maxpwr[i]) != DDI_SUCCESS) { rval = EINVAL; } } break; case DEVCTL_PM_CHANGE_PWR_LOW: /* * power off both components via pm_power_has_changed() calls */ for (i = (COMPONENTS - 1); i >= 0; --i) { GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_CHANGE_PWR_LOW:" " comp %d new 0", nodename, instance, i)); mutex_enter(&dstatep->lock); level_tmp = dstatep->level[i]; dstatep->level[i] = 0; if (pm_power_has_changed(dstatep->dip, i, 0) != DDI_SUCCESS) { dstatep->level[i] = level_tmp; rval = EINVAL; } mutex_exit(&dstatep->lock); } break; case DEVCTL_PM_CHANGE_PWR_HIGH: /* * power up both components to MAXPWR via * pm_power_has_changed() calls */ for (i = 0; i < COMPONENTS; i++) { GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_CHANGE_PWR_HIGH:" " comp %d new %d", nodename, instance, i, maxpwr[i])); mutex_enter(&dstatep->lock); level_tmp = dstatep->level[i]; dstatep->level[i] = maxpwr[i]; if (pm_power_has_changed(dstatep->dip, i, maxpwr[i]) != DDI_SUCCESS) { dstatep->level[i] = level_tmp; rval = EINVAL; } mutex_exit(&dstatep->lock); } break; case DEVCTL_PM_POWER: /* * test if the gen_drv_power() routine has been called, * then clear */ mutex_enter(&dstatep->lock); state = (dstatep->flag & POWER_FLAG) ? 1 : 0; if (copyout(&state, dcp->cpyout_buf, sizeof (uint_t)) != 0) { cmn_err(CE_WARN, "%s%d: DEVCTL_PM_POWER:" " copyout failed\n", nodename, instance); rval = EINVAL; } GEN_DEBUG((CE_CONT, "%s%d: %s POWER_FLAG: %d", nodename, instance, "DEVCTL_PM_POWER", state)); dstatep->flag &= ~POWER_FLAG; mutex_exit(&dstatep->lock); break; case DEVCTL_PM_NO_LOWER_POWER: /* * issue to not invoke pm_lower_power() on detach */ mutex_enter(&dstatep->lock); dstatep->flag &= ~LOWER_POWER_FLAG; mutex_exit(&dstatep->lock); GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_NO_LOWER_POWER", nodename, instance)); break; default: return (ENOTTY); } return (rval); }