bnx2x: Handle a rarely missed interrupt
authorYaniv Rosner <yaniv.rosner@broadcom.com>
Sun, 2 Dec 2012 04:05:54 +0000 (04:05 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 3 Dec 2012 01:23:00 +0000 (20:23 -0500)
A rare case of no link due to a missed interrupt may occur due to a
race condition between acknowledging the IGU via the BAR and restoring the NIG
interrupt mask via the GRC.
To solve it, we wait for the IGU ack command to finish prior to restoring the
NIG interrupt mask.

Signed-off-by: Yaniv Rosner <yaniv.rosner@broadcom.com>
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c

index 03647bf3ddb9e823ff605c5d2c1fb7a109f62526..02ea644573caa5bfbc0cd2a26017909bb253740f 100644 (file)
@@ -915,6 +915,7 @@ struct bnx2x_common {
 #define BNX2X_IGU_STAS_MSG_VF_CNT 64
 #define BNX2X_IGU_STAS_MSG_PF_CNT 4
 
+#define MAX_IGU_ATTN_ACK_TO       100
 /* end of common */
 
 /* port */
index 983a0c86ee330cc62740aff0f48e42d8bd94ce0a..d76ca90eea94c516051277174692ea73f12a3d27 100644 (file)
@@ -3588,6 +3588,21 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
 
        /* now set back the mask */
        if (asserted & ATTN_NIG_FOR_FUNC) {
+               /* Verify that IGU ack through BAR was written before restoring
+                * NIG mask. This loop should exit after 2-3 iterations max.
+                */
+               if (bp->common.int_block != INT_BLOCK_HC) {
+                       u32 cnt = 0, igu_acked;
+                       do {
+                               igu_acked = REG_RD(bp,
+                                                  IGU_REG_ATTENTION_ACK_BITS);
+                       } while (((igu_acked & ATTN_NIG_FOR_FUNC) == 0) &&
+                                (++cnt < MAX_IGU_ATTN_ACK_TO));
+                       if (!igu_acked)
+                               DP(NETIF_MSG_HW,
+                                  "Failed to verify IGU ack on time\n");
+                       barrier();
+               }
                REG_WR(bp, nig_int_mask_addr, nig_mask);
                bnx2x_release_phy_lock(bp);
        }