qlcnic: refactor Legacy interrupt handling for 83xx
authorHimanshu Madhani <himanshu.madhani@qlogic.com>
Mon, 18 Feb 2013 12:06:15 +0000 (12:06 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 19 Feb 2013 05:47:01 +0000 (00:47 -0500)
o Cleanly seperate 83xx Legacy interrupt handling code from 82xx
o Update 83xx Legacy interrupt handling code to match with the spec

Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c

index e92cc522615e7262b035f2ecefc78e5f9ea31233..cd5ae8813cb3967537bc047a475db69329993736 100644 (file)
@@ -388,12 +388,45 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
        return 0;
 }
 
-inline void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
-                                   struct qlcnic_host_sds_ring *sds_ring)
+inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter)
+{
+       writel(0, adapter->tgt_mask_reg);
+}
+
+/* Enable MSI-x and INT-x interrupts */
+void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
+                            struct qlcnic_host_sds_ring *sds_ring)
 {
        writel(0, sds_ring->crb_intr_mask);
-       if (!QLCNIC_IS_MSI_FAMILY(adapter))
-               writel(0, adapter->tgt_mask_reg);
+}
+
+/* Disable MSI-x and INT-x interrupts */
+void qlcnic_83xx_disable_intr(struct qlcnic_adapter *adapter,
+                             struct qlcnic_host_sds_ring *sds_ring)
+{
+       writel(1, sds_ring->crb_intr_mask);
+}
+
+inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter
+                                                   *adapter)
+{
+       u32 mask;
+
+       /* Mailbox in MSI-x mode and Legacy Interrupt share the same
+        * source register. We could be here before contexts are created
+        * and sds_ring->crb_intr_mask has not been initialized, calculate
+        * BAR offset for Interrupt Source Register
+        */
+       mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+       writel(0, adapter->ahw->pci_base0 + mask);
+}
+
+inline void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter)
+{
+       u32 mask;
+
+       mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+       writel(1, adapter->ahw->pci_base0 + mask);
 }
 
 static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
@@ -419,8 +452,12 @@ irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
                adapter->stats.spurious_intr++;
                return IRQ_NONE;
        }
+       /* The barrier is required to ensure writes to the registers */
+       wmb();
+
        /* clear the interrupt trigger control register */
        writel(0, adapter->isr_int_vec);
+       intr_val = readl(adapter->isr_int_vec);
        do {
                intr_val = readl(adapter->tgt_status_reg);
                if (QLC_83XX_INTX_FUNC(intr_val) != ahw->pci_func)
@@ -429,13 +466,51 @@ irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
        } while (QLC_83XX_VALID_INTX_BIT30(intr_val) &&
                 (retries < QLC_83XX_LEGACY_INTX_MAX_RETRY));
 
-       if (retries == QLC_83XX_LEGACY_INTX_MAX_RETRY) {
-               dev_info(&adapter->pdev->dev,
-                        "Reached maximum retries to clear legacy interrupt\n");
+       return IRQ_HANDLED;
+}
+
+static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
+{
+       u32 resp, event;
+       unsigned long flags;
+
+       spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+
+       resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
+       if (!(resp & QLCNIC_SET_OWNER))
+               goto out;
+
+       event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
+       if (event &  QLCNIC_MBX_ASYNC_EVENT)
+               qlcnic_83xx_process_aen(adapter);
+out:
+       qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+       spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+}
+
+irqreturn_t qlcnic_83xx_intr(int irq, void *data)
+{
+       struct qlcnic_adapter *adapter = data;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (qlcnic_83xx_clear_legacy_intr(adapter) == IRQ_NONE)
                return IRQ_NONE;
+
+       qlcnic_83xx_poll_process_aen(adapter);
+
+       if (ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+               ahw->diag_cnt++;
+               qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+               return IRQ_HANDLED;
        }
 
-       mdelay(QLC_83XX_LEGACY_INTX_DELAY);
+       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+               qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+       } else {
+               sds_ring = &adapter->recv_ctx->sds_rings[0];
+               napi_schedule(&sds_ring->napi);
+       }
 
        return IRQ_HANDLED;
 }
