Exemplo n.º 1
0
/*
 * Set up MSI-X
 */
static int xhci_setup_msix(struct xhci_hcd *xhci)
{
	int i, ret = 0;
	struct usb_hcd *hcd = xhci_to_hcd(xhci);
	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);

	/*
	 * calculate number of msi-x vectors supported.
	 * - HCS_MAX_INTRS: the max number of interrupts the host can handle,
	 *   with max number of interrupters based on the xhci HCSPARAMS1.
	 * - num_online_cpus: maximum msi-x vectors per CPUs core.
	 *   Add additional 1 vector to ensure always available interrupt.
	 */
	xhci->msix_count = min(num_online_cpus() + 1,
				HCS_MAX_INTRS(xhci->hcs_params1));

	xhci->msix_entries =
		kmalloc((sizeof(struct msix_entry))*xhci->msix_count,
				GFP_KERNEL);
	if (!xhci->msix_entries) {
		xhci_err(xhci, "Failed to allocate MSI-X entries\n");
		return -ENOMEM;
	}

	for (i = 0; i < xhci->msix_count; i++) {
		xhci->msix_entries[i].entry = i;
		xhci->msix_entries[i].vector = 0;
	}

	ret = pci_enable_msix_exact(pdev, xhci->msix_entries, xhci->msix_count);
	if (ret) {
		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
				"Failed to enable MSI-X");
		goto free_entries;
	}

	for (i = 0; i < xhci->msix_count; i++) {
		ret = request_irq(xhci->msix_entries[i].vector,
				xhci_msi_irq,
				0, "xhci_hcd", xhci_to_hcd(xhci));
		if (ret)
			goto disable_msix;
	}

	hcd->msix_enabled = 1;
	return ret;

disable_msix:
	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt");
	xhci_free_irq(xhci);
	pci_disable_msix(pdev);
free_entries:
	kfree(xhci->msix_entries);
	xhci->msix_entries = NULL;
	return ret;
}
Exemplo n.º 2
0
Arquivo: init.c Projeto: 020gzh/linux
static int isci_setup_interrupts(struct pci_dev *pdev)
{
	int err, i, num_msix;
	struct isci_host *ihost;
	struct isci_pci_info *pci_info = to_pci_info(pdev);

	/*
	 *  Determine the number of vectors associated with this
	 *  PCI function.
	 */
	num_msix = num_controllers(pdev) * SCI_NUM_MSI_X_INT;

	for (i = 0; i < num_msix; i++)
		pci_info->msix_entries[i].entry = i;

	err = pci_enable_msix_exact(pdev, pci_info->msix_entries, num_msix);
	if (err)
		goto intx;

	for (i = 0; i < num_msix; i++) {
		int id = i / SCI_NUM_MSI_X_INT;
		struct msix_entry *msix = &pci_info->msix_entries[i];
		irq_handler_t isr;

		ihost = pci_info->hosts[id];
		/* odd numbered vectors are error interrupts */
		if (i & 1)
			isr = isci_error_isr;
		else
			isr = isci_msix_isr;

		err = devm_request_irq(&pdev->dev, msix->vector, isr, 0,
				       DRV_NAME"-msix", ihost);
		if (!err)
			continue;

		dev_info(&pdev->dev, "msix setup failed falling back to intx\n");
		while (i--) {
			id = i / SCI_NUM_MSI_X_INT;
			ihost = pci_info->hosts[id];
			msix = &pci_info->msix_entries[i];
			devm_free_irq(&pdev->dev, msix->vector, ihost);
		}
		pci_disable_msix(pdev);
		goto intx;
	}
	return 0;

 intx:
	for_each_isci_host(i, ihost, pdev) {
		err = devm_request_irq(&pdev->dev, pdev->irq, isci_intx_isr,
				       IRQF_SHARED, DRV_NAME"-intx", ihost);
		if (err)
			break;
	}
Exemplo n.º 3
0
static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter,
			     unsigned int *irq)
{
	struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION };
	int ret;

	ret = pci_enable_msix_exact(adapter->dev, &entry, 1);
	if (ret)
		return ret;

	*irq = entry.vector;

	return 0;
}
Exemplo n.º 4
0
static
int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev,
			  struct pci_dev *dev, struct xen_pci_op *op)
{
	struct xen_pcibk_dev_data *dev_data;
	int i, result;
	struct msix_entry *entries;

	if (unlikely(verbose_request))
		printk(KERN_DEBUG DRV_NAME ": %s: enable MSI-X\n",
		       pci_name(dev));
	if (op->value > SH_INFO_MAX_VEC)
		return -EINVAL;

	entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL);
	if (entries == NULL)
		return -ENOMEM;

	for (i = 0; i < op->value; i++) {
		entries[i].entry = op->msix_entries[i].entry;
		entries[i].vector = op->msix_entries[i].vector;
	}

	result = pci_enable_msix_exact(dev, entries, op->value);
	if (result == 0) {
		for (i = 0; i < op->value; i++) {
			op->msix_entries[i].entry = entries[i].entry;
			if (entries[i].vector)
				op->msix_entries[i].vector =
					xen_pirq_from_irq(entries[i].vector);
				if (unlikely(verbose_request))
					printk(KERN_DEBUG DRV_NAME ": %s: " \
						"MSI-X[%d]: %d\n",
						pci_name(dev), i,
						op->msix_entries[i].vector);
		}
	} else
		pr_warn_ratelimited("%s: error enabling MSI-X for guest %u: err %d!\n",
				    pci_name(dev), pdev->xdev->otherend_id,
				    result);
	kfree(entries);

	op->value = result;
	dev_data = pci_get_drvdata(dev);
	if (dev_data)
		dev_data->ack_intr = 0;

	return result > 0 ? 0 : result;
}
Exemplo n.º 5
0
static int adf_enable_msix(struct adf_accel_dev *accel_dev)
{
    struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
    struct adf_hw_device_data *hw_data = accel_dev->hw_device;
    uint32_t msix_num_entries = hw_data->num_banks + 1;
    int i;

    for (i = 0; i < msix_num_entries; i++)
        pci_dev_info->msix_entries.entries[i].entry = i;

    if (pci_enable_msix_exact(pci_dev_info->pci_dev,
                              pci_dev_info->msix_entries.entries,
                              msix_num_entries)) {
        pr_err("QAT: Failed to enable MSIX IRQ\n");
        return -EFAULT;
    }
    return 0;
}
Exemplo n.º 6
0
/**
 * pcie_port_enable_msix - try to set up MSI-X as interrupt mode for given port
 * @dev: PCI Express port to handle
 * @vectors: Array of interrupt vectors to populate
 * @mask: Bitmask of port capabilities returned by get_port_device_capability()
 *
 * Return value: 0 on success, error code on failure
 */
static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
{
	struct msix_entry *msix_entries;
	int idx[PCIE_PORT_DEVICE_MAXSERVICES];
	int nr_entries, status, pos, i, nvec;
	u16 reg16;
	u32 reg32;

	nr_entries = pci_msix_vec_count(dev);
	if (nr_entries < 0)
		return nr_entries;
	BUG_ON(!nr_entries);
	if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES)
		nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES;

	msix_entries = kzalloc(sizeof(*msix_entries) * nr_entries, GFP_KERNEL);
	if (!msix_entries)
		return -ENOMEM;

	/*
	 * Allocate as many entries as the port wants, so that we can check
	 * which of them will be useful.  Moreover, if nr_entries is correctly
	 * equal to the number of entries this port actually uses, we'll happily
	 * go through without any tricks.
	 */
	for (i = 0; i < nr_entries; i++)
		msix_entries[i].entry = i;

	status = pci_enable_msix_exact(dev, msix_entries, nr_entries);
	if (status)
		goto Exit;

	for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
		idx[i] = -1;
	status = -EIO;
	nvec = 0;

	if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
		int entry;

		/*
		 * The code below follows the PCI Express Base Specification 2.0
		 * stating in Section 6.1.6 that "PME and Hot-Plug Event
		 * interrupts (when both are implemented) always share the same
		 * MSI or MSI-X vector, as indicated by the Interrupt Message
		 * Number field in the PCI Express Capabilities register", where
		 * according to Section 7.8.2 of the specification "For MSI-X,
		 * the value in this field indicates which MSI-X Table entry is
		 * used to generate the interrupt message."
		 */
		pcie_capability_read_word(dev, PCI_EXP_FLAGS, &reg16);
		entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
		if (entry >= nr_entries)
			goto Error;

		i = pcie_port_msix_add_entry(msix_entries, entry, nvec);
		if (i == nvec)
			nvec++;

		idx[PCIE_PORT_SERVICE_PME_SHIFT] = i;
		idx[PCIE_PORT_SERVICE_HP_SHIFT] = i;
	}
