smp 64bit
[linux-2.6.git] / drivers / net / bnx2.c
index 652eb05..09a53ff 100644 (file)
@@ -9,9 +9,20 @@
  * Written by: Michael Chan  (mchan@broadcom.com)
  */
 
+#include <linux/config.h>
+
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < 0x020500)
+#if defined(CONFIG_MODVERSIONS) && defined(MODULE) && ! defined(MODVERSIONS)
+#define MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#endif
 
 #include <linux/module.h>
+#if (LINUX_VERSION_CODE >= 0x020600)
 #include <linux/moduleparam.h>
+#endif
 
 #include <linux/kernel.h>
 #include <linux/timer.h>
@@ -25,7 +36,9 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#if (LINUX_VERSION_CODE >= 0x020600)
 #include <linux/dma-mapping.h>
+#endif
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <net/tcp.h>
 #include <net/checksum.h>
 #define BCM_TSO 1
+#ifndef NETIF_F_GSO
+#define gso_size tso_size
 #endif
+#endif
+#if (LINUX_VERSION_CODE >= 0x020600)
 #include <linux/workqueue.h>
+#endif
+#ifndef BNX2_BOOT_DISK
 #include <linux/crc32.h>
+#endif
 #include <linux/prefetch.h>
 #include <linux/cache.h>
 #include <linux/zlib.h>
@@ -56,8 +76,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.4.44"
-#define DRV_MODULE_RELDATE     "August 10, 2006"
+#define DRV_MODULE_VERSION     "1.4.43f"
+#define DRV_MODULE_RELDATE     "June 26, 2006"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -72,10 +92,12 @@ MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
+#if (LINUX_VERSION_CODE >= 0x20600)
 static int disable_msi = 0;
 
 module_param(disable_msi, int, 0);
 MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
+#endif
 
 typedef enum {
        BCM5706 = 0,
@@ -207,12 +229,26 @@ static struct flash_spec flash_table[] =
 
 MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
 
+#ifdef BNX2_BOOT_DISK
+u32 ether_crc_le(size_t len, unsigned char const *p)
+{
+       u32 crc = ~0;
+       int i;
+#define CRCPOLY_LE 0xedb88320
+
+       while (len--) {
+               crc ^= *p++;
+               for (i = 0; i < 8; i++)
+                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+       }
+       return crc;
+}
+#endif
+
 static inline u32 bnx2_tx_avail(struct bnx2 *bp)
 {
-       u32 diff;
+       u32 diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons);
 
-       smp_mb();
-       diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons);
        if (diff > MAX_TX_DESC_CNT)
                diff = (diff & MAX_TX_DESC_CNT) - 1;
        return (bp->tx_ring_size - diff);
@@ -372,7 +408,11 @@ bnx2_disable_int_sync(struct bnx2 *bp)
 {
        atomic_inc(&bp->intr_sem);
        bnx2_disable_int(bp);
+#if (LINUX_VERSION_CODE >= 0x2051c)
        synchronize_irq(bp->pdev->irq);
+#else
+       synchronize_irq();
+#endif
 }
 
 static void
@@ -434,11 +474,12 @@ bnx2_alloc_mem(struct bnx2 *bp)
 {
        int i, status_blk_size;
 
-       bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
+       bp->tx_buf_ring = kmalloc(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,
@@ -1424,7 +1465,8 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
 
        /* wait for an acknowledgement. */
        for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
-               msleep(10);
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(HZ / 100);
 
                val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);
 
@@ -1571,7 +1613,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
        struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
        unsigned long align;
 
-       skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+       skb = dev_alloc_skb(bp->rx_buf_size);
        if (skb == NULL) {
                return -ENOMEM;
        }
@@ -1580,6 +1622,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
                skb_reserve(skb, 8 - align);
        }
 
+       skb->dev = bp->dev;
        mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
                PCI_DMA_FROMDEVICE);
 
@@ -1640,7 +1683,7 @@ bnx2_tx_int(struct bnx2 *bp)
                skb = tx_buf->skb;
 #ifdef BCM_TSO 
                /* partial BD completions possible with TSO packets */
