vserver 1.9.5.x5
[linux-2.6.git] / drivers / net / tg3.c
index 0e46154..b5931a0 100644 (file)
@@ -4,12 +4,15 @@
  * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
  * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
  * Copyright (C) 2004 Sun Microsystems Inc.
+ *
+ * Firmware is:
+ *     Copyright (C) 2000-2003 Broadcom Corporation.
  */
 
 #include <linux/config.h>
 
 #include <linux/module.h>
-
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/compiler.h>
@@ -57,8 +60,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.8"
-#define DRV_MODULE_RELDATE     "July 14, 2004"
+#define DRV_MODULE_VERSION     "3.23"
+#define DRV_MODULE_RELDATE     "February 15, 2005"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -138,10 +141,11 @@ static char version[] __devinitdata =
 MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@pobox.com)");
 MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver");
 MODULE_LICENSE("GPL");
-MODULE_PARM(tg3_debug, "i");
-MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");
+MODULE_VERSION(DRV_MODULE_VERSION);
 
 static int tg3_debug = -1;     /* -1 == use TG3_DEF_MSG_ENABLE as value */
+module_param(tg3_debug, int, 0);
+MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");
 
 static struct pci_device_id tg3_pci_tbl[] = {
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700,
@@ -202,6 +206,14 @@ static struct pci_device_id tg3_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX,
@@ -221,8 +233,8 @@ static struct pci_device_id tg3_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, tg3_pci_tbl);
 
-struct {
-       char string[ETH_GSTRING_LEN];
+static struct {
+       const char string[ETH_GSTRING_LEN];
 } ethtool_stats_keys[TG3_NUM_STATS] = {
        { "rx_octets" },
        { "rx_fragments" },
@@ -328,7 +340,7 @@ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val)
                pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
                spin_unlock_irqrestore(&tp->indirect_lock, flags);
        } else {
-               unsigned long dest = tp->regs + off;
+               void __iomem *dest = tp->regs + off;
                writel(val, dest);
                readl(dest);    /* always flush PCI write */
        }
@@ -336,7 +348,7 @@ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val)
 
 static inline void _tw32_rx_mbox(struct tg3 *tp, u32 off, u32 val)
 {
-       unsigned long mbox = tp->regs + off;
+       void __iomem *mbox = tp->regs + off;
        writel(val, mbox);
        if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
                readl(mbox);
@@ -344,7 +356,7 @@ static inline void _tw32_rx_mbox(struct tg3 *tp, u32 off, u32 val)
 
 static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
 {
-       unsigned long mbox = tp->regs + off;
+       void __iomem *mbox = tp->regs + off;
        writel(val, mbox);
        if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)
                writel(val, mbox);
@@ -414,6 +426,20 @@ static void tg3_enable_ints(struct tg3 *tp)
        tg3_cond_int(tp);
 }
 
+/* tg3_restart_ints
+ *  similar to tg3_enable_ints, but it can return without flushing the
+ *  PIO write which reenables interrupts
+ */
+static void tg3_restart_ints(struct tg3 *tp)
+{
+       tw32(TG3PCI_MISC_HOST_CTRL,
+               (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
+       tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
+       mmiowb();
+
+       tg3_cond_int(tp);
+}
+
 static inline void tg3_netif_stop(struct tg3 *tp)
 {
        netif_poll_disable(tp->dev);
@@ -442,9 +468,14 @@ static void tg3_switch_clocks(struct tg3 *tp)
                       0x1f);
        tp->pci_clock_ctrl = clock_ctrl;
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 &&
-           (orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) {
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+               if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) {
+                       tw32_f(TG3PCI_CLOCK_CTRL,
+                              clock_ctrl | CLOCK_CTRL_625_CORE);
+                       udelay(40);
+               }
+       } else if ((orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) {
                tw32_f(TG3PCI_CLOCK_CTRL,
                     clock_ctrl |
                     (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));
@@ -462,7 +493,8 @@ static void tg3_switch_clocks(struct tg3 *tp)
 static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
 {
        u32 frame_val;
-       int loops, ret;
+       unsigned int loops;
+       int ret;
 
        if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
                tw32_f(MAC_MI_MODE,
@@ -470,7 +502,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
                udelay(80);
        }
 
-       *val = 0xffffffff;
+       *val = 0x0;
 
        frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
                      MI_COM_PHY_ADDR_MASK);
@@ -481,7 +513,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
        tw32_f(MAC_MI_COM, frame_val);
 
        loops = PHY_BUSY_LOOPS;
-       while (loops-- > 0) {
+       while (loops != 0) {
                udelay(10);
                frame_val = tr32(MAC_MI_COM);
 
@@ -490,10 +522,11 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
                        frame_val = tr32(MAC_MI_COM);
                        break;
                }
+               loops -= 1;
        }
 
        ret = -EBUSY;
-       if (loops > 0) {
+       if (loops != 0) {
                *val = frame_val & MI_COM_DATA_MASK;
                ret = 0;
        }
@@ -509,7 +542,8 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
 static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
 {
        u32 frame_val;
-       int loops, ret;
+       unsigned int loops;
+       int ret;
 
        if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
                tw32_f(MAC_MI_MODE,
@@ -527,7 +561,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
        tw32_f(MAC_MI_COM, frame_val);
 
        loops = PHY_BUSY_LOOPS;
-       while (loops-- > 0) {
+       while (loops != 0) {
                udelay(10);
                frame_val = tr32(MAC_MI_COM);
                if ((frame_val & MI_COM_BUSY) == 0) {
@@ -535,10 +569,11 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
                        frame_val = tr32(MAC_MI_COM);
                        break;
                }
+               loops -= 1;
        }
 
        ret = -EBUSY;
-       if (loops > 0)
+       if (loops != 0)
                ret = 0;
 
        if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
@@ -556,9 +591,10 @@ static void tg3_phy_set_wirespeed(struct tg3 *tp)
        if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
                return;
 
-       tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
-       tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
-       tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
+       if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007) &&
+           !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val))
+               tg3_writephy(tp, MII_TG3_AUX_CTRL,
+                            (val | (1 << 15) | (1 << 4)));
 }
 
 static int tg3_bmcr_reset(struct tg3 *tp)
@@ -599,9 +635,10 @@ static int tg3_wait_macro_done(struct tg3 *tp)
        while (limit--) {
                u32 tmp32;
 
-               tg3_readphy(tp, 0x16, &tmp32);
-               if ((tmp32 & 0x1000) == 0)
-                       break;
+               if (!tg3_readphy(tp, 0x16, &tmp32)) {
+                       if ((tmp32 & 0x1000) == 0)
+                               break;
+               }
        }
        if (limit <= 0)
                return -EBUSY;
@@ -653,9 +690,9 @@ static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp)
                for (i = 0; i < 6; i += 2) {
                        u32 low, high;
 
-                       tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low);
-                       tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high);
-                       if (tg3_wait_macro_done(tp)) {
+                       if (tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low) ||
+                           tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high) ||
+                           tg3_wait_macro_done(tp)) {
                                *resetp = 1;
                                return -EBUSY;
                        }
@@ -711,7 +748,9 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
                }
 
                /* Disable transmitter and interrupt.  */
-               tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
+               if (tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32))
+                       continue;
+
                reg32 |= 0x3000;
                tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
 
@@ -720,7 +759,9 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
                             BMCR_FULLDPLX | TG3_BMCR_SPEED1000);
 
                /* Set to master mode.  */
-               tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig);
+               if (tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig))
+                       continue;
+
                tg3_writephy(tp, MII_TG3_CTRL,
                             (MII_TG3_CTRL_AS_MASTER |
                              MII_TG3_CTRL_ENABLE_AS_MASTER));
@@ -758,9 +799,11 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
 
        tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
 
-       tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
-       reg32 &= ~0x3000;
-       tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+       if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32)) {
+               reg32 &= ~0x3000;
+               tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+       } else if (!err)
+               err = -EBUSY;
 
        return err;
 }
@@ -824,9 +867,9 @@ out:
                u32 phy_reg;
 
                /* Set bit 14 with read-modify-write to preserve other bits */
-               tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007);
-               tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy_reg);
-               tg3_writephy(tp, MII_TG3_AUX_CTRL, phy_reg | 0x4000);
+               if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007) &&
+                   !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy_reg))
+                       tg3_writephy(tp, MII_TG3_AUX_CTRL, phy_reg | 0x4000);
        }
        tg3_phy_set_wirespeed(tp);
        return 0;
@@ -858,34 +901,42 @@ static void tg3_frob_aux_power(struct tg3 *tp)
                              GRC_LCLCTRL_GPIO_OUTPUT1));
                        udelay(100);
                } else {
+                       u32 no_gpio2;
+                       u32 grc_local_ctrl;
+
                        if (tp_peer != tp &&
                            (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0)
                                return;
 
+                       /* On 5753 and variants, GPIO2 cannot be used. */
+                       no_gpio2 = tp->nic_sram_data_cfg &
+                                   NIC_SRAM_DATA_CFG_NO_GPIO2;
+
+                       grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 |
+                                        GRC_LCLCTRL_GPIO_OE1 |
+                                        GRC_LCLCTRL_GPIO_OE2 |
+                                        GRC_LCLCTRL_GPIO_OUTPUT1 |
+                                        GRC_LCLCTRL_GPIO_OUTPUT2;
+                       if (no_gpio2) {
+                               grc_local_ctrl &= ~(GRC_LCLCTRL_GPIO_OE2 |
+                                                   GRC_LCLCTRL_GPIO_OUTPUT2);
+                       }
                        tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
-                            (GRC_LCLCTRL_GPIO_OE0 |
-                             GRC_LCLCTRL_GPIO_OE1 |
-                             GRC_LCLCTRL_GPIO_OE2 |
-                             GRC_LCLCTRL_GPIO_OUTPUT1 |
-                             GRC_LCLCTRL_GPIO_OUTPUT2));
+                                               grc_local_ctrl);
                        udelay(100);
 
-                       tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
-                            (GRC_LCLCTRL_GPIO_OE0 |
-                             GRC_LCLCTRL_GPIO_OE1 |
-                             GRC_LCLCTRL_GPIO_OE2 |
-                             GRC_LCLCTRL_GPIO_OUTPUT0 |
-                             GRC_LCLCTRL_GPIO_OUTPUT1 |
-                             GRC_LCLCTRL_GPIO_OUTPUT2));
-                       udelay(100);
+                       grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT0;
 
                        tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
-                            (GRC_LCLCTRL_GPIO_OE0 |
-                             GRC_LCLCTRL_GPIO_OE1 |
-                             GRC_LCLCTRL_GPIO_OE2 |
-                             GRC_LCLCTRL_GPIO_OUTPUT0 |
-                             GRC_LCLCTRL_GPIO_OUTPUT1));
+                                               grc_local_ctrl);
                        udelay(100);
+
+                       if (!no_gpio2) {
+                               grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT2;
+                               tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+                                      grc_local_ctrl);
+                               udelay(100);
+                       }
                }
        } else {
                if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
@@ -980,7 +1031,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
                tp->link_config.orig_autoneg = tp->link_config.autoneg;
        }
 
