/*ARGSUSED*/ static int ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { dev_info_t *root = ddi_root_node(); int instance; ppb_devstate_t *ppb; dev_info_t *pdip; ddi_acc_handle_t config_handle; char *bus; switch (cmd) { case DDI_ATTACH: /* * Make sure the "device_type" property exists. */ (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci"); /* * Allocate and get soft state structure. */ instance = ddi_get_instance(devi); if (ddi_soft_state_zalloc(ppb_state, instance) != DDI_SUCCESS) return (DDI_FAILURE); ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, instance); ppb->dip = devi; mutex_init(&ppb->ppb_mutex, NULL, MUTEX_DRIVER, NULL); ppb->ppb_soft_state = PCI_SOFT_STATE_CLOSED; if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) { mutex_destroy(&ppb->ppb_mutex); ddi_soft_state_free(ppb_state, instance); return (DDI_FAILURE); } ppb_pwr_setup(ppb, devi); if (PM_CAPABLE(ppb->ppb_pwr_p)) { mutex_enter(&ppb->ppb_pwr_p->pwr_mutex); /* * Before reading config registers, make sure power is * on, and remains on. */ ppb->ppb_pwr_p->pwr_fp++; pci_pwr_change(ppb->ppb_pwr_p, ppb->ppb_pwr_p->current_lvl, pci_pwr_new_lvl(ppb->ppb_pwr_p)); } ppb->ppb_cache_line_size = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ); ppb->ppb_latency_timer = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER); /* * Check whether the "ranges" property is present. * Otherwise create the ranges property by reading * the configuration registers */ if (ddi_prop_exists(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, "ranges") == 0) { ppb_create_ranges_prop(devi, config_handle); } pci_config_teardown(&config_handle); if (PM_CAPABLE(ppb->ppb_pwr_p)) { ppb->ppb_pwr_p->pwr_fp--; pci_pwr_change(ppb->ppb_pwr_p, ppb->ppb_pwr_p->current_lvl, pci_pwr_new_lvl(ppb->ppb_pwr_p)); mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); } ppb->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO; for (pdip = ddi_get_parent(ppb->dip); pdip && (pdip != root) && (ppb->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV); pdip = ddi_get_parent(pdip)) { if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "device_type", &bus) != DDI_PROP_SUCCESS) break; if (strcmp(bus, "pciex") == 0) ppb->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV; ddi_prop_free(bus); } /* * Initialize hotplug support on this bus. */ if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) if (pcie_init(devi, NULL) != DDI_SUCCESS) { (void) ppb_detach(devi, DDI_DETACH); return (DDI_FAILURE); } else ppb_init_hotplug(ppb); DEBUG1(DBG_ATTACH, devi, "ppb_attach(): this nexus %s hotplug slots\n", ppb->hotplug_capable == B_TRUE ? "has":"has no"); ppb_fm_init(ppb); ddi_report_dev(devi); return (DDI_SUCCESS); case DDI_RESUME: /* * Get the soft state structure for the bridge. */ ppb = (ppb_devstate_t *) ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); pci_pwr_resume(devi, ppb->ppb_pwr_p); return (DDI_SUCCESS); } return (DDI_FAILURE); }
/*ARGSUSED*/ static int ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { dev_info_t *root = ddi_root_node(); int instance; ppb_devstate_t *ppb; dev_info_t *pdip; ddi_acc_handle_t config_handle; char *bus; int ret; switch (cmd) { case DDI_ATTACH: /* * Make sure the "device_type" property exists. */ (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci"); /* * Allocate and get soft state structure. */ instance = ddi_get_instance(devi); if (ddi_soft_state_zalloc(ppb_state, instance) != DDI_SUCCESS) return (DDI_FAILURE); ppb = ddi_get_soft_state(ppb_state, instance); ppb->dip = devi; /* * don't enable ereports if immediate child of npe */ if (strcmp(ddi_driver_name(ddi_get_parent(devi)), "npe") == 0) ppb->ppb_fmcap = DDI_FM_ERRCB_CAPABLE | DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; else ppb->ppb_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE | DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; ddi_fm_init(devi, &ppb->ppb_fmcap, &ppb->ppb_fm_ibc); mutex_init(&ppb->ppb_mutex, NULL, MUTEX_DRIVER, NULL); mutex_init(&ppb->ppb_err_mutex, NULL, MUTEX_DRIVER, (void *)ppb->ppb_fm_ibc); mutex_init(&ppb->ppb_peek_poke_mutex, NULL, MUTEX_DRIVER, (void *)ppb->ppb_fm_ibc); if (ppb->ppb_fmcap & (DDI_FM_ERRCB_CAPABLE | DDI_FM_EREPORT_CAPABLE)) pci_ereport_setup(devi); if (ppb->ppb_fmcap & DDI_FM_ERRCB_CAPABLE) ddi_fm_handler_register(devi, ppb_fm_callback, NULL); if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) { 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); ddi_fm_fini(devi); ddi_soft_state_free(ppb_state, instance); return (DDI_FAILURE); } ppb->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO; for (pdip = ddi_get_parent(devi); pdip && (pdip != root) && (ppb->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV); pdip = ddi_get_parent(pdip)) { if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "device_type", &bus) != DDI_PROP_SUCCESS) break; if (strcmp(bus, "pciex") == 0) ppb->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV; ddi_prop_free(bus); } if (ppb_support_ht_msimap == 1) (void) ppb_ht_msimap_set(config_handle, HT_MSIMAP_ENABLE); else if (ppb_support_ht_msimap == -1) (void) ppb_ht_msimap_set(config_handle, HT_MSIMAP_DISABLE); pci_config_teardown(&config_handle); /* * Initialize hotplug support on this bus. */ if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) ret = pcie_init(devi, NULL); else ret = pcihp_init(devi); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "pci: Failed to setup hotplug framework"); (void) ppb_detach(devi, DDI_DETACH); return (ret); } ddi_report_dev(devi); return (DDI_SUCCESS); case DDI_RESUME: /* * Get the soft state structure for the bridge. */ ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); ppb_restore_config_regs(ppb); return (DDI_SUCCESS); default: break; } return (DDI_FAILURE); }