@@ -460,14 +535,20 @@ done:
 
 void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
 {
-       u32 val = 0;
-       u32 num_msix = adapter->ahw->num_msix - 1;
+       u32 val = 0, num_msix = adapter->ahw->num_msix - 1;
 
-       val = (num_msix << 8);
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               num_msix = adapter->ahw->num_msix - 1;
+       else
+               num_msix = 0;
 
        QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
-       if (adapter->flags & QLCNIC_MSIX_ENABLED)
-               free_irq(adapter->msix_entries[num_msix].vector, adapter);
+
+       qlcnic_83xx_disable_mbx_intr(adapter);
+
+       msleep(20);
+       synchronize_irq(adapter->msix_entries[num_msix].vector);
+       free_irq(adapter->msix_entries[num_msix].vector, adapter);
 }
 
 int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
@@ -486,13 +567,23 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
                handler = qlcnic_83xx_handle_aen;
                val = adapter->msix_entries[adapter->ahw->num_msix - 1].vector;
                snprintf(name, (IFNAMSIZ + 4),
-                        "%s[%s]", adapter->netdev->name, "aen");
+                        "%s[%s]", "qlcnic", "aen");
                err = request_irq(val, handler, flags, name, adapter);
                if (err) {
                        dev_err(&adapter->pdev->dev,
                                "failed to register MBX interrupt\n");
                        return err;
                }
+       } else {
+               handler = qlcnic_83xx_intr;
+               val = adapter->msix_entries[0].vector;
+               err = request_irq(val, handler, flags, "qlcnic", adapter);
+               if (err) {
+                       dev_err(&adapter->pdev->dev,
+                               "failed to register INTx interrupt\n");
+                       return err;
+               }
+               qlcnic_83xx_clear_legacy_intr_mask(adapter);
        }
 
        /* Enable mailbox interrupt */
@@ -604,6 +695,7 @@ void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter)
                val = BIT_2;
 
        QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+       qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
 }
 
 void qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter,
@@ -700,6 +792,7 @@ int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
        int i;
        u16 opcode;
        u8 mbx_err_code;
+       unsigned long flags;
        u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
 
@@ -711,7 +804,7 @@ int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
                return 0;
        }
 
-       spin_lock(&ahw->mbx_lock);
+       spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
        mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
 
        if (mbx_val) {
@@ -721,7 +814,7 @@ int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
                      "Mailbox not available, 0x%x, collect FW dump\n",
                      mbx_val);
                cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
-               spin_unlock(&ahw->mbx_lock);
+               spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
                return cmd->rsp.arg[0];
        }
 
@@ -776,7 +869,7 @@ poll:
 out:
        /* clear fw mbx control register */
        QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
-       spin_unlock(&ahw->mbx_lock);
+       spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
        return rsp;
 }
 
@@ -1194,7 +1287,7 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
        if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                        sds_ring = &adapter->recv_ctx->sds_rings[ring];
-                       writel(1, sds_ring->crb_intr_mask);
+                       qlcnic_83xx_disable_intr(adapter, sds_ring);
                }
        }
 
@@ -1730,6 +1823,7 @@ irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
        resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
        if (!(resp & QLCNIC_SET_OWNER))
                goto out;
+
        event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
        if (event &  QLCNIC_MBX_ASYNC_EVENT)
                qlcnic_83xx_process_aen(adapter);
index f60e28ab99417419bd7837cf06603ce9e498e2c3..127fa273e421207ee7053d0c332dc0f014eac796 100644 (file)
@@ -368,9 +368,12 @@ irqreturn_t qlcnic_83xx_handle_aen(int, void *);
 int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
 void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *);
 irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_intr(int, void *);
 irqreturn_t qlcnic_83xx_tmp_intr(int, void *);
 void qlcnic_83xx_enable_intr(struct qlcnic_adapter *,
                             struct qlcnic_host_sds_ring *);
+void qlcnic_83xx_disable_intr(struct qlcnic_adapter *,
+                            struct qlcnic_host_sds_ring *);
 void qlcnic_83xx_check_vf(struct qlcnic_adapter *,
                          const struct pci_device_id *);
 void qlcnic_83xx_process_aen(struct qlcnic_adapter *);
index 93839f8a2f0f8400172f29f80c14a531058d4a6b..662292de148625076970eaee6dd05b491a6b1906 100644 (file)
@@ -1558,24 +1558,6 @@ skip:
        return count;
 }
 
