]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
bnx2x: Prevent an illegal pointer dereference during panic
[karo-tx-linux.git] / drivers / net / ethernet / broadcom / bnx2x / bnx2x_main.c
index a6704b555042dfd26eab956f64082578bcf51a09..c2609c41340e31c348032ca190ef62ff7d219a9b 100644 (file)
@@ -751,6 +751,10 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
        return rc;
 }
 
+#define MCPR_TRACE_BUFFER_SIZE (0x800)
+#define SCRATCH_BUFFER_SIZE(bp)        \
+       (CHIP_IS_E1(bp) ? 0x10000 : (CHIP_IS_E1H(bp) ? 0x20000 : 0x28000))
+
 void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
 {
        u32 addr, val;
@@ -775,7 +779,17 @@ void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
                trace_shmem_base = bp->common.shmem_base;
        else
                trace_shmem_base = SHMEM2_RD(bp, other_shmem_base_addr);
-       addr = trace_shmem_base - 0x800;
+
+       /* sanity */
+       if (trace_shmem_base < MCPR_SCRATCH_BASE(bp) + MCPR_TRACE_BUFFER_SIZE ||
+           trace_shmem_base >= MCPR_SCRATCH_BASE(bp) +
+                               SCRATCH_BUFFER_SIZE(bp)) {
+               BNX2X_ERR("Unable to dump trace buffer (mark %x)\n",
+                         trace_shmem_base);
+               return;
+       }
+
+       addr = trace_shmem_base - MCPR_TRACE_BUFFER_SIZE;
 
        /* validate TRCB signature */
        mark = REG_RD(bp, addr);
@@ -787,14 +801,17 @@ void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
        /* read cyclic buffer pointer */
        addr += 4;
        mark = REG_RD(bp, addr);
-       mark = (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH)
-                       + ((mark + 0x3) & ~0x3) - 0x08000000;
+       mark = MCPR_SCRATCH_BASE(bp) + ((mark + 0x3) & ~0x3) - 0x08000000;
+       if (mark >= trace_shmem_base || mark < addr + 4) {
+               BNX2X_ERR("Mark doesn't fall inside Trace Buffer\n");
+               return;
+       }
        printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark);
 
        printk("%s", lvl);
 
        /* dump buffer after the mark */
-       for (offset = mark; offset <= trace_shmem_base; offset += 0x8*4) {
+       for (offset = mark; offset < trace_shmem_base; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
                        data[word] = htonl(REG_RD(bp, offset + 4*word));
                data[8] = 0x0;
@@ -4703,6 +4720,14 @@ bool bnx2x_chk_parity_attn(struct bnx2x *bp, bool *global, bool print)
        attn.sig[3] = REG_RD(bp,
                MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 +
                             port*4);
+       /* Since MCP attentions can't be disabled inside the block, we need to
+        * read AEU registers to see whether they're currently disabled
+        */
+       attn.sig[3] &= ((REG_RD(bp,
+                               !port ? MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0
+                                     : MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0) &
+                        MISC_AEU_ENABLE_MCP_PRTY_BITS) |
+                       ~MISC_AEU_ENABLE_MCP_PRTY_BITS);
 
        if (!CHIP_IS_E1x(bp))
                attn.sig[4] = REG_RD(bp,
@@ -5447,26 +5472,24 @@ static void bnx2x_timer(unsigned long data)
        if (IS_PF(bp) &&
            !BP_NOMCP(bp)) {
                int mb_idx = BP_FW_MB_IDX(bp);
-               u32 drv_pulse;
-               u32 mcp_pulse;
+               u16 drv_pulse;
+               u16 mcp_pulse;
 
                ++bp->fw_drv_pulse_wr_seq;
                bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
-               /* TBD - add SYSTEM_TIME */
                drv_pulse = bp->fw_drv_pulse_wr_seq;
                bnx2x_drv_pulse(bp);
 
                mcp_pulse = (SHMEM_RD(bp, func_mb[mb_idx].mcp_pulse_mb) &
                             MCP_PULSE_SEQ_MASK);
                /* The delta between driver pulse and mcp response
-                * should be 1 (before mcp response) or 0 (after mcp response)
+                * should not get too big. If the MFW is more than 5 pulses
+                * behind, we should worry about it enough to generate an error
+                * log.
                 */
-               if ((drv_pulse != mcp_pulse) &&
-                   (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) {
-                       /* someone lost a heartbeat... */
-                       BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
+               if (((drv_pulse - mcp_pulse) & MCP_PULSE_SEQ_MASK) > 5)
+                       BNX2X_ERR("MFW seems hanged: drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
                                  drv_pulse, mcp_pulse);
-               }
        }
 
        if (bp->state == BNX2X_STATE_OPEN)
@@ -11679,9 +11702,6 @@ static int bnx2x_init_bp(struct bnx2x *bp)
 static int bnx2x_open(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       bool global = false;
-       int other_engine = BP_PATH(bp) ? 0 : 1;
-       bool other_load_status, load_status;
        int rc;
 
        bp->stats_init = true;
@@ -11697,6 +11717,10 @@ static int bnx2x_open(struct net_device *dev)
         * Parity recovery is only relevant for PF driver.
         */
        if (IS_PF(bp)) {
+               int other_engine = BP_PATH(bp) ? 0 : 1;
+               bool other_load_status, load_status;
+               bool global = false;
+
                other_load_status = bnx2x_get_load_status(bp, other_engine);
                load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
                if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
@@ -12606,24 +12630,24 @@ static int set_max_cos_est(int chip_id)
                return BNX2X_MULTI_TX_COS_E1X;
        case BCM57712:
        case BCM57712_MF:
-       case BCM57712_VF:
                return BNX2X_MULTI_TX_COS_E2_E3A0;
        case BCM57800:
        case BCM57800_MF:
-       case BCM57800_VF:
        case BCM57810:
        case BCM57810_MF:
        case BCM57840_4_10:
        case BCM57840_2_20:
        case BCM57840_O:
        case BCM57840_MFO:
-       case BCM57810_VF:
        case BCM57840_MF:
-       case BCM57840_VF:
        case BCM57811:
        case BCM57811_MF:
-       case BCM57811_VF:
                return BNX2X_MULTI_TX_COS_E3B0;
+       case BCM57712_VF:
+       case BCM57800_VF:
+       case BCM57810_VF:
+       case BCM57840_VF:
+       case BCM57811_VF:
                return 1;
        default:
                pr_err("Unknown board_type (%d), aborting\n", chip_id);