-       if (tp->phy_id != PHY_ID_SERDES) {
+       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
                tp->link_config.speed = SPEED_10;
                tp->link_config.duplex = DUPLEX_HALF;
                tp->link_config.autoneg = AUTONEG_ENABLE;
@@ -992,7 +1043,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
        if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) {
                u32 mac_mode;
 
-               if (tp->phy_id != PHY_ID_SERDES) {
+               if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
                        tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
                        udelay(40);
 
@@ -1114,29 +1165,33 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
        u32 old_rx_mode = tp->rx_mode;
        u32 old_tx_mode = tp->tx_mode;
 
-       if (local_adv & ADVERTISE_PAUSE_CAP) {
-               if (local_adv & ADVERTISE_PAUSE_ASYM) {
-                       if (remote_adv & LPA_PAUSE_CAP)
-                               new_tg3_flags |=
-                                       (TG3_FLAG_RX_PAUSE |
-                                        TG3_FLAG_TX_PAUSE);
-                       else if (remote_adv & LPA_PAUSE_ASYM)
-                               new_tg3_flags |=
-                                       (TG3_FLAG_RX_PAUSE);
-               } else {
-                       if (remote_adv & LPA_PAUSE_CAP)
-                               new_tg3_flags |=
-                                       (TG3_FLAG_RX_PAUSE |
-                                        TG3_FLAG_TX_PAUSE);
+       if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
+               if (local_adv & ADVERTISE_PAUSE_CAP) {
+                       if (local_adv & ADVERTISE_PAUSE_ASYM) {
+                               if (remote_adv & LPA_PAUSE_CAP)
+                                       new_tg3_flags |=
+                                               (TG3_FLAG_RX_PAUSE |
+                                               TG3_FLAG_TX_PAUSE);
+                               else if (remote_adv & LPA_PAUSE_ASYM)
+                                       new_tg3_flags |=
+                                               (TG3_FLAG_RX_PAUSE);
+                       } else {
+                               if (remote_adv & LPA_PAUSE_CAP)
+                                       new_tg3_flags |=
+                                               (TG3_FLAG_RX_PAUSE |
+                                               TG3_FLAG_TX_PAUSE);
+                       }
+               } else if (local_adv & ADVERTISE_PAUSE_ASYM) {
+                       if ((remote_adv & LPA_PAUSE_CAP) &&
+                       (remote_adv & LPA_PAUSE_ASYM))
+                               new_tg3_flags |= TG3_FLAG_TX_PAUSE;
                }
-       } else if (local_adv & ADVERTISE_PAUSE_ASYM) {
-               if ((remote_adv & LPA_PAUSE_CAP) &&
-                   (remote_adv & LPA_PAUSE_ASYM))
-                       new_tg3_flags |= TG3_FLAG_TX_PAUSE;
-       }
 
-       tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
-       tp->tg3_flags |= new_tg3_flags;
+               tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
+               tp->tg3_flags |= new_tg3_flags;
+       } else {
+               new_tg3_flags = tp->tg3_flags;
+       }
 
        if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
                tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
@@ -1197,7 +1252,7 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8
        };
 }
 
-static int tg3_phy_copper_begin(struct tg3 *tp)
+static void tg3_phy_copper_begin(struct tg3 *tp)
 {
        u32 new_adv;
        int i;
@@ -1312,15 +1367,16 @@ static int tg3_phy_copper_begin(struct tg3 *tp)
                if (tp->link_config.duplex == DUPLEX_FULL)
                        bmcr |= BMCR_FULLDPLX;
 
-               tg3_readphy(tp, MII_BMCR, &orig_bmcr);
-               if (bmcr != orig_bmcr) {
+               if (!tg3_readphy(tp, MII_BMCR, &orig_bmcr) &&
+                   (bmcr != orig_bmcr)) {
                        tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK);
                        for (i = 0; i < 1500; i++) {
                                u32 tmp;
 
                                udelay(10);
-                               tg3_readphy(tp, MII_BMSR, &tmp);
-                               tg3_readphy(tp, MII_BMSR, &tmp);
+                               if (tg3_readphy(tp, MII_BMSR, &tmp) ||
+                                   tg3_readphy(tp, MII_BMSR, &tmp))
+                                       continue;
                                if (!(tmp & BMSR_LSTATUS)) {
                                        udelay(40);
                                        break;
@@ -1333,8 +1389,6 @@ static int tg3_phy_copper_begin(struct tg3 *tp)
                tg3_writephy(tp, MII_BMCR,
                             BMCR_ANENABLE | BMCR_ANRESTART);
        }
-
-       return 0;
 }
 
 static int tg3_init_5401phy_dsp(struct tg3 *tp)
@@ -1369,7 +1423,9 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp)
 {
        u32 adv_reg, all_mask;
 
-       tg3_readphy(tp, MII_ADVERTISE, &adv_reg);
+       if (tg3_readphy(tp, MII_ADVERTISE, &adv_reg))
+               return 0;
+
        all_mask = (ADVERTISE_10HALF | ADVERTISE_10FULL |
                    ADVERTISE_100HALF | ADVERTISE_100FULL);
        if ((adv_reg & all_mask) != all_mask)
@@ -1377,7 +1433,9 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp)
        if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
                u32 tg3_ctrl;
 
-               tg3_readphy(tp, MII_TG3_CTRL, &tg3_ctrl);
+               if (tg3_readphy(tp, MII_TG3_CTRL, &tg3_ctrl))
+                       return 0;
+
                all_mask = (MII_TG3_CTRL_ADV_1000_HALF |
                            MII_TG3_CTRL_ADV_1000_FULL);
                if ((tg3_ctrl & all_mask) != all_mask)
@@ -1417,8 +1475,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
            netif_carrier_ok(tp->dev)) {
                tg3_readphy(tp, MII_BMSR, &bmsr);
-               tg3_readphy(tp, MII_BMSR, &bmsr);
-               if (!(bmsr & BMSR_LSTATUS))
+               if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+                   !(bmsr & BMSR_LSTATUS))
                        force_reset = 1;
        }
        if (force_reset)
@@ -1426,9 +1484,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
 
        if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
                tg3_readphy(tp, MII_BMSR, &bmsr);
-               tg3_readphy(tp, MII_BMSR, &bmsr);
-
-               if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
+               if (tg3_readphy(tp, MII_BMSR, &bmsr) ||
+                   !(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
                        bmsr = 0;
 
                if (!(bmsr & BMSR_LSTATUS)) {
@@ -1439,8 +1496,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                        tg3_readphy(tp, MII_BMSR, &bmsr);
                        for (i = 0; i < 1000; i++) {
                                udelay(10);
-                               tg3_readphy(tp, MII_BMSR, &bmsr);
-                               if (bmsr & BMSR_LSTATUS) {
+                               if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+                                   (bmsr & BMSR_LSTATUS)) {
                                        udelay(40);
                                        break;
                                }
@@ -1487,11 +1544,23 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
        current_speed = SPEED_INVALID;
        current_duplex = DUPLEX_INVALID;
 
+       if (tp->tg3_flags2 & TG3_FLG2_CAPACITIVE_COUPLING) {
+               u32 val;
+
+               tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007);
+               tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
+               if (!(val & (1 << 10))) {
+                       val |= (1 << 10);
+                       tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
+                       goto relink;
+               }
+       }
+
        bmsr = 0;
        for (i = 0; i < 100; i++) {
                tg3_readphy(tp, MII_BMSR, &bmsr);
-               tg3_readphy(tp, MII_BMSR, &bmsr);
-               if (bmsr & BMSR_LSTATUS)
+               if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+                   (bmsr & BMSR_LSTATUS))
                        break;
                udelay(40);
        }
@@ -1502,8 +1571,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
                for (i = 0; i < 2000; i++) {
                        udelay(10);
-                       tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
-                       if (aux_stat)
+                       if (!tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat) &&
+                           aux_stat)
                                break;
                }
 
@@ -1514,7 +1583,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                bmcr = 0;
                for (i = 0; i < 200; i++) {
                        tg3_readphy(tp, MII_BMCR, &bmcr);
-                       tg3_readphy(tp, MII_BMCR, &bmcr);
+                       if (tg3_readphy(tp, MII_BMCR, &bmcr))
+                               continue;
                        if (bmcr && bmcr != 0x7fff)
                                break;
                        udelay(10);
@@ -1551,10 +1621,13 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
            (tp->link_config.autoneg == AUTONEG_ENABLE)) {
                u32 local_adv, remote_adv;
 
-               tg3_readphy(tp, MII_ADVERTISE, &local_adv);
+               if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
+                       local_adv = 0;
                local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
 
-               tg3_readphy(tp, MII_LPA, &remote_adv);
+               if (tg3_readphy(tp, MII_LPA, &remote_adv))
+                       remote_adv = 0;
+
                remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
 
                /* If we are not advertising full pause capability,
@@ -1566,15 +1639,15 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                        tg3_setup_flow_control(tp, local_adv, remote_adv);
                }
        }
-
+relink:
        if (current_link_up == 0) {
                u32 tmp;
 
                tg3_phy_copper_begin(tp);
 
                tg3_readphy(tp, MII_BMSR, &tmp);
-               tg3_readphy(tp, MII_BMSR, &tmp);
-               if (tmp & BMSR_LSTATUS)
+               if (!tg3_readphy(tp, MII_BMSR, &tmp) &&
+                   (tmp & BMSR_LSTATUS))
                        current_link_up = 1;
        }
 
@@ -1616,7 +1689,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
        tw32_f(MAC_MODE, tp->mac_mode);
        udelay(40);
 
-       if (tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | TG3_FLAG_POLL_SERDES)) {
+       if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
                /* Polled via timer. */
                tw32_f(MAC_EVENT, 0);
        } else {
@@ -1965,190 +2038,332 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
 static int fiber_autoneg(struct tg3 *tp, u32 *flags)
 {
        int res = 0;
+       struct tg3_fiber_aneginfo aninfo;
+       int status = ANEG_FAILED;
+       unsigned int tick;
+       u32 tmp;
 
-       if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) {
-               u32 dig_status;
+       tw32_f(MAC_TX_AUTO_NEG, 0);
 
-               dig_status = tr32(SG_DIG_STATUS);
-               *flags = 0;
-               if (dig_status & SG_DIG_PARTNER_ASYM_PAUSE)
-                       *flags |= MR_LP_ADV_ASYM_PAUSE;
-               if (dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE)
-                       *flags |= MR_LP_ADV_SYM_PAUSE;
+       tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
+       tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
+       udelay(40);
 
-               if ((dig_status & SG_DIG_AUTONEG_COMPLETE) &&
-                   !(dig_status & (SG_DIG_AUTONEG_ERROR |
-                                   SG_DIG_PARTNER_FAULT_MASK)))
-                       res = 1;
-       } else {
-               struct tg3_fiber_aneginfo aninfo;
-               int status = ANEG_FAILED;
-               unsigned int tick;
-               u32 tmp;
+       tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
+       udelay(40);
 
-               tw32_f(MAC_TX_AUTO_NEG, 0);
+       memset(&aninfo, 0, sizeof(aninfo));
+       aninfo.flags |= MR_AN_ENABLE;
+       aninfo.state = ANEG_STATE_UNKNOWN;
+       aninfo.cur_time = 0;
+       tick = 0;
+       while (++tick < 195000) {
+               status = tg3_fiber_aneg_smachine(tp, &aninfo);
+               if (status == ANEG_DONE || status == ANEG_FAILED)
+                       break;
 
-               tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
-               tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
-               udelay(40);
+               udelay(1);
+       }
 
-               tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
-               udelay(40);
+       tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
+       tw32_f(MAC_MODE, tp->mac_mode);
+       udelay(40);
 
-               memset(&aninfo, 0, sizeof(aninfo));
-               aninfo.flags |= MR_AN_ENABLE;
-               aninfo.state = ANEG_STATE_UNKNOWN;
-               aninfo.cur_time = 0;
-               tick = 0;
-               while (++tick < 195000) {
-                       status = tg3_fiber_aneg_smachine(tp, &aninfo);
-                       if (status == ANEG_DONE || status == ANEG_FAILED)
-                               break;
+       *flags = aninfo.flags;
 
-                       udelay(1);
-               }
+       if (status == ANEG_DONE &&
+           (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK |
+                            MR_LP_ADV_FULL_DUPLEX)))
+               res = 1;
 
-               tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
-               tw32_f(MAC_MODE, tp->mac_mode);
-               udelay(40);
+       return res;
+}
 
-               *flags = aninfo.flags;
+static void tg3_init_bcm8002(struct tg3 *tp)
+{
+       u32 mac_status = tr32(MAC_STATUS);
+       int i;
 
-               if (status == ANEG_DONE &&
-                   (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK |
-                                    MR_LP_ADV_FULL_DUPLEX)))
-                       res = 1;
-       }
+       /* Reset when initting first time or we have a link. */
+       if ((tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) &&
+           !(mac_status & MAC_STATUS_PCS_SYNCED))
+               return;
 