-               if (skb_is_gso(skb)) {
+               if (skb_shinfo(skb)->gso_size) {
                        u16 last_idx, last_ring_idx;
 
                        last_idx = sw_cons +
@@ -1687,21 +1730,17 @@ bnx2_tx_int(struct bnx2 *bp)
        }
 
        bp->tx_cons = sw_cons;
-       /* Need to make the tx_cons update visible to bnx2_start_xmit()
-        * before checking for netif_queue_stopped().  Without the
-        * memory barrier, there is a small possibility that bnx2_start_xmit()
-        * will miss it and cause the queue to be stopped forever.
-        */
-       smp_mb();
 
-       if (unlikely(netif_queue_stopped(bp->dev)) &&
-                    (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) {
-               netif_tx_lock(bp->dev);
+       if (unlikely(netif_queue_stopped(bp->dev))) {
+               spin_lock(&bp->tx_lock);
                if ((netif_queue_stopped(bp->dev)) &&
-                   (bnx2_tx_avail(bp) > bp->tx_wake_thresh))
+                   (bnx2_tx_avail(bp) > MAX_SKB_FRAGS)) {
+
                        netif_wake_queue(bp->dev);
-               netif_tx_unlock(bp->dev);
+               }
+               spin_unlock(&bp->tx_lock);
        }
+
 }
 
 static inline void
@@ -1792,7 +1831,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
                if ((bp->dev->mtu > 1500) && (len <= RX_COPY_THRESH)) {
                        struct sk_buff *new_skb;
 
-                       new_skb = netdev_alloc_skb(bp->dev, len + 2);
+                       new_skb = dev_alloc_skb(len + 2);
                        if (new_skb == NULL)
                                goto reuse_rx;
 
@@ -1803,6 +1842,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
 
                        skb_reserve(new_skb, 2);
                        skb_put(new_skb, len);
+                       new_skb->dev = bp->dev;
 
                        bnx2_reuse_rx_skb(bp, skb,
                                sw_ring_cons, sw_ring_prod);
@@ -1884,6 +1924,7 @@ next_rx:
 
 }
 
+#ifdef CONFIG_PCI_MSI
 /* MSI ISR - The only difference between this and the INTx ISR
  * is that the MSI interrupt is always serviced.
  */
@@ -1906,6 +1947,7 @@ bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
 
        return IRQ_HANDLED;
 }
+#endif
 
 static irqreturn_t
 bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
@@ -2537,9 +2579,11 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
                        (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
                        PCI_PM_CTRL_PME_STATUS);
 
-               if (pmcsr & PCI_PM_CTRL_STATE_MASK)
+               if (pmcsr & PCI_PM_CTRL_STATE_MASK) {
                        /* delay required during transition out of D3hot */
-                       msleep(20);
+                       current->state = TASK_UNINTERRUPTIBLE;
+                       schedule_timeout(HZ / 50);
+               }
 
                val = REG_RD(bp, BNX2_EMAC_MODE);
                val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
@@ -2902,7 +2946,6 @@ bnx2_init_nvram(struct bnx2 *bp)
 
        rc = 0;
        if (val & 0x40000000) {
-
                /* Flash interface has been reconfigured */
                for (j = 0, flash = &flash_table[0]; j < entry_count;
                     j++, flash++) {
@@ -3296,8 +3339,10 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
        REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
 
        if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
-           (CHIP_ID(bp) == CHIP_ID_5706_A1))
-               msleep(15);
+           (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(HZ / 50);
+       }
 
        /* Reset takes approximate 30 usec */
        for (i = 0; i < 10; i++) {
@@ -3508,8 +3553,6 @@ bnx2_init_tx_ring(struct bnx2 *bp)
        struct tx_bd *txbd;
        u32 val;
 
-       bp->tx_wake_thresh = bp->tx_ring_size / 2;
-
        txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
                
        txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32;
@@ -3649,7 +3692,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
                                skb_shinfo(skb)->frags[j].size,
                                PCI_DMA_TODEVICE);
                }
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                i += j + 1;
        }
 
@@ -3675,7 +3718,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
 
                rx_buf->skb = NULL;
 
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
        }
 }
 
