[BNX2]: Add firmware decompression
[linux-2.6.git] / drivers / net / bnx2.c
index 7d21370..c6510e1 100644 (file)
@@ -9,20 +9,62 @@
  * Written by: Michael Chan  (mchan@broadcom.com)
  */
 
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <linux/time.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#ifdef NETIF_F_HW_VLAN_TX
+#include <linux/if_vlan.h>
+#define BCM_VLAN 1
+#endif
+#ifdef NETIF_F_TSO
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/checksum.h>
+#define BCM_TSO 1
+#endif
+#include <linux/workqueue.h>
+#include <linux/crc32.h>
+#include <linux/prefetch.h>
+#include <linux/cache.h>
+#include <linux/zlib.h>
+
 #include "bnx2.h"
 #include "bnx2_fw.h"
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.4.38"
-#define DRV_MODULE_RELDATE     "February 10, 2006"
+#define DRV_MODULE_VERSION     "1.4.40"
+#define DRV_MODULE_RELDATE     "May 22, 2006"
 
 #define RUN_AT(x) (jiffies + (x))
 
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (5*HZ)
 
-static char version[] __devinitdata =
+static const char version[] __devinitdata =
        "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
 MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
@@ -313,8 +355,6 @@ bnx2_disable_int(struct bnx2 *bp)
 static void
 bnx2_enable_int(struct bnx2 *bp)
 {
-       u32 val;
-
        REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
               BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
               BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bp->last_status_idx);
@@ -322,8 +362,7 @@ bnx2_enable_int(struct bnx2 *bp)
        REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
               BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx);
 
-       val = REG_RD(bp, BNX2_HC_COMMAND);
-       REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW);
+       REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
 }
 
 static void
