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