@@ -3959,7 +4002,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
                return -EINVAL;
 
        pkt_size = 1514;
-       skb = netdev_alloc_skb(bp->dev, pkt_size);
+       skb = dev_alloc_skb(pkt_size);
        if (!skb)
                return -ENOMEM;
        packet = skb_put(skb, pkt_size);
@@ -4153,7 +4196,8 @@ bnx2_test_intr(struct bnx2 *bp)
                        break;
                }
 
-               msleep_interruptible(10);
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(HZ / 100);
        }
        if (i < 10)
                return 0;
@@ -4256,6 +4300,7 @@ bnx2_open(struct net_device *dev)
        if (rc)
                return rc;
 
+#ifdef CONFIG_PCI_MSI
        if ((CHIP_ID(bp) != CHIP_ID_5706_A0) &&
                (CHIP_ID(bp) != CHIP_ID_5706_A1) &&
                !disable_msi) {
@@ -4267,11 +4312,13 @@ bnx2_open(struct net_device *dev)
                }
                else {
                        rc = request_irq(bp->pdev->irq, bnx2_interrupt,
-                                       IRQF_SHARED, dev->name, dev);
+                                       SA_SHIRQ, dev->name, dev);
                }
        }
-       else {
-               rc = request_irq(bp->pdev->irq, bnx2_interrupt, IRQF_SHARED,
+       else
+#endif
+       {
+               rc = request_irq(bp->pdev->irq, bnx2_interrupt, SA_SHIRQ,
                                dev->name, dev);
        }
        if (rc) {
@@ -4283,10 +4330,12 @@ bnx2_open(struct net_device *dev)
 
        if (rc) {
                free_irq(bp->pdev->irq, dev);
+#ifdef CONFIG_PCI_MSI
                if (bp->flags & USING_MSI_FLAG) {
                        pci_disable_msi(bp->pdev);
                        bp->flags &= ~USING_MSI_FLAG;
                }
+#endif
                bnx2_free_skbs(bp);
                bnx2_free_mem(bp);
                return rc;
@@ -4298,6 +4347,7 @@ bnx2_open(struct net_device *dev)
 
        bnx2_enable_int(bp);
 
+#ifdef CONFIG_PCI_MSI
        if (bp->flags & USING_MSI_FLAG) {
                /* Test MSI to make sure it is working
                 * If MSI test fails, go back to INTx mode
@@ -4318,7 +4368,7 @@ bnx2_open(struct net_device *dev)
 
                        if (!rc) {
                                rc = request_irq(bp->pdev->irq, bnx2_interrupt,
-                                       IRQF_SHARED, dev->name, dev);
+                                       SA_SHIRQ, dev->name, dev);
                        }
                        if (rc) {
                                bnx2_free_skbs(bp);
@@ -4332,6 +4382,7 @@ bnx2_open(struct net_device *dev)
        if (bp->flags & USING_MSI_FLAG) {
                printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
        }
+#endif
 
        netif_start_queue(dev);
 
@@ -4362,7 +4413,11 @@ bnx2_tx_timeout(struct net_device *dev)
        struct bnx2 *bp = netdev_priv(dev);
 
        /* This allows the netif to be shutdown gracefully before resetting */
+#if (LINUX_VERSION_CODE >= 0x20600)
        schedule_work(&bp->reset_task);
+#else
+       schedule_task(&bp->reset_task);
+#endif
 }
 
 #ifdef BCM_VLAN
@@ -4396,9 +4451,98 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
 }
 #endif
 
+/* Test for DMA addresses > 40-bit.
+ * Only 64-bit systems without IOMMU requires DMA address checking.
+ */
+static inline int bnx2_40bit_overflow_test(struct bnx2 *bp, dma_addr_t mapping,
+                                          int len)
+{
+#if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64)
+       if (CHIP_NUM(bp) == CHIP_NUM_5708)
+               return (((u64) mapping + len) > DMA_40BIT_MASK);
+       return 0;
+#else
+       return 0;
+#endif
+}
+
+#if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64)
+/* Workaround 40-bit hardware DMA bugs. */
+static int bnx2_dma_hwbug_workaround(struct bnx2 *bp, struct sk_buff **skb,
+                                    u16 *last_plus_one, u32 base_flags,
+                                    u32 mss)
+{
+       struct sk_buff *new_skb = skb_copy(*skb, GFP_ATOMIC);
+       dma_addr_t new_addr = 0;
+       int i, ret = 0;
+       u16 hw_prod = *last_plus_one;
+       u16 start, hw_start, prod;
+
+       prod = TX_RING_IDX(hw_prod);
+       start = prod - 1 - skb_shinfo(*skb)->nr_frags;
+       hw_start = hw_prod - 1 - skb_shinfo(*skb)->nr_frags;
+       start &= MAX_TX_DESC_CNT;
+       if (start > prod) {
+               start--;
+               hw_start--;
+       }
+
+       if (!new_skb) {
+               ret = -1;
+       } else {
+               struct tx_bd *txbd;
+
+               /* New SKB is guaranteed to be linear. */
+               new_addr = pci_map_single(bp->pdev, new_skb->data, new_skb->len,
+                                         PCI_DMA_TODEVICE);
+               txbd = &bp->tx_desc_ring[start];
+
+               txbd->tx_bd_haddr_hi = (u64) new_addr >> 32;
+               txbd->tx_bd_haddr_lo = (u64) new_addr & 0xffffffff;
+               txbd->tx_bd_mss_nbytes = new_skb->len | (mss << 16);
+               txbd->tx_bd_vlan_tag_flags = base_flags | TX_BD_FLAGS_START |
+                                            TX_BD_FLAGS_END;
+
+               *last_plus_one = NEXT_TX_BD(hw_start);
+       }
+
+       /* Now clean up the sw ring entries. */
+       i = 0;
+       while (start != prod) {
+               int len;
+
+               if (i == 0)
+                       len = skb_headlen(*skb);
+               else
+                       len = skb_shinfo(*skb)->frags[i-1].size;
+
+               pci_unmap_single(bp->pdev,
+                                pci_unmap_addr(&tp->tx_buf_ring[start],
+                                               mapping),
+                                len, PCI_DMA_TODEVICE);
+               if (i == 0) {
+                       bp->tx_buf_ring[start].skb = new_skb;
+                       pci_unmap_addr_set(&bp->tx_buf_ring[start], mapping,
+                                          new_addr);
+               }
+               hw_start = NEXT_TX_BD(hw_start);
+               start = TX_RING_IDX(hw_start);
+               i++;
+       }
+
+       dev_kfree_skb(*skb);
+
+       *skb = new_skb;
+
+       return ret;
+}
+#endif
+
 /* Called with netif_tx_lock.
- * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
- * netif_wake_queue().
+ * 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
+ * netif_stop_queue/wake_queue race conditions.
  */
 static int
 bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -4409,7 +4553,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct sw_bd *tx_buf;
        u32 len, vlan_tag_flags, last_frag, mss;
        u16 prod, ring_prod;
-       int i;
+       int i, would_hit_hwbug = 0;
 
        if (unlikely(bnx2_tx_avail(bp) < (skb_shinfo(skb)->nr_frags + 1))) {
                netif_stop_queue(dev);
@@ -4427,20 +4571,24 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
                vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
        }
 
+#ifdef BCM_VLAN
        if (bp->vlgrp != 0 && vlan_tx_tag_present(skb)) {
                vlan_tag_flags |=
                        (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
        }
+#endif
 #ifdef BCM_TSO 
        if ((mss = skb_shinfo(skb)->gso_size) &&
                (skb->len > (bp->dev->mtu + ETH_HLEN))) {
                u32 tcp_opt_len, ip_tcp_len;
 
+#if (LINUX_VERSION_CODE > 0x2060b)
                if (skb_header_cloned(skb) &&
                    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
                        dev_kfree_skb(skb);
                        return NETDEV_TX_OK;
                }
+#endif
 
                tcp_opt_len = ((skb->h.th->doff - 5) * 4);
                vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
@@ -4502,10 +4650,26 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
                txbd->tx_bd_mss_nbytes = len | (mss << 16);
                txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
 
+               if (bnx2_40bit_overflow_test(bp, mapping, len))
+                       would_hit_hwbug = 1;
        }
+
        txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
 
        prod = NEXT_TX_BD(prod);
+
+#if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64)
+       if (unlikely(would_hit_hwbug)) {
+               /* If the workaround fails due to memory/mapping
+                * failure, silently drop this packet.
+                */
+               if (bnx2_dma_hwbug_workaround(bp, &skb, &prod,
+                                             vlan_tag_flags, mss))
+                       return NETDEV_TX_OK;
+
+       }
+#endif
+
        bp->tx_prod_bseq += skb->len;
 
        REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, prod);
@@ -4517,9 +4681,12 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->trans_start = jiffies;
 
        if (unlikely(bnx2_tx_avail(bp) <= MAX_SKB_FRAGS)) {
+               spin_lock(&bp->tx_lock);
                netif_stop_queue(dev);
-               if (bnx2_tx_avail(bp) > bp->tx_wake_thresh)
+               
+               if (bnx2_tx_avail(bp) > MAX_SKB_FRAGS)
                        netif_wake_queue(dev);
+               spin_unlock(&bp->tx_lock);
        }
 
        return NETDEV_TX_OK;
@@ -4536,8 +4703,10 @@ bnx2_close(struct net_device *dev)
         * linkwatch_event() may be on the workqueue and it will try to get
         * the rtnl_lock which we are holding.
         */
-       while (bp->in_reset_task)
-               msleep(1);
+       while (bp->in_reset_task) {
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(1);
+       }
 
        bnx2_netif_stop(bp);
        del_timer_sync(&bp->timer);
@@ -4549,10 +4718,12 @@ bnx2_close(struct net_device *dev)
                reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
        bnx2_reset_chip(bp, reset_code);
        free_irq(bp->pdev->irq, dev);
+#ifdef CONFIG_PCI_MSI
        if (bp->flags & USING_MSI_FLAG) {
                pci_disable_msi(bp->pdev);
                bp->flags &= ~USING_MSI_FLAG;
        }
+#endif
        bnx2_free_skbs(bp);
        bnx2_free_mem(bp);
        bp->link_up = 0;
@@ -4900,7 +5071,8 @@ bnx2_nway_reset(struct net_device *dev)
                bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
                spin_unlock_bh(&bp->phy_lock);
 
-               msleep(20);
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(HZ / 50);
 
                spin_lock_bh(&bp->phy_lock);
                if (CHIP_NUM(bp) == CHIP_NUM_5706) {
@@ -4919,6 +5091,7 @@ bnx2_nway_reset(struct net_device *dev)
        return 0;
 }
 
+#if (LINUX_VERSION_CODE >= 0x20418)
 static int
 bnx2_get_eeprom_len(struct net_device *dev)
 {
@@ -4929,7 +5102,9 @@ bnx2_get_eeprom_len(struct net_device *dev)
 
        return (int) bp->flash_size;
 }
+#endif
 
+#ifdef ETHTOOL_GEEPROM
 static int
 bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                u8 *eebuf)
@@ -4943,7 +5118,9 @@ bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 
        return rc;
 }
+#endif
 
+#ifdef ETHTOOL_SEEPROM
 static int
 bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                u8 *eebuf)
