bnxt_en: Improve the IRQ disable sequence during shutdown.
authorMichael Chan <michael.chan@broadcom.com>
Thu, 29 Dec 2016 17:13:33 +0000 (12:13 -0500)
committerDavid S. Miller <davem@davemloft.net>
Thu, 29 Dec 2016 19:37:23 +0000 (14:37 -0500)
The IRQ is disabled by writing to the completion ring doorbell.  This
should be done before the hardware completion ring is freed for correctness.
The current code disables IRQs after all the completion rings are freed.

Fix it by calling bnxt_disable_int_sync() before freeing the completion
rings.  Rearrange the code to avoid forward declaration.

Signed-off-by: Michael Chan <michael.chan@broadocm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnxt/bnxt.c

index 3fbc8427be2ee5957ff244646bca7af63a581d24..277573b3d2610e55e3cb283b0402ac998d0e8750 100644 (file)
@@ -2953,6 +2953,45 @@ alloc_mem_err:
        return rc;
 }
 
+static void bnxt_disable_int(struct bnxt *bp)
+{
+       int i;
+
+       if (!bp->bnapi)
+               return;
+
+       for (i = 0; i < bp->cp_nr_rings; i++) {
+               struct bnxt_napi *bnapi = bp->bnapi[i];
+               struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+
+               BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons);
+       }
+}
+
+static void bnxt_disable_int_sync(struct bnxt *bp)
+{
+       int i;
+
+       atomic_inc(&bp->intr_sem);
+
+       bnxt_disable_int(bp);
+       for (i = 0; i < bp->cp_nr_rings; i++)
+               synchronize_irq(bp->irq_tbl[i].vector);
+}
+
+static void bnxt_enable_int(struct bnxt *bp)
+{
+       int i;
+
+       atomic_set(&bp->intr_sem, 0);
+       for (i = 0; i < bp->cp_nr_rings; i++) {
+               struct bnxt_napi *bnapi = bp->bnapi[i];
+               struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+
+               BNXT_CP_DB_REARM(cpr->cp_doorbell, cpr->cp_raw_cons);
+       }
+}
+
 void bnxt_hwrm_cmd_hdr_init(struct bnxt *bp, void *request, u16 req_type,
                            u16 cmpl_ring, u16 target_id)
 {
@@ -3937,6 +3976,12 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
                }
        }
 
+       /* The completion rings are about to be freed.  After that the
+        * IRQ doorbell will not work anymore.  So we need to disable
+        * IRQ here.
+        */
+       bnxt_disable_int_sync(bp);
+
        for (i = 0; i < bp->cp_nr_rings; i++) {
                struct bnxt_napi *bnapi = bp->bnapi[i];
                struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
@@ -4658,34 +4703,6 @@ static int bnxt_init_nic(struct bnxt *bp, bool irq_re_init)
        return bnxt_init_chip(bp, irq_re_init);
 }
 
-static void bnxt_disable_int(struct bnxt *bp)
-{
-       int i;
-
-       if (!bp->bnapi)
-               return;
-
-       for (i = 0; i < bp->cp_nr_rings; i++) {
-               struct bnxt_napi *bnapi = bp->bnapi[i];
-               struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
-
-               BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons);
-       }
-}
-
-static void bnxt_enable_int(struct bnxt *bp)
-{
-       int i;
-
-       atomic_set(&bp->intr_sem, 0);
-       for (i = 0; i < bp->cp_nr_rings; i++) {
-               struct bnxt_napi *bnapi = bp->bnapi[i];
-               struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
-
-               BNXT_CP_DB_REARM(cpr->cp_doorbell, cpr->cp_raw_cons);
-       }
-}
-
 static int bnxt_set_real_num_queues(struct bnxt *bp)
 {
        int rc;
@@ -5640,19 +5657,6 @@ static int bnxt_open(struct net_device *dev)
        return __bnxt_open_nic(bp, true, true);
 }
 
-static void bnxt_disable_int_sync(struct bnxt *bp)
-{
-       int i;
-
-       atomic_inc(&bp->intr_sem);
-       if (!netif_running(bp->dev))
-               return;
-
-       bnxt_disable_int(bp);
-       for (i = 0; i < bp->cp_nr_rings; i++)
-               synchronize_irq(bp->irq_tbl[i].vector);
-}
-
 int bnxt_close_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
 {
        int rc = 0;
@@ -5674,13 +5678,12 @@ int bnxt_close_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
        while (test_bit(BNXT_STATE_IN_SP_TASK, &bp->state))
                msleep(20);
 
-       /* Flush rings before disabling interrupts */
+       /* Flush rings and and disable interrupts */
        bnxt_shutdown_nic(bp, irq_re_init);
 
        /* TODO CHIMP_FW: Link/PHY related cleanup if (link_re_init) */
 
        bnxt_disable_napi(bp);
-       bnxt_disable_int_sync(bp);
        del_timer_sync(&bp->timer);
        bnxt_free_skbs(bp);