[BNX2]: Add firmware decompression
[linux-2.6.git] / drivers / net / bnx2.c
index ec08f83..c6510e1 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2.c: Broadcom NX2 network driver.
  *
- * Copyright (c) 2004, 2005 Broadcom Corporation
+ * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -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.30"
-#define DRV_MODULE_RELDATE     "October 11, 2005"
+#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>");
@@ -46,7 +88,7 @@ typedef enum {
 } board_t;
 
 /* indexed by board_t, above */
-static struct {
+static const struct {
        char *name;
 } board_info[] __devinitdata = {
        { "Broadcom NetXtreme II BCM5706 1000Base-T" },
@@ -313,13 +355,14 @@ 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);
 
        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
@@ -356,15 +399,13 @@ bnx2_netif_start(struct bnx2 *bp)
 static void
 bnx2_free_mem(struct bnx2 *bp)
 {
-       if (bp->stats_blk) {
-               pci_free_consistent(bp->pdev, sizeof(struct statistics_block),
-                                   bp->stats_blk, bp->stats_blk_mapping);
-               bp->stats_blk = NULL;
-       }
+       int i;
+
        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,
@@ -374,25 +415,28 @@ bnx2_free_mem(struct bnx2 *bp)
        }
        kfree(bp->tx_buf_ring);
        bp->tx_buf_ring = NULL;
-       if (bp->rx_desc_ring) {
-               pci_free_consistent(bp->pdev,
-                                   sizeof(struct rx_bd) * RX_DESC_CNT,
-                                   bp->rx_desc_ring, bp->rx_desc_mapping);
-               bp->rx_desc_ring = NULL;
-       }
-       kfree(bp->rx_buf_ring);
+       for (i = 0; i < bp->rx_max_ring; i++) {
+               if (bp->rx_desc_ring[i])
+                       pci_free_consistent(bp->pdev,
+                                           sizeof(struct rx_bd) * RX_DESC_CNT,
+                                           bp->rx_desc_ring[i],
+                                           bp->rx_desc_mapping[i]);
+               bp->rx_desc_ring[i] = NULL;
+       }
+       vfree(bp->rx_buf_ring);
        bp->rx_buf_ring = NULL;
 }
 
 static int
 bnx2_alloc_mem(struct bnx2 *bp)
 {
-       bp->tx_buf_ring = kmalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
-                                    GFP_KERNEL);
+       int i, status_blk_size;
+
+       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,
@@ -400,34 +444,40 @@ bnx2_alloc_mem(struct bnx2 *bp)
        if (bp->tx_desc_ring == NULL)
                goto alloc_mem_err;
 
-       bp->rx_buf_ring = kmalloc(sizeof(struct sw_bd) * RX_DESC_CNT,
-                                    GFP_KERNEL);
+       bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT *
+                                 bp->rx_max_ring);
        if (bp->rx_buf_ring == NULL)
                goto alloc_mem_err;
 
-       memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT);
-       bp->rx_desc_ring = pci_alloc_consistent(bp->pdev,
-                                               sizeof(struct rx_bd) *
-                                               RX_DESC_CNT,
-                                               &bp->rx_desc_mapping);
-       if (bp->rx_desc_ring == NULL)
-               goto alloc_mem_err;
+       memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT *
+                                  bp->rx_max_ring);
+
+       for (i = 0; i < bp->rx_max_ring; i++) {
+               bp->rx_desc_ring[i] =
+                       pci_alloc_consistent(bp->pdev,
+                                            sizeof(struct rx_bd) * RX_DESC_CNT,
+                                            &bp->rx_desc_mapping[i]);
+               if (bp->rx_desc_ring[i] == NULL)
+                       goto alloc_mem_err;
+
+       }
 
-       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;
 
@@ -1327,6 +1377,38 @@ bnx2_set_mac_loopback(struct bnx2 *bp)
        return 0;
 }
 