@@ -362,15 +401,11 @@ bnx2_free_mem(struct bnx2 *bp)
 {
        int i;
 
-       if (bp->stats_blk) {
-               pci_free_consistent(bp->pdev, sizeof(struct statistics_block),
-                                   bp->stats_blk, bp->stats_blk_mapping);
-               bp->stats_blk = NULL;
-       }
        if (bp->status_blk) {
-               pci_free_consistent(bp->pdev, sizeof(struct status_block),
+               pci_free_consistent(bp->pdev, bp->status_stats_size,
                                    bp->status_blk, bp->status_blk_mapping);
                bp->status_blk = NULL;
+               bp->stats_blk = NULL;
        }
        if (bp->tx_desc_ring) {
                pci_free_consistent(bp->pdev,
@@ -395,14 +430,13 @@ bnx2_free_mem(struct bnx2 *bp)
 static int
 bnx2_alloc_mem(struct bnx2 *bp)
 {
-       int i;
+       int i, status_blk_size;
 
-       bp->tx_buf_ring = kmalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
-                                    GFP_KERNEL);
+       bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
+                                 GFP_KERNEL);
        if (bp->tx_buf_ring == NULL)
                return -ENOMEM;
 
-       memset(bp->tx_buf_ring, 0, sizeof(struct sw_bd) * TX_DESC_CNT);
        bp->tx_desc_ring = pci_alloc_consistent(bp->pdev,
                                                sizeof(struct tx_bd) *
                                                TX_DESC_CNT,
@@ -428,21 +462,22 @@ bnx2_alloc_mem(struct bnx2 *bp)
 
        }
 
-       bp->status_blk = pci_alloc_consistent(bp->pdev,
-                                             sizeof(struct status_block),
+       /* Combine status and statistics blocks into one allocation. */
+       status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
+       bp->status_stats_size = status_blk_size +
+                               sizeof(struct statistics_block);
+
+       bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
                                              &bp->status_blk_mapping);
        if (bp->status_blk == NULL)
                goto alloc_mem_err;
 
-       memset(bp->status_blk, 0, sizeof(struct status_block));
+       memset(bp->status_blk, 0, bp->status_stats_size);
 
-       bp->stats_blk = pci_alloc_consistent(bp->pdev,
-                                            sizeof(struct statistics_block),
-                                            &bp->stats_blk_mapping);
-       if (bp->stats_blk == NULL)
-               goto alloc_mem_err;
+       bp->stats_blk = (void *) ((unsigned long) bp->status_blk +
+                                 status_blk_size);
 
-       memset(bp->stats_blk, 0, sizeof(struct statistics_block));
+       bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
 
        return 0;
 
@@ -1786,7 +1821,7 @@ reuse_rx:
                skb->protocol = eth_type_trans(skb, bp->dev);
 
                if ((len > (bp->dev->mtu + ETH_HLEN)) &&
-                       (htons(skb->protocol) != 0x8100)) {
+                       (ntohs(skb->protocol) != 0x8100)) {
 
                        dev_kfree_skb_irq(skb);
                        goto next_rx;
@@ -1926,6 +1961,13 @@ bnx2_poll(struct net_device *dev, int *budget)
                spin_lock(&bp->phy_lock);
                bnx2_phy_int(bp);
                spin_unlock(&bp->phy_lock);
+
+               /* This is needed to take care of transient status
+                * during link changes.
+                */
+               REG_WR(bp, BNX2_HC_COMMAND,
+                      bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+               REG_RD(bp, BNX2_HC_COMMAND);
        }
 
        if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
@@ -1968,7 +2010,7 @@ bnx2_poll(struct net_device *dev, int *budget)
        return 1;
 }
 
-/* Called with rtnl_lock from vlan functions and also dev->xmit_lock
+/* Called with rtnl_lock from vlan functions and also netif_tx_lock
  * from set_multicast.
  */
 static void
@@ -2042,6 +2084,92 @@ bnx2_set_rx_mode(struct net_device *dev)
        spin_unlock_bh(&bp->phy_lock);
 }
 
+#define FW_BUF_SIZE    0x8000
+
+static int
+bnx2_gunzip_init(struct bnx2 *bp)
+{
+       if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL)
+               goto gunzip_nomem1;
+
+       if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL)
+               goto gunzip_nomem2;
+
+       bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+       if (bp->strm->workspace == NULL)
+               goto gunzip_nomem3;
+
+       return 0;
+
+gunzip_nomem3:
+       kfree(bp->strm);
+       bp->strm = NULL;
+
+gunzip_nomem2:
+       vfree(bp->gunzip_buf);
+       bp->gunzip_buf = NULL;
+
+gunzip_nomem1:
+       printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for "
+                           "uncompression.\n", bp->dev->name);
+       return -ENOMEM;
+}
+
+static void
+bnx2_gunzip_end(struct bnx2 *bp)
+{
+       kfree(bp->strm->workspace);
+
+       kfree(bp->strm);
+       bp->strm = NULL;
+
+       if (bp->gunzip_buf) {
+               vfree(bp->gunzip_buf);
+               bp->gunzip_buf = NULL;
+       }
+}
+
+static int
+bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen)
+{
+       int n, rc;
+
+       /* check gzip header */
+       if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
+               return -EINVAL;
+
+       n = 10;
+
+#define FNAME  0x8
+       if (zbuf[3] & FNAME)
+               while ((zbuf[n++] != 0) && (n < len));
+
+       bp->strm->next_in = zbuf + n;
+       bp->strm->avail_in = len - n;
+       bp->strm->next_out = bp->gunzip_buf;
+       bp->strm->avail_out = FW_BUF_SIZE;
+
+       rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
+       if (rc != Z_OK)
+               return rc;
+
+       rc = zlib_inflate(bp->strm, Z_FINISH);
+
+       *outlen = FW_BUF_SIZE - bp->strm->avail_out;
+       *outbuf = bp->gunzip_buf;
+
+       if ((rc != Z_OK) && (rc != Z_STREAM_END))
+               printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
+                      bp->dev->name, bp->strm->msg);
+
+       zlib_inflateEnd(bp->strm);
+
+       if (rc == Z_STREAM_END)
+               return 0;
+
+       return rc;
+}
+
 static void
 load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
        u32 rv2p_proc)