@@ -4957,6 +5134,7 @@ bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 
        return rc;
 }
+#endif
 
 static int
 bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
@@ -5129,16 +5307,6 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data)
        return 0;
 }
 
-static int
-bnx2_set_tso(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-       else
-               dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
-       return 0;
-}
-
 #define BNX2_NUM_STATS 46
 
 static struct {
@@ -5312,9 +5480,12 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
                }
 
                /* wait for link up */
-               msleep_interruptible(3000);
-               if ((!bp->link_up) && !(bp->phy_flags & PHY_SERDES_FLAG))
-                       msleep_interruptible(4000);
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(3 * HZ);
+               if ((!bp->link_up) && !(bp->phy_flags & PHY_SERDES_FLAG)) {
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(4 * HZ);
+               }
        }
 
        if (bnx2_test_nvram(bp) != 0) {
@@ -5420,7 +5591,8 @@ bnx2_phys_id(struct net_device *dev, u32 data)
                                BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
                                BNX2_EMAC_LED_TRAFFIC);
                }
-               msleep_interruptible(500);
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(HZ / 2);
                if (signal_pending(current))
                        break;
        }
@@ -5439,9 +5611,15 @@ static struct ethtool_ops bnx2_ethtool_ops = {
        .set_wol                = bnx2_set_wol,
        .nway_reset             = bnx2_nway_reset,
        .get_link               = ethtool_op_get_link,
+#if (LINUX_VERSION_CODE >= 0x20418)
        .get_eeprom_len         = bnx2_get_eeprom_len,
+#endif
+#ifdef ETHTOOL_GEEPROM
        .get_eeprom             = bnx2_get_eeprom,
+#endif
+#ifdef ETHTOOL_SEEPROM
        .set_eeprom             = bnx2_set_eeprom,
+#endif
        .get_coalesce           = bnx2_get_coalesce,
        .set_coalesce           = bnx2_set_coalesce,
        .get_ringparam          = bnx2_get_ringparam,
@@ -5451,12 +5629,14 @@ static struct ethtool_ops bnx2_ethtool_ops = {
        .get_rx_csum            = bnx2_get_rx_csum,
        .set_rx_csum            = bnx2_set_rx_csum,
        .get_tx_csum            = ethtool_op_get_tx_csum,
+#if (LINUX_VERSION_CODE >= 0x20418)
        .set_tx_csum            = ethtool_op_set_tx_csum,
+#endif
        .get_sg                 = ethtool_op_get_sg,
        .set_sg                 = ethtool_op_set_sg,
 #ifdef BCM_TSO
        .get_tso                = ethtool_op_get_tso,
-       .set_tso                = bnx2_set_tso,
+       .set_tso                = ethtool_op_set_tso,
 #endif
        .self_test_count        = bnx2_self_test_count,
        .self_test              = bnx2_self_test,
@@ -5464,14 +5644,20 @@ static struct ethtool_ops bnx2_ethtool_ops = {
        .phys_id                = bnx2_phys_id,
        .get_stats_count        = bnx2_get_stats_count,
        .get_ethtool_stats      = bnx2_get_ethtool_stats,
+#ifdef ETHTOOL_GPERMADDR
        .get_perm_addr          = ethtool_op_get_perm_addr,
+#endif
 };
 
 /* Called with rtnl_lock */
 static int
 bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
+#if (LINUX_VERSION_CODE >= 0x020607)
        struct mii_ioctl_data *data = if_mii(ifr);
+#else
+       struct mii_ioctl_data *data = (struct mii_ioctl_data *) &ifr->ifr_ifru;
+#endif
        struct bnx2 *bp = netdev_priv(dev);
        int err;
 
@@ -5553,9 +5739,22 @@ poll_bnx2(struct net_device *dev)
 {
        struct bnx2 *bp = netdev_priv(dev);
 
-       disable_irq(bp->pdev->irq);
-       bnx2_interrupt(bp->pdev->irq, dev, NULL);
-       enable_irq(bp->pdev->irq);
+#if defined(RED_HAT_LINUX_KERNEL) && (LINUX_VERSION_CODE < 0x020600)
+       if (netdump_mode) {
+               bnx2_interrupt(bp->pdev->irq, dev, NULL);
+               if (dev->poll_list.prev) {
+                       int budget = 64;
+
+                       bnx2_poll(dev, &budget);
+               }
+       }
+       else
+#endif
+       {
+               disable_irq(bp->pdev->irq);
+               bnx2_interrupt(bp->pdev->irq, dev, NULL);
+               enable_irq(bp->pdev->irq);
+       }
 }
 #endif
 
@@ -5566,9 +5765,12 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        unsigned long mem_len;
        int rc;
        u32 reg;
+       u64 dma_mask, persist_dma_mask;
 
        SET_MODULE_OWNER(dev);
+#if (LINUX_VERSION_CODE >= 0x20419)
        SET_NETDEV_DEV(dev, &pdev->dev);
+#endif
        bp = netdev_priv(dev);
 
        bp->flags = 0;
@@ -5577,20 +5779,20 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        /* enable device (incl. PCI PM wakeup), and bus-mastering */
        rc = pci_enable_device(pdev);
        if (rc) {
-               dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
+               printk(KERN_ERR PFX "Cannot enable PCI device, aborting.");
                goto err_out;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               dev_err(&pdev->dev,
-                       "Cannot find PCI device base address, aborting.\n");
+               printk(KERN_ERR PFX "Cannot find PCI device base address, "
+                      "aborting.\n");
                rc = -ENODEV;
                goto err_out_disable;
        }
 
        rc = pci_request_regions(pdev, DRV_MODULE_NAME);
        if (rc) {
-               dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
+               printk(KERN_ERR PFX "Cannot obtain PCI resources, aborting.\n");
                goto err_out_disable;
        }
 
@@ -5598,30 +5800,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
        bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
        if (bp->pm_cap == 0) {
-               dev_err(&pdev->dev,
-                       "Cannot find power management capability, aborting.\n");
+               printk(KERN_ERR PFX "Cannot find power management capability, "
+                              "aborting.\n");
                rc = -EIO;
                goto err_out_release;
        }
 
        bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
        if (bp->pcix_cap == 0) {
-               dev_err(&pdev->dev, "Cannot find PCIX capability, aborting.\n");
-               rc = -EIO;
-               goto err_out_release;
-       }
-
-       if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
-               bp->flags |= USING_DAC_FLAG;
-               if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
-                       dev_err(&pdev->dev,
-                               "pci_set_consistent_dma_mask failed, aborting.\n");
-                       rc = -EIO;
-                       goto err_out_release;
-               }
-       }
-       else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
-               dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
+               printk(KERN_ERR PFX "Cannot find PCIX capability, aborting.\n");
                rc = -EIO;
                goto err_out_release;
        }
