コード例 #1
0
/*
 * Walk the irq_cache_table and re-configure the link device to
 * the saved state.
 */
void
acpi_restore_link_devices(void)
{
	irq_cache_t *irqcachep;
	acpi_psm_lnk_t psmlnk;
	int i, status;

	/* XXX: may not need to hold this mutex */
	mutex_enter(&acpi_irq_cache_mutex);
	for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid;
	    irqcachep++, i++) {
		if (irqcachep->lnkobj != NULL) {
			/* only field used from psmlnk in set_irq is lnkobj */
			psmlnk.lnkobj = irqcachep->lnkobj;
			status = acpi_set_irq_resource(&psmlnk, irqcachep->irq);
			/* warn if set_irq failed; soldier on */
			if (status != ACPI_PSM_SUCCESS)
				cmn_err(CE_WARN, "Could not restore interrupt "
				    "link device for IRQ 0x%x: Devices using "
				    "this IRQ may no longer function properly."
				    "\n", irqcachep->irq);
		}
	}
	mutex_exit(&acpi_irq_cache_mutex);
}
コード例 #2
0
ファイル: xpv_uppc.c プロジェクト: apprisi/illumos-gate
/*
 * Configures the irq for the interrupt link device identified by
 * acpipsmlnkp.
 *
 * Gets the current and the list of possible irq settings for the
 * device. If xen_uppc_unconditional_srs is not set, and the current
 * resource setting is in the list of possible irq settings,
 * current irq resource setting is passed to the caller.
 *
 * Otherwise, picks an irq number from the list of possible irq
 * settings, and sets the irq of the device to this value.
 * If prefer_crs is set, among a set of irq numbers in the list that have
 * the least number of devices sharing the interrupt, we pick current irq
 * resource setting if it is a member of this set.
 *
 * Passes the irq number in the value pointed to by pci_irqp, and
 * polarity and sensitivity in the structure pointed to by dipintrflagp
 * to the caller.
 *
 * Note that if setting the irq resource failed, but successfuly obtained
 * the current irq resource settings, passes the current irq resources
 * and considers it a success.
 *
 * Returns:
 * ACPI_PSM_SUCCESS on success.
 *
 * ACPI_PSM_FAILURE if an error occured during the configuration or
 * if a suitable irq was not found for this device, or if setting the
 * irq resource and obtaining the current resource fails.
 *
 */
static int
xen_uppc_acpi_irq_configure(acpi_psm_lnk_t *acpipsmlnkp, dev_info_t *dip,
    int *pci_irqp, iflag_t *dipintr_flagp)
{
	int i, min_share, foundnow, done = 0;
	int32_t irq;
	int32_t share_irq = -1;
	int32_t chosen_irq = -1;
	int cur_irq = -1;
	acpi_irqlist_t *irqlistp;
	acpi_irqlist_t *irqlistent;

	if ((acpi_get_possible_irq_resources(acpipsmlnkp, &irqlistp))
	    == ACPI_PSM_FAILURE) {
		XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: Unable to determine "
		    "or assign IRQ for device %s, instance #%d: The system was "
		    "unable to get the list of potential IRQs from ACPI.",
		    ddi_get_name(dip), ddi_get_instance(dip)));

		return (ACPI_PSM_FAILURE);
	}

	if ((acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq,
	    dipintr_flagp) == ACPI_PSM_SUCCESS) &&
	    (!xen_uppc_unconditional_srs) &&
	    (cur_irq > 0)) {

		if (acpi_irqlist_find_irq(irqlistp, cur_irq, NULL)
		    == ACPI_PSM_SUCCESS) {

			acpi_free_irqlist(irqlistp);
			ASSERT(pci_irqp != NULL);
			*pci_irqp = cur_irq;
			return (ACPI_PSM_SUCCESS);
		}
		XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: Could not find the "
		    "current irq %d for device %s, instance #%d in ACPI's "
		    "list of possible irqs for this device. Picking one from "
		    " the latter list.", cur_irq, ddi_get_name(dip),
		    ddi_get_instance(dip)));

	}

	irqlistent = irqlistp;
	min_share = 255;

	while (irqlistent != NULL) {

		for (foundnow = 0, i = 0; i < irqlistent->num_irqs; i++) {

			irq = irqlistp->irqs[i];

			if ((irq > MAX_ISA_IRQ) ||
			    (irqlistent->intr_flags.intr_el == INTR_EL_EDGE) ||
			    (irq == 0))
				continue;

			if (xen_uppc_reserved_irqlist[irq])
				continue;

			if (xen_uppc_irq_shared_table[irq] == 0) {
				chosen_irq = irq;
				foundnow = 1;
				if (!(xen_uppc_prefer_crs) ||
				    (irq == cur_irq)) {
					done = 1;
					break;
				}
			}

			if ((xen_uppc_irq_shared_table[irq] < min_share) ||
			    ((xen_uppc_irq_shared_table[irq] == min_share) &&
			    (cur_irq == irq) && (xen_uppc_prefer_crs))) {
				min_share = xen_uppc_irq_shared_table[irq];
				share_irq = irq;
				foundnow = 1;
			}
		}

		/* If we found an IRQ in the inner loop, save the details */
		if (foundnow && ((chosen_irq != -1) || (share_irq != -1))) {
			/*
			 * Copy the acpi_prs_private_t and flags from this
			 * irq list entry, since we found an irq from this
			 * entry.
			 */
			acpipsmlnkp->acpi_prs_prv = irqlistent->acpi_prs_prv;
			*dipintr_flagp = irqlistent->intr_flags;
		}

		if (done)
			break;

		/* Load the next entry in the irqlist */
		irqlistent = irqlistent->next;
	}

	acpi_free_irqlist(irqlistp);

	if (chosen_irq != -1)
		irq = chosen_irq;
	else if (share_irq != -1)
		irq = share_irq;
	else {
		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Could not find a "
		    "suitable irq from the list of possible irqs for device "
		    "%s, instance #%d in ACPI's list of possible\n",
		    ddi_get_name(dip), ddi_get_instance(dip)));

		return (ACPI_PSM_FAILURE);
	}


	XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Setting irq %d "
	    "for device %s instance #%d\n", irq, ddi_get_name(dip),
	    ddi_get_instance(dip)));

	if ((acpi_set_irq_resource(acpipsmlnkp, irq)) == ACPI_PSM_SUCCESS) {
		/*
		 * setting irq was successful, check to make sure CRS
		 * reflects that. If CRS does not agree with what we
		 * set, return the irq that was set.
		 */

		if (acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq,
		    dipintr_flagp) == ACPI_PSM_SUCCESS) {

			if (cur_irq != irq)
				XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: "
				    "IRQ resource set (irqno %d) for device %s "
				    "instance #%d, differs from current "
				    "setting irqno %d",
				    irq, ddi_get_name(dip),
				    ddi_get_instance(dip), cur_irq));
		}
		/*
		 * return the irq that was set, and not what CRS reports,
		 * since CRS has been seen to be bogus on some systems
		 */
		cur_irq = irq;
	} else {
		XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: set resource irq %d "
		    "failed for device %s instance #%d",
		    irq, ddi_get_name(dip), ddi_get_instance(dip)));
		if (cur_irq == -1)
			return (ACPI_PSM_FAILURE);
	}

	ASSERT(pci_irqp != NULL);
	*pci_irqp = cur_irq;
	return (ACPI_PSM_SUCCESS);
}