-       return res;
+       /* Set PLL lock range. */
+       tg3_writephy(tp, 0x16, 0x8007);
+
+       /* SW reset */
+       tg3_writephy(tp, MII_BMCR, BMCR_RESET);
+
+       /* Wait for reset to complete. */
+       /* XXX schedule_timeout() ... */
+       for (i = 0; i < 500; i++)
+               udelay(10);
+
+       /* Config mode; select PMA/Ch 1 regs. */
+       tg3_writephy(tp, 0x10, 0x8411);
+
+       /* Enable auto-lock and comdet, select txclk for tx. */
+       tg3_writephy(tp, 0x11, 0x0a10);
+
+       tg3_writephy(tp, 0x18, 0x00a0);
+       tg3_writephy(tp, 0x16, 0x41ff);
+
+       /* Assert and deassert POR. */
+       tg3_writephy(tp, 0x13, 0x0400);
+       udelay(40);
+       tg3_writephy(tp, 0x13, 0x0000);
+
+       tg3_writephy(tp, 0x11, 0x0a50);
+       udelay(40);
+       tg3_writephy(tp, 0x11, 0x0a10);
+
+       /* Wait for signal to stabilize */
+       /* XXX schedule_timeout() ... */
+       for (i = 0; i < 15000; i++)
+               udelay(10);
+
+       /* Deselect the channel register so we can read the PHYID
+        * later.
+        */
+       tg3_writephy(tp, 0x10, 0x8011);
 }
 
-static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
+static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 {
-       u32 orig_pause_cfg;
-       u16 orig_active_speed;
-       u8 orig_active_duplex;
+       u32 sg_dig_ctrl, sg_dig_status;
+       u32 serdes_cfg, expected_sg_dig_ctrl;
+       int workaround, port_a;
        int current_link_up;
-       int i;
 
-       orig_pause_cfg =
-               (tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
-                                 TG3_FLAG_TX_PAUSE));
-       orig_active_speed = tp->link_config.active_speed;
-       orig_active_duplex = tp->link_config.active_duplex;
+       serdes_cfg = 0;
+       expected_sg_dig_ctrl = 0;
+       workaround = 0;
+       port_a = 1;
+       current_link_up = 0;
 
-       tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
-       tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
-       tw32_f(MAC_MODE, tp->mac_mode);
-       udelay(40);
+       if (tp->pci_chip_rev_id != CHIPREV_ID_5704_A0 &&
+           tp->pci_chip_rev_id != CHIPREV_ID_5704_A1) {
+               workaround = 1;
+               if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
+                       port_a = 0;
 
-       if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) {
-               /* Allow time for the hardware to auto-negotiate (195ms) */
-               unsigned int tick = 0;
+               /* preserve bits 0-11,13,14 for signal pre-emphasis */
+               /* preserve bits 20-23 for voltage regulator */
+               serdes_cfg = tr32(MAC_SERDES_CFG) & 0x00f06fff;
+       }
 
-               while (++tick < 195000) { 
-                       if (tr32(SG_DIG_STATUS) & SG_DIG_AUTONEG_COMPLETE)
-                               break;
-                       udelay(1);
+       sg_dig_ctrl = tr32(SG_DIG_CTRL);
+
+       if (tp->link_config.autoneg != AUTONEG_ENABLE) {
+               if (sg_dig_ctrl & (1 << 31)) {
+                       if (workaround) {
+                               u32 val = serdes_cfg;
+
+                               if (port_a)
+                                       val |= 0xc010000;
+                               else
+                                       val |= 0x4010000;
+                               tw32_f(MAC_SERDES_CFG, val);
+                       }
+                       tw32_f(SG_DIG_CTRL, 0x01388400);
+               }
+               if (mac_status & MAC_STATUS_PCS_SYNCED) {
+                       tg3_setup_flow_control(tp, 0, 0);
+                       current_link_up = 1;
                }
-               if (tick >= 195000)
-                       printk(KERN_INFO PFX "%s: HW autoneg failed !\n",
-                           tp->dev->name);
+               goto out;
        }
 
-       /* Reset when initting first time or we have a link. */
-       if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
-           (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
-               /* Set PLL lock range. */
-               tg3_writephy(tp, 0x16, 0x8007);
+       /* Want auto-negotiation.  */
+       expected_sg_dig_ctrl = 0x81388400;
 
-               /* SW reset */
-               tg3_writephy(tp, MII_BMCR, BMCR_RESET);
+       /* Pause capability */
+       expected_sg_dig_ctrl |= (1 << 11);
 
-               /* Wait for reset to complete. */
-               /* XXX schedule_timeout() ... */
-               for (i = 0; i < 500; i++)
-                       udelay(10);
+       /* Asymettric pause */
+       expected_sg_dig_ctrl |= (1 << 12);
 
-               /* Config mode; select PMA/Ch 1 regs. */
-               tg3_writephy(tp, 0x10, 0x8411);
+       if (sg_dig_ctrl != expected_sg_dig_ctrl) {
+               if (workaround)
+                       tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
+               tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
+               udelay(5);
+               tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
 
-               /* Enable auto-lock and comdet, select txclk for tx. */
-               tg3_writephy(tp, 0x11, 0x0a10);
+               tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
+       } else if (mac_status & (MAC_STATUS_PCS_SYNCED |
+                                MAC_STATUS_SIGNAL_DET)) {
+               int i;
 
-               tg3_writephy(tp, 0x18, 0x00a0);
-               tg3_writephy(tp, 0x16, 0x41ff);
+               /* Giver time to negotiate (~200ms) */
+               for (i = 0; i < 40000; i++) {
+                       sg_dig_status = tr32(SG_DIG_STATUS);
+                       if (sg_dig_status & (0x3))
+                               break;
+                       udelay(5);
+               }
+               mac_status = tr32(MAC_STATUS);
 
-               /* Assert and deassert POR. */
-               tg3_writephy(tp, 0x13, 0x0400);
-               udelay(40);
-               tg3_writephy(tp, 0x13, 0x0000);
+               if ((sg_dig_status & (1 << 1)) &&
+                   (mac_status & MAC_STATUS_PCS_SYNCED)) {
+                       u32 local_adv, remote_adv;
 
-               tg3_writephy(tp, 0x11, 0x0a50);
-               udelay(40);
-               tg3_writephy(tp, 0x11, 0x0a10);
+                       local_adv = ADVERTISE_PAUSE_CAP;
+                       remote_adv = 0;
+                       if (sg_dig_status & (1 << 19))
+                               remote_adv |= LPA_PAUSE_CAP;
+                       if (sg_dig_status & (1 << 20))
+                               remote_adv |= LPA_PAUSE_ASYM;
 
-               /* Wait for signal to stabilize */
-               /* XXX schedule_timeout() ... */
-               for (i = 0; i < 15000; i++)
-                       udelay(10);
+                       tg3_setup_flow_control(tp, local_adv, remote_adv);
+                       current_link_up = 1;
+                       tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+               } else if (!(sg_dig_status & (1 << 1))) {
+                       if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED)
+                               tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+                       else {
+                               if (workaround) {
+                                       u32 val = serdes_cfg;
+
+                                       if (port_a)
+                                               val |= 0xc010000;
+                                       else
+                                               val |= 0x4010000;
+
+                                       tw32_f(MAC_SERDES_CFG, val);
+                               }
 
-               /* Deselect the channel register so we can read the PHYID
-                * later.
-                */
-               tg3_writephy(tp, 0x10, 0x8011);
+                               tw32_f(SG_DIG_CTRL, 0x01388400);
+                               udelay(40);
+
+                               /* Link parallel detection - link is up */
+                               /* only if we have PCS_SYNC and not */
+                               /* receiving config code words */
+                               mac_status = tr32(MAC_STATUS);
+                               if ((mac_status & MAC_STATUS_PCS_SYNCED) &&
+                                   !(mac_status & MAC_STATUS_RCVD_CFG)) {
+                                       tg3_setup_flow_control(tp, 0, 0);
+                                       current_link_up = 1;
+                               }
+                       }
+               }
        }
 
-       /* Enable link change interrupt unless serdes polling.  */
-       if (!(tp->tg3_flags & TG3_FLAG_POLL_SERDES))
-               tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
-       else
-               tw32_f(MAC_EVENT, 0);
-       udelay(40);
+out:
+       return current_link_up;
+}
 
-       current_link_up = 0;
-       if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
-               if (tp->link_config.autoneg == AUTONEG_ENABLE) {
-                       u32 flags;
+static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
+{
+       int current_link_up = 0;
+
+       if (!(mac_status & MAC_STATUS_PCS_SYNCED)) {
+               tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL;
+               goto out;
+       }
+
+       if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+               u32 flags;
+               int i;
   
-                       if (fiber_autoneg(tp, &flags)) {
-                               u32 local_adv, remote_adv;
+               if (fiber_autoneg(tp, &flags)) {
+                       u32 local_adv, remote_adv;
 
-                               local_adv = ADVERTISE_PAUSE_CAP;
-                               remote_adv = 0;
-                               if (flags & MR_LP_ADV_SYM_PAUSE)
-                                       remote_adv |= LPA_PAUSE_CAP;
-                               if (flags & MR_LP_ADV_ASYM_PAUSE)
-                                       remote_adv |= LPA_PAUSE_ASYM;
+                       local_adv = ADVERTISE_PAUSE_CAP;
+                       remote_adv = 0;
+                       if (flags & MR_LP_ADV_SYM_PAUSE)
+                               remote_adv |= LPA_PAUSE_CAP;
+                       if (flags & MR_LP_ADV_ASYM_PAUSE)
+                               remote_adv |= LPA_PAUSE_ASYM;
 
-                               tg3_setup_flow_control(tp, local_adv, remote_adv);
+                       tg3_setup_flow_control(tp, local_adv, remote_adv);
 
-                               tp->tg3_flags |=
-                                       TG3_FLAG_GOT_SERDES_FLOWCTL;
-                               current_link_up = 1;
-                       }
-                       for (i = 0; i < 60; i++) {
-                               udelay(20);
-                               tw32_f(MAC_STATUS,
-                                    (MAC_STATUS_SYNC_CHANGED |
-                                     MAC_STATUS_CFG_CHANGED));
-                               udelay(40);
-                               if ((tr32(MAC_STATUS) &
-                                    (MAC_STATUS_SYNC_CHANGED |
-                                     MAC_STATUS_CFG_CHANGED)) == 0)
-                                       break;
-                       }
-                       if (current_link_up == 0 &&
-                           (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
-                               current_link_up = 1;
-                       }
-               } else {
-                       /* Forcing 1000FD link up. */
-                       current_link_up = 1;
                        tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
+                       current_link_up = 1;
                }
-       } else
-               tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL;
+               for (i = 0; i < 30; i++) {
+                       udelay(20);
+                       tw32_f(MAC_STATUS,
+                              (MAC_STATUS_SYNC_CHANGED |
+                               MAC_STATUS_CFG_CHANGED));
+                       udelay(40);
+                       if ((tr32(MAC_STATUS) &
+                            (MAC_STATUS_SYNC_CHANGED |
+                             MAC_STATUS_CFG_CHANGED)) == 0)
+                               break;
+               }
+
+               mac_status = tr32(MAC_STATUS);
+               if (current_link_up == 0 &&
+                   (mac_status & MAC_STATUS_PCS_SYNCED) &&
+                   !(mac_status & MAC_STATUS_RCVD_CFG))
+                       current_link_up = 1;
+       } else {
+               /* Forcing 1000FD link up. */
+               current_link_up = 1;
+               tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
+
+               tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS));
+               udelay(40);
+       }
+
+out:
+       return current_link_up;
+}
+
+static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
+{
+       u32 orig_pause_cfg;
+       u16 orig_active_speed;
+       u8 orig_active_duplex;
+       u32 mac_status;
+       int current_link_up;
+       int i;
+
+       orig_pause_cfg =
+               (tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
+                                 TG3_FLAG_TX_PAUSE));
+       orig_active_speed = tp->link_config.active_speed;
+       orig_active_duplex = tp->link_config.active_duplex;
+
+       if (!(tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) &&
+           netif_carrier_ok(tp->dev) &&
+           (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) {
+               mac_status = tr32(MAC_STATUS);
+               mac_status &= (MAC_STATUS_PCS_SYNCED |
+                              MAC_STATUS_SIGNAL_DET |
+                              MAC_STATUS_CFG_CHANGED |
+                              MAC_STATUS_RCVD_CFG);
+               if (mac_status == (MAC_STATUS_PCS_SYNCED |
+                                  MAC_STATUS_SIGNAL_DET)) {
+                       tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED |
+                                           MAC_STATUS_CFG_CHANGED));
+                       return 0;
+               }
+       }
+
+       tw32_f(MAC_TX_AUTO_NEG, 0);
+
+       tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
+       tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
+       tw32_f(MAC_MODE, tp->mac_mode);
+       udelay(40);
+
+       if (tp->phy_id == PHY_ID_BCM8002)
+               tg3_init_bcm8002(tp);
+
+       /* Enable link change event even when serdes polling.  */
+       tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
+       udelay(40);
+
+       current_link_up = 0;
+       mac_status = tr32(MAC_STATUS);
+
+       if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG)
+               current_link_up = tg3_setup_fiber_hw_autoneg(tp, mac_status);
+       else
+               current_link_up = tg3_setup_fiber_by_hand(tp, mac_status);
 
        tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
        tw32_f(MAC_MODE, tp->mac_mode);