@@ -2051,9 +2179,9 @@ load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
 
 
        for (i = 0; i < rv2p_code_len; i += 8) {
-               REG_WR(bp, BNX2_RV2P_INSTR_HIGH, *rv2p_code);
+               REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code));
                rv2p_code++;
-               REG_WR(bp, BNX2_RV2P_INSTR_LOW, *rv2p_code);
+               REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code));
                rv2p_code++;
 
                if (rv2p_proc == RV2P_PROC1) {
@@ -2093,7 +2221,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
                int j;
 
                for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
-                       REG_WR_IND(bp, offset, fw->text[j]);
+                       REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
                }
        }
 
@@ -2149,15 +2277,32 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
        REG_WR_IND(bp, cpu_reg->mode, val);
 }
 
-static void
+static int
 bnx2_init_cpus(struct bnx2 *bp)
 {
        struct cpu_reg cpu_reg;
        struct fw_info fw;
+       int rc = 0;
+       void *text;
+       u32 text_len;
+
+       if ((rc = bnx2_gunzip_init(bp)) != 0)
+               return rc;
 
        /* Initialize the RV2P processor. */
-       load_rv2p_fw(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), RV2P_PROC1);
-       load_rv2p_fw(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), RV2P_PROC2);
+       rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text,
+                        &text_len);
+       if (rc)
+               goto init_cpu_err;
+
+       load_rv2p_fw(bp, text, text_len, RV2P_PROC1);
+
+       rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text,
+                        &text_len);
+       if (rc)
+               goto init_cpu_err;
+
+       load_rv2p_fw(bp, text, text_len, RV2P_PROC2);
 
        /* Initialize the RX Processor. */
        cpu_reg.mode = BNX2_RXP_CPU_MODE;
@@ -2181,7 +2326,13 @@ bnx2_init_cpus(struct bnx2 *bp)
        fw.text_addr = bnx2_RXP_b06FwTextAddr;
        fw.text_len = bnx2_RXP_b06FwTextLen;
        fw.text_index = 0;
-       fw.text = bnx2_RXP_b06FwText;
+
+       rc = bnx2_gunzip(bp, bnx2_RXP_b06FwText, sizeof(bnx2_RXP_b06FwText),
+                        &text, &text_len);
+       if (rc)
+               goto init_cpu_err;
+
+       fw.text = text;
 
        fw.data_addr = bnx2_RXP_b06FwDataAddr;
        fw.data_len = bnx2_RXP_b06FwDataLen;
@@ -2227,7 +2378,13 @@ bnx2_init_cpus(struct bnx2 *bp)
        fw.text_addr = bnx2_TXP_b06FwTextAddr;
        fw.text_len = bnx2_TXP_b06FwTextLen;
        fw.text_index = 0;
-       fw.text = bnx2_TXP_b06FwText;
+
+       rc = bnx2_gunzip(bp, bnx2_TXP_b06FwText, sizeof(bnx2_TXP_b06FwText),
+                        &text, &text_len);
+       if (rc)
+               goto init_cpu_err;
+
+       fw.text = text;
 
        fw.data_addr = bnx2_TXP_b06FwDataAddr;
        fw.data_len = bnx2_TXP_b06FwDataLen;
@@ -2273,7 +2430,13 @@ bnx2_init_cpus(struct bnx2 *bp)
        fw.text_addr = bnx2_TPAT_b06FwTextAddr;
        fw.text_len = bnx2_TPAT_b06FwTextLen;
        fw.text_index = 0;
-       fw.text = bnx2_TPAT_b06FwText;
+
+       rc = bnx2_gunzip(bp, bnx2_TPAT_b06FwText, sizeof(bnx2_TPAT_b06FwText),
+                        &text, &text_len);
+       if (rc)
+               goto init_cpu_err;
+
+       fw.text = text;
 
        fw.data_addr = bnx2_TPAT_b06FwDataAddr;
        fw.data_len = bnx2_TPAT_b06FwDataLen;
@@ -2319,7 +2482,13 @@ bnx2_init_cpus(struct bnx2 *bp)
        fw.text_addr = bnx2_COM_b06FwTextAddr;
        fw.text_len = bnx2_COM_b06FwTextLen;
        fw.text_index = 0;