@@ -5630,7 +5817,12 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->pdev = pdev;
 
        spin_lock_init(&bp->phy_lock);
+       spin_lock_init(&bp->tx_lock);
+#if (LINUX_VERSION_CODE >= 0x20600)
        INIT_WORK(&bp->reset_task, bnx2_reset_task, bp);
+#else
+       INIT_TQUEUE(&bp->reset_task, bnx2_reset_task, bp);
+#endif
 
        dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
        mem_len = MB_GET_CID_ADDR(17);
@@ -5640,7 +5832,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->regview = ioremap_nocache(dev->base_addr, mem_len);
 
        if (!bp->regview) {
-               dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
+               printk(KERN_ERR PFX "Cannot map register space, aborting.\n");
                rc = -ENOMEM;
                goto err_out_release;
        }
@@ -5657,6 +5849,33 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
        bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
 
+       /* 5708 cannot support DMA addresses > 40-bit.
+        * On 64-bit systems with IOMMU, use 40-bit dma_mask.
+        * On 64-bit systems without IOMMU, use 64-bit dma_mask and
+        * do DMA address check in bnx2_start_xmit().
+        */
+       if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+               persist_dma_mask = dma_mask = DMA_40BIT_MASK;
+#ifdef CONFIG_HIGHMEM
+               dma_mask = DMA_64BIT_MASK;
+#endif
+       } else
+               persist_dma_mask = dma_mask = DMA_64BIT_MASK;
+       
+       /* Configure DMA attributes. */
+       if (pci_set_dma_mask(pdev, dma_mask) == 0) {
+               dev->features |= NETIF_F_HIGHDMA;
+               rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
+               if (rc) {
+                       printk(KERN_ERR PFX "pci_set_consistent_dma_mask "
+                              "failed, aborting.\n");
+                       goto err_out_unmap;
+               }
+       } else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
+               printk(KERN_ERR PFX "System does not support DMA, aborting.\n");
+               goto err_out_unmap;
+       }
+
        /* Get bus information. */
        reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
        if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