@@ -2159,19 +2374,24 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
                 (tp->hw_status->status & ~SD_STATUS_LINK_CHG));
 
        for (i = 0; i < 100; i++) {
-               udelay(20);
-               tw32_f(MAC_STATUS,
-                    (MAC_STATUS_SYNC_CHANGED |
-                     MAC_STATUS_CFG_CHANGED));
-               udelay(40);
-               if ((tr32(MAC_STATUS) &
-                    (MAC_STATUS_SYNC_CHANGED |
-                     MAC_STATUS_CFG_CHANGED)) == 0)
+               tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED |
+                                   MAC_STATUS_CFG_CHANGED));
+               udelay(5);
+               if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED |
+                                        MAC_STATUS_CFG_CHANGED)) == 0)
                        break;
        }
 
-       if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0)
+       mac_status = tr32(MAC_STATUS);
+       if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
                current_link_up = 0;
+               if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+                       tw32_f(MAC_MODE, (tp->mac_mode |
+                                         MAC_MODE_SEND_CONFIGS));
+                       udelay(1);
+                       tw32_f(MAC_MODE, tp->mac_mode);
+               }
+       }
 
        if (current_link_up == 1) {
                tp->link_config.active_speed = SPEED_1000;
@@ -2203,15 +2423,6 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
                        tg3_link_report(tp);
        }
 
-       if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) {
-               tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY);
-               udelay(40);
-               if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
-                       tw32_f(MAC_MODE, tp->mac_mode);
-                       udelay(40);
-               }
-       }
-
        return 0;
 }
 
@@ -2219,7 +2430,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
 {
        int err;
 
-       if (tp->phy_id == PHY_ID_SERDES) {
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
                err = tg3_setup_fiber_phy(tp, force_reset);
        } else {
                err = tg3_setup_copper_phy(tp, force_reset);
@@ -2502,7 +2713,11 @@ static int tg3_rx(struct tg3 *tp, int budget)
 
                len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
 
-               if (len > RX_COPY_THRESHOLD) {
+               if (len > RX_COPY_THRESHOLD 
+                       && tp->rx_offset == 2
+                       /* rx_offset != 2 iff this is a 5701 card running
+                        * in PCI-X mode [see tg3_get_invariants()] */
+               ) {
                        int skb_size;
 
                        skb_size = tg3_alloc_rx_skb(tp, opaque_key,
@@ -2581,6 +2796,7 @@ next_pkt_nopost:
                tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
                             sw_idx);
        }
+       mmiowb();
 
        return received;
 }
@@ -2639,7 +2855,7 @@ static int tg3_poll(struct net_device *netdev, int *budget)
        if (done) {
                spin_lock_irqsave(&tp->lock, flags);
                __netif_rx_complete(netdev);
-               tg3_enable_ints(tp);
+               tg3_restart_ints(tp);
                spin_unlock_irqrestore(&tp->lock, flags);
        }
 
@@ -2738,11 +2954,11 @@ static void tg3_reset_task(void *_data)
        tg3_halt(tp);
        tg3_init_hw(tp);
 
+       tg3_netif_start(tp);
+
        spin_unlock(&tp->tx_lock);
        spin_unlock_irq(&tp->lock);
 
-       tg3_netif_start(tp);
-
        if (restart_timer)
                mod_timer(&tp->timer, jiffies + 1);
 }
@@ -2812,6 +3028,7 @@ static void tg3_set_txd(struct tg3 *tp, int entry,
                        dma_addr_t mapping, int len, u32 flags,
                        u32 mss_and_is_end)
 {
+       struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
        int is_end = (mss_and_is_end & 0x1);
        u32 mss = (mss_and_is_end >> 1);
        u32 vlan_tag = 0;
@@ -2823,35 +3040,11 @@ static void tg3_set_txd(struct tg3 *tp, int entry,
                flags &= 0xffff;
        }
        vlan_tag |= (mss << TXD_MSS_SHIFT);
-       if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-               struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
-
-               txd->addr_hi = ((u64) mapping >> 32);
-               txd->addr_lo = ((u64) mapping & 0xffffffff);
-               txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
-               txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
-       } else {
-               struct tx_ring_info *txr = &tp->tx_buffers[entry];
-               unsigned long txd;
 
-               txd = (tp->regs +
-                      NIC_SRAM_WIN_BASE +
-                      NIC_SRAM_TX_BUFFER_DESC);
-               txd += (entry * TXD_SIZE);
-
-               /* Save some PIOs */
-               if (sizeof(dma_addr_t) != sizeof(u32))
-                       writel(((u64) mapping >> 32),
-                              txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
-
-               writel(((u64) mapping & 0xffffffff),
-                      txd + TXD_ADDR + TG3_64BIT_REG_LOW);
-               writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS);
-               if (txr->prev_vlan_tag != vlan_tag) {
-                       writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG);
-                       txr->prev_vlan_tag = vlan_tag;
-               }
-       }
+       txd->addr_hi = ((u64) mapping >> 32);
+       txd->addr_lo = ((u64) mapping & 0xffffffff);
+       txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
+       txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
 }
 
 static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len)
@@ -2892,7 +3085,11 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
         * So we really do need to disable interrupts when taking
         * tx_lock here.
         */
-       spin_lock_irqsave(&tp->tx_lock, flags);
+       local_irq_save(flags);
+       if (!spin_trylock(&tp->tx_lock)) { 
+               local_irq_restore(flags);
+               return NETDEV_TX_LOCKED; 
+       } 
 
        /* This is a hard error, log it. */
        if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
@@ -2900,7 +3097,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                spin_unlock_irqrestore(&tp->tx_lock, flags);
                printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
                       dev->name);
-               return 1;
+               return NETDEV_TX_BUSY;
        }
 
        entry = tp->tx_prod;
@@ -2921,11 +3118,19 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
                skb->nh.iph->check = 0;
                skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len);
-               skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
-                                                     skb->nh.iph->daddr,
-                                                     0, IPPROTO_TCP, 0);
+               if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
+                       skb->h.th->check = 0;
+                       base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
+               }
+               else {
+                       skb->h.th->check =
+                               ~csum_tcpudp_magic(skb->nh.iph->saddr,
+                                                  skb->nh.iph->daddr,
+                                                  0, IPPROTO_TCP, 0);
+               }
 
-               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+               if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) ||
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
                        if (tcp_opt_len || skb->nh.iph->ihl > 5) {
                                int tsflags;
 
@@ -2992,7 +3197,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                would_hit_hwbug = entry + 1;
                        }
 
-                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+                       if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
                                tg3_set_txd(tp, entry, mapping, len,
                                            base_flags, (i == last)|(mss << 1));
                        else
@@ -3040,30 +3245,19 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        /* Packets are ready, update Tx producer idx local and on card. */
-       if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-               tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 +
-                             TG3_64BIT_REG_LOW), entry);
-       } else {
-               /* First, make sure tg3 sees last descriptor fully
-                * in SRAM.
-                */
-               if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
-                       tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW);
-
-               tw32_tx_mbox((MAILBOX_SNDNIC_PROD_IDX_0 +
-                             TG3_64BIT_REG_LOW), entry);
-       }
+       tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
 
        tp->tx_prod = entry;
        if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
                netif_stop_queue(dev);
 
 out_unlock:
+       mmiowb();
        spin_unlock_irqrestore(&tp->tx_lock, flags);
 
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
@@ -3102,9 +3296,10 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 
        tg3_init_hw(tp);
 
+       tg3_netif_start(tp);
+
        spin_unlock(&tp->tx_lock);
        spin_unlock_irq(&tp->lock);
-       tg3_netif_start(tp);
 
        return 0;
 }
@@ -3190,7 +3385,6 @@ static void tg3_free_rings(struct tg3 *tp)
  */
 static void tg3_init_rings(struct tg3 *tp)
 {
-       unsigned long start, end;
        u32 i;
 
        /* Free up all the SKBs. */
@@ -3200,21 +3394,7 @@ static void tg3_init_rings(struct tg3 *tp)
        memset(tp->rx_std, 0, TG3_RX_RING_BYTES);
        memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES);
        memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
-
-       if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-               memset(tp->tx_ring, 0, TG3_TX_RING_BYTES);
-       } else {
-               start = (tp->regs +
-                        NIC_SRAM_WIN_BASE +
-                        NIC_SRAM_TX_BUFFER_DESC);
-               end = start + TG3_TX_RING_BYTES;
-               while (start < end) {
-                       writel(0, start);
-                       start += 4;
-               }
-               for (i = 0; i < TG3_TX_RING_SIZE; i++)
-                       tp->tx_buffers[i].prev_vlan_tag = 0;
-       }
+       memset(tp->tx_ring, 0, TG3_TX_RING_BYTES);
 
        /* Initialize invariants of the rings, we only set this
         * stuff once.  This works because the card does not
@@ -3345,15 +3525,10 @@ static int tg3_alloc_consistent(struct tg3 *tp)
        if (!tp->rx_rcb)
                goto err_out;
 
-       if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-               tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES,
-                                                  &tp->tx_desc_mapping);
-               if (!tp->tx_ring)
-                       goto err_out;
-       } else {
-               tp->tx_ring = NULL;
-               tp->tx_desc_mapping = 0;
-       }
+       tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES,
+                                          &tp->tx_desc_mapping);
+       if (!tp->tx_ring)
+               goto err_out;
 
        tp->hw_status = pci_alloc_consistent(tp->pdev,
                                             TG3_HW_STATUS_SIZE,
@@ -3595,6 +3770,8 @@ static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
        }
 }
 
+static void tg3_stop_fw(struct tg3 *);
+
 /* tp->lock is held. */
 static int tg3_chip_reset(struct tg3 *tp)
 {
@@ -3602,7 +3779,7 @@ static int tg3_chip_reset(struct tg3 *tp)
        u32 flags_save;
        int i;
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704))
+       if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X))
                tg3_nvram_lock(tp);
 
        /*
@@ -3688,7 +3865,7 @@ static int tg3_chip_reset(struct tg3 *tp)
                val |= PCISTATE_RETRY_SAME_DMA;
        pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
 
-       pci_restore_state(tp->pdev, tp->pci_cfg_state);
+       pci_restore_state(tp->pdev);
 
        /* Make sure PCI-X relaxed ordering bit is clear. */
        pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
@@ -3697,6 +3874,11 @@ static int tg3_chip_reset(struct tg3 *tp)
 
        tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
 
+       if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
+               tg3_stop_fw(tp);
+               tw32(0x5000, 0x400);
+       }
+
        tw32(GRC_MODE, tp->grc_mode);
 
        if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
@@ -3713,7 +3895,7 @@ static int tg3_chip_reset(struct tg3 *tp)
                tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
        }
 
-       if (tp->phy_id == PHY_ID_SERDES) {
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
                tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
                tw32_f(MAC_MODE, tp->mac_mode);
        } else