-static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
-{
-       unsigned long flags;
-       u32 mask, resp, event;
-
-       spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
-       resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
-       if (!(resp & QLCNIC_SET_OWNER))
-               goto out;
-       event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
-       if (event &  QLCNIC_MBX_ASYNC_EVENT)
-               qlcnic_83xx_process_aen(adapter);
-out:
-       mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
-       writel(0, adapter->ahw->pci_base0 + mask);
-       spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
-}
-
 static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
 {
        int tx_complete;
@@ -1589,15 +1571,11 @@ static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
        /* tx ring count = 1 */
        tx_ring = adapter->tx_ring;
 
-       if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
-               qlcnic_83xx_poll_process_aen(adapter);
-
        tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
        work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
        if ((work_done < budget) && tx_complete) {
                napi_complete(&sds_ring->napi);
-               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
-                       qlcnic_83xx_enable_intr(adapter, sds_ring);
+               qlcnic_83xx_enable_intr(adapter, sds_ring);
        }
 
        return work_done;
@@ -1653,7 +1631,8 @@ void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter)
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
                napi_enable(&sds_ring->napi);
-               qlcnic_83xx_enable_intr(adapter, sds_ring);
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_enable_intr(adapter, sds_ring);
        }
 
        if (adapter->flags & QLCNIC_MSIX_ENABLED) {
@@ -1677,7 +1656,8 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter)
 
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
-               writel(1, sds_ring->crb_intr_mask);
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_disable_intr(adapter, sds_ring);
                napi_synchronize(&sds_ring->napi);
                napi_disable(&sds_ring->napi);
        }
index f084dc12a73381aaa39cb6dcf11b97f23699446d..3a0f18215d62fdd797c0783a91783e8816d0188d 100644 (file)
@@ -1269,20 +1269,27 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
                        handler = qlcnic_msi_intr;
                else {
                        flags |= IRQF_SHARED;
-                       handler = qlcnic_intr;
+                       if (qlcnic_82xx_check(adapter))
+                               handler = qlcnic_intr;
+                       else
+                               handler = qlcnic_83xx_intr;
                }
        }
        adapter->irq = netdev->irq;
 
        if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
-               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-                       sds_ring = &recv_ctx->sds_rings[ring];
-                       snprintf(sds_ring->name, sizeof(int) + IFNAMSIZ,
-                                "%s[%d]", netdev->name, ring);
-                       err = request_irq(sds_ring->irq, handler, flags,
-                                         sds_ring->name, sds_ring);
-                       if (err)
-                               return err;
+               if (qlcnic_82xx_check(adapter) ||
+                   (qlcnic_83xx_check(adapter) &&
+                    (adapter->flags & QLCNIC_MSIX_ENABLED))) {
+                       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                               sds_ring = &recv_ctx->sds_rings[ring];
+                               snprintf(sds_ring->name, sizeof(int) + IFNAMSIZ,
+                                        "%s[%d]", netdev->name, ring);
+                               err = request_irq(sds_ring->irq, handler, flags,
+                                                 sds_ring->name, sds_ring);
+                               if (err)
+                                       return err;
+                       }
                }
                if (qlcnic_83xx_check(adapter) &&
                    (adapter->flags & QLCNIC_MSIX_ENABLED)) {
@@ -1292,7 +1299,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
                                tx_ring = &adapter->tx_ring[ring];
                                snprintf(tx_ring->name, sizeof(int) + IFNAMSIZ,
                                         "%s[%d]", netdev->name,
-                               adapter->max_sds_rings + ring);
+                                        adapter->max_sds_rings + ring);
                                err = request_irq(tx_ring->irq, handler, flags,
                                                  tx_ring->name, tx_ring);
                                if (err)
@@ -1313,9 +1320,13 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
        if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
-               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-                       sds_ring = &recv_ctx->sds_rings[ring];
-                       free_irq(sds_ring->irq, sds_ring);
+               if (qlcnic_82xx_check(adapter) ||
+                   (qlcnic_83xx_check(adapter) &&
+                    (adapter->flags & QLCNIC_MSIX_ENABLED))) {
+                       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                               sds_ring = &recv_ctx->sds_rings[ring];
+                               free_irq(sds_ring->irq, sds_ring);
+                       }
                }
                if (qlcnic_83xx_check(adapter)) {
                        for (ring = 0; ring < adapter->max_drv_tx_rings;
This page took 0.034539 seconds and 5 git commands to generate.