@@ -5712,8 +5931,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
                !(bp->flags & PCIX_FLAG)) {
 
-               dev_err(&pdev->dev,
-                       "5706 A1 can only be used in a PCIX bus, aborting.\n");
+               printk(KERN_ERR PFX "5706 A1 can only be used in a PCIX bus, "
+                      "aborting.\n");
                goto err_out_unmap;
        }
 
@@ -5734,7 +5953,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
        if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
            BNX2_DEV_INFO_SIGNATURE_MAGIC) {
-               dev_err(&pdev->dev, "Firmware not running, aborting.\n");
+               printk(KERN_ERR PFX "Firmware not running, aborting.\n");
                rc = -ENODEV;
                goto err_out_unmap;
        }
@@ -5752,7 +5971,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;
-       bnx2_set_rx_ring_size(bp, 255);
+       bnx2_set_rx_ring_size(bp, 100);
 
        bp->rx_csum = 1;
 
@@ -5860,14 +6079,23 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                printk(KERN_INFO "%s", version);
 
        /* dev zeroed in init_etherdev */
+#if (LINUX_VERSION_CODE >= 0x20418)
        dev = alloc_etherdev(sizeof(*bp));
+#else
+       dev = init_etherdev(NULL, sizeof(*bp));
+#endif
 
        if (!dev)
                return -ENOMEM;
 
        rc = bnx2_init_board(pdev, dev);
        if (rc < 0) {
+#if (LINUX_VERSION_CODE >= 0x20418)
                free_netdev(dev);
+#else
+               unregister_netdev(dev);
+               kfree(dev);
+#endif
                return rc;
        }
 