@@ -3728,7 +3910,7 @@ static int tg3_chip_reset(struct tg3 *tp)
                udelay(10);
        }
        if (i >= 100000 &&
-           !(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
+           !(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {
                printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, "
                       "firmware will not restart magic=%08x\n",
                       tp->dev->name, val);
@@ -4399,7 +4581,7 @@ static u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = {
        0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, 0x00000000, 0x00000000,
 };
 
-u32 tg3TsoFwRodata[] = {
+static u32 tg3TsoFwRodata[] = {
        0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
        0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x496e0000, 0x73746b6f,
        0x66662a2a, 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000,
@@ -4407,7 +4589,7 @@ u32 tg3TsoFwRodata[] = {
        0x00000000,
 };
 
-u32 tg3TsoFwData[] = {
+static u32 tg3TsoFwData[] = {
        0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x362e3000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000,
@@ -4588,14 +4770,14 @@ static u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = {
        0x00000000, 0x00000000, 0x00000000,
 };
 
-u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = {
+static u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = {
        0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
        0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000,
        0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
        0x00000000, 0x00000000, 0x00000000,
 };
 
-u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = {
+static u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = {
        0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x322e3000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000,
 };
@@ -4607,7 +4789,7 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
        unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
        int err, i;
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+       if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
                return 0;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
@@ -4691,9 +4873,8 @@ static void __tg3_set_mac_addr(struct tg3 *tp)
                tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
        }
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
                for (i = 0; i < 12; i++) {
                        tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
                        tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
@@ -4739,7 +4920,8 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr,
                      (bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS),
                       maxlen_flags);
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)
+       if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
+           (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750))
                tg3_write_mem(tp,
                              (bdinfo_addr + TG3_BDINFO_NIC_ADDR),
                              nic_addr);
@@ -4810,10 +4992,7 @@ static int tg3_reset_hw(struct tg3 *tp)
                          GRC_MODE_4X_NIC_SEND_RINGS |
                          GRC_MODE_NO_TX_PHDR_CSUM |
                          GRC_MODE_NO_RX_PHDR_CSUM);
-       if (tp->tg3_flags & TG3_FLAG_HOST_TXDS)
-               tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
-       else
-               tp->grc_mode |= GRC_MODE_4X_NIC_SEND_RINGS;
+       tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
        if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM)
                tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
        if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM)
@@ -4966,18 +5145,11 @@ static int tg3_reset_hw(struct tg3 *tp)
        tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
        tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
 
-       if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-               tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
-                              tp->tx_desc_mapping,
-                              (TG3_TX_RING_SIZE <<
-                               BDINFO_FLAGS_MAXLEN_SHIFT),
-                              NIC_SRAM_TX_BUFFER_DESC);
-       } else {
-               tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
-                              0,
-                              BDINFO_FLAGS_DISABLED,
-                              NIC_SRAM_TX_BUFFER_DESC);
-       }
+       tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
+                      tp->tx_desc_mapping,
+                      (TG3_TX_RING_SIZE <<
+                       BDINFO_FLAGS_MAXLEN_SHIFT),
+                      NIC_SRAM_TX_BUFFER_DESC);
 
        /* There is only one receive return ring on 5705/5750, no need
         * to explicitly disable the others.
@@ -5051,7 +5223,7 @@ static int tg3_reset_hw(struct tg3 *tp)
        }
 
 #if TG3_TSO_SUPPORT != 0
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+       if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
                rdmac_mode |= (1 << 27);
 #endif
 
@@ -5201,7 +5373,7 @@ static int tg3_reset_hw(struct tg3 *tp)
        tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
        tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
 #if TG3_TSO_SUPPORT != 0
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+       if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
                tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
 #endif
        tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE);
@@ -5243,16 +5415,18 @@ static int tg3_reset_hw(struct tg3 *tp)
        tw32(MAC_LED_CTRL, tp->led_ctrl);
 
        tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
-       if (tp->phy_id == PHY_ID_SERDES) {
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
                tw32_f(MAC_RX_MODE, RX_MODE_RESET);
                udelay(10);
        }
        tw32_f(MAC_RX_MODE, tp->rx_mode);
        udelay(10);
 
-       if (tp->phy_id == PHY_ID_SERDES) {
-               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+               if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
+                       !(tp->tg3_flags2 & TG3_FLG2_SERDES_PREEMPHASIS)) {
                        /* Set drive transmission level to 1.2V  */
+                       /* only if the signal pre-emphasis bit is not set  */
                        val = tr32(MAC_SERDES_CFG);
                        val &= 0xfffff000;
                        val |= 0x880;
@@ -5268,22 +5442,8 @@ static int tg3_reset_hw(struct tg3 *tp)
        tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2);
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
-           tp->phy_id == PHY_ID_SERDES) {
-               /* Enable hardware link auto-negotiation */
-               u32 digctrl, txctrl;
-
-               digctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_CRC16_CLEAR_N |
-                   SG_DIG_LOCAL_DUPLEX_STATUS | SG_DIG_LOCAL_LINK_STATUS |
-                   (2 << SG_DIG_SPEED_STATUS_SHIFT) | SG_DIG_FIBER_MODE |
-                   SG_DIG_GBIC_ENABLE;
-
-               txctrl = tr32(MAC_SERDES_CFG);
-               tw32_f(MAC_SERDES_CFG, txctrl | MAC_SERDES_CFG_EDGE_SELECT);
-               tw32_f(SG_DIG_CTRL, digctrl | SG_DIG_SOFT_RESET);
-               tr32(SG_DIG_CTRL);
-               udelay(5);
-               tw32_f(SG_DIG_CTRL, digctrl);
-
+           (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+               /* Use hardware link auto-negotiation */
                tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG;
        }
 
@@ -5291,13 +5451,14 @@ static int tg3_reset_hw(struct tg3 *tp)
        if (err)
                return err;
 
-       if (tp->phy_id != PHY_ID_SERDES) {
+       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
                u32 tmp;
 
                /* Clear CRC stats. */
-               tg3_readphy(tp, 0x1e, &tmp);
-               tg3_writephy(tp, 0x1e, tmp | 0x8000);
-               tg3_readphy(tp, 0x14, &tmp);
+               if (!tg3_readphy(tp, 0x1e, &tmp)) {
+                       tg3_writephy(tp, 0x1e, tmp | 0x8000);
+                       tg3_readphy(tp, 0x14, &tmp);
+               }
        }
 
        __tg3_set_rx_mode(tp->dev);
@@ -5483,7 +5644,8 @@ static void tg3_timer(unsigned long __opaque)
                                need_setup = 1;
                        }
                        if (! netif_carrier_ok(tp->dev) &&
-                           (mac_stat & MAC_STATUS_PCS_SYNCED)) {
+                           (mac_stat & (MAC_STATUS_PCS_SYNCED |
+                                        MAC_STATUS_SIGNAL_DET))) {
                                need_setup = 1;
                        }
                        if (need_setup) {
@@ -5536,8 +5698,8 @@ static int tg3_open(struct net_device *dev)
        spin_unlock(&tp->tx_lock);
        spin_unlock_irq(&tp->lock);
 
-       /* If you move this call, make sure TG3_FLAG_HOST_TXDS in
-        * tp->tg3_flags is accurate at that new place.
+       /* The placement of this call is tied
+        * to the setup and use of Host TX descriptors.
         */
        err = tg3_alloc_consistent(tp);
        if (err)
@@ -5879,16 +6041,18 @@ static unsigned long calc_crc_errors(struct tg3 *tp)
 {
        struct tg3_hw_stats *hw_stats = tp->hw_stats;
 
-       if (tp->phy_id != PHY_ID_SERDES &&
+       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
                unsigned long flags;
                u32 val;
 
                spin_lock_irqsave(&tp->lock, flags);
-               tg3_readphy(tp, 0x1e, &val);
-               tg3_writephy(tp, 0x1e, val | 0x8000);
-               tg3_readphy(tp, 0x14, &val);
+               if (!tg3_readphy(tp, 0x1e, &val)) {
+                       tg3_writephy(tp, 0x1e, val | 0x8000);
+                       tg3_readphy(tp, 0x14, &val);
+               } else
+                       val = 0;
                spin_unlock_irqrestore(&tp->lock, flags);
 
                tp->phy_crc_errors += val;
@@ -6152,7 +6316,9 @@ static void tg3_set_rx_mode(struct net_device *dev)
        struct tg3 *tp = netdev_priv(dev);
 
        spin_lock_irq(&tp->lock);
+       spin_lock(&tp->tx_lock);
        __tg3_set_rx_mode(dev);
+       spin_unlock(&tp->tx_lock);
        spin_unlock_irq(&tp->lock);
 }
 
@@ -6232,14 +6398,16 @@ do {    p = (u32 *)(orig_p + (reg));            \
 
 static int tg3_get_eeprom_len(struct net_device *dev)
 {
-       return EEPROM_CHIP_SIZE;
+       struct tg3 *tp = netdev_priv(dev);
+
+       return tp->nvram_size;
 }
 
-static int __devinit tg3_nvram_read_using_eeprom(struct tg3 *tp,
-                                                u32 offset, u32 *val);
+static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val);
+
 static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
 {
-       struct tg3 *tp = dev->priv;
+       struct tg3 *tp = netdev_priv(dev);
        int ret;
        u8  *pd;
        u32 i, offset, len, val, b_offset, b_count;
@@ -6248,10 +6416,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        len = eeprom->len;
        eeprom->len = 0;
 
-       ret = tg3_nvram_read_using_eeprom(tp, 0, &eeprom->magic);
-       if (ret)
-               return ret;
-       eeprom->magic = swab32(eeprom->magic);
+       eeprom->magic = TG3_EEPROM_MAGIC;
 
        if (offset & 3) {
                /* adjustments to start on required 4 byte boundary */
@@ -6261,9 +6426,10 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                        /* i.e. offset=1 len=2 */
                        b_count = len;
                }
-               ret = tg3_nvram_read_using_eeprom(tp, offset-b_offset, &val);
+               ret = tg3_nvram_read(tp, offset-b_offset, &val);
                if (ret)
                        return ret;
+               val = cpu_to_le32(val);
                memcpy(data, ((char*)&val) + b_offset, b_count);
                len -= b_count;
                offset += b_count;
@@ -6273,12 +6439,13 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        /* read bytes upto the last 4 byte boundary */
        pd = &data[eeprom->len];
        for (i = 0; i < (len - (len & 3)); i += 4) {
-               ret = tg3_nvram_read_using_eeprom(tp, offset + i, 
-                               (u32*)(pd + i));
+               ret = tg3_nvram_read(tp, offset + i, &val);
                if (ret) {
                        eeprom->len += i;
                        return ret;
                }
+               val = cpu_to_le32(val);
+               memcpy(pd + i, &val, 4);
        }
        eeprom->len += i;
 
@@ -6287,15 +6454,72 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                pd = &data[eeprom->len];
                b_count = len & 3;
                b_offset = offset + len - b_count;
-               ret = tg3_nvram_read_using_eeprom(tp, b_offset, &val);
+               ret = tg3_nvram_read(tp, b_offset, &val);
                if (ret)
                        return ret;
+               val = cpu_to_le32(val);
                memcpy(pd, ((char*)&val), b_count);
                eeprom->len += b_count;
        }
        return 0;
 }
 
+static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf); 
+
+static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
+{
+       struct tg3 *tp = netdev_priv(dev);
+       int ret;
+       u32 offset, len, b_offset, odd_len, start, end;
+       u8 *buf;
+
+       if (eeprom->magic != TG3_EEPROM_MAGIC)
+               return -EINVAL;
+
+       offset = eeprom->offset;
+       len = eeprom->len;
+
+       if ((b_offset = (offset & 3))) {
+               /* adjustments to start on required 4 byte boundary */
+               ret = tg3_nvram_read(tp, offset-b_offset, &start);
+               if (ret)
+                       return ret;
+               start = cpu_to_le32(start);
+               len += b_offset;
+               offset &= ~3;
+       }
+
+       odd_len = 0;
+       if ((len & 3) && ((len > 4) || (b_offset == 0))) {
+               /* adjustments to end on required 4 byte boundary */
+               odd_len = 1;
+               len = (len + 3) & ~3;
+               ret = tg3_nvram_read(tp, offset+len-4, &end);
+               if (ret)
+                       return ret;
+               end = cpu_to_le32(end);
+       }
+
+       buf = data;
+       if (b_offset || odd_len) {
+               buf = kmalloc(len, GFP_KERNEL);
+               if (buf == 0)
+                       return -ENOMEM;
+               if (b_offset)
+                       memcpy(buf, &start, 4);
+               if (odd_len)
+                       memcpy(buf+len-4, &end, 4);
+               memcpy(buf + b_offset, data, eeprom->len);
+       }
+
+       ret = tg3_nvram_write_block(tp, offset, len, buf);
+
+       if (buf != data)
+               kfree(buf);
+
+       return ret;
+}
+
 static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct tg3 *tp = netdev_priv(dev);