-       fw.text = bnx2_COM_b06FwText;
+
+       rc = bnx2_gunzip(bp, bnx2_COM_b06FwText, sizeof(bnx2_COM_b06FwText),
+                        &text, &text_len);
+       if (rc)
+               goto init_cpu_err;
+
+       fw.text = text;
 
        fw.data_addr = bnx2_COM_b06FwDataAddr;
        fw.data_len = bnx2_COM_b06FwDataLen;
@@ -2343,6 +2512,9 @@ bnx2_init_cpus(struct bnx2 *bp)
 
        load_cpu_fw(bp, &cpu_reg, &fw);
 
+init_cpu_err:
+       bnx2_gunzip_end(bp);
+       return rc;
 }
 
 static int
@@ -2904,7 +3076,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                int buf_size)
 {
        u32 written, offset32, len32;
-       u8 *buf, start[4], end[4];
+       u8 *buf, start[4], end[4], *flash_buffer = NULL;
        int rc = 0;
        int align_start, align_end;
 
@@ -2944,12 +3116,19 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                memcpy(buf + align_start, data_buf, buf_size);
        }
 
+       if (bp->flash_info->buffered == 0) {
+               flash_buffer = kmalloc(264, GFP_KERNEL);
+               if (flash_buffer == NULL) {
+                       rc = -ENOMEM;
+                       goto nvram_write_end;
+               }
+       }
+
        written = 0;
        while ((written < len32) && (rc == 0)) {
                u32 page_start, page_end, data_start, data_end;
                u32 addr, cmd_flags;
                int i;
-               u8 flash_buffer[264];
 
                /* Find the page_start addr */
                page_start = offset32 + written;
@@ -3020,7 +3199,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
                }
 
                /* Loop to write the new data from data_start to data_end */