@@ -5895,8 +6123,9 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev->poll_controller = poll_bnx2;
 #endif
 
+#if (LINUX_VERSION_CODE >= 0x20418)
        if ((rc = register_netdev(dev))) {
-               dev_err(&pdev->dev, "Cannot register net device\n");
+               printk(KERN_ERR PFX "Cannot register net device\n");
                if (bp->regview)
                        iounmap(bp->regview);
                pci_release_regions(pdev);
@@ -5905,11 +6134,14 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                free_netdev(dev);
                return rc;
        }
+#endif
 
        pci_set_drvdata(pdev, dev);
 
        memcpy(dev->dev_addr, bp->mac_addr, 6);
+#ifdef ETHTOOL_GPERMADDR
        memcpy(dev->perm_addr, bp->mac_addr, 6);
+#endif
        bp->name = board_info[ent->driver_data].name,
        printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, "
                "IRQ %d, ",
@@ -5928,15 +6160,12 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                printk("%2.2x", dev->dev_addr[i]);
        printk("\n");
 
-       dev->features |= NETIF_F_SG;
-       if (bp->flags & USING_DAC_FLAG)
-               dev->features |= NETIF_F_HIGHDMA;
-       dev->features |= NETIF_F_IP_CSUM;
+       dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 #ifdef BCM_VLAN
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 #endif
 #ifdef BCM_TSO
