|
@@ -864,6 +864,7 @@ static void liquidio_schedule_droq_pkt_handlers(struct octeon_device *oct)
|
|
|
* @param irq unused
|
|
|
* @param dev octeon device
|
|
|
*/
|
|
|
+static
|
|
|
irqreturn_t liquidio_legacy_intr_handler(int irq __attribute__((unused)),
|
|
|
void *dev)
|
|
|
{
|
|
@@ -884,3 +885,202 @@ irqreturn_t liquidio_legacy_intr_handler(int irq __attribute__((unused)),
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
+/**
|
|
|
+ * \brief Setup interrupt for octeon device
|
|
|
+ * @param oct octeon device
|
|
|
+ *
|
|
|
+ * Enable interrupt in Octeon device as given in the PCI interrupt mask.
|
|
|
+ */
|
|
|
+int octeon_setup_interrupt(struct octeon_device *oct)
|
|
|
+{
|
|
|
+ struct msix_entry *msix_entries;
|
|
|
+ char *queue_irq_names = NULL;
|
|
|
+ int i, num_interrupts = 0;
|
|
|
+ int num_alloc_ioq_vectors;
|
|
|
+ char *aux_irq_name = NULL;
|
|
|
+ int num_ioq_vectors;
|
|
|
+ int irqret, err;
|
|
|
+
|
|
|
+ if (oct->msix_on) {
|
|
|
+ if (OCTEON_CN23XX_PF(oct)) {
|
|
|
+ oct->num_msix_irqs = oct->sriov_info.num_pf_rings;
|
|
|
+ num_interrupts = MAX_IOQ_INTERRUPTS_PER_PF + 1;
|
|
|
+
|
|
|
+ /* one non ioq interrupt for handling
|
|
|
+ * sli_mac_pf_int_sum
|
|
|
+ */
|
|
|
+ oct->num_msix_irqs += 1;
|
|
|
+ } else if (OCTEON_CN23XX_VF(oct)) {
|
|
|
+ oct->num_msix_irqs = oct->sriov_info.rings_per_vf;
|
|
|
+ num_interrupts = MAX_IOQ_INTERRUPTS_PER_VF;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* allocate storage for the names assigned to each irq */
|
|
|
+ oct->irq_name_storage =
|
|
|
+ kcalloc(num_interrupts, INTRNAMSIZ, GFP_KERNEL);
|
|
|
+ if (!oct->irq_name_storage) {
|
|
|
+ dev_err(&oct->pci_dev->dev, "Irq name storage alloc failed...\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ queue_irq_names = oct->irq_name_storage;
|
|
|
+
|
|
|
+ if (OCTEON_CN23XX_PF(oct))
|
|
|
+ aux_irq_name = &queue_irq_names
|
|
|
+ [IRQ_NAME_OFF(MAX_IOQ_INTERRUPTS_PER_PF)];
|
|
|
+
|
|
|
+ oct->msix_entries = kcalloc(oct->num_msix_irqs,
|
|
|
+ sizeof(struct msix_entry),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!oct->msix_entries) {
|
|
|
+ dev_err(&oct->pci_dev->dev, "Memory Alloc failed...\n");
|
|
|
+ kfree(oct->irq_name_storage);
|
|
|
+ oct->irq_name_storage = NULL;
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ msix_entries = (struct msix_entry *)oct->msix_entries;
|
|
|
+
|
|
|
+ /*Assumption is that pf msix vectors start from pf srn to pf to
|
|
|
+ * trs and not from 0. if not change this code
|
|
|
+ */
|
|
|
+ if (OCTEON_CN23XX_PF(oct)) {
|
|
|
+ for (i = 0; i < oct->num_msix_irqs - 1; i++)
|
|
|
+ msix_entries[i].entry =
|
|
|
+ oct->sriov_info.pf_srn + i;
|
|
|
+
|
|
|
+ msix_entries[oct->num_msix_irqs - 1].entry =
|
|
|
+ oct->sriov_info.trs;
|
|
|
+ } else if (OCTEON_CN23XX_VF(oct)) {
|
|
|
+ for (i = 0; i < oct->num_msix_irqs; i++)
|
|
|
+ msix_entries[i].entry = i;
|
|
|
+ }
|
|
|
+ num_alloc_ioq_vectors = pci_enable_msix_range(
|
|
|
+ oct->pci_dev, msix_entries,
|
|
|
+ oct->num_msix_irqs,
|
|
|
+ oct->num_msix_irqs);
|
|
|
+ if (num_alloc_ioq_vectors < 0) {
|
|
|
+ dev_err(&oct->pci_dev->dev, "unable to Allocate MSI-X interrupts\n");
|
|
|
+ kfree(oct->msix_entries);
|
|
|
+ oct->msix_entries = NULL;
|
|
|
+ kfree(oct->irq_name_storage);
|
|
|
+ oct->irq_name_storage = NULL;
|
|
|
+ return num_alloc_ioq_vectors;
|
|
|
+ }
|
|
|
+
|
|
|
+ dev_dbg(&oct->pci_dev->dev, "OCTEON: Enough MSI-X interrupts are allocated...\n");
|
|
|
+
|
|
|
+ num_ioq_vectors = oct->num_msix_irqs;
|
|
|
+ /** For PF, there is one non-ioq interrupt handler */
|
|
|
+ if (OCTEON_CN23XX_PF(oct)) {
|
|
|
+ num_ioq_vectors -= 1;
|
|
|
+
|
|
|
+ snprintf(aux_irq_name, INTRNAMSIZ,
|
|
|
+ "LiquidIO%u-pf%u-aux", oct->octeon_id,
|
|
|
+ oct->pf_num);
|
|
|
+ irqret = request_irq(
|
|
|
+ msix_entries[num_ioq_vectors].vector,
|
|
|
+ liquidio_legacy_intr_handler, 0,
|
|
|
+ aux_irq_name, oct);
|
|
|
+ if (irqret) {
|
|
|
+ dev_err(&oct->pci_dev->dev,
|
|
|
+ "Request_irq failed for MSIX interrupt Error: %d\n",
|
|
|
+ irqret);
|
|
|
+ pci_disable_msix(oct->pci_dev);
|
|
|
+ kfree(oct->msix_entries);
|
|
|
+ kfree(oct->irq_name_storage);
|
|
|
+ oct->irq_name_storage = NULL;
|
|
|
+ oct->msix_entries = NULL;
|
|
|
+ return irqret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (i = 0 ; i < num_ioq_vectors ; i++) {
|
|
|
+ if (OCTEON_CN23XX_PF(oct))
|
|
|
+ snprintf(&queue_irq_names[IRQ_NAME_OFF(i)],
|
|
|
+ INTRNAMSIZ, "LiquidIO%u-pf%u-rxtx-%u",
|
|
|
+ oct->octeon_id, oct->pf_num, i);
|
|
|
+
|
|
|
+ if (OCTEON_CN23XX_VF(oct))
|
|
|
+ snprintf(&queue_irq_names[IRQ_NAME_OFF(i)],
|
|
|
+ INTRNAMSIZ, "LiquidIO%u-vf%u-rxtx-%u",
|
|
|
+ oct->octeon_id, oct->vf_num, i);
|
|
|
+
|
|
|
+ irqret = request_irq(msix_entries[i].vector,
|
|
|
+ liquidio_msix_intr_handler, 0,
|
|
|
+ &queue_irq_names[IRQ_NAME_OFF(i)],
|
|
|
+ &oct->ioq_vector[i]);
|
|
|
+
|
|
|
+ if (irqret) {
|
|
|
+ dev_err(&oct->pci_dev->dev,
|
|
|
+ "Request_irq failed for MSIX interrupt Error: %d\n",
|
|
|
+ irqret);
|
|
|
+ /** Freeing the non-ioq irq vector here . */
|
|
|
+ free_irq(msix_entries[num_ioq_vectors].vector,
|
|
|
+ oct);
|
|
|
+
|
|
|
+ while (i) {
|
|
|
+ i--;
|
|
|
+ /** clearing affinity mask. */
|
|
|
+ irq_set_affinity_hint(
|
|
|
+ msix_entries[i].vector,
|
|
|
+ NULL);
|
|
|
+ free_irq(msix_entries[i].vector,
|
|
|
+ &oct->ioq_vector[i]);
|
|
|
+ }
|
|
|
+ pci_disable_msix(oct->pci_dev);
|
|
|
+ kfree(oct->msix_entries);
|
|
|
+ kfree(oct->irq_name_storage);
|
|
|
+ oct->irq_name_storage = NULL;
|
|
|
+ oct->msix_entries = NULL;
|
|
|
+ return irqret;
|
|
|
+ }
|
|
|
+ oct->ioq_vector[i].vector = msix_entries[i].vector;
|
|
|
+ /* assign the cpu mask for this msix interrupt vector */
|
|
|
+ irq_set_affinity_hint(msix_entries[i].vector,
|
|
|
+ &oct->ioq_vector[i].affinity_mask
|
|
|
+ );
|
|
|
+ }
|
|
|
+ dev_dbg(&oct->pci_dev->dev, "OCTEON[%d]: MSI-X enabled\n",
|
|
|
+ oct->octeon_id);
|
|
|
+ } else {
|
|
|
+ err = pci_enable_msi(oct->pci_dev);
|
|
|
+ if (err)
|
|
|
+ dev_warn(&oct->pci_dev->dev, "Reverting to legacy interrupts. Error: %d\n",
|
|
|
+ err);
|
|
|
+ else
|
|
|
+ oct->flags |= LIO_FLAG_MSI_ENABLED;
|
|
|
+
|
|
|
+ /* allocate storage for the names assigned to the irq */
|
|
|
+ oct->irq_name_storage = kcalloc(1, INTRNAMSIZ, GFP_KERNEL);
|
|
|
+ if (!oct->irq_name_storage)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ queue_irq_names = oct->irq_name_storage;
|
|
|
+
|
|
|
+ if (OCTEON_CN23XX_PF(oct))
|
|
|
+ snprintf(&queue_irq_names[IRQ_NAME_OFF(0)], INTRNAMSIZ,
|
|
|
+ "LiquidIO%u-pf%u-rxtx-%u",
|
|
|
+ oct->octeon_id, oct->pf_num, 0);
|
|
|
+
|
|
|
+ if (OCTEON_CN23XX_VF(oct))
|
|
|
+ snprintf(&queue_irq_names[IRQ_NAME_OFF(0)], INTRNAMSIZ,
|
|
|
+ "LiquidIO%u-vf%u-rxtx-%u",
|
|
|
+ oct->octeon_id, oct->vf_num, 0);
|
|
|
+
|
|
|
+ irqret = request_irq(oct->pci_dev->irq,
|
|
|
+ liquidio_legacy_intr_handler,
|
|
|
+ IRQF_SHARED,
|
|
|
+ &queue_irq_names[IRQ_NAME_OFF(0)], oct);
|
|
|
+ if (irqret) {
|
|
|
+ if (oct->flags & LIO_FLAG_MSI_ENABLED)
|
|
|
+ pci_disable_msi(oct->pci_dev);
|
|
|
+ dev_err(&oct->pci_dev->dev, "Request IRQ failed with code: %d\n",
|
|
|
+ irqret);
|
|
|
+ kfree(oct->irq_name_storage);
|
|
|
+ oct->irq_name_storage = NULL;
|
|
|
+ return irqret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|