boolean_t create_pcie_root_bus(uchar_t bus, dev_info_t *dip) { pcie_bus_t *bus_p; /* * Currently this is being hard-coded. * We need to figure out if the root bus does indeed * have PCI-Ex in the path by looking for MCFG in * the ACPI tables */ if (look_for_any_pciex_device(bus) == B_FALSE) return (B_FALSE); #ifdef DEBUG if (pci_boot_debug) cmn_err(CE_CONT, "Found PCI-Ex in the system\n"); #endif /* DEBUG */ (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "device_type", "pciex"); (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "compatible", "pciex_root_complex"); pcie_rc_init_bus(dip); /* save base addr in bus_t for pci_cfgacc_xxx() */ bus_p = PCIE_DIP2BUS(dip); bus_p->bus_cfgacc_base = mcfg_mem_base; return (B_TRUE); }
/* * Update ops vector with platform specific (ACPI, CK8-04,...) functions. */ void pciehpc_update_ops(pcie_hp_ctrl_t *ctrl_p) { boolean_t hp_native_mode = B_FALSE; uint32_t osc_flags = OSC_CONTROL_PCIE_NAT_HP; /* * Call _OSC method to determine if hotplug mode is native or ACPI. * If _OSC method succeeds hp_native_mode below will be set according to * if native hotplug control was granted or not by BIOS. * * If _OSC method fails for any reason or if native hotplug control was * not granted assume it's ACPI mode and update platform specific * (ACPI, CK8-04,...) impl. ops */ if (pcie_acpi_osc(ctrl_p->hc_dip, &osc_flags) == DDI_SUCCESS) { hp_native_mode = (osc_flags & OSC_CONTROL_PCIE_NAT_HP) ? B_TRUE : B_FALSE; } if (!hp_native_mode) { pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); /* update ops vector for ACPI mode */ pciehpc_acpi_setup_ops(ctrl_p); bus_p->bus_hp_sup_modes |= PCIE_ACPI_HP_MODE; bus_p->bus_hp_curr_mode = PCIE_ACPI_HP_MODE; } }
/* * This function is similar to pciehpc_slotinfo_init() with some * changes: * - no need for kernel thread to handle ATTN button events * - function ops for connect/disconnect are different * * ASSUMPTION: No conflict in doing reads to HP registers directly. * Otherwise, there are no ACPI interfaces to do LED control or to get * the hot plug capabilities (ATTN button, MRL, etc.). */ static int pciehpc_acpi_slotinfo_init(pcie_hp_ctrl_t *ctrl_p) { uint32_t slot_capabilities; pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); mutex_enter(&ctrl_p->hc_mutex); /* * setup DDI HP framework slot information structure */ slot_p->hs_device_num = 0; slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE; slot_p->hs_info.cn_type_str = PCIE_ACPI_HP_TYPE; slot_p->hs_info.cn_child = NULL; slot_p->hs_minor = PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip), slot_p->hs_device_num); /* read Slot Capabilities Register */ slot_capabilities = pciehpc_reg_get32(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCAP); /* setup slot number/name */ pciehpc_set_slot_name(ctrl_p); /* check if Attn Button present */ ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ? B_TRUE : B_FALSE; /* check if Manual Retention Latch sensor present */ ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ? B_TRUE : B_FALSE; /* * PCI-E (draft) version 1.1 defines EMI Lock Present bit * in Slot Capabilities register. Check for it. */ ctrl_p->hc_has_emi_lock = (slot_capabilities & PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE; /* get current slot state from the hw */ pciehpc_get_slot_state(slot_p); if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED) slot_p->hs_condition = AP_COND_OK; mutex_exit(&ctrl_p->hc_mutex); /* setup Notify() handler for hot plug events from ACPI BIOS */ if (pciehpc_acpi_install_event_handler(ctrl_p) != AE_OK) return (DDI_FAILURE); PCIE_DBG("ACPI hot plug is enabled for slot #%d\n", slot_p->hs_phy_slot_num); return (DDI_SUCCESS); }
int pcieb_plat_peekpoke(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, ddi_get_instance(dip)); if (!PCIE_IS_RP(PCIE_DIP2BUS(dip))) return (ddi_ctlops(dip, rdip, ctlop, arg, result)); return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, ddi_ctlops, &pcieb->pcieb_err_mutex, &pcieb->pcieb_peek_poke_mutex, pcieb_peekpoke_cb)); }
/*ARGSUSED*/ static int pciehpc_acpi_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result) { pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); uint16_t status; ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); /* get the current state of the slot */ pciehpc_get_slot_state(slot_p); /* check if the slot is already in the state less than 'powered' */ if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { /* slot is in the 'disconnected' state */ PCIE_DBG("slot %d already disconnected\n", slot_p->hs_phy_slot_num); ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF); *result = slot_p->hs_info.cn_state; return (DDI_SUCCESS); } /* read the Slot Status Register */ status = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS); /* make sure the slot has a device present */ if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { /* slot is empty */ PCIE_DBG("slot %d is empty", slot_p->hs_phy_slot_num); goto cleanup; } /* turn off power to the slot using ACPI method (EJ0) */ if (pciehpc_acpi_power_off_slot(ctrl_p) != AE_OK) goto cleanup; /* get the current state of the slot */ pciehpc_get_slot_state(slot_p); *result = slot_p->hs_info.cn_state; return (DDI_SUCCESS); cleanup: return (DDI_FAILURE); }
static void px_set_mps(px_t *px_p) { dev_info_t *dip; pcie_bus_t *bus_p; int max_supported; dip = px_p->px_dip; bus_p = PCIE_DIP2BUS(dip); bus_p->bus_mps = -1; if (pcie_root_port(dip) == DDI_FAILURE) { if (px_lib_get_root_complex_mps(px_p, dip, &max_supported) < 0) { DBG(DBG_MPS, dip, "MPS: Can not get RC MPS\n"); return; } DBG(DBG_MPS, dip, "MPS: Root Complex MPS Cap of = %x\n", max_supported); if (pcie_max_mps < max_supported) max_supported = pcie_max_mps; (void) pcie_get_fabric_mps(dip, ddi_get_child(dip), &max_supported); bus_p->bus_mps = max_supported; (void) px_lib_set_root_complex_mps(px_p, dip, bus_p->bus_mps); DBG(DBG_MPS, dip, "MPS: Root Complex MPS Set to = %x\n", bus_p->bus_mps); } }
/*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); }
void pcieb_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) { pf_eh_enter(PCIE_DIP2BUS(dip)); (void) pf_scan_fabric(dip, derr, NULL); pf_eh_exit(PCIE_DIP2BUS(dip)); }
/*ARGSUSED*/ static int pciehpc_acpi_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result) { pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); uint16_t status, control; ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); /* get the current state of the slot */ pciehpc_get_slot_state(slot_p); /* check if the slot is already in the 'ENABLED' state */ if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_ENABLED) { /* slot is already in the 'connected' state */ PCIE_DBG("slot %d already connected\n", slot_p->hs_phy_slot_num); *result = slot_p->hs_info.cn_state; return (DDI_SUCCESS); } /* read the Slot Status Register */ status = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS); /* make sure the MRL switch is closed if present */ if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) { /* MRL switch is open */ cmn_err(CE_WARN, "MRL switch is open on slot %d", slot_p->hs_phy_slot_num); goto cleanup; } /* make sure the slot has a device present */ if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { /* slot is empty */ PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num); goto cleanup; } /* get the current state of Slot Control Register */ control = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL); /* check if the slot's power state is ON */ if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) { /* slot is already powered up */ PCIE_DBG("slot %d already connected\n", slot_p->hs_phy_slot_num); *result = slot_p->hs_info.cn_state; return (DDI_SUCCESS); } /* turn on power to the slot using ACPI method (PS0) */ if (pciehpc_acpi_power_on_slot(ctrl_p) != AE_OK) goto cleanup; *result = slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED; return (DDI_SUCCESS); cleanup: return (DDI_FAILURE); }