/* * 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); }
/* * 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); }