Esempio n. 1
0
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);
}
Esempio n. 4
0
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);
}
Esempio n. 6
0
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);
	}
}
Esempio n. 7
0
/*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);
	}
}
Esempio n. 8
0
/*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 *)&regops) == 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)&regops) != 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);
}
Esempio n. 9
0
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);
}