/*
 * Intialize hot plug control for ACPI mode.
 */
static int
pciehpc_acpi_hpc_init(pcie_hp_ctrl_t *ctrl_p)
{
	ACPI_HANDLE pcibus_obj;
	int status = AE_ERROR;
	ACPI_HANDLE slot_dev_obj;
	ACPI_HANDLE hdl;
	pciehpc_acpi_t *acpi_p;
	uint16_t bus_methods = 0;
	uint16_t slot_methods = 0;

	/* get the ACPI object for the bus node */
	status = acpica_get_handle(ctrl_p->hc_dip, &pcibus_obj);
	if (status != AE_OK)
		return (DDI_FAILURE);

	/* get the ACPI object handle for the child node */
	status = AcpiGetNextObject(ACPI_TYPE_DEVICE, pcibus_obj,
	    NULL, &slot_dev_obj);
	if (status != AE_OK)
		return (DDI_FAILURE);

	/*
	 * gather the info about the ACPI methods present on the bus node
	 * and the child nodes.
	 */
	if (AcpiGetHandle(pcibus_obj, "_OSC", &hdl) == AE_OK)
		bus_methods |= PCIEHPC_ACPI_OSC_PRESENT;
	if (AcpiGetHandle(pcibus_obj, "_OSHP", &hdl) == AE_OK)
		bus_methods |= PCIEHPC_ACPI_OSHP_PRESENT;
	if (AcpiGetHandle(pcibus_obj, "_HPX", &hdl) == AE_OK)
		bus_methods |= PCIEHPC_ACPI_HPX_PRESENT;
	if (AcpiGetHandle(pcibus_obj, "_HPP", &hdl) == AE_OK)
		bus_methods |= PCIEHPC_ACPI_HPP_PRESENT;
	if (AcpiGetHandle(pcibus_obj, "_DSM", &hdl) == AE_OK)
		bus_methods |= PCIEHPC_ACPI_DSM_PRESENT;
	if (AcpiGetHandle(slot_dev_obj, "_SUN", &hdl) == AE_OK)
		slot_methods |= PCIEHPC_ACPI_SUN_PRESENT;
	if (AcpiGetHandle(slot_dev_obj, "_PS0", &hdl) == AE_OK)
		slot_methods |= PCIEHPC_ACPI_PS0_PRESENT;
	if (AcpiGetHandle(slot_dev_obj, "_EJ0", &hdl) == AE_OK)
		slot_methods |= PCIEHPC_ACPI_EJ0_PRESENT;
	if (AcpiGetHandle(slot_dev_obj, "_STA", &hdl) == AE_OK)
		slot_methods |= PCIEHPC_ACPI_STA_PRESENT;

	/* save ACPI object handles, etc. */
	acpi_p = kmem_zalloc(sizeof (pciehpc_acpi_t), KM_SLEEP);
	acpi_p->bus_obj = pcibus_obj;
	acpi_p->slot_dev_obj = slot_dev_obj;
	acpi_p->bus_methods = bus_methods;
	acpi_p->slot_methods = slot_methods;
	ctrl_p->hc_misc_data = acpi_p;

	return (DDI_SUCCESS);
}
/*
 * Look first for an ACPI PCI bus node matching busid, then for a _PRT on the
 * parent node; then drop into the bridge-chasing code (which will also
 * look for _PRTs on the way up the tree of bridges)
 *
 * Stores polarity and sensitivity in the structure pointed to by
 * intr_flagp, and irqno in the value pointed to by pci_irqp.  *
 * Returns:
 *  	ACPI_PSM_SUCCESS on success.
 *	ACPI_PSM_PARTIAL to indicate need to configure the interrupt
 *	link device.
 * 	ACPI_PSM_FAILURE  if an error prevented the system from
 *	obtaining irq information for dip.
 */
int
acpi_translate_pci_irq(dev_info_t *dip, int ipin, int *pci_irqp,
    iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp)
{
	ACPI_HANDLE pciobj;
	int status = AE_ERROR;
	dev_info_t *curdip, *parentdip;
	int curpin, curbus, curdev;


	curpin = ipin;
	curdip = dip;
	while (curdip != ddi_root_node()) {
		parentdip = ddi_get_parent(curdip);
		ASSERT(parentdip != NULL);

		if (get_bdf(curdip, &curbus, &curdev, NULL) != 0)
			break;

		status = acpica_get_handle(parentdip, &pciobj);
		if ((status == AE_OK) && psm_node_has_prt(pciobj)) {
			return (acpi_get_gsiv(curdip, pciobj, curdev, curpin,
			    pci_irqp, intr_flagp, acpipsmlnkp));
		}

		/* if we got here, we need to traverse a bridge upwards */
		if (!psm_is_pci_bridge(parentdip))
			break;

		/*
		 * This is the rotating scheme that Compaq is using
		 * and documented in the PCI-PCI spec.  Also, if the
		 * PCI-PCI bridge is behind another PCI-PCI bridge,
		 * then it needs to keep ascending until an interrupt
		 * entry is found or the top is reached
		 */
		curpin = (curdev + curpin) % PCI_INTD;
		curdip = parentdip;
	}

	/*
	 * We should never, ever get here; didn't find a _PRT
	 */
	return (ACPI_PSM_FAILURE);
}
Example #3
0
static int
acpinex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
	int instance;
	acpinex_softstate_t *softsp;

	switch (cmd) {
	case DDI_ATTACH:
		break;

	case DDI_RESUME:
		return (DDI_SUCCESS);

	default:
		return (DDI_FAILURE);
	}

	/* Get and check instance number. */
	instance = ddi_get_instance(devi);
	if (instance >= ACPINEX_INSTANCE_MAX) {
		cmn_err(CE_WARN, "acpinex: instance number %d is out of range "
		    "in acpinex_attach(), max %d.",
		    instance, ACPINEX_INSTANCE_MAX - 1);
		return (DDI_FAILURE);
	}

	/* Get soft state structure. */
	if (ddi_soft_state_zalloc(acpinex_softstates, instance)
	    != DDI_SUCCESS) {
		cmn_err(CE_WARN, "!acpinex: failed to allocate soft state "
		    "object in acpinex_attach().");
		return (DDI_FAILURE);
	}
	softsp = ddi_get_soft_state(acpinex_softstates, instance);

	/* Initialize soft state structure */
	softsp->ans_dip = devi;
	(void) ddi_pathname(devi, softsp->ans_path);
	if (ACPI_FAILURE(acpica_get_handle(devi, &softsp->ans_hdl))) {
		ACPINEX_DEBUG(CE_WARN,
		    "!acpinex: failed to get ACPI handle for %s.",
		    softsp->ans_path);
		ddi_soft_state_free(acpinex_softstates, instance);
		return (DDI_FAILURE);
	}
	mutex_init(&softsp->ans_lock, NULL, MUTEX_DRIVER, NULL);

	/* Install event handler for child/descendant objects. */
	if (acpinex_event_scan(softsp, B_TRUE) != DDI_SUCCESS) {
		cmn_err(CE_WARN, "!acpinex: failed to install event handler "
		    "for children of %s.", softsp->ans_path);
	}

	/* nothing to suspend/resume here */
	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
	    "pm-hardware-state", "no-suspend-resume");
	(void) ddi_prop_update_int(DDI_DEV_T_NONE, devi,
	    DDI_NO_AUTODETACH, 1);

	acpinex_fm_init(softsp);
	ddi_report_dev(devi);

	return (DDI_SUCCESS);
}