@@ -6310,7 +6534,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                cmd->supported |= (SUPPORTED_1000baseT_Half |
                                   SUPPORTED_1000baseT_Full);
 
-       if (tp->phy_id != PHY_ID_SERDES)
+       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES))
                cmd->supported |= (SUPPORTED_100baseT_Half |
                                  SUPPORTED_100baseT_Full |
                                  SUPPORTED_10baseT_Half |
@@ -6339,7 +6563,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
            tp->link_config.phy_is_low_power)
                return -EAGAIN;
 
-       if (tp->phy_id == PHY_ID_SERDES) {
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
                /* These are the only valid advertisement bits allowed.  */
                if (cmd->autoneg == AUTONEG_ENABLE &&
                    (cmd->advertising & ~(ADVERTISED_1000baseT_Half |
@@ -6397,7 +6621,7 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EINVAL;
        if ((wol->wolopts & WAKE_MAGIC) &&
-           tp->phy_id == PHY_ID_SERDES &&
+           tp->tg3_flags2 & TG3_FLG2_PHY_SERDES &&
            !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
                return -EINVAL;
   
@@ -6444,10 +6668,10 @@ static int tg3_nway_reset(struct net_device *dev)
        int r;
   
        spin_lock_irq(&tp->lock);
-       tg3_readphy(tp, MII_BMCR, &bmcr);
-       tg3_readphy(tp, MII_BMCR, &bmcr);
        r = -EINVAL;
-       if (bmcr & BMCR_ANENABLE) {
+       tg3_readphy(tp, MII_BMCR, &bmcr);
+       if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
+           (bmcr & BMCR_ANENABLE)) {
                tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART);
                r = 0;
        }
@@ -6493,10 +6717,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
 
        tg3_halt(tp);
        tg3_init_hw(tp);
-       netif_wake_queue(tp->dev);
+       tg3_netif_start(tp);
        spin_unlock(&tp->tx_lock);
        spin_unlock_irq(&tp->lock);
-       tg3_netif_start(tp);
   
        return 0;
 }
@@ -6506,8 +6729,8 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
        struct tg3 *tp = netdev_priv(dev);
   
        epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
-       epause->rx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0;
-       epause->tx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0;
+       epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0;
+       epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0;
 }
   
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
@@ -6522,18 +6745,18 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
        else
                tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
        if (epause->rx_pause)
-               tp->tg3_flags |= TG3_FLAG_PAUSE_RX;
+               tp->tg3_flags |= TG3_FLAG_RX_PAUSE;
        else
-               tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX;
+               tp->tg3_flags &= ~TG3_FLAG_RX_PAUSE;
        if (epause->tx_pause)
-               tp->tg3_flags |= TG3_FLAG_PAUSE_TX;
+               tp->tg3_flags |= TG3_FLAG_TX_PAUSE;
        else
-               tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX;
+               tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE;
        tg3_halt(tp);
        tg3_init_hw(tp);
+       tg3_netif_start(tp);
        spin_unlock(&tp->tx_lock);
        spin_unlock_irq(&tp->lock);
-       tg3_netif_start(tp);
   
        return 0;
 }
@@ -6602,7 +6825,7 @@ static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
 static void tg3_get_ethtool_stats (struct net_device *dev,
                                   struct ethtool_stats *estats, u64 *tmp_stats)
 {
-       struct tg3 *tp = dev->priv;
+       struct tg3 *tp = netdev_priv(dev);
        memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats));
 }
 
@@ -6620,7 +6843,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCGMIIREG: {
                u32 mii_regval;
 
-               if (tp->phy_id == PHY_ID_SERDES)
+               if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                        break;                  /* We have no PHY */
 
                spin_lock_irq(&tp->lock);
@@ -6633,7 +6856,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        }
 
        case SIOCSMIIREG:
-               if (tp->phy_id == PHY_ID_SERDES)
+               if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                        break;                  /* We have no PHY */
 
                if (!capable(CAP_NET_ADMIN))
@@ -6696,6 +6919,7 @@ static struct ethtool_ops tg3_ethtool_ops = {
        .get_link               = ethtool_op_get_link,
        .get_eeprom_len         = tg3_get_eeprom_len,
        .get_eeprom             = tg3_get_eeprom,
+       .set_eeprom             = tg3_set_eeprom,
        .get_ringparam          = tg3_get_ringparam,
        .set_ringparam          = tg3_set_ringparam,
        .get_pauseparam         = tg3_get_pauseparam,
@@ -6715,12 +6939,109 @@ static struct ethtool_ops tg3_ethtool_ops = {
        .get_ethtool_stats      = tg3_get_ethtool_stats,
 };
 
+static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
+{
+       u32 cursize, val;
+
+       tp->nvram_size = EEPROM_CHIP_SIZE;
+
+       if (tg3_nvram_read(tp, 0, &val) != 0)
+               return;
+
+       if (swab32(val) != TG3_EEPROM_MAGIC)
+               return;
+
+       /*
+        * Size the chip by reading offsets at increasing powers of two.
+        * When we encounter our validation signature, we know the addressing
+        * has wrapped around, and thus have our chip size.
+        */
+       cursize = 0x800;
+
+       while (cursize < tp->nvram_size) {
+               if (tg3_nvram_read(tp, cursize, &val) != 0)
+                       return;
+
+               if (swab32(val) == TG3_EEPROM_MAGIC)
+                       break;
+
+               cursize <<= 1;
+       }
+
+       tp->nvram_size = cursize;
+}
+               
+static void __devinit tg3_get_nvram_size(struct tg3 *tp)
+{
+       u32 val;
+
+       if (tg3_nvram_read(tp, 0xf0, &val) == 0) {
+               if (val != 0) {
+                       tp->nvram_size = (val >> 16) * 1024;
+                       return;
+               }
+       }
+       tp->nvram_size = 0x20000;
+}
+
+static void __devinit tg3_get_nvram_info(struct tg3 *tp)
+{
+       u32 nvcfg1;
+
+       nvcfg1 = tr32(NVRAM_CFG1);
+       if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
+               tp->tg3_flags2 |= TG3_FLG2_FLASH;
+       }
+       else {
+               nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
+               tw32(NVRAM_CFG1, nvcfg1);
+       }
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+               switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
+                       case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
+                               tp->nvram_jedecnum = JEDEC_ATMEL;
+                               tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
+                               tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+                               break;
+                       case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED:
+                               tp->nvram_jedecnum = JEDEC_ATMEL;
+                               tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE;
+                               break;
+                       case FLASH_VENDOR_ATMEL_EEPROM:
+                               tp->nvram_jedecnum = JEDEC_ATMEL;
+                               tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
+                               tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+                               break;
+                       case FLASH_VENDOR_ST:
+                               tp->nvram_jedecnum = JEDEC_ST;
+                               tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE;
+                               tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+                               break;
+                       case FLASH_VENDOR_SAIFUN:
+                               tp->nvram_jedecnum = JEDEC_SAIFUN;
+                               tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE;
+                               break;
+                       case FLASH_VENDOR_SST_SMALL:
+                       case FLASH_VENDOR_SST_LARGE:
+                               tp->nvram_jedecnum = JEDEC_SST;
+                               tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE;
+                               break;
+               }
+       }
+       else {
+               tp->nvram_jedecnum = JEDEC_ATMEL;
+               tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
+               tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+       }
+}
+
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
 static void __devinit tg3_nvram_init(struct tg3 *tp)
 {
        int j;
 
-       if (tp->tg3_flags2 & TG3_FLG2_SUN_5704)
+       if (tp->tg3_flags2 & TG3_FLG2_SUN_570X)
                return;
 
        tw32_f(GRC_EEPROM_ADDR,
@@ -6739,37 +7060,32 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
-               u32 nvcfg1;
+               tp->tg3_flags |= TG3_FLAG_NVRAM;
 
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
                        u32 nvaccess = tr32(NVRAM_ACCESS);
 
-                       tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+                       tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
                }
 
-               nvcfg1 = tr32(NVRAM_CFG1);
-
-               tp->tg3_flags |= TG3_FLAG_NVRAM;
-               if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
-                       if (nvcfg1 & NVRAM_CFG1_BUFFERED_MODE)
-                               tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
-               } else {
-                       nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
-                       tw32(NVRAM_CFG1, nvcfg1);
-               }
+               tg3_get_nvram_info(tp);
+               tg3_get_nvram_size(tp);
 
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
                        u32 nvaccess = tr32(NVRAM_ACCESS);
 
-                       tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
+                       tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
                }
+
        } else {
                tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
+
+               tg3_get_eeprom_size(tp);
        }
 }
 
-static int __devinit tg3_nvram_read_using_eeprom(struct tg3 *tp,
-                                                u32 offset, u32 *val)
+static int tg3_nvram_read_using_eeprom(struct tg3 *tp,
+                                       u32 offset, u32 *val)
 {
        u32 tmp;
        int i;
@@ -6802,23 +7118,46 @@ static int __devinit tg3_nvram_read_using_eeprom(struct tg3 *tp,
        return 0;
 }
 
-static int __devinit tg3_nvram_read(struct tg3 *tp,
-                                   u32 offset, u32 *val)
+#define NVRAM_CMD_TIMEOUT 10000
+
+static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
 {
        int i;
 
-       if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) {
-               printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 5704\n");
+       tw32(NVRAM_CMD, nvram_cmd);
+       for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) {
+               udelay(10);
+               if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
+                       udelay(10);
+                       break;
+               }
+       }
+       if (i == NVRAM_CMD_TIMEOUT) {
+               return -EBUSY;
+       }
+       return 0;
+}
+
+static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
+{
+       int ret;
+
+       if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
+               printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n");
                return -EINVAL;
        }
 
        if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
                return tg3_nvram_read_using_eeprom(tp, offset, val);
 
-       if (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED)
-               offset = ((offset / NVRAM_BUFFERED_PAGE_SIZE) <<
-                         NVRAM_BUFFERED_PAGE_POS) +
-                       (offset % NVRAM_BUFFERED_PAGE_SIZE);
+       if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
+               (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+               (tp->nvram_jedecnum == JEDEC_ATMEL)) {
+
+               offset = ((offset / tp->nvram_pagesize) <<
+                         ATMEL_AT45DB0X1B_PAGE_POS) +
+                       (offset % tp->nvram_pagesize);
+       }
 
        if (offset > NVRAM_ADDR_MSK)
                return -EINVAL;
@@ -6832,19 +7171,11 @@ static int __devinit tg3_nvram_read(struct tg3 *tp,
        }
 
        tw32(NVRAM_ADDR, offset);
-       tw32(NVRAM_CMD,
-            NVRAM_CMD_RD | NVRAM_CMD_GO |
-            NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
+       ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO |
+               NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
 
-       /* Wait for done bit to clear. */
-       for (i = 0; i < 1000; i++) {
-               udelay(10);
-               if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
-                       udelay(10);
-                       *val = swab32(tr32(NVRAM_RDDATA));
-                       break;
-               }
-       }
+       if (ret == 0)
+               *val = swab32(tr32(NVRAM_RDDATA));
 
        tg3_nvram_unlock(tp);
 
@@ -6854,10 +7185,268 @@ static int __devinit tg3_nvram_read(struct tg3 *tp,
                tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
        }
 
-       if (i >= 1000)
-               return -EBUSY;
+       return ret;
+}
 