-               for (addr = data_start; addr < data_end; addr += 4, i++) {
+               for (addr = data_start; addr < data_end; addr += 4, i += 4) {
                        if ((addr == page_end - 4) ||
                                ((bp->flash_info->buffered) &&
                                 (addr == data_end - 4))) {
@@ -3068,6 +3247,9 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
        }
 
 nvram_write_end:
+       if (bp->flash_info->buffered == 0)
+               kfree(flash_buffer);
+
        if (align_start || align_end)
                kfree(buf);
        return rc;
@@ -3205,7 +3387,9 @@ bnx2_init_chip(struct bnx2 *bp)
         * context block must have already been enabled. */
        bnx2_init_context(bp);
 
-       bnx2_init_cpus(bp);
+       if ((rc = bnx2_init_cpus(bp)) != 0)
+               return rc;
+
        bnx2_init_nvram(bp);
 
        bnx2_set_mac_addr(bp);
@@ -3307,6 +3491,8 @@ bnx2_init_chip(struct bnx2 *bp)
 
        udelay(20);
 
+       bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
+
        return rc;
 }
 
@@ -3503,7 +3689,9 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
        if (rc)
                return rc;
 
-       bnx2_init_chip(bp);
+       if ((rc = bnx2_init_chip(bp)) != 0)
+               return rc;
+
        bnx2_init_tx_ring(bp);
        bnx2_init_rx_ring(bp);
        return 0;
@@ -3746,7 +3934,6 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
        struct sk_buff *skb, *rx_skb;
        unsigned char *packet;
        u16 rx_start_idx, rx_idx;
-       u32 val;
        dma_addr_t map;
        struct tx_bd *txbd;
        struct sw_bd *rx_buf;
@@ -3777,8 +3964,9 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
        map = pci_map_single(bp->pdev, skb->data, pkt_size,
                PCI_DMA_TODEVICE);
 
-       val = REG_RD(bp, BNX2_HC_COMMAND);
-       REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+       REG_WR(bp, BNX2_HC_COMMAND,
+              bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+
        REG_RD(bp, BNX2_HC_COMMAND);
 
        udelay(5);
@@ -3802,8 +3990,9 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
 
        udelay(100);
 
-       val = REG_RD(bp, BNX2_HC_COMMAND);
-       REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+       REG_WR(bp, BNX2_HC_COMMAND,
+              bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
+
        REG_RD(bp, BNX2_HC_COMMAND);
 
        udelay(5);
@@ -3939,7 +4128,6 @@ static int
 bnx2_test_intr(struct bnx2 *bp)
 {
        int i;
-       u32 val;
        u16 status_idx;
 
        if (!netif_running(bp->dev))
@@ -3948,8 +4136,7 @@ bnx2_test_intr(struct bnx2 *bp)
        status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
 
        /* This register is not touched during run-time. */
-       val = REG_RD(bp, BNX2_HC_COMMAND);
-       REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW);
+       REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
        REG_RD(bp, BNX2_HC_COMMAND);
 
        for (i = 0; i < 10; i++) {
@@ -3982,6 +4169,8 @@ bnx2_timer(unsigned long data)
        msg = (u32) ++bp->fw_drv_pulse_wr_seq;
        REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB, msg);
 
+       bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
+
        if ((bp->phy_flags & PHY_SERDES_FLAG) &&
            (CHIP_NUM(bp) == CHIP_NUM_5706)) {
 
@@ -4200,7 +4389,7 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
 }
 #endif
 
-/* Called with dev->xmit_lock.
+/* Called with netif_tx_lock.
  * hard_start_xmit is pseudo-lockless - a lock is only required when
  * the tx queue is full. This way, we get the benefit of lockless
  * operations most of the time without the complexities to handle
@@ -4258,7 +4447,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
                ip_tcp_len = (skb->nh.iph->ihl << 2) + sizeof(struct tcphdr);
 
                skb->nh.iph->check = 0;
-               skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len);
+               skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
                skb->h.th->check =
                        ~csum_tcpudp_magic(skb->nh.iph->saddr,
                                            skb->nh.iph->daddr,
@@ -4452,6 +4641,10 @@ bnx2_get_stats(struct net_device *dev)
                net_stats->tx_aborted_errors +
                net_stats->tx_carrier_errors;
 
+       net_stats->rx_missed_errors =
+               (unsigned long) (stats_blk->stat_IfInMBUFDiscards +
+               stats_blk->stat_FwRxDrop);
+
        return net_stats;
 }
 
@@ -4934,7 +5127,7 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data)
        return 0;
 }
 
-#define BNX2_NUM_STATS 45
+#define BNX2_NUM_STATS 46
 
 static struct {
        char string[ETH_GSTRING_LEN];
@@ -4984,6 +5177,7 @@ static struct {
        { "rx_mac_ctrl_frames" },
        { "rx_filtered_packets" },
        { "rx_discards" },
+       { "rx_fw_discards" },
 };
 
 #define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
@@ -5034,6 +5228,7 @@ static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
     STATS_OFFSET32(stat_MacControlFramesReceived),                    
     STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),                  
     STATS_OFFSET32(stat_IfInMBUFDiscards),                            
+    STATS_OFFSET32(stat_FwRxDrop),
 };
 
 /* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
@@ -5044,7 +5239,7 @@ static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
        4,0,4,4,4,4,4,4,4,4,
        4,4,4,4,4,4,4,4,4,4,
        4,4,4,4,4,4,4,4,4,4,
-       4,4,4,4,4,
+       4,4,4,4,4,4,
 };
 
 static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
@@ -5052,7 +5247,7 @@ static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
        4,4,4,4,4,4,4,4,4,4,
        4,4,4,4,4,4,4,4,4,4,
        4,4,4,4,4,4,4,4,4,4,
-       4,4,4,4,4,
+       4,4,4,4,4,4,
 };
 
 #define BNX2_NUM_TESTS 6
@@ -5582,7 +5777,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                }
        }
 
-       if (CHIP_NUM(bp) == CHIP_NUM_5708)
+       if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
+           (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
+           (CHIP_ID(bp) == CHIP_ID_5708_B1))
                bp->flags |= NO_WOL_FLAG;
 
        if (CHIP_ID(bp) == CHIP_ID_5706_A0) {