Exemple #1
0
int
pci_intr_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
    int *counts, pci_intr_type_t max_type)
{

	if (counts != NULL && counts[PCI_INTR_TYPE_INTX] == 0)
		return EINVAL;

	return pci_intx_alloc(pa, ihps);
}
/*
 * Interrupt handler allocation utility. This function calls each allocation
 * function as specified by arguments.
 * Currently callee functions are pci_intx_alloc(), pci_msi_alloc_exact(),
 * and pci_msix_alloc_exact().
 * pa       : pci_attach_args
 * ihps     : interrupt handlers
 * counts   : The array of number of required interrupt handlers.
 *            It is overwritten by allocated the number of handlers.
 *            CAUTION: The size of counts[] must be PCI_INTR_TYPE_SIZE.
 * max_type : "max" type of using interrupts. See below.
 *     e.g.
 *         If you want to use 5 MSI-X, 1 MSI, or INTx, you use "counts" as
 *             int counts[PCI_INTR_TYPE_SIZE];
 *             counts[PCI_INTR_TYPE_MSIX] = 5;
 *             counts[PCI_INTR_TYPE_MSI] = 1;
 *             counts[PCI_INTR_TYPE_INTX] = 1;
 *             error = pci_intr_alloc(pa, ihps, counts, PCI_INTR_TYPE_MSIX);
 *
 *         If you want to use hardware max number MSI-X or 1 MSI,
 *         and not to use INTx, you use "counts" as
 *             int counts[PCI_INTR_TYPE_SIZE];
 *             counts[PCI_INTR_TYPE_MSIX] = -1;
 *             counts[PCI_INTR_TYPE_MSI] = 1;
 *             counts[PCI_INTR_TYPE_INTX] = 0;
 *             error = pci_intr_alloc(pa, ihps, counts, PCI_INTR_TYPE_MSIX);
 *
 *         If you want to use 3 MSI or INTx, you can use "counts" as
 *             int counts[PCI_INTR_TYPE_SIZE];
 *             counts[PCI_INTR_TYPE_MSI] = 3;
 *             counts[PCI_INTR_TYPE_INTX] = 1;
 *             error = pci_intr_alloc(pa, ihps, counts, PCI_INTR_TYPE_MSI);
 *
 *         If you want to use 1 MSI or INTx (probably most general usage),
 *         you can simply use this API like
 *         below
 *             error = pci_intr_alloc(pa, ihps, NULL, 0);
 *                                                    ^ ignored
 */
int
pci_intr_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
    int *counts, pci_intr_type_t max_type)
{
	int error;
	int intx_count, msi_count, msix_count;

	intx_count = msi_count = msix_count = 0;
	if (counts == NULL) { /* simple pattern */
		msi_count = 1;
		intx_count = 1;
	} else {
		switch(max_type) {
		case PCI_INTR_TYPE_MSIX:
			msix_count = counts[PCI_INTR_TYPE_MSIX];
			/* FALLTHROUGH */
		case PCI_INTR_TYPE_MSI:
			msi_count = counts[PCI_INTR_TYPE_MSI];
			/* FALLTHROUGH */
		case PCI_INTR_TYPE_INTX:
			intx_count = counts[PCI_INTR_TYPE_INTX];
			break;
		default:
			return EINVAL;
		}
	}

	if (counts != NULL)
		memset(counts, 0, sizeof(counts[0]) * PCI_INTR_TYPE_SIZE);
	error = EINVAL;

	/* try MSI-X */
	if (msix_count == -1) /* use hardware max */
		msix_count = pci_msix_count(pa->pa_pc, pa->pa_tag);
	if (msix_count > 0) {
		error = pci_msix_alloc_exact(pa, ihps, msix_count);
		if (error == 0) {
			KASSERTMSG(counts != NULL,
			    "If MSI-X is used, counts must not be NULL.");
			counts[PCI_INTR_TYPE_MSIX] = msix_count;
			goto out;
		}
	}

	/* try MSI */
	if (msi_count == -1) /* use hardware max */
		msi_count = pci_msi_count(pa->pa_pc, pa->pa_tag);
	if (msi_count > 0) {
		error = pci_msi_alloc_exact(pa, ihps, msi_count);
		if (error == 0) {
			if (counts != NULL)
				counts[PCI_INTR_TYPE_MSI] = msi_count;
			goto out;
		}
	}

	/* try INTx */
	if (intx_count != 0) { /* The number of INTx is always 1. */
		error = pci_intx_alloc(pa, ihps);
		if (error == 0) {
			if (counts != NULL)
				counts[PCI_INTR_TYPE_INTX] = 1;
		}
	}

 out:
	return error;
}