-       return 0;
+static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
+                                   u32 offset, u32 len, u8 *buf)
+{
+       int i, j, rc = 0;
+       u32 val;
+
+       for (i = 0; i < len; i += 4) {
+               u32 addr, data;
+
+               addr = offset + i;
+
+               memcpy(&data, buf + i, 4);
+
+               tw32(GRC_EEPROM_DATA, cpu_to_le32(data));
+
+               val = tr32(GRC_EEPROM_ADDR);
+               tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
+
+               val &= ~(EEPROM_ADDR_ADDR_MASK | EEPROM_ADDR_DEVID_MASK |
+                       EEPROM_ADDR_READ);
+               tw32(GRC_EEPROM_ADDR, val |
+                       (0 << EEPROM_ADDR_DEVID_SHIFT) |
+                       (addr & EEPROM_ADDR_ADDR_MASK) |
+                       EEPROM_ADDR_START |
+                       EEPROM_ADDR_WRITE);
+               
+               for (j = 0; j < 10000; j++) {
+                       val = tr32(GRC_EEPROM_ADDR);
+
+                       if (val & EEPROM_ADDR_COMPLETE)
+                               break;
+                       udelay(100);
+               }
+               if (!(val & EEPROM_ADDR_COMPLETE)) {
+                       rc = -EBUSY;
+                       break;
+               }
+       }
+
+       return rc;
+}
+
+/* offset and length are dword aligned */
+static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
+               u8 *buf)
+{
+       int ret = 0;
+       u32 pagesize = tp->nvram_pagesize;
+       u32 pagemask = pagesize - 1;
+       u32 nvram_cmd;
+       u8 *tmp;
+
+       tmp = kmalloc(pagesize, GFP_KERNEL);
+       if (tmp == NULL)
+               return -ENOMEM;
+
+       while (len) {
+               int j;
+               u32 phy_addr, page_off, size, nvaccess;
+
+               phy_addr = offset & ~pagemask;
+       
+               for (j = 0; j < pagesize; j += 4) {
+                       if ((ret = tg3_nvram_read(tp, phy_addr + j,
+                                               (u32 *) (tmp + j))))
+                               break;
+               }
+               if (ret)
+                       break;
+
+               page_off = offset & pagemask;
+               size = pagesize;
+               if (len < size)
+                       size = len;
+
+               len -= size;
+
+               memcpy(tmp + page_off, buf, size);
+
+               offset = offset + (pagesize - page_off);
+
+               nvaccess = tr32(NVRAM_ACCESS);
+               tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+
+               /*
+                * Before we can erase the flash page, we need
+                * to issue a special "write enable" command.
+                */
+               nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
+
+               if (tg3_nvram_exec_cmd(tp, nvram_cmd))
+                       break;
+
+               /* Erase the target page */
+               tw32(NVRAM_ADDR, phy_addr);
+
+               nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR |
+                       NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE;
+
+               if (tg3_nvram_exec_cmd(tp, nvram_cmd))
+                       break;
+
+               /* Issue another write enable to start the write. */
+               nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
+
+               if (tg3_nvram_exec_cmd(tp, nvram_cmd))
+                       break;
+
+               for (j = 0; j < pagesize; j += 4) {
+                       u32 data;
+
+                       data = *((u32 *) (tmp + j));
+                       tw32(NVRAM_WRDATA, cpu_to_be32(data));
+
+                       tw32(NVRAM_ADDR, phy_addr + j);
+
+                       nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE |
+                               NVRAM_CMD_WR;
+
+                       if (j == 0)
+                               nvram_cmd |= NVRAM_CMD_FIRST;
+                       else if (j == (pagesize - 4))
+                               nvram_cmd |= NVRAM_CMD_LAST;
+
+                       if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd)))
+                               break;
+               }
+               if (ret)
+                       break;
+       }
+
+       nvram_cmd = NVRAM_CMD_WRDI | NVRAM_CMD_GO | NVRAM_CMD_DONE;
+       tg3_nvram_exec_cmd(tp, nvram_cmd);
+
+       kfree(tmp);
+
+       return ret;
+}
+
+/* offset and length are dword aligned */
+static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
+               u8 *buf)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < len; i += 4, offset += 4) {
+               u32 data, page_off, phy_addr, nvram_cmd;
+
+               memcpy(&data, buf + i, 4);
+               tw32(NVRAM_WRDATA, cpu_to_be32(data));
+
+               page_off = offset % tp->nvram_pagesize;
+
+               if ((tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+                       (tp->nvram_jedecnum == JEDEC_ATMEL)) {
+
+                       phy_addr = ((offset / tp->nvram_pagesize) <<
+                                   ATMEL_AT45DB0X1B_PAGE_POS) + page_off;
+               }
+               else {
+                       phy_addr = offset;
+               }
+
+               tw32(NVRAM_ADDR, phy_addr);
+
+               nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR;
+
+               if ((page_off == 0) || (i == 0))
+                       nvram_cmd |= NVRAM_CMD_FIRST;
+               else if (page_off == (tp->nvram_pagesize - 4))
+                       nvram_cmd |= NVRAM_CMD_LAST;
+
+               if (i == (len - 4))
+                       nvram_cmd |= NVRAM_CMD_LAST;
+
+               if ((tp->nvram_jedecnum == JEDEC_ST) &&
+                       (nvram_cmd & NVRAM_CMD_FIRST)) {
+
+                       if ((ret = tg3_nvram_exec_cmd(tp,
+                               NVRAM_CMD_WREN | NVRAM_CMD_GO |
+                               NVRAM_CMD_DONE)))
+
+                               break;
+               }
+               if (!(tp->tg3_flags2 & TG3_FLG2_FLASH)) {
+                       /* We always do complete word writes to eeprom. */
+                       nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST);
+               }
+
+               if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd)))
+                       break;
+       }
+       return ret;
+}
+
+/* offset and length are dword aligned */
+static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
+{
+       int ret;
+
+       if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
+               printk(KERN_ERR PFX "Attempt to do nvram_write on Sun 570X\n");
+               return -EINVAL;
+       }
+
+       if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
+               tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+                      GRC_LCLCTRL_GPIO_OE1);
+               udelay(40);
+       }
+
+       if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) {
+               ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf);
+       }
+       else {
+               u32 grc_mode;
+
+               tg3_nvram_lock(tp);
+
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+                       u32 nvaccess = tr32(NVRAM_ACCESS);
+
+                       tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+
+                       tw32(NVRAM_WRITE1, 0x406);
+               }
+
+               grc_mode = tr32(GRC_MODE);
+               tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE);
+
+               if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) ||
+                       !(tp->tg3_flags2 & TG3_FLG2_FLASH)) {
+
+                       ret = tg3_nvram_write_block_buffered(tp, offset, len,
+                               buf);
+               }
+               else {
+                       ret = tg3_nvram_write_block_unbuffered(tp, offset, len,
+                               buf);
+               }
+
+               grc_mode = tr32(GRC_MODE);
+               tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE);
+
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+                       u32 nvaccess = tr32(NVRAM_ACCESS);
+
+                       tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
+               }
+               tg3_nvram_unlock(tp);
+       }
+
+       if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
+               tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+                      GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1);
+               udelay(40);
+       }
+
+       return ret;
 }
 
 struct subsys_tbl_ent {
@@ -6870,10 +7459,10 @@ static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
        { PCI_VENDOR_ID_BROADCOM, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */
        { PCI_VENDOR_ID_BROADCOM, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */
        { PCI_VENDOR_ID_BROADCOM, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */
-       { PCI_VENDOR_ID_BROADCOM, 0x0003, PHY_ID_SERDES  }, /* BCM95700A9 */
+       { PCI_VENDOR_ID_BROADCOM, 0x0003, 0 },              /* BCM95700A9 */
        { PCI_VENDOR_ID_BROADCOM, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */
        { PCI_VENDOR_ID_BROADCOM, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */
-       { PCI_VENDOR_ID_BROADCOM, 0x0007, PHY_ID_SERDES  }, /* BCM95701A7 */
+       { PCI_VENDOR_ID_BROADCOM, 0x0007, 0 },              /* BCM95701A7 */
        { PCI_VENDOR_ID_BROADCOM, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */
        { PCI_VENDOR_ID_BROADCOM, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */
        { PCI_VENDOR_ID_BROADCOM, 0x0009, PHY_ID_BCM5703 }, /* BCM95703Ax1 */
@@ -6882,7 +7471,7 @@ static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
        /* 3com boards. */
        { PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */
        { PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */
-       { PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES  }, /* 3C996SX */
+       { PCI_VENDOR_ID_3COM, 0x1004, 0 },              /* 3C996SX */
        { PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */
        { PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */
 
@@ -6895,63 +7484,74 @@ static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
        /* Compaq boards. */
        { PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
        { PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */
-       { PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES  }, /* CHANGELING */
+       { PCI_VENDOR_ID_COMPAQ, 0x007d, 0 },              /* CHANGELING */
        { PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */
        { PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }, /* NC7780_2 */
 
        /* IBM boards. */
-       { PCI_VENDOR_ID_IBM, 0x0281, PHY_ID_SERDES } /* IBM??? */
+       { PCI_VENDOR_ID_IBM, 0x0281, 0 } /* IBM??? */
 };
 
-static int __devinit tg3_phy_probe(struct tg3 *tp)
+static inline struct subsys_tbl_ent *lookup_by_subsys(struct tg3 *tp)
 {
-       u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2;
-       u32 hw_phy_id, hw_phy_id_masked;
-       u32 val;
-       int i, eeprom_signature_found, err;
+       int i;
 
-       tp->phy_id = PHY_ID_INVALID;
        for (i = 0; i < ARRAY_SIZE(subsys_id_to_phy_id); i++) {
                if ((subsys_id_to_phy_id[i].subsys_vendor ==
                     tp->pdev->subsystem_vendor) &&
                    (subsys_id_to_phy_id[i].subsys_devid ==
-                    tp->pdev->subsystem_device)) {
-                       tp->phy_id = subsys_id_to_phy_id[i].phy_id;
-                       break;
-               }
+                    tp->pdev->subsystem_device))
+                       return &subsys_id_to_phy_id[i];
        }
+       return NULL;
+}
 
+static int __devinit tg3_phy_probe(struct tg3 *tp)
+{
+       u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2;
+       u32 hw_phy_id, hw_phy_id_masked;
+       u32 val;
+       int eeprom_signature_found, eeprom_phy_serdes, err;
+
+       tp->phy_id = PHY_ID_INVALID;
        eeprom_phy_id = PHY_ID_INVALID;
+       eeprom_phy_serdes = 0;
        eeprom_signature_found = 0;
        tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
        if (val == NIC_SRAM_DATA_SIG_MAGIC) {
                u32 nic_cfg, led_cfg;
+               u32 nic_phy_id, ver, cfg2 = 0;
 
                tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
                tp->nic_sram_data_cfg = nic_cfg;
 
+               tg3_read_mem(tp, NIC_SRAM_DATA_VER, &ver);
+               ver >>= NIC_SRAM_DATA_VER_SHIFT;
+               if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703) &&
+                   (ver > 0) && (ver < 0x100))
+                       tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
+
                eeprom_signature_found = 1;
 
                if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
-                   NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) {
-                       eeprom_phy_id = PHY_ID_SERDES;
-               } else {
-                       u32 nic_phy_id;
+                   NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER)
+                       eeprom_phy_serdes = 1;
 
-                       tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id);
-                       if (nic_phy_id != 0) {
-                               u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK;
-                               u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK;
+               tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id);
+               if (nic_phy_id != 0) {
+                       u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK;
+                       u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK;
 
-                               eeprom_phy_id  = (id1 >> 16) << 10;
-                               eeprom_phy_id |= (id2 & 0xfc00) << 16;
-                               eeprom_phy_id |= (id2 & 0x03ff) <<  0;
-                       }
-               }
+                       eeprom_phy_id  = (id1 >> 16) << 10;
+                       eeprom_phy_id |= (id2 & 0xfc00) << 16;
+                       eeprom_phy_id |= (id2 & 0x03ff) <<  0;
+               } else
+                       eeprom_phy_id = 0;
 
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
-                       tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &led_cfg);
-                       led_cfg &= (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
+                       led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
                                    SHASTA_EXT_LED_MODE_MASK);
                } else
                        led_cfg = nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK;
@@ -6996,9 +7596,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
                    tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
                        tp->led_ctrl = LED_CTRL_MODE_PHY_2;
 
-               if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
-                    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
-                    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) &&
+               if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
                    (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP))
                        tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
 
@@ -7009,6 +7608,14 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
                }
                if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
                        tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
+
+               if (cfg2 & (1 << 17))
+                       tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
+
+               /* serdes signal pre-emphasis in register 0x590 set by */
+               /* bootcode if bit 18 is set */
+               if (cfg2 & (1 << 18))
+                       tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS;
        }
 
        /* Reading the PHY ID register can conflict with ASF
@@ -7035,27 +7642,37 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
 
        if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) {
                tp->phy_id = hw_phy_id;
+               if (hw_phy_id_masked == PHY_ID_BCM8002)
+                       tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
        } else {
-               /* phy_id currently holds the value found in the
-                * subsys_id_to_phy_id[] table or PHY_ID_INVALID
-                * if a match was not found there.
-                */
-               if (tp->phy_id == PHY_ID_INVALID) {
-                       if (!eeprom_signature_found ||
-                           !KNOWN_PHY_ID(eeprom_phy_id & PHY_ID_MASK))
-                               return -ENODEV;
+               if (eeprom_signature_found) {
                        tp->phy_id = eeprom_phy_id;
+                       if (eeprom_phy_serdes)
+                               tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+               } else {
+                       struct subsys_tbl_ent *p;
+
+                       /* No eeprom signature?  Try the hardcoded
+                        * subsys device table.
+                        */
+                       p = lookup_by_subsys(tp);
+                       if (!p)
+                               return -ENODEV;
+
+                       tp->phy_id = p->phy_id;
+                       if (!tp->phy_id ||
+                           tp->phy_id == PHY_ID_BCM8002)
+                               tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
                }
        }
 
-       if (tp->phy_id != PHY_ID_SERDES &&
+       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
            !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
                u32 bmsr, adv_reg, tg3_ctrl;
 
                tg3_readphy(tp, MII_BMSR, &bmsr);
-               tg3_readphy(tp, MII_BMSR, &bmsr);
-
-               if (bmsr & BMSR_LSTATUS)
+               if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+                   (bmsr & BMSR_LSTATUS))
                        goto skip_phy_reset;
                    
                err = tg3_phy_reset(tp);
@@ -7105,7 +7722,7 @@ skip_phy_reset:
        if (!eeprom_signature_found)
                tp->led_ctrl = LED_CTRL_MODE_PHY_1;
 
-       if (tp->phy_id == PHY_ID_SERDES)
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                tp->link_config.advertising =
                        (ADVERTISED_1000baseT_Half |
                         ADVERTISED_1000baseT_Full |
@@ -7124,11 +7741,11 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
        unsigned char vpd_data[256];
        int i;
 
-       if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) {
+       if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
                /* Sun decided not to put the necessary bits in the
                 * NVRAM of their onboard tg3 parts :(
                 */
-               strcpy(tp->board_part_number, "Sun 5704");
+               strcpy(tp->board_part_number, "Sun 570X");
                return;
        }
 
@@ -7189,27 +7806,21 @@ out_not_found:
 }
 
 #ifdef CONFIG_SPARC64
-static int __devinit tg3_is_sun_5704(struct tg3 *tp)
+static int __devinit tg3_is_sun_570X(struct tg3 *tp)
 {
        struct pci_dev *pdev = tp->pdev;
        struct pcidev_cookie *pcp = pdev->sysdata;
 
        if (pcp != NULL) {
                int node = pcp->prom_node;
-               u32 venid, devid;
+               u32 venid;
                int err;
 
                err = prom_getproperty(node, "subsystem-vendor-id",
                                       (char *) &venid, sizeof(venid));
                if (err == 0 || err == -1)
                        return 0;
-               err = prom_getproperty(node, "subsystem-id",
-                                      (char *) &devid, sizeof(devid));
-               if (err == 0 || err == -1)
-                       return 0;
-
-               if (venid == PCI_VENDOR_ID_SUN &&
-                   devid == PCI_DEVICE_ID_TIGON3_5704)
+               if (venid == PCI_VENDOR_ID_SUN)
                        return 1;
        }
        return 0;
@@ -7226,8 +7837,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        int err;
 
 #ifdef CONFIG_SPARC64
-       if (tg3_is_sun_5704(tp))
-               tp->tg3_flags2 |= TG3_FLG2_SUN_5704;
+       if (tg3_is_sun_570X(tp))
+               tp->tg3_flags2 |= TG3_FLG2_SUN_570X;
 #endif
 
        /* If we have an AMD 762 or Intel ICH/ICH0/ICH2 chipset, write
@@ -7285,6 +7896,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        tp->pci_hdr_type     = (cacheline_sz_reg >> 16) & 0xff;
        tp->pci_bist         = (cacheline_sz_reg >> 24) & 0xff;
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+               tp->tg3_flags2 |= TG3_FLG2_HW_TSO;
+
        if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
                tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
 
@@ -7453,7 +8067,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                    chiprevid == CHIPREV_ID_5701_B0 ||
                    chiprevid == CHIPREV_ID_5701_B2 ||
                    chiprevid == CHIPREV_ID_5701_B5) {
-                       unsigned long sram_base;
+                       void __iomem *sram_base;
 
                        /* Write some dummy words into the SRAM status block
                         * area, see if it reads back correctly.  If the return
@@ -7472,32 +8086,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        udelay(50);
        tg3_nvram_init(tp);
 
-       /* Always use host TXDs, it performs better in particular
-        * with multi-frag packets.  The tests below are kept here
-        * as documentation should we change this decision again
-        * in the future.
-        */
-       tp->tg3_flags |= TG3_FLAG_HOST_TXDS;
-
-#if 0
-       /* Determine if TX descriptors will reside in
-        * main memory or in the chip SRAM.
-        */
-       if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
-               tp->tg3_flags |= TG3_FLAG_HOST_TXDS;
-#endif
-
        grc_misc_cfg = tr32(GRC_MISC_CFG);
        grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
 
+       /* Broadcom's driver says that CIOBE multisplit has a bug */
+#if 0
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
            grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) {
                tp->tg3_flags |= TG3_FLAG_SPLIT_MODE;
                tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ;
        }
-
+#endif
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
            (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
             grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
@@ -7512,7 +8111,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
              tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2 ||
              tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) ||
            (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
-            tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F))
+            (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F ||
+             tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)))
                tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
 
        err = tg3_phy_probe(tp);