Exemplo n.º 7
0
int fnic_set_intr_mode(struct fnic *fnic)
{
	unsigned int n = ARRAY_SIZE(fnic->rq);
	unsigned int m = ARRAY_SIZE(fnic->wq);
	unsigned int o = ARRAY_SIZE(fnic->wq_copy);
	unsigned int i;

	/*
	 * Set interrupt mode (INTx, MSI, MSI-X) depending
	 * system capabilities.
	 *
	 * Try MSI-X first
	 *
	 * We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs
	 * (last INTR is used for WQ/RQ errors and notification area)
	 */

	BUG_ON(ARRAY_SIZE(fnic->msix_entry) < n + m + o + 1);
	for (i = 0; i < n + m + o + 1; i++)
		fnic->msix_entry[i].entry = i;

	if (fnic->rq_count >= n &&
	    fnic->raw_wq_count >= m &&
	    fnic->wq_copy_count >= o &&
	    fnic->cq_count >= n + m + o) {
		if (!pci_enable_msix_exact(fnic->pdev, fnic->msix_entry,
					   n + m + o + 1)) {
			fnic->rq_count = n;
			fnic->raw_wq_count = m;
			fnic->wq_copy_count = o;
			fnic->wq_count = m + o;
			fnic->cq_count = n + m + o;
			fnic->intr_count = n + m + o + 1;
			fnic->err_intr_offset = FNIC_MSIX_ERR_NOTIFY;

			FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
				     "Using MSI-X Interrupts\n");
			vnic_dev_set_intr_mode(fnic->vdev,
					       VNIC_DEV_INTR_MODE_MSIX);
			return 0;
		}
	}

	/*
	 * Next try MSI
	 * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 1 INTR
	 */
	if (fnic->rq_count >= 1 &&
	    fnic->raw_wq_count >= 1 &&
	    fnic->wq_copy_count >= 1 &&
	    fnic->cq_count >= 3 &&
	    fnic->intr_count >= 1 &&
	    !pci_enable_msi(fnic->pdev)) {

		fnic->rq_count = 1;
		fnic->raw_wq_count = 1;
		fnic->wq_copy_count = 1;
		fnic->wq_count = 2;
		fnic->cq_count = 3;
		fnic->intr_count = 1;
		fnic->err_intr_offset = 0;

		FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
			     "Using MSI Interrupts\n");
		vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSI);

		return 0;
	}

	/*
	 * Next try INTx
	 * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 3 INTRs
	 * 1 INTR is used for all 3 queues, 1 INTR for queue errors
	 * 1 INTR for notification area
	 */

	if (fnic->rq_count >= 1 &&
	    fnic->raw_wq_count >= 1 &&
	    fnic->wq_copy_count >= 1 &&
	    fnic->cq_count >= 3 &&
	    fnic->intr_count >= 3) {

		fnic->rq_count = 1;
		fnic->raw_wq_count = 1;
		fnic->wq_copy_count = 1;
		fnic->cq_count = 3;
		fnic->intr_count = 3;

		FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
			     "Using Legacy Interrupts\n");
		vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX);

		return 0;
	}

	vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);

	return -EINVAL;
}
Exemplo n.º 8
0
static int nitrox_enable_msix(struct nitrox_device *ndev)
{
	struct msix_entry *entries;
	char **names;
	int i, nr_entries, ret;

	/*
	 * PF MSI-X vectors
	 *
	 * Entry 0: NPS PKT ring 0
	 * Entry 1: AQMQ ring 0
	 * Entry 2: ZQM ring 0
	 * Entry 3: NPS PKT ring 1
	 * Entry 4: AQMQ ring 1
	 * Entry 5: ZQM ring 1
	 * ....
	 * Entry 192: NPS_CORE_INT_ACTIVE
	 */
	nr_entries = (ndev->nr_queues * NR_RING_VECTORS) + 1;
	entries = kzalloc_node(nr_entries * sizeof(struct msix_entry),
			       GFP_KERNEL, ndev->node);
	if (!entries)
		return -ENOMEM;

	names = kcalloc(nr_entries, sizeof(char *), GFP_KERNEL);
	if (!names) {
		kfree(entries);
		return -ENOMEM;
	}

	/* fill entires */
	for (i = 0; i < (nr_entries - 1); i++)
		entries[i].entry = i;

	entries[i].entry = NPS_CORE_INT_ACTIVE_ENTRY;

	for (i = 0; i < nr_entries; i++) {
		*(names + i) = kzalloc(MAX_MSIX_VECTOR_NAME, GFP_KERNEL);
		if (!(*(names + i))) {
			ret = -ENOMEM;
			goto msix_fail;
		}
	}
	ndev->msix.entries = entries;
	ndev->msix.names = names;
	ndev->msix.nr_entries = nr_entries;

	ret = pci_enable_msix_exact(ndev->pdev, ndev->msix.entries,
				    ndev->msix.nr_entries);
	if (ret) {
		dev_err(&ndev->pdev->dev, "Failed to enable MSI-X IRQ(s) %d\n",
			ret);
		goto msix_fail;
	}
	return 0;

msix_fail:
	for (i = 0; i < nr_entries; i++)
		kfree(*(names + i));

	kfree(entries);
	kfree(names);
	return ret;
}