/*ARGSUSED*/ static int ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) { ppb_devstate_t *ppb; int ret = DDI_SUCCESS; switch (cmd) { case DDI_DETACH: /* * And finally free the per-pci soft state after * uninitializing hotplug support for this bus. */ ppb = (ppb_devstate_t *) ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); ppb_fm_fini(ppb); if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) ret = pcie_uninit(devi); else if (ppb->hotplug_capable == B_TRUE) ret = pcihp_init(devi); else ddi_remove_minor_node(devi, "devctl"); if (ret != DDI_SUCCESS) return (DDI_FAILURE); (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type"); if (ppb->ppb_pwr_p != NULL) { ppb_pwr_teardown(ppb, devi); } mutex_destroy(&ppb->ppb_mutex); ddi_soft_state_free(ppb_state, ddi_get_instance(devi)); return (DDI_SUCCESS); case DDI_SUSPEND: ppb = (ppb_devstate_t *) ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); pci_pwr_suspend(devi, ppb->ppb_pwr_p); return (DDI_SUCCESS); } return (DDI_FAILURE); }
/*ARGSUSED*/ static int ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) { ppb_devstate_t *ppb; int ret; switch (cmd) { case DDI_DETACH: (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type"); ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE) ddi_fm_handler_unregister(devi); if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE | DDI_FM_EREPORT_CAPABLE)) pci_ereport_teardown(devi); /* * Uninitialize hotplug support on this bus. */ ret = (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) ? pcie_uninit(devi) : pcihp_uninit(devi); if (ret != DDI_SUCCESS) return (DDI_FAILURE); mutex_destroy(&ppb->ppb_peek_poke_mutex); mutex_destroy(&ppb->ppb_err_mutex); mutex_destroy(&ppb->ppb_mutex); ddi_fm_fini(devi); /* * And finally free the per-pci soft state. */ ddi_soft_state_free(ppb_state, ddi_get_instance(devi)); return (DDI_SUCCESS); case DDI_SUSPEND: ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); ppb_save_config_regs(ppb); return (DDI_SUCCESS); default: break; } return (DDI_FAILURE); }
/*ARGSUSED*/ static int px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { int instance = ddi_get_instance(dip); px_t *px_p = INST_TO_STATE(instance); pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); int ret; /* * Make sure we are currently attached */ if (px_p->px_state != PX_ATTACHED) { DBG(DBG_DETACH, dip, "Instance not attached\n"); return (DDI_FAILURE); } mutex_enter(&px_p->px_mutex); switch (cmd) { case DDI_DETACH: DBG(DBG_DETACH, dip, "DDI_DETACH\n"); /* * remove cpr callback */ px_cpr_rem_callb(px_p); (void) pcie_hpintr_disable(dip); if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) (void) px_lib_hotplug_uninit(dip); if (pcie_uninit(dip) != DDI_SUCCESS) { mutex_exit(&px_p->px_mutex); return (DDI_FAILURE); } /* Destroy bus_t for the whole fabric */ pcie_fab_fini_bus(dip, PCIE_BUS_ALL); /* * things which used to be done in obj_destroy * are now in-lined here. */ px_p->px_state = PX_DETACHED; pxtool_uninit(dip); px_disable_err_intr(px_p); px_fm_detach(px_p); px_pec_detach(px_p); px_pwr_teardown(dip); pwr_common_teardown(dip); px_msi_detach(px_p); px_msiq_detach(px_p); px_mmu_detach(px_p); px_ib_detach(px_p); if (px_lib_dev_fini(dip) != DDI_SUCCESS) { DBG(DBG_DETACH, dip, "px_lib_dev_fini failed\n"); } /* * Free the px soft state structure and the rest of the * resources it's using. */ px_free_props(px_p); pcie_rc_fini_bus(dip); px_dbg_detach(dip, &px_p->px_dbg_hdl); mutex_exit(&px_p->px_mutex); mutex_destroy(&px_p->px_mutex); px_p->px_dev_hdl = NULL; ddi_soft_state_free(px_state_p, instance); return (DDI_SUCCESS); case DDI_SUSPEND: if (pcie_pwr_suspend(dip) != DDI_SUCCESS) { mutex_exit(&px_p->px_mutex); return (DDI_FAILURE); } if ((ret = px_lib_suspend(dip)) == DDI_SUCCESS) px_p->px_state = PX_SUSPENDED; mutex_exit(&px_p->px_mutex); return (ret); default: DBG(DBG_DETACH, dip, "unsupported detach op\n"); mutex_exit(&px_p->px_mutex); return (DDI_FAILURE); } }
/*ARGSUSED*/ static int px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { px_t *px_p; /* per bus state pointer */ int instance = DIP_TO_INST(dip); int ret = DDI_SUCCESS; devhandle_t dev_hdl = NULL; pcie_hp_regops_t regops; pcie_bus_t *bus_p; switch (cmd) { case DDI_ATTACH: DBG(DBG_ATTACH, dip, "DDI_ATTACH\n"); /* See pci_cfgacc.c */ pci_cfgacc_acc_p = pci_cfgacc_acc; /* * Allocate and get the per-px soft state structure. */ if (ddi_soft_state_zalloc(px_state_p, instance) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: can't allocate px state", ddi_driver_name(dip), instance); goto err_bad_px_softstate; } px_p = INST_TO_STATE(instance); px_p->px_dip = dip; mutex_init(&px_p->px_mutex, NULL, MUTEX_DRIVER, NULL); px_p->px_soft_state = PCI_SOFT_STATE_CLOSED; (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, "device_type", "pciex"); /* Initialize px_dbg for high pil printing */ px_dbg_attach(dip, &px_p->px_dbg_hdl); pcie_rc_init_bus(dip); /* * Get key properties of the pci bridge node and * determine it's type (psycho, schizo, etc ...). */ if (px_get_props(px_p, dip) == DDI_FAILURE) goto err_bad_px_prop; if (px_lib_dev_init(dip, &dev_hdl) != DDI_SUCCESS) goto err_bad_dev_init; /* Initialize device handle */ px_p->px_dev_hdl = dev_hdl; /* Cache the BDF of the root port nexus */ px_p->px_bdf = px_lib_get_bdf(px_p); /* * Initialize interrupt block. Note that this * initialize error handling for the PEC as well. */ if ((ret = px_ib_attach(px_p)) != DDI_SUCCESS) goto err_bad_ib; if (px_cb_attach(px_p) != DDI_SUCCESS) goto err_bad_cb; /* * Start creating the modules. * Note that attach() routines should * register and enable their own interrupts. */ if ((px_mmu_attach(px_p)) != DDI_SUCCESS) goto err_bad_mmu; if ((px_msiq_attach(px_p)) != DDI_SUCCESS) goto err_bad_msiq; if ((px_msi_attach(px_p)) != DDI_SUCCESS) goto err_bad_msi; if ((px_pec_attach(px_p)) != DDI_SUCCESS) goto err_bad_pec; if ((px_dma_attach(px_p)) != DDI_SUCCESS) goto err_bad_dma; /* nothing to uninitialize on DMA */ if ((px_fm_attach(px_p)) != DDI_SUCCESS) goto err_bad_dma; /* * All of the error handlers have been registered * by now so it's time to activate all the interrupt. */ if ((px_enable_err_intr(px_p)) != DDI_SUCCESS) goto err_bad_intr; if (px_lib_hotplug_init(dip, (void *)®ops) == DDI_SUCCESS) { pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE; } (void) px_set_mps(px_p); if (pcie_init(dip, (caddr_t)®ops) != DDI_SUCCESS) goto err_bad_hotplug; (void) pcie_hpintr_enable(dip); if (pxtool_init(dip) != DDI_SUCCESS) goto err_bad_pcitool_node; /* * power management setup. Even if it fails, attach will * succeed as this is a optional feature. Since we are * always at full power, this is not critical. */ if (pwr_common_setup(dip) != DDI_SUCCESS) { DBG(DBG_PWR, dip, "pwr_common_setup failed\n"); } else if (px_pwr_setup(dip) != DDI_SUCCESS) { DBG(DBG_PWR, dip, "px_pwr_setup failed \n"); pwr_common_teardown(dip); } /* * add cpr callback */ px_cpr_add_callb(px_p); /* * do fabric sync in case we don't need to wait for * any bridge driver to be ready */ (void) px_lib_fabric_sync(dip); ddi_report_dev(dip); px_p->px_state = PX_ATTACHED; /* * save base addr in bus_t for pci_cfgacc_xxx(), this * depends of px structure being properly initialized. */ bus_p = PCIE_DIP2BUS(dip); bus_p->bus_cfgacc_base = px_lib_get_cfgacc_base(dip); /* * Partially populate bus_t for all devices in this fabric * for device type macros to work. */ /* * Populate bus_t for all devices in this fabric, after FMA * is initializated, so that config access errors could * trigger panic. */ pcie_fab_init_bus(dip, PCIE_BUS_ALL); DBG(DBG_ATTACH, dip, "attach success\n"); break; err_bad_pcitool_node: (void) pcie_hpintr_disable(dip); (void) pcie_uninit(dip); err_bad_hotplug: (void) px_lib_hotplug_uninit(dip); px_disable_err_intr(px_p); err_bad_intr: px_fm_detach(px_p); err_bad_dma: px_pec_detach(px_p); err_bad_pec: px_msi_detach(px_p); err_bad_msi: px_msiq_detach(px_p); err_bad_msiq: px_mmu_detach(px_p); err_bad_mmu: err_bad_cb: px_ib_detach(px_p); err_bad_ib: if (px_lib_dev_fini(dip) != DDI_SUCCESS) { DBG(DBG_ATTACH, dip, "px_lib_dev_fini failed\n"); } err_bad_dev_init: px_free_props(px_p); err_bad_px_prop: pcie_rc_fini_bus(dip); px_dbg_detach(dip, &px_p->px_dbg_hdl); mutex_destroy(&px_p->px_mutex); ddi_soft_state_free(px_state_p, instance); err_bad_px_softstate: ret = DDI_FAILURE; break; case DDI_RESUME: DBG(DBG_ATTACH, dip, "DDI_RESUME\n"); px_p = INST_TO_STATE(instance); mutex_enter(&px_p->px_mutex); /* suspend might have not succeeded */ if (px_p->px_state != PX_SUSPENDED) { DBG(DBG_ATTACH, px_p->px_dip, "instance NOT suspended\n"); ret = DDI_FAILURE; break; } px_msiq_resume(px_p); px_lib_resume(dip); (void) pcie_pwr_resume(dip); px_p->px_state = PX_ATTACHED; mutex_exit(&px_p->px_mutex); break; default: DBG(DBG_ATTACH, dip, "unsupported attach op\n"); ret = DDI_FAILURE; break; } return (ret); }