+static int bnx2_test_link(struct bnx2 *);
+
+static int
+bnx2_set_phy_loopback(struct bnx2 *bp)
+{
+       u32 mac_mode;
+       int rc, i;
+
+       spin_lock_bh(&bp->phy_lock);
+       rc = bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
+                           BMCR_SPEED1000);
+       spin_unlock_bh(&bp->phy_lock);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < 10; i++) {
+               if (bnx2_test_link(bp) == 0)
+                       break;
+               udelay(10);
+       }
+
+       mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
+       mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
+                     BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
+                     BNX2_EMAC_MODE_25G);
+
+       mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
+       REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
+       bp->link_up = 1;
+       return 0;
+}
+
 static int
 bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
 {
@@ -1484,7 +1566,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
        struct sk_buff *skb;
        struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
        dma_addr_t mapping;
-       struct rx_bd *rxbd = &bp->rx_desc_ring[index];
+       struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
        unsigned long align;
 
        skb = dev_alloc_skb(bp->rx_buf_size);
@@ -1620,23 +1702,30 @@ static inline void
 bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
        u16 cons, u16 prod)
 {
-       struct sw_bd *cons_rx_buf = &bp->rx_buf_ring[cons];
-       struct sw_bd *prod_rx_buf = &bp->rx_buf_ring[prod];
-       struct rx_bd *cons_bd = &bp->rx_desc_ring[cons];
-       struct rx_bd *prod_bd = &bp->rx_desc_ring[prod];
+       struct sw_bd *cons_rx_buf, *prod_rx_buf;
+       struct rx_bd *cons_bd, *prod_bd;
+
+       cons_rx_buf = &bp->rx_buf_ring[cons];
+       prod_rx_buf = &bp->rx_buf_ring[prod];
 
        pci_dma_sync_single_for_device(bp->pdev,
                pci_unmap_addr(cons_rx_buf, mapping),
                bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
-       prod_rx_buf->skb = cons_rx_buf->skb;
-       pci_unmap_addr_set(prod_rx_buf, mapping,
-                       pci_unmap_addr(cons_rx_buf, mapping));
+       bp->rx_prod_bseq += bp->rx_buf_use_size;
 
-       memcpy(prod_bd, cons_bd, 8);
+       prod_rx_buf->skb = skb;
 
-       bp->rx_prod_bseq += bp->rx_buf_use_size;
+       if (cons == prod)
+               return;
+
+       pci_unmap_addr_set(prod_rx_buf, mapping,
+                       pci_unmap_addr(cons_rx_buf, mapping));
 
+       cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
+       prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
+       prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
+       prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
 }
 
 static int
@@ -1663,14 +1752,19 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
                u32 status;
                struct sw_bd *rx_buf;
                struct sk_buff *skb;
+               dma_addr_t dma_addr;
 
                sw_ring_cons = RX_RING_IDX(sw_cons);
                sw_ring_prod = RX_RING_IDX(sw_prod);
 
                rx_buf = &bp->rx_buf_ring[sw_ring_cons];
                skb = rx_buf->skb;
-               pci_dma_sync_single_for_cpu(bp->pdev,
-                       pci_unmap_addr(rx_buf, mapping),
+
+               rx_buf->skb = NULL;
+
+               dma_addr = pci_unmap_addr(rx_buf, mapping);
+
+               pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
                        bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
                rx_hdr = (struct l2_fhdr *) skb->data;
@@ -1711,8 +1805,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
                        skb = new_skb;
                }
                else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) {
-                       pci_unmap_single(bp->pdev,
-                               pci_unmap_addr(rx_buf, mapping),
+                       pci_unmap_single(bp->pdev, dma_addr,
                                bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
 
                        skb_reserve(skb, bp->rx_offset);
@@ -1728,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;
@@ -1758,8 +1851,6 @@ reuse_rx:
                rx_pkt++;
 
 next_rx:
-               rx_buf->skb = NULL;
-
                sw_cons = NEXT_RX_BD(sw_cons);
                sw_prod = NEXT_RX_BD(sw_prod);
 
@@ -1795,7 +1886,7 @@ static irqreturn_t
 bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
 {
        struct net_device *dev = dev_instance;
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        prefetch(bp->status_blk);
        REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
@@ -1815,7 +1906,7 @@ static irqreturn_t
 bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
        struct net_device *dev = dev_instance;
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        /* When using INTx, it is possible for the interrupt to arrive
         * at the CPU before the status block posted prior to the
@@ -1860,7 +1951,7 @@ bnx2_has_work(struct bnx2 *bp)
 static int
 bnx2_poll(struct net_device *dev, int *budget)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        if ((bp->status_blk->status_attn_bits &
                STATUS_ATTN_BITS_LINK_STATE) !=
@@ -1870,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)
@@ -1892,22 +1990,33 @@ bnx2_poll(struct net_device *dev, int *budget)
 
        if (!bnx2_has_work(bp)) {
                netif_rx_complete(dev);
+               if (likely(bp->flags & USING_MSI_FLAG)) {
+                       REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+                              BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+                              bp->last_status_idx);
+                       return 0;
+               }
                REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
-                       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
-                       bp->last_status_idx);
+                      BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+                      BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
+                      bp->last_status_idx);
+
+               REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+                      BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+                      bp->last_status_idx);
                return 0;
        }
 
        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
 bnx2_set_rx_mode(struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        u32 rx_mode, sort_mode;
        int i;
 
@@ -1975,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)
@@ -1984,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) {
@@ -2026,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]));
                }
        }
 
@@ -2082,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;
@@ -2114,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;
@@ -2160,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;
@@ -2206,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;
@@ -2252,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;
@@ -2276,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
@@ -2709,9 +2948,16 @@ bnx2_init_nvram(struct bnx2 *bp)
        if (j == entry_count) {
                bp->flash_info = NULL;
                printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
-               rc = -ENODEV;
+               return -ENODEV;
        }
 
+       val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
+       val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
+       if (val)
+               bp->flash_size = val;
+       else
+               bp->flash_size = bp->flash_info->total_size;
+
        return rc;
 }
 
@@ -2830,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;
 
@@ -2870,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;
@@ -2946,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))) {
@@ -2994,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;
@@ -3131,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);
@@ -3233,6 +3491,8 @@ bnx2_init_chip(struct bnx2 *bp)
 
        udelay(20);
 
+       bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
+
        return rc;
 }
 
@@ -3286,27 +3546,35 @@ bnx2_init_rx_ring(struct bnx2 *bp)
        bp->hw_rx_cons = 0;
        bp->rx_prod_bseq = 0;
                
-       rxbd = &bp->rx_desc_ring[0];
-       for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
-               rxbd->rx_bd_len = bp->rx_buf_use_size;
-               rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
-       }
+       for (i = 0; i < bp->rx_max_ring; i++) {
+               int j;
 
-       rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping >> 32;
-       rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping & 0xffffffff;
+               rxbd = &bp->rx_desc_ring[i][0];
+               for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
+                       rxbd->rx_bd_len = bp->rx_buf_use_size;
+                       rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
+               }
+               if (i == (bp->rx_max_ring - 1))
+                       j = 0;
+               else
+                       j = i + 1;
+               rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping[j] >> 32;
+               rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping[j] &
+                                      0xffffffff;
+       }
 
        val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
        val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
        val |= 0x02 << 8;
        CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
 
-       val = (u64) bp->rx_desc_mapping >> 32;
+       val = (u64) bp->rx_desc_mapping[0] >> 32;
        CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
 
-       val = (u64) bp->rx_desc_mapping & 0xffffffff;
+       val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
        CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
 
-       for ( ;ring_prod < bp->rx_ring_size; ) {
+       for (i = 0; i < bp->rx_ring_size; i++) {
                if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) {
                        break;
                }
@@ -3321,6 +3589,29 @@ bnx2_init_rx_ring(struct bnx2 *bp)
 }
 
 static void
+bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
+{
+       u32 num_rings, max;
+
+       bp->rx_ring_size = size;
+       num_rings = 1;
+       while (size > MAX_RX_DESC_CNT) {
+               size -= MAX_RX_DESC_CNT;
+               num_rings++;
+       }
+       /* round to next power of 2 */
+       max = MAX_RX_RINGS;
+       while ((max & num_rings) == 0)
+               max >>= 1;
+
+       if (num_rings != max)
+               max <<= 1;
+
+       bp->rx_max_ring = max;
+       bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
+}
+
+static void
 bnx2_free_tx_skbs(struct bnx2 *bp)
 {
        int i;
@@ -3365,7 +3656,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
        if (bp->rx_buf_ring == NULL)
                return;
 
-       for (i = 0; i < RX_DESC_CNT; i++) {
+       for (i = 0; i < bp->rx_max_ring_idx; i++) {
                struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
                struct sk_buff *skb = rx_buf->skb;
 
@@ -3398,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;
@@ -3422,7 +3715,7 @@ bnx2_test_registers(struct bnx2 *bp)
 {
        int ret;
        int i;
-       static struct {
+       static const struct {
                u16   offset;
                u16   flags;
                u32   rw_mask;
@@ -3452,74 +3745,9 @@ bnx2_test_registers(struct bnx2 *bp)
                { 0x0c00, 0, 0x00000000, 0x00000001 },
                { 0x0c04, 0, 0x00000000, 0x03ff0001 },
                { 0x0c08, 0, 0x0f0ff073, 0x00000000 },
-               { 0x0c0c, 0, 0x00ffffff, 0x00000000 },
-               { 0x0c30, 0, 0x00000000, 0xffffffff },
-               { 0x0c34, 0, 0x00000000, 0xffffffff },
-               { 0x0c38, 0, 0x00000000, 0xffffffff },
-               { 0x0c3c, 0, 0x00000000, 0xffffffff },
-               { 0x0c40, 0, 0x00000000, 0xffffffff },
-               { 0x0c44, 0, 0x00000000, 0xffffffff },
-               { 0x0c48, 0, 0x00000000, 0x0007ffff },
-               { 0x0c4c, 0, 0x00000000, 0xffffffff },
-               { 0x0c50, 0, 0x00000000, 0xffffffff },
-               { 0x0c54, 0, 0x00000000, 0xffffffff },
-               { 0x0c58, 0, 0x00000000, 0xffffffff },
-               { 0x0c5c, 0, 0x00000000, 0xffffffff },
-               { 0x0c60, 0, 0x00000000, 0xffffffff },
-               { 0x0c64, 0, 0x00000000, 0xffffffff },
-               { 0x0c68, 0, 0x00000000, 0xffffffff },
-               { 0x0c6c, 0, 0x00000000, 0xffffffff },
-               { 0x0c70, 0, 0x00000000, 0xffffffff },
-               { 0x0c74, 0, 0x00000000, 0xffffffff },
-               { 0x0c78, 0, 0x00000000, 0xffffffff },
-               { 0x0c7c, 0, 0x00000000, 0xffffffff },
-               { 0x0c80, 0, 0x00000000, 0xffffffff },
-               { 0x0c84, 0, 0x00000000, 0xffffffff },
-               { 0x0c88, 0, 0x00000000, 0xffffffff },
-               { 0x0c8c, 0, 0x00000000, 0xffffffff },
-               { 0x0c90, 0, 0x00000000, 0xffffffff },
-               { 0x0c94, 0, 0x00000000, 0xffffffff },
-               { 0x0c98, 0, 0x00000000, 0xffffffff },
-               { 0x0c9c, 0, 0x00000000, 0xffffffff },
-               { 0x0ca0, 0, 0x00000000, 0xffffffff },
-               { 0x0ca4, 0, 0x00000000, 0xffffffff },
-               { 0x0ca8, 0, 0x00000000, 0x0007ffff },
-               { 0x0cac, 0, 0x00000000, 0xffffffff },
-               { 0x0cb0, 0, 0x00000000, 0xffffffff },
-               { 0x0cb4, 0, 0x00000000, 0xffffffff },
-               { 0x0cb8, 0, 0x00000000, 0xffffffff },
-               { 0x0cbc, 0, 0x00000000, 0xffffffff },
-               { 0x0cc0, 0, 0x00000000, 0xffffffff },
-               { 0x0cc4, 0, 0x00000000, 0xffffffff },
-               { 0x0cc8, 0, 0x00000000, 0xffffffff },
-               { 0x0ccc, 0, 0x00000000, 0xffffffff },
-               { 0x0cd0, 0, 0x00000000, 0xffffffff },
-               { 0x0cd4, 0, 0x00000000, 0xffffffff },
-               { 0x0cd8, 0, 0x00000000, 0xffffffff },
-               { 0x0cdc, 0, 0x00000000, 0xffffffff },
-               { 0x0ce0, 0, 0x00000000, 0xffffffff },
-               { 0x0ce4, 0, 0x00000000, 0xffffffff },
-               { 0x0ce8, 0, 0x00000000, 0xffffffff },
-               { 0x0cec, 0, 0x00000000, 0xffffffff },
-               { 0x0cf0, 0, 0x00000000, 0xffffffff },
-               { 0x0cf4, 0, 0x00000000, 0xffffffff },
-               { 0x0cf8, 0, 0x00000000, 0xffffffff },
-               { 0x0cfc, 0, 0x00000000, 0xffffffff },
-               { 0x0d00, 0, 0x00000000, 0xffffffff },
-               { 0x0d04, 0, 0x00000000, 0xffffffff },
 
                { 0x1000, 0, 0x00000000, 0x00000001 },
                { 0x1004, 0, 0x00000000, 0x000f0001 },
-               { 0x1044, 0, 0x00000000, 0xffc003ff },
-               { 0x1080, 0, 0x00000000, 0x0001ffff },
-               { 0x1084, 0, 0x00000000, 0xffffffff },
-               { 0x1088, 0, 0x00000000, 0xffffffff },
-               { 0x108c, 0, 0x00000000, 0xffffffff },
-               { 0x1090, 0, 0x00000000, 0xffffffff },
-               { 0x1094, 0, 0x00000000, 0xffffffff },
-               { 0x1098, 0, 0x00000000, 0xffffffff },
-               { 0x109c, 0, 0x00000000, 0xffffffff },
-               { 0x10a0, 0, 0x00000000, 0xffffffff },
 
                { 0x1408, 0, 0x01c00800, 0x00000000 },
                { 0x149c, 0, 0x8000ffff, 0x00000000 },
@@ -3531,111 +3759,9 @@ bnx2_test_registers(struct bnx2 *bp)
                { 0x14c4, 0, 0x00003fff, 0x00000000 },
                { 0x14cc, 0, 0x00000000, 0x00000001 },
                { 0x14d0, 0, 0xffffffff, 0x00000000 },
-               { 0x1500, 0, 0x00000000, 0xffffffff },
-               { 0x1504, 0, 0x00000000, 0xffffffff },
-               { 0x1508, 0, 0x00000000, 0xffffffff },
-               { 0x150c, 0, 0x00000000, 0xffffffff },
-               { 0x1510, 0, 0x00000000, 0xffffffff },
-               { 0x1514, 0, 0x00000000, 0xffffffff },
-               { 0x1518, 0, 0x00000000, 0xffffffff },
-               { 0x151c, 0, 0x00000000, 0xffffffff },
-               { 0x1520, 0, 0x00000000, 0xffffffff },
-               { 0x1524, 0, 0x00000000, 0xffffffff },
-               { 0x1528, 0, 0x00000000, 0xffffffff },
-               { 0x152c, 0, 0x00000000, 0xffffffff },
-               { 0x1530, 0, 0x00000000, 0xffffffff },
-               { 0x1534, 0, 0x00000000, 0xffffffff },
-               { 0x1538, 0, 0x00000000, 0xffffffff },
-               { 0x153c, 0, 0x00000000, 0xffffffff },
-               { 0x1540, 0, 0x00000000, 0xffffffff },
-               { 0x1544, 0, 0x00000000, 0xffffffff },
-               { 0x1548, 0, 0x00000000, 0xffffffff },
-               { 0x154c, 0, 0x00000000, 0xffffffff },
-               { 0x1550, 0, 0x00000000, 0xffffffff },
-               { 0x1554, 0, 0x00000000, 0xffffffff },
-               { 0x1558, 0, 0x00000000, 0xffffffff },
-               { 0x1600, 0, 0x00000000, 0xffffffff },
-               { 0x1604, 0, 0x00000000, 0xffffffff },
-               { 0x1608, 0, 0x00000000, 0xffffffff },
-               { 0x160c, 0, 0x00000000, 0xffffffff },
-               { 0x1610, 0, 0x00000000, 0xffffffff },
-               { 0x1614, 0, 0x00000000, 0xffffffff },
-               { 0x1618, 0, 0x00000000, 0xffffffff },
-               { 0x161c, 0, 0x00000000, 0xffffffff },
-               { 0x1620, 0, 0x00000000, 0xffffffff },
-               { 0x1624, 0, 0x00000000, 0xffffffff },
-               { 0x1628, 0, 0x00000000, 0xffffffff },
-               { 0x162c, 0, 0x00000000, 0xffffffff },
-               { 0x1630, 0, 0x00000000, 0xffffffff },
-               { 0x1634, 0, 0x00000000, 0xffffffff },
-               { 0x1638, 0, 0x00000000, 0xffffffff },
-               { 0x163c, 0, 0x00000000, 0xffffffff },
-               { 0x1640, 0, 0x00000000, 0xffffffff },
-               { 0x1644, 0, 0x00000000, 0xffffffff },
-               { 0x1648, 0, 0x00000000, 0xffffffff },
-               { 0x164c, 0, 0x00000000, 0xffffffff },
-               { 0x1650, 0, 0x00000000, 0xffffffff },
-               { 0x1654, 0, 0x00000000, 0xffffffff },
 
                { 0x1800, 0, 0x00000000, 0x00000001 },
                { 0x1804, 0, 0x00000000, 0x00000003 },
-               { 0x1840, 0, 0x00000000, 0xffffffff },
-               { 0x1844, 0, 0x00000000, 0xffffffff },
-               { 0x1848, 0, 0x00000000, 0xffffffff },
-               { 0x184c, 0, 0x00000000, 0xffffffff },
-               { 0x1850, 0, 0x00000000, 0xffffffff },
-               { 0x1900, 0, 0x7ffbffff, 0x00000000 },
-               { 0x1904, 0, 0xffffffff, 0x00000000 },
-               { 0x190c, 0, 0xffffffff, 0x00000000 },
-               { 0x1914, 0, 0xffffffff, 0x00000000 },
-               { 0x191c, 0, 0xffffffff, 0x00000000 },
-               { 0x1924, 0, 0xffffffff, 0x00000000 },
-               { 0x192c, 0, 0xffffffff, 0x00000000 },
-               { 0x1934, 0, 0xffffffff, 0x00000000 },
-               { 0x193c, 0, 0xffffffff, 0x00000000 },
-               { 0x1944, 0, 0xffffffff, 0x00000000 },
-               { 0x194c, 0, 0xffffffff, 0x00000000 },
-               { 0x1954, 0, 0xffffffff, 0x00000000 },
-               { 0x195c, 0, 0xffffffff, 0x00000000 },
-               { 0x1964, 0, 0xffffffff, 0x00000000 },
-               { 0x196c, 0, 0xffffffff, 0x00000000 },
-               { 0x1974, 0, 0xffffffff, 0x00000000 },
-               { 0x197c, 0, 0xffffffff, 0x00000000 },
-               { 0x1980, 0, 0x0700ffff, 0x00000000 },
-
-               { 0x1c00, 0, 0x00000000, 0x00000001 },
-               { 0x1c04, 0, 0x00000000, 0x00000003 },
-               { 0x1c08, 0, 0x0000000f, 0x00000000 },
-               { 0x1c40, 0, 0x00000000, 0xffffffff },
-               { 0x1c44, 0, 0x00000000, 0xffffffff },
-               { 0x1c48, 0, 0x00000000, 0xffffffff },
-               { 0x1c4c, 0, 0x00000000, 0xffffffff },
-               { 0x1c50, 0, 0x00000000, 0xffffffff },
-               { 0x1d00, 0, 0x7ffbffff, 0x00000000 },
-               { 0x1d04, 0, 0xffffffff, 0x00000000 },
-               { 0x1d0c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d14, 0, 0xffffffff, 0x00000000 },
-               { 0x1d1c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d24, 0, 0xffffffff, 0x00000000 },
-               { 0x1d2c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d34, 0, 0xffffffff, 0x00000000 },
-               { 0x1d3c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d44, 0, 0xffffffff, 0x00000000 },
-               { 0x1d4c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d54, 0, 0xffffffff, 0x00000000 },
-               { 0x1d5c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d64, 0, 0xffffffff, 0x00000000 },
-               { 0x1d6c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d74, 0, 0xffffffff, 0x00000000 },
-               { 0x1d7c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d80, 0, 0x0700ffff, 0x00000000 },
-
-               { 0x2004, 0, 0x00000000, 0x0337000f },
-               { 0x2008, 0, 0xffffffff, 0x00000000 },
-               { 0x200c, 0, 0xffffffff, 0x00000000 },
-               { 0x2010, 0, 0xffffffff, 0x00000000 },
-               { 0x2014, 0, 0x801fff80, 0x00000000 },
-               { 0x2018, 0, 0x000003ff, 0x00000000 },
 
                { 0x2800, 0, 0x00000000, 0x00000001 },
                { 0x2804, 0, 0x00000000, 0x00003f01 },
@@ -3653,16 +3779,6 @@ bnx2_test_registers(struct bnx2 *bp)
                { 0x2c00, 0, 0x00000000, 0x00000011 },
                { 0x2c04, 0, 0x00000000, 0x00030007 },
 
-               { 0x3000, 0, 0x00000000, 0x00000001 },
-               { 0x3004, 0, 0x00000000, 0x007007ff },
-               { 0x3008, 0, 0x00000003, 0x00000000 },
-               { 0x300c, 0, 0xffffffff, 0x00000000 },
-               { 0x3010, 0, 0xffffffff, 0x00000000 },
-               { 0x3014, 0, 0xffffffff, 0x00000000 },
-               { 0x3034, 0, 0xffffffff, 0x00000000 },
-               { 0x3038, 0, 0xffffffff, 0x00000000 },
-               { 0x3050, 0, 0x00000001, 0x00000000 },
-
                { 0x3c00, 0, 0x00000000, 0x00000001 },
                { 0x3c04, 0, 0x00000000, 0x00070000 },
                { 0x3c08, 0, 0x00007f71, 0x07f00000 },
@@ -3672,88 +3788,11 @@ bnx2_test_registers(struct bnx2 *bp)
                { 0x3c18, 0, 0x00000000, 0xffffffff },
                { 0x3c1c, 0, 0xfffff000, 0x00000000 },
                { 0x3c20, 0, 0xffffff00, 0x00000000 },
-               { 0x3c24, 0, 0xffffffff, 0x00000000 },
-               { 0x3c28, 0, 0xffffffff, 0x00000000 },
-               { 0x3c2c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c30, 0, 0xffffffff, 0x00000000 },
-               { 0x3c34, 0, 0xffffffff, 0x00000000 },
-               { 0x3c38, 0, 0xffffffff, 0x00000000 },
-               { 0x3c3c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c40, 0, 0xffffffff, 0x00000000 },
-               { 0x3c44, 0, 0xffffffff, 0x00000000 },
-               { 0x3c48, 0, 0xffffffff, 0x00000000 },
-               { 0x3c4c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c50, 0, 0xffffffff, 0x00000000 },
-               { 0x3c54, 0, 0xffffffff, 0x00000000 },
-               { 0x3c58, 0, 0xffffffff, 0x00000000 },
-               { 0x3c5c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c60, 0, 0xffffffff, 0x00000000 },
-               { 0x3c64, 0, 0xffffffff, 0x00000000 },
-               { 0x3c68, 0, 0xffffffff, 0x00000000 },
-               { 0x3c6c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c70, 0, 0xffffffff, 0x00000000 },
-               { 0x3c74, 0, 0x0000003f, 0x00000000 },
-               { 0x3c78, 0, 0x00000000, 0x00000000 },
-               { 0x3c7c, 0, 0x00000000, 0x00000000 },
-               { 0x3c80, 0, 0x3fffffff, 0x00000000 },
-               { 0x3c84, 0, 0x0000003f, 0x00000000 },
-               { 0x3c88, 0, 0x00000000, 0xffffffff },
-               { 0x3c8c, 0, 0x00000000, 0xffffffff },
-
-               { 0x4000, 0, 0x00000000, 0x00000001 },
-               { 0x4004, 0, 0x00000000, 0x00030000 },
-               { 0x4008, 0, 0x00000ff0, 0x00000000 },
-               { 0x400c, 0, 0xffffffff, 0x00000000 },
-               { 0x4088, 0, 0x00000000, 0x00070303 },
-
-               { 0x4400, 0, 0x00000000, 0x00000001 },
-               { 0x4404, 0, 0x00000000, 0x00003f01 },
-               { 0x4408, 0, 0x7fff00ff, 0x00000000 },
-               { 0x440c, 0, 0xffffffff, 0x00000000 },
-               { 0x4410, 0, 0xffff,     0x0000 },
-               { 0x4414, 0, 0xffff,     0x0000 },
-               { 0x4418, 0, 0xffff,     0x0000 },
-               { 0x441c, 0, 0xffff,     0x0000 },
-               { 0x4428, 0, 0xffffffff, 0x00000000 },
-               { 0x442c, 0, 0xffffffff, 0x00000000 },
-               { 0x4430, 0, 0xffffffff, 0x00000000 },
-               { 0x4434, 0, 0xffffffff, 0x00000000 },
-               { 0x4438, 0, 0xffffffff, 0x00000000 },
-               { 0x443c, 0, 0xffffffff, 0x00000000 },
-               { 0x4440, 0, 0xffffffff, 0x00000000 },
-               { 0x4444, 0, 0xffffffff, 0x00000000 },
-
-               { 0x4c00, 0, 0x00000000, 0x00000001 },
-               { 0x4c04, 0, 0x00000000, 0x0000003f },
-               { 0x4c08, 0, 0xffffffff, 0x00000000 },
-               { 0x4c0c, 0, 0x0007fc00, 0x00000000 },
-               { 0x4c10, 0, 0x80003fe0, 0x00000000 },
-               { 0x4c14, 0, 0xffffffff, 0x00000000 },
-               { 0x4c44, 0, 0x00000000, 0x9fff9fff },
-               { 0x4c48, 0, 0x00000000, 0xb3009fff },
-               { 0x4c4c, 0, 0x00000000, 0x77f33b30 },
-               { 0x4c50, 0, 0x00000000, 0xffffffff },
 
                { 0x5004, 0, 0x00000000, 0x0000007f },
                { 0x5008, 0, 0x0f0007ff, 0x00000000 },
                { 0x500c, 0, 0xf800f800, 0x07ff07ff },
 
-               { 0x5400, 0, 0x00000008, 0x00000001 },
-               { 0x5404, 0, 0x00000000, 0x0000003f },
-               { 0x5408, 0, 0x0000001f, 0x00000000 },
-               { 0x540c, 0, 0xffffffff, 0x00000000 },
-               { 0x5410, 0, 0xffffffff, 0x00000000 },
-               { 0x5414, 0, 0x0000ffff, 0x00000000 },
-               { 0x5418, 0, 0x0000ffff, 0x00000000 },
-               { 0x541c, 0, 0x0000ffff, 0x00000000 },
-               { 0x5420, 0, 0x0000ffff, 0x00000000 },
-               { 0x5428, 0, 0x000000ff, 0x00000000 },
-               { 0x542c, 0, 0xff00ffff, 0x00000000 },
-               { 0x5430, 0, 0x001fff80, 0x00000000 },
-               { 0x5438, 0, 0xffffffff, 0x00000000 },
-               { 0x543c, 0, 0xffffffff, 0x00000000 },
-               { 0x5440, 0, 0xf800f800, 0x07ff07ff },
-
                { 0x5c00, 0, 0x00000000, 0x00000001 },
                { 0x5c04, 0, 0x00000000, 0x0003000f },
                { 0x5c08, 0, 0x00000003, 0x00000000 },
@@ -3837,7 +3876,7 @@ reg_test_err:
 static int
 bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
 {
-       static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
+       static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
                0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
        int i;
 
@@ -3862,7 +3901,7 @@ bnx2_test_memory(struct bnx2 *bp)
 {
        int ret = 0;
        int i;
-       static struct {
+       static const struct {
                u32   offset;
                u32   len;
        } mem_tbl[] = {
@@ -3885,26 +3924,32 @@ bnx2_test_memory(struct bnx2 *bp)
        return ret;
 }
 
+#define BNX2_MAC_LOOPBACK      0
+#define BNX2_PHY_LOOPBACK      1
+
 static int
-bnx2_test_loopback(struct bnx2 *bp)
+bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
 {
        unsigned int pkt_size, num_pkts, i;
        struct sk_buff *skb, *rx_skb;
        unsigned char *packet;
-       u16 rx_start_idx, rx_idx, send_idx;
-       u32 send_bseq, val;
+       u16 rx_start_idx, rx_idx;
        dma_addr_t map;
        struct tx_bd *txbd;
        struct sw_bd *rx_buf;
        struct l2_fhdr *rx_hdr;
        int ret = -ENODEV;
 
-       if (!netif_running(bp->dev))
-               return -ENODEV;
-
-       bp->loopback = MAC_LOOPBACK;
-       bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_DIAG);
-       bnx2_set_mac_loopback(bp);
+       if (loopback_mode == BNX2_MAC_LOOPBACK) {
+               bp->loopback = MAC_LOOPBACK;
+               bnx2_set_mac_loopback(bp);
+       }
+       else if (loopback_mode == BNX2_PHY_LOOPBACK) {
+               bp->loopback = 0;
+               bnx2_set_phy_loopback(bp);
+       }
+       else
+               return -EINVAL;
 
        pkt_size = 1514;
        skb = dev_alloc_skb(pkt_size);
@@ -3919,18 +3964,17 @@ bnx2_test_loopback(struct bnx2 *bp)
        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);
        rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0;
 
-       send_idx = 0;
-       send_bseq = 0;
        num_pkts = 0;
 
-       txbd = &bp->tx_desc_ring[send_idx];
+       txbd = &bp->tx_desc_ring[TX_RING_IDX(bp->tx_prod)];
 
        txbd->tx_bd_haddr_hi = (u64) map >> 32;
        txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
@@ -3938,18 +3982,17 @@ bnx2_test_loopback(struct bnx2 *bp)
        txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
 
        num_pkts++;
-       send_idx = NEXT_TX_BD(send_idx);
-
-       send_bseq += pkt_size;
-
-       REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, send_idx);
-       REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, send_bseq);
+       bp->tx_prod = NEXT_TX_BD(bp->tx_prod);
+       bp->tx_prod_bseq += pkt_size;
 
+       REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, bp->tx_prod);
+       REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, bp->tx_prod_bseq);
 
        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);
@@ -3957,7 +4000,7 @@ bnx2_test_loopback(struct bnx2 *bp)
        pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
        dev_kfree_skb_irq(skb);
 
-       if (bp->status_blk->status_tx_quick_consumer_index0 != send_idx) {
+       if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) {
                goto loopback_test_done;
        }
 
@@ -4003,6 +4046,30 @@ loopback_test_done:
        return ret;
 }
 
+#define BNX2_MAC_LOOPBACK_FAILED       1
+#define BNX2_PHY_LOOPBACK_FAILED       2
+#define BNX2_LOOPBACK_FAILED           (BNX2_MAC_LOOPBACK_FAILED |     \
+                                        BNX2_PHY_LOOPBACK_FAILED)
+
+static int
+bnx2_test_loopback(struct bnx2 *bp)
+{
+       int rc = 0;
+
+       if (!netif_running(bp->dev))
+               return BNX2_LOOPBACK_FAILED;
+
+       bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
+       spin_lock_bh(&bp->phy_lock);
+       bnx2_init_phy(bp);
+       spin_unlock_bh(&bp->phy_lock);
+       if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
+               rc |= BNX2_MAC_LOOPBACK_FAILED;
+       if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
+               rc |= BNX2_PHY_LOOPBACK_FAILED;
+       return rc;
+}
+
 #define NVRAM_SIZE 0x200
 #define CRC32_RESIDUAL 0xdebb20e3
 
@@ -4061,7 +4128,6 @@ static int
 bnx2_test_intr(struct bnx2 *bp)
 {
        int i;
-       u32 val;
        u16 status_idx;
 
        if (!netif_running(bp->dev))
@@ -4070,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++) {
@@ -4104,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)) {
 
@@ -4172,7 +4239,7 @@ bnx2_restart_timer:
 static int
 bnx2_open(struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        int rc;
 
        bnx2_set_power_state(bp, PCI_D0);
@@ -4285,7 +4352,7 @@ bnx2_reset_task(void *data)
 static void
 bnx2_tx_timeout(struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        /* This allows the netif to be shutdown gracefully before resetting */
        schedule_work(&bp->reset_task);
@@ -4296,7 +4363,7 @@ bnx2_tx_timeout(struct net_device *dev)
 static void
 bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        bnx2_netif_stop(bp);
 
@@ -4310,7 +4377,7 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
 static void
 bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        bnx2_netif_stop(bp);
 
@@ -4322,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
@@ -4331,7 +4398,7 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
 static int
 bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        dma_addr_t mapping;
        struct tx_bd *txbd;
        struct sw_bd *tx_buf;
@@ -4380,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,
@@ -4460,7 +4527,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static int
 bnx2_close(struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        u32 reset_code;
 
        /* Calling flush_scheduled_work() may deadlock because
@@ -4508,7 +4575,7 @@ bnx2_close(struct net_device *dev)
 static struct net_device_stats *
 bnx2_get_stats(struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        struct statistics_block *stats_blk = bp->stats_blk;
        struct net_device_stats *net_stats = &bp->net_stats;
 
@@ -4574,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;
 }
 
@@ -4582,7 +4653,7 @@ bnx2_get_stats(struct net_device *dev)
 static int
 bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        cmd->supported = SUPPORTED_Autoneg;
        if (bp->phy_flags & PHY_SERDES_FLAG) {
@@ -4629,7 +4700,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static int
 bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        u8 autoneg = bp->autoneg;
        u8 req_duplex = bp->req_duplex;
        u16 req_line_speed = bp->req_line_speed;
@@ -4701,7 +4772,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void
 bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        strcpy(info->driver, DRV_MODULE_NAME);
        strcpy(info->version, DRV_MODULE_VERSION);
@@ -4709,15 +4780,72 @@ bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        info->fw_version[0] = ((bp->fw_ver & 0xff000000) >> 24) + '0';
        info->fw_version[2] = ((bp->fw_ver & 0xff0000) >> 16) + '0';
        info->fw_version[4] = ((bp->fw_ver & 0xff00) >> 8) + '0';
-       info->fw_version[6] = (bp->fw_ver & 0xff) + '0';
-       info->fw_version[1] = info->fw_version[3] = info->fw_version[5] = '.';
-       info->fw_version[7] = 0;
+       info->fw_version[1] = info->fw_version[3] = '.';
+       info->fw_version[5] = 0;
+}
+
+#define BNX2_REGDUMP_LEN               (32 * 1024)
+
+static int
+bnx2_get_regs_len(struct net_device *dev)
+{
+       return BNX2_REGDUMP_LEN;
+}
+
+static void
+bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
+{
+       u32 *p = _p, i, offset;
+       u8 *orig_p = _p;
+       struct bnx2 *bp = netdev_priv(dev);
+       u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
+                                0x0800, 0x0880, 0x0c00, 0x0c10,
+                                0x0c30, 0x0d08, 0x1000, 0x101c,
+                                0x1040, 0x1048, 0x1080, 0x10a4,
+                                0x1400, 0x1490, 0x1498, 0x14f0,
+                                0x1500, 0x155c, 0x1580, 0x15dc,
+                                0x1600, 0x1658, 0x1680, 0x16d8,
+                                0x1800, 0x1820, 0x1840, 0x1854,
+                                0x1880, 0x1894, 0x1900, 0x1984,
+                                0x1c00, 0x1c0c, 0x1c40, 0x1c54,
+                                0x1c80, 0x1c94, 0x1d00, 0x1d84,
+                                0x2000, 0x2030, 0x23c0, 0x2400,
+                                0x2800, 0x2820, 0x2830, 0x2850,
+                                0x2b40, 0x2c10, 0x2fc0, 0x3058,
+                                0x3c00, 0x3c94, 0x4000, 0x4010,
+                                0x4080, 0x4090, 0x43c0, 0x4458,
+                                0x4c00, 0x4c18, 0x4c40, 0x4c54,
+                                0x4fc0, 0x5010, 0x53c0, 0x5444,
+                                0x5c00, 0x5c18, 0x5c80, 0x5c90,
+                                0x5fc0, 0x6000, 0x6400, 0x6428,
+                                0x6800, 0x6848, 0x684c, 0x6860,
+                                0x6888, 0x6910, 0x8000 };
+
+       regs->version = 0;
+
+       memset(p, 0, BNX2_REGDUMP_LEN);
+
+       if (!netif_running(bp->dev))
+               return;
+
+       i = 0;
+       offset = reg_boundaries[0];
+       p += offset;
+       while (offset < BNX2_REGDUMP_LEN) {
+               *p++ = REG_RD(bp, offset);
+               offset += 4;
+               if (offset == reg_boundaries[i + 1]) {
+                       offset = reg_boundaries[i + 2];
+                       p = (u32 *) (orig_p + offset);
+                       i += 2;
+               }
+       }
 }
 
 static void
 bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        if (bp->flags & NO_WOL_FLAG) {
                wol->supported = 0;
@@ -4736,7 +4864,7 @@ bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static int
 bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EINVAL;
@@ -4756,7 +4884,7 @@ bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static int
 bnx2_nway_reset(struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        u32 bmcr;
 
        if (!(bp->autoneg & AUTONEG_SPEED)) {
@@ -4792,19 +4920,19 @@ bnx2_nway_reset(struct net_device *dev)
 static int
 bnx2_get_eeprom_len(struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
-       if (bp->flash_info == 0)
+       if (bp->flash_info == NULL)
                return 0;
 
-       return (int) bp->flash_info->total_size;
+       return (int) bp->flash_size;
 }
 
 static int
 bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                u8 *eebuf)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        int rc;
 
        /* parameters already validated in ethtool_get_eeprom */
@@ -4818,7 +4946,7 @@ static int
 bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                u8 *eebuf)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        int rc;
 
        /* parameters already validated in ethtool_set_eeprom */
@@ -4831,7 +4959,7 @@ bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 static int
 bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        memset(coal, 0, sizeof(struct ethtool_coalesce));
 
@@ -4853,7 +4981,7 @@ bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
 static int
 bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
        if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
@@ -4897,9 +5025,9 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
 static void
 bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
-       ering->rx_max_pending = MAX_RX_DESC_CNT;
+       ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
        ering->rx_mini_max_pending = 0;
        ering->rx_jumbo_max_pending = 0;
 
@@ -4914,19 +5042,30 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 static int
 bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
-       if ((ering->rx_pending > MAX_RX_DESC_CNT) ||
+       if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
                (ering->tx_pending > MAX_TX_DESC_CNT) ||
                (ering->tx_pending <= MAX_SKB_FRAGS)) {
 
                return -EINVAL;
        }
-       bp->rx_ring_size = ering->rx_pending;
+       if (netif_running(bp->dev)) {
+               bnx2_netif_stop(bp);
+               bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
+               bnx2_free_skbs(bp);
+               bnx2_free_mem(bp);
+       }
+
+       bnx2_set_rx_ring_size(bp, ering->rx_pending);
        bp->tx_ring_size = ering->tx_pending;
 
        if (netif_running(bp->dev)) {
-               bnx2_netif_stop(bp);
+               int rc;
+
+               rc = bnx2_alloc_mem(bp);
+               if (rc)
+                       return rc;
                bnx2_init_nic(bp);
                bnx2_netif_start(bp);
        }
@@ -4937,7 +5076,7 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 static void
 bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
        epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
@@ -4947,7 +5086,7 @@ bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 static int
 bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        bp->req_flow_ctrl = 0;
        if (epause->rx_pause)
@@ -4974,7 +5113,7 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 static u32
 bnx2_get_rx_csum(struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        return bp->rx_csum;
 }
@@ -4982,13 +5121,13 @@ bnx2_get_rx_csum(struct net_device *dev)
 static int
 bnx2_set_rx_csum(struct net_device *dev, u32 data)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        bp->rx_csum = data;
        return 0;
 }
 
-#define BNX2_NUM_STATS 45
+#define BNX2_NUM_STATS 46
 
 static struct {
        char string[ETH_GSTRING_LEN];
@@ -5038,11 +5177,12 @@ 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)
 
-static unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
+static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
     STATS_OFFSET32(stat_IfHCInOctets_hi),
     STATS_OFFSET32(stat_IfHCInBadOctets_hi),
     STATS_OFFSET32(stat_IfHCOutOctets_hi),
@@ -5088,6 +5228,7 @@ static 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
@@ -5098,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] = {
@@ -5106,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
@@ -5131,7 +5272,7 @@ bnx2_self_test_count(struct net_device *dev)
 static void
 bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
        if (etest->flags & ETH_TEST_FL_OFFLINE) {
@@ -5147,10 +5288,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
                        buf[1] = 1;
                        etest->flags |= ETH_TEST_FL_FAILED;
                }
-               if (bnx2_test_loopback(bp) != 0) {
-                       buf[2] = 1;
+               if ((buf[2] = bnx2_test_loopback(bp)) != 0)
                        etest->flags |= ETH_TEST_FL_FAILED;
-               }
 
                if (!netif_running(bp->dev)) {
                        bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
@@ -5207,7 +5346,7 @@ static void
 bnx2_get_ethtool_stats(struct net_device *dev,
                struct ethtool_stats *stats, u64 *buf)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        int i;
        u32 *hw_stats = (u32 *) bp->stats_blk;
        u8 *stats_len_arr = NULL;
@@ -5247,7 +5386,7 @@ bnx2_get_ethtool_stats(struct net_device *dev,
 static int
 bnx2_phys_id(struct net_device *dev, u32 data)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        int i;
        u32 save;
 
@@ -5282,6 +5421,8 @@ static struct ethtool_ops bnx2_ethtool_ops = {
        .get_settings           = bnx2_get_settings,
        .set_settings           = bnx2_set_settings,
        .get_drvinfo            = bnx2_get_drvinfo,
+       .get_regs_len           = bnx2_get_regs_len,
+       .get_regs               = bnx2_get_regs,
        .get_wol                = bnx2_get_wol,
        .set_wol                = bnx2_set_wol,
        .nway_reset             = bnx2_nway_reset,
@@ -5319,7 +5460,7 @@ static int
 bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct mii_ioctl_data *data = if_mii(ifr);
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        int err;
 
        switch(cmd) {
@@ -5361,7 +5502,7 @@ static int
 bnx2_change_mac_addr(struct net_device *dev, void *p)
 {
        struct sockaddr *addr = p;
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EINVAL;
@@ -5377,7 +5518,7 @@ bnx2_change_mac_addr(struct net_device *dev, void *p)
 static int
 bnx2_change_mtu(struct net_device *dev, int new_mtu)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
                ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
@@ -5398,7 +5539,7 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu)
 static void
 poll_bnx2(struct net_device *dev)
 {
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        disable_irq(bp->pdev->irq);
        bnx2_interrupt(bp->pdev->irq, dev, NULL);
@@ -5416,7 +5557,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
        SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
-       bp = dev->priv;
+       bp = netdev_priv(dev);
 
        bp->flags = 0;
        bp->phy_flags = 0;
@@ -5600,7 +5741,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->mac_addr[5] = (u8) reg;
 
        bp->tx_ring_size = MAX_TX_DESC_CNT;
-       bp->rx_ring_size = 100;
+       bnx2_set_rx_ring_size(bp, 100);
 
        bp->rx_csum = 1;
 
@@ -5636,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) {
@@ -5735,7 +5878,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev->ethtool_ops = &bnx2_ethtool_ops;
        dev->weight = 64;
 
-       bp = dev->priv;
+       bp = netdev_priv(dev);
 
 #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
        dev->poll_controller = poll_bnx2;
@@ -5794,7 +5937,7 @@ static void __devexit
 bnx2_remove_one(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        flush_scheduled_work();
 
@@ -5813,12 +5956,13 @@ static int
 bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
        u32 reset_code;
 
        if (!netif_running(dev))
                return 0;
 
+       flush_scheduled_work();
        bnx2_netif_stop(bp);
        netif_device_detach(dev);
        del_timer_sync(&bp->timer);
@@ -5838,7 +5982,7 @@ static int
 bnx2_resume(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
-       struct bnx2 *bp = dev->priv;
+       struct bnx2 *bp = netdev_priv(dev);
 
        if (!netif_running(dev))
                return 0;