@@ -7524,7 +8124,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 
        tg3_read_partno(tp);
 
-       if (tp->phy_id == PHY_ID_SERDES) {
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
                tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT;
        } else {
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
@@ -7547,13 +8147,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
         * upon subsystem IDs.
         */
        if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
-           tp->phy_id != PHY_ID_SERDES) {
+           !(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
                tp->tg3_flags |= (TG3_FLAG_USE_MI_INTERRUPT |
                                  TG3_FLAG_USE_LINKCHG_REG);
        }
 
        /* For all SERDES we poll the MAC status register. */
-       if (tp->phy_id == PHY_ID_SERDES)
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                tp->tg3_flags |= TG3_FLAG_POLL_SERDES;
        else
                tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
@@ -7624,7 +8224,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
 
        mac_offset = 0x7c;
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
-           !(tp->tg3_flags & TG3_FLG2_SUN_5704)) {
+           !(tp->tg3_flags & TG3_FLG2_SUN_570X)) {
                if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
                        mac_offset = 0xcc;
                if (tg3_nvram_lock(tp))
@@ -7646,7 +8246,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
                dev->dev_addr[5] = (lo >>  0) & 0xff;
        }
        /* Next, try NVRAM. */
-       else if (!(tp->tg3_flags & TG3_FLG2_SUN_5704) &&
+       else if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) &&
                 !tg3_nvram_read(tp, mac_offset + 0, &hi) &&
                 !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
                dev->dev_addr[0] = ((hi >> 16) & 0xff);
@@ -7819,7 +8419,8 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
 #endif
 
        if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
-               tp->dma_rwctrl |= 0x001f0000;
+               /* DMA read watermark not used on PCIE */
+               tp->dma_rwctrl |= 0x00180000;
        } else if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
@@ -7988,8 +8589,8 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
        case PHY_ID_BCM5704:    return "5704";
        case PHY_ID_BCM5705:    return "5705";
        case PHY_ID_BCM5750:    return "5750";
-       case PHY_ID_BCM8002:    return "8002";
-       case PHY_ID_SERDES:     return "serdes";
+       case PHY_ID_BCM8002:    return "8002/serdes";
+       case 0:                 return "serdes";
        default:                return "unknown";
        };
 }
@@ -8096,6 +8697,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        if (pci_using_dac)
                dev->features |= NETIF_F_HIGHDMA;
+       dev->features |= NETIF_F_LLTX;
 #if TG3_VLAN_TAG_USED
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
        dev->vlan_rx_register = tg3_vlan_rx_register;
@@ -8141,7 +8743,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        spin_lock_init(&tp->indirect_lock);
        INIT_WORK(&tp->reset_task, tg3_reset_task, tp);
 
-       tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
+       tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len);
        if (tp->regs == 0UL) {
                printk(KERN_ERR PFX "Cannot map device registers, "
                       "aborting.\n");
@@ -8192,11 +8794,13 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        }
 
 #if TG3_TSO_SUPPORT != 0
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+       if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
+               tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
+       }
+       else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
            tp->pci_chip_rev_id == CHIPREV_ID_5705_A0 ||
-           ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0 &&
-            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750)) {
+           (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) {
                tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
        } else {
                tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
@@ -8234,7 +8838,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
         */
        if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
            (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
-               pci_save_state(tp->pdev, tp->pci_cfg_state);
+               pci_save_state(tp->pdev);
                tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
                tg3_halt(tp);
        }
@@ -8257,6 +8861,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        if (tp->tg3_flags2 & TG3_FLG2_IS_5788)
                dev->features &= ~NETIF_F_HIGHDMA;
 
+       /* flow control autonegotiation is default behavior */
+       tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+
        err = register_netdev(dev);
        if (err) {
                printk(KERN_ERR PFX "Cannot register net device, "
@@ -8270,7 +8877,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
         * of the PCI config space.  We need to restore this after
         * GRC_MISC_CFG core clock resets and some resume events.
         */
-       pci_save_state(tp->pdev, tp->pci_cfg_state);
+       pci_save_state(tp->pdev);
 
        printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (PCI%s:%s:%s) %sBaseT Ethernet ",
               dev->name,
@@ -8288,11 +8895,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                printk("%2.2x%c", dev->dev_addr[i],
                       i == 5 ? '\n' : ':');
 
-       printk(KERN_INFO "%s: HostTXDS[%d] RXcsums[%d] LinkChgREG[%d] "
+       printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] "
               "MIirq[%d] ASF[%d] Split[%d] WireSpeed[%d] "
               "TSOcap[%d] \n",
               dev->name,
-              (tp->tg3_flags & TG3_FLAG_HOST_TXDS) != 0,
               (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0,
               (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0,
               (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0,
@@ -8304,7 +8910,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        return 0;
 
 err_out_iounmap:
-       iounmap((void *) tp->regs);
+       iounmap(tp->regs);
 
 err_out_free_dev:
        free_netdev(dev);
@@ -8326,7 +8932,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
                struct tg3 *tp = netdev_priv(dev);
 
                unregister_netdev(dev);
-               iounmap((void *)tp->regs);
+               iounmap(tp->regs);
                free_netdev(dev);
                pci_release_regions(pdev);
                pci_disable_device(pdev);
@@ -8371,11 +8977,11 @@ static int tg3_suspend(struct pci_dev *pdev, u32 state)
                tp->timer.expires = jiffies + tp->timer_offset;
                add_timer(&tp->timer);
 
-               spin_unlock(&tp->tx_lock);
-               spin_unlock_irq(&tp->lock);
-
                netif_device_attach(dev);
                tg3_netif_start(tp);
+
+               spin_unlock(&tp->tx_lock);
+               spin_unlock_irq(&tp->lock);
        }
 
        return err;
@@ -8390,7 +8996,7 @@ static int tg3_resume(struct pci_dev *pdev)
        if (!netif_running(dev))
                return 0;
 
-       pci_restore_state(tp->pdev, tp->pci_cfg_state);
+       pci_restore_state(tp->pdev);
 
        err = tg3_set_power_state(tp, 0);
        if (err)
@@ -8408,11 +9014,11 @@ static int tg3_resume(struct pci_dev *pdev)
 
        tg3_enable_ints(tp);
 
+       tg3_netif_start(tp);
+
        spin_unlock(&tp->tx_lock);
        spin_unlock_irq(&tp->lock);
 
-       tg3_netif_start(tp);
-
        return 0;
 }