-       dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
+       dev->features |= NETIF_F_TSO;
 #endif
 
        netif_carrier_off(bp->dev);
@@ -5950,14 +6179,20 @@ bnx2_remove_one(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        struct bnx2 *bp = netdev_priv(dev);
 
+#if (LINUX_VERSION_CODE >= 0x20600)
        flush_scheduled_work();
+#endif
 
        unregister_netdev(dev);
 
        if (bp->regview)
                iounmap(bp->regview);
 
+#if (LINUX_VERSION_CODE >= 0x20418)
        free_netdev(dev);
+#else
+       kfree(dev);
+#endif
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
@@ -5973,19 +6208,22 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
        if (!netif_running(dev))
                return 0;
 
-       flush_scheduled_work();
        bnx2_netif_stop(bp);
        netif_device_detach(dev);
        del_timer_sync(&bp->timer);
        if (bp->flags & NO_WOL_FLAG)
-               reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
+               reset_code = BNX2_DRV_MSG_CODE_UNLOAD;
        else if (bp->wol)
                reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
        else
                reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
        bnx2_reset_chip(bp, reset_code);
        bnx2_free_skbs(bp);
+#if (LINUX_VERSION_CODE < 0x2060b)
+       bnx2_set_power_state(bp, state);
+#else
        bnx2_set_power_state(bp, pci_choose_state(pdev, state));
+#endif
        return 0;
 }