netdev: Add netdev->addr_list_lock protection.
[safe/jmp/linux-2.6] / drivers / net / tg3.c
index b571b20..633c128 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/brcmphy.h>
 #include <linux/if_vlan.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
@@ -64,8 +66,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.86"
-#define DRV_MODULE_RELDATE     "November 9, 2007"
+#define DRV_MODULE_VERSION     "3.93"
+#define DRV_MODULE_RELDATE     "May 22, 2008"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -203,6 +205,7 @@ static struct pci_device_id tg3_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -804,6 +807,575 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
        return ret;
 }
 
+static int tg3_bmcr_reset(struct tg3 *tp)
+{
+       u32 phy_control;
+       int limit, err;
+
+       /* OK, reset it, and poll the BMCR_RESET bit until it
+        * clears or we time out.
+        */
+       phy_control = BMCR_RESET;
+       err = tg3_writephy(tp, MII_BMCR, phy_control);
+       if (err != 0)
+               return -EBUSY;
+
+       limit = 5000;
+       while (limit--) {
+               err = tg3_readphy(tp, MII_BMCR, &phy_control);
+               if (err != 0)
+                       return -EBUSY;
+
+               if ((phy_control & BMCR_RESET) == 0) {
+                       udelay(40);
+                       break;
+               }
+               udelay(10);
+       }
+       if (limit <= 0)
+               return -EBUSY;
+
+       return 0;
+}
+
+static int tg3_mdio_read(struct mii_bus *bp, int mii_id, int reg)
+{
+       struct tg3 *tp = (struct tg3 *)bp->priv;
+       u32 val;
+
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
+               return -EAGAIN;
+
+       if (tg3_readphy(tp, reg, &val))
+               return -EIO;
+
+       return val;
+}
+
+static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val)
+{
+       struct tg3 *tp = (struct tg3 *)bp->priv;
+
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
+               return -EAGAIN;
+
+       if (tg3_writephy(tp, reg, val))
+               return -EIO;
+
+       return 0;
+}
+
+static int tg3_mdio_reset(struct mii_bus *bp)
+{
+       return 0;
+}
+
+static void tg3_mdio_config(struct tg3 *tp)
+{
+       u32 val;
+
+       if (tp->mdio_bus.phy_map[PHY_ADDR]->interface !=
+           PHY_INTERFACE_MODE_RGMII)
+               return;
+
+       val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC |
+                                   MAC_PHYCFG1_RGMII_SND_STAT_EN);
+       if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) {
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+                       val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+                       val |= MAC_PHYCFG1_RGMII_SND_STAT_EN;
+       }
+       tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV);
+
+       val = tr32(MAC_PHYCFG2) & ~(MAC_PHYCFG2_INBAND_ENABLE);
+       if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE))
+               val |= MAC_PHYCFG2_INBAND_ENABLE;
+       tw32(MAC_PHYCFG2, val);
+
+       val = tr32(MAC_EXT_RGMII_MODE);
+       val &= ~(MAC_RGMII_MODE_RX_INT_B |
+                MAC_RGMII_MODE_RX_QUALITY |
+                MAC_RGMII_MODE_RX_ACTIVITY |
+                MAC_RGMII_MODE_RX_ENG_DET |
+                MAC_RGMII_MODE_TX_ENABLE |
+                MAC_RGMII_MODE_TX_LOWPWR |
+                MAC_RGMII_MODE_TX_RESET);
+       if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) {
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+                       val |= MAC_RGMII_MODE_RX_INT_B |
+                              MAC_RGMII_MODE_RX_QUALITY |
+                              MAC_RGMII_MODE_RX_ACTIVITY |
+                              MAC_RGMII_MODE_RX_ENG_DET;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+                       val |= MAC_RGMII_MODE_TX_ENABLE |
+                              MAC_RGMII_MODE_TX_LOWPWR |
+                              MAC_RGMII_MODE_TX_RESET;
+       }
+       tw32(MAC_EXT_RGMII_MODE, val);
+}
+
+static void tg3_mdio_start(struct tg3 *tp)
+{
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
+               mutex_lock(&tp->mdio_bus.mdio_lock);
+               tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
+               mutex_unlock(&tp->mdio_bus.mdio_lock);
+       }
+
+       tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
+       tw32_f(MAC_MI_MODE, tp->mi_mode);
+       udelay(80);
+
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)
+               tg3_mdio_config(tp);
+}
+
+static void tg3_mdio_stop(struct tg3 *tp)
+{
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
+               mutex_lock(&tp->mdio_bus.mdio_lock);
+               tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED;
+               mutex_unlock(&tp->mdio_bus.mdio_lock);
+       }
+}
+
+static int tg3_mdio_init(struct tg3 *tp)
+{
+       int i;
+       u32 reg;
+       struct phy_device *phydev;
+       struct mii_bus *mdio_bus = &tp->mdio_bus;
+
+       tg3_mdio_start(tp);
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) ||
+           (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED))
+               return 0;
+
+       memset(mdio_bus, 0, sizeof(*mdio_bus));
+
+       mdio_bus->name     = "tg3 mdio bus";
+       snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x",
+                (tp->pdev->bus->number << 8) | tp->pdev->devfn);
+       mdio_bus->priv     = tp;
+       mdio_bus->dev      = &tp->pdev->dev;
+       mdio_bus->read     = &tg3_mdio_read;
+       mdio_bus->write    = &tg3_mdio_write;
+       mdio_bus->reset    = &tg3_mdio_reset;
+       mdio_bus->phy_mask = ~(1 << PHY_ADDR);
+       mdio_bus->irq      = &tp->mdio_irq[0];
+
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               mdio_bus->irq[i] = PHY_POLL;
+
+       /* The bus registration will look for all the PHYs on the mdio bus.
+        * Unfortunately, it does not ensure the PHY is powered up before
+        * accessing the PHY ID registers.  A chip reset is the
+        * quickest way to bring the device back to an operational state..
+        */
+       if (tg3_readphy(tp, MII_BMCR, &reg) || (reg & BMCR_PDOWN))
+               tg3_bmcr_reset(tp);
+
+       i = mdiobus_register(mdio_bus);
+       if (i) {
+               printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n",
+                       tp->dev->name, i);
+               return i;
+       }
+
+       tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED;
+
+       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+       switch (phydev->phy_id) {
+       case TG3_PHY_ID_BCM50610:
+               phydev->interface = PHY_INTERFACE_MODE_RGMII;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)
+                       phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+                       phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+                       phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE;
+               break;
+       case TG3_PHY_ID_BCMAC131:
+               phydev->interface = PHY_INTERFACE_MODE_MII;
+               break;
+       }
+
+       tg3_mdio_config(tp);
+
+       return 0;
+}
+
+static void tg3_mdio_fini(struct tg3 *tp)
+{
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
+               tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED;
+               mdiobus_unregister(&tp->mdio_bus);
+               tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
+       }
+}
+
+/* tp->lock is held. */
+static void tg3_wait_for_event_ack(struct tg3 *tp)
+{
+       int i;
+
+       /* Wait for up to 2.5 milliseconds */
+       for (i = 0; i < 250000; i++) {
+               if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
+                       break;
+               udelay(10);
+       }
+}
+
+/* tp->lock is held. */
+static void tg3_ump_link_report(struct tg3 *tp)
+{
+       u32 reg;
+       u32 val;
+
+       if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
+           !(tp->tg3_flags  & TG3_FLAG_ENABLE_ASF))
+               return;
+
+       tg3_wait_for_event_ack(tp);
+
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
+
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
+
+       val = 0;
+       if (!tg3_readphy(tp, MII_BMCR, &reg))
+               val = reg << 16;
+       if (!tg3_readphy(tp, MII_BMSR, &reg))
+               val |= (reg & 0xffff);
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
+
+       val = 0;
+       if (!tg3_readphy(tp, MII_ADVERTISE, &reg))
+               val = reg << 16;
+       if (!tg3_readphy(tp, MII_LPA, &reg))
+               val |= (reg & 0xffff);
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
+
+       val = 0;
+       if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) {
+               if (!tg3_readphy(tp, MII_CTRL1000, &reg))
+                       val = reg << 16;
+               if (!tg3_readphy(tp, MII_STAT1000, &reg))
+                       val |= (reg & 0xffff);
+       }
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
+
+       if (!tg3_readphy(tp, MII_PHYADDR, &reg))
+               val = reg << 16;
+       else
+               val = 0;
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
+
+       val = tr32(GRC_RX_CPU_EVENT);
+       val |= GRC_RX_CPU_DRIVER_EVENT;
+       tw32_f(GRC_RX_CPU_EVENT, val);
+}
+
+static void tg3_link_report(struct tg3 *tp)
+{
+       if (!netif_carrier_ok(tp->dev)) {
+               if (netif_msg_link(tp))
+                       printk(KERN_INFO PFX "%s: Link is down.\n",
+                              tp->dev->name);
+               tg3_ump_link_report(tp);
+       } else if (netif_msg_link(tp)) {
+               printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
+                      tp->dev->name,
+                      (tp->link_config.active_speed == SPEED_1000 ?
+                       1000 :
+                       (tp->link_config.active_speed == SPEED_100 ?
+                        100 : 10)),
+                      (tp->link_config.active_duplex == DUPLEX_FULL ?
+                       "full" : "half"));
+
+               printk(KERN_INFO PFX
+                      "%s: Flow control is %s for TX and %s for RX.\n",
+                      tp->dev->name,
+                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
+                      "on" : "off",
+                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
+                      "on" : "off");
+               tg3_ump_link_report(tp);
+       }
+}
+
+static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl)
+{
+       u16 miireg;
+
+       if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+               miireg = ADVERTISE_PAUSE_CAP;
+       else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+               miireg = ADVERTISE_PAUSE_ASYM;
+       else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+               miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+       else
+               miireg = 0;
+
+       return miireg;
+}
+
+static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
+{
+       u16 miireg;
+
+       if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+               miireg = ADVERTISE_1000XPAUSE;
+       else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+               miireg = ADVERTISE_1000XPSE_ASYM;
+       else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+               miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
+       else
+               miireg = 0;
+
+       return miireg;
+}
+
+static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
+{
+       u8 cap = 0;
+
+       if (lcladv & ADVERTISE_PAUSE_CAP) {
+               if (lcladv & ADVERTISE_PAUSE_ASYM) {
+                       if (rmtadv & LPA_PAUSE_CAP)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+                       else if (rmtadv & LPA_PAUSE_ASYM)
+                               cap = TG3_FLOW_CTRL_RX;
+               } else {
+                       if (rmtadv & LPA_PAUSE_CAP)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+               }
+       } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
+               if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
+                       cap = TG3_FLOW_CTRL_TX;
+       }
+
+       return cap;
+}
+
+static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
+{
+       u8 cap = 0;
+
+       if (lcladv & ADVERTISE_1000XPAUSE) {
+               if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+                       if (rmtadv & LPA_1000XPAUSE)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+                       else if (rmtadv & LPA_1000XPAUSE_ASYM)
+                               cap = TG3_FLOW_CTRL_RX;
+               } else {
+                       if (rmtadv & LPA_1000XPAUSE)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+               }
+       } else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+               if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
+                       cap = TG3_FLOW_CTRL_TX;
+       }
+
+       return cap;
+}
+
+static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv)
+{
+       u8 autoneg;
+       u8 flowctrl = 0;
+       u32 old_rx_mode = tp->rx_mode;
+       u32 old_tx_mode = tp->tx_mode;
+
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
+               autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg;
+       else
+               autoneg = tp->link_config.autoneg;
+
+       if (autoneg == AUTONEG_ENABLE &&
+           (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
+               if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+                       flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
+               else
+                       flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv);
+       } else
+               flowctrl = tp->link_config.flowctrl;
+
+       tp->link_config.active_flowctrl = flowctrl;
+
+       if (flowctrl & TG3_FLOW_CTRL_RX)
+               tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
+       else
+               tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
+
+       if (old_rx_mode != tp->rx_mode)
+               tw32_f(MAC_RX_MODE, tp->rx_mode);
+
+       if (flowctrl & TG3_FLOW_CTRL_TX)
+               tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
+       else
+               tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
+
+       if (old_tx_mode != tp->tx_mode)
+               tw32_f(MAC_TX_MODE, tp->tx_mode);
+}
+
+static void tg3_adjust_link(struct net_device *dev)
+{
+       u8 oldflowctrl, linkmesg = 0;
+       u32 mac_mode, lcl_adv, rmt_adv;
+       struct tg3 *tp = netdev_priv(dev);
+       struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+       spin_lock(&tp->lock);
+
+       mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK |
+                                   MAC_MODE_HALF_DUPLEX);
+
+       oldflowctrl = tp->link_config.active_flowctrl;
+
+       if (phydev->link) {
+               lcl_adv = 0;
+               rmt_adv = 0;
+
+               if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10)
+                       mac_mode |= MAC_MODE_PORT_MODE_MII;
+               else
+                       mac_mode |= MAC_MODE_PORT_MODE_GMII;
+
+               if (phydev->duplex == DUPLEX_HALF)
+                       mac_mode |= MAC_MODE_HALF_DUPLEX;
+               else {
+                       lcl_adv = tg3_advert_flowctrl_1000T(
+                                 tp->link_config.flowctrl);
+
+                       if (phydev->pause)
+                               rmt_adv = LPA_PAUSE_CAP;
+                       if (phydev->asym_pause)
+                               rmt_adv |= LPA_PAUSE_ASYM;
+               }
+
+               tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
+       } else
+               mac_mode |= MAC_MODE_PORT_MODE_GMII;
+
+       if (mac_mode != tp->mac_mode) {
+               tp->mac_mode = mac_mode;
+               tw32_f(MAC_MODE, tp->mac_mode);
+               udelay(40);
+       }
+
+       if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF)
+               tw32(MAC_TX_LENGTHS,
+                    ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+                     (6 << TX_LENGTHS_IPG_SHIFT) |
+                     (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
+       else
+               tw32(MAC_TX_LENGTHS,
+                    ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+                     (6 << TX_LENGTHS_IPG_SHIFT) |
+                     (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
+
+       if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) ||
+           (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) ||
+           phydev->speed != tp->link_config.active_speed ||
+           phydev->duplex != tp->link_config.active_duplex ||
+           oldflowctrl != tp->link_config.active_flowctrl)
+           linkmesg = 1;
+
+       tp->link_config.active_speed = phydev->speed;
+       tp->link_config.active_duplex = phydev->duplex;
+
+       spin_unlock(&tp->lock);
+
+       if (linkmesg)
+               tg3_link_report(tp);
+}
+
+static int tg3_phy_init(struct tg3 *tp)
+{
+       struct phy_device *phydev;
+
+       if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)
+               return 0;
+
+       /* Bring the PHY back to a known state. */
+       tg3_bmcr_reset(tp);
+
+       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+       /* Attach the MAC to the PHY. */
+       phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link,
+                            phydev->dev_flags, phydev->interface);
+       if (IS_ERR(phydev)) {
+               printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name);
+               return PTR_ERR(phydev);
+       }
+
+       tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED;
+
+       /* Mask with MAC supported features. */
+       phydev->supported &= (PHY_GBIT_FEATURES |
+                             SUPPORTED_Pause |
+                             SUPPORTED_Asym_Pause);
+
+       phydev->advertising = phydev->supported;
+
+       printk(KERN_INFO
+              "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
+              tp->dev->name, phydev->drv->name, phydev->dev.bus_id);
+
+       return 0;
+}
+
+static void tg3_phy_start(struct tg3 *tp)
+{
+       struct phy_device *phydev;
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+               return;
+
+       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+       if (tp->link_config.phy_is_low_power) {
+               tp->link_config.phy_is_low_power = 0;
+               phydev->speed = tp->link_config.orig_speed;
+               phydev->duplex = tp->link_config.orig_duplex;
+               phydev->autoneg = tp->link_config.orig_autoneg;
+               phydev->advertising = tp->link_config.orig_advertising;
+       }
+
+       phy_start(phydev);
+
+       phy_start_aneg(phydev);
+}
+
+static void tg3_phy_stop(struct tg3 *tp)
+{
+       if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+               return;
+
+       phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]);
+}
+
+static void tg3_phy_fini(struct tg3 *tp)
+{
+       if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+               phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]);
+               tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED;
+       }
+}
+
+static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
+{
+       tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
+       tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
+}
+
 static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
 {
        u32 phy;
@@ -855,35 +1427,47 @@ static void tg3_phy_set_wirespeed(struct tg3 *tp)
                             (val | (1 << 15) | (1 << 4)));
 }
 
-static int tg3_bmcr_reset(struct tg3 *tp)
+static void tg3_phy_apply_otp(struct tg3 *tp)
 {
-       u32 phy_control;
-       int limit, err;
+       u32 otp, phy;
 
-       /* OK, reset it, and poll the BMCR_RESET bit until it
-        * clears or we time out.
-        */
-       phy_control = BMCR_RESET;
-       err = tg3_writephy(tp, MII_BMCR, phy_control);
-       if (err != 0)
-               return -EBUSY;
+       if (!tp->phy_otp)
+               return;
 
-       limit = 5000;
-       while (limit--) {
-               err = tg3_readphy(tp, MII_BMCR, &phy_control);
-               if (err != 0)
-                       return -EBUSY;
+       otp = tp->phy_otp;
 
-               if ((phy_control & BMCR_RESET) == 0) {
-                       udelay(40);
-                       break;
-               }
-               udelay(10);
-       }
-       if (limit <= 0)
-               return -EBUSY;
+       /* Enable SM_DSP clock and tx 6dB coding. */
+       phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
+             MII_TG3_AUXCTL_ACTL_SMDSP_ENA |
+             MII_TG3_AUXCTL_ACTL_TX_6DB;
+       tg3_writephy(tp, MII_TG3_AUX_CTRL, phy);
 
-       return 0;
+       phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT);
+       phy |= MII_TG3_DSP_TAP1_AGCTGT_DFLT;
+       tg3_phydsp_write(tp, MII_TG3_DSP_TAP1, phy);
+
+       phy = ((otp & TG3_OTP_HPFFLTR_MASK) >> TG3_OTP_HPFFLTR_SHIFT) |
+             ((otp & TG3_OTP_HPFOVER_MASK) >> TG3_OTP_HPFOVER_SHIFT);
+       tg3_phydsp_write(tp, MII_TG3_DSP_AADJ1CH0, phy);
+
+       phy = ((otp & TG3_OTP_LPFDIS_MASK) >> TG3_OTP_LPFDIS_SHIFT);
+       phy |= MII_TG3_DSP_AADJ1CH3_ADCCKADJ;
+       tg3_phydsp_write(tp, MII_TG3_DSP_AADJ1CH3, phy);
+
+       phy = ((otp & TG3_OTP_VDAC_MASK) >> TG3_OTP_VDAC_SHIFT);
+       tg3_phydsp_write(tp, MII_TG3_DSP_EXP75, phy);
+
+       phy = ((otp & TG3_OTP_10BTAMP_MASK) >> TG3_OTP_10BTAMP_SHIFT);
+       tg3_phydsp_write(tp, MII_TG3_DSP_EXP96, phy);
+
+       phy = ((otp & TG3_OTP_ROFF_MASK) >> TG3_OTP_ROFF_SHIFT) |
+             ((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT);
+       tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy);
+
+       /* Turn off SM_DSP clock. */
+       phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
+             MII_TG3_AUXCTL_ACTL_TX_6DB;
+       tg3_writephy(tp, MII_TG3_AUX_CTRL, phy);
 }
 
 static int tg3_wait_macro_done(struct tg3 *tp)
@@ -1066,13 +1650,12 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
        return err;
 }
 
-static void tg3_link_report(struct tg3 *);
-
 /* This will reset the tigon3 PHY if there is no valid
  * link unless the FORCE argument is non-zero.
  */
 static int tg3_phy_reset(struct tg3 *tp)
 {
+       u32 cpmuctrl;
        u32 phy_status;
        int err;
 
@@ -1102,10 +1685,28 @@ static int tg3_phy_reset(struct tg3 *tp)
                goto out;
        }
 
+       cpmuctrl = 0;
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+           GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) {
+               cpmuctrl = tr32(TG3_CPMU_CTRL);
+               if (cpmuctrl & CPMU_CTRL_GPHY_10MB_RXONLY)
+                       tw32(TG3_CPMU_CTRL,
+                            cpmuctrl & ~CPMU_CTRL_GPHY_10MB_RXONLY);
+       }
+
        err = tg3_bmcr_reset(tp);
        if (err)
                return err;
 
+       if (cpmuctrl & CPMU_CTRL_GPHY_10MB_RXONLY) {
+               u32 phy;
+
+               phy = MII_TG3_DSP_EXP8_AEDW | MII_TG3_DSP_EXP8_REJ2MHz;
+               tg3_phydsp_write(tp, MII_TG3_DSP_EXP8, phy);
+
+               tw32(TG3_CPMU_CTRL, cpmuctrl);
+       }
+
        if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
                u32 val;
 
@@ -1124,6 +1725,8 @@ static int tg3_phy_reset(struct tg3 *tp)
                             MII_TG3_MISC_SHDW_APD_WKTM_84MS);
        }
 
+       tg3_phy_apply_otp(tp);
+
 out:
        if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) {
                tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
@@ -1225,6 +1828,21 @@ static void tg3_frob_aux_power(struct tg3 *tp)
                                     GRC_LCLCTRL_GPIO_OUTPUT0 |
                                     GRC_LCLCTRL_GPIO_OUTPUT1),
                                    100);
+               } else if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) {
+                       /* The 5761 non-e device swaps GPIO 0 and GPIO 2. */
+                       u32 grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 |
+                                            GRC_LCLCTRL_GPIO_OE1 |
+                                            GRC_LCLCTRL_GPIO_OE2 |
+                                            GRC_LCLCTRL_GPIO_OUTPUT0 |
+                                            GRC_LCLCTRL_GPIO_OUTPUT1 |
+                                            tp->grc_local_ctrl;
+                       tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100);
+
+                       grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT2;
+                       tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100);
+
+                       grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT0;
+                       tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100);
                } else {
                        u32 no_gpio2;
                        u32 grc_local_ctrl = 0;
@@ -1336,7 +1954,7 @@ static void tg3_power_down_phy(struct tg3 *tp)
                tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
                udelay(40);
                return;
-       } else {
+       } else if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
                tg3_writephy(tp, MII_TG3_EXT_CTRL,
                             MII_TG3_EXT_CTRL_FORCE_LED_OFF);
                tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
@@ -1410,7 +2028,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                       "requested.\n",
                       tp->dev->name, state);
                return -EINVAL;
-       };
+       }
 
        power_control |= PCI_PM_CTRL_PME_ENABLE;
 
@@ -1418,18 +2036,55 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
        tw32(TG3PCI_MISC_HOST_CTRL,
             misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
 
-       if (tp->link_config.phy_is_low_power == 0) {
-               tp->link_config.phy_is_low_power = 1;
-               tp->link_config.orig_speed = tp->link_config.speed;
-               tp->link_config.orig_duplex = tp->link_config.duplex;
-               tp->link_config.orig_autoneg = tp->link_config.autoneg;
-       }
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) &&
+                   !tp->link_config.phy_is_low_power) {
+                       struct phy_device *phydev;
+                       u32 advertising;
+
+                       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+                       tp->link_config.phy_is_low_power = 1;
+
+                       tp->link_config.orig_speed = phydev->speed;
+                       tp->link_config.orig_duplex = phydev->duplex;
+                       tp->link_config.orig_autoneg = phydev->autoneg;
+                       tp->link_config.orig_advertising = phydev->advertising;
+
+                       advertising = ADVERTISED_TP |
+                                     ADVERTISED_Pause |
+                                     ADVERTISED_Autoneg |
+                                     ADVERTISED_10baseT_Half;
+
+                       if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+                           (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
+                               if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)
+                                       advertising |=
+                                               ADVERTISED_100baseT_Half |
+                                               ADVERTISED_100baseT_Full |
+                                               ADVERTISED_10baseT_Full;
+                               else
+                                       advertising |= ADVERTISED_10baseT_Full;
+                       }
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
-               tp->link_config.speed = SPEED_10;
-               tp->link_config.duplex = DUPLEX_HALF;
-               tp->link_config.autoneg = AUTONEG_ENABLE;
-               tg3_setup_phy(tp, 0);
+                       phydev->advertising = advertising;
+
+                       phy_start_aneg(phydev);
+               }
+       } else {
+               if (tp->link_config.phy_is_low_power == 0) {
+                       tp->link_config.phy_is_low_power = 1;
+                       tp->link_config.orig_speed = tp->link_config.speed;
+                       tp->link_config.orig_duplex = tp->link_config.duplex;
+                       tp->link_config.orig_autoneg = tp->link_config.autoneg;
+               }
+
+               if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
+                       tp->link_config.speed = SPEED_10;
+                       tp->link_config.duplex = DUPLEX_HALF;
+                       tp->link_config.autoneg = AUTONEG_ENABLE;
+                       tg3_setup_phy(tp, 0);
+               }
        }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
@@ -1460,8 +2115,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                u32 mac_mode;
 
                if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
-                       tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
-                       udelay(40);
+                       if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
+                               tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+                               udelay(40);
+                       }
 
                        if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
                                mac_mode = MAC_MODE_PORT_MODE_GMII;
@@ -1586,114 +2243,6 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
        return 0;
 }
 
-static void tg3_link_report(struct tg3 *tp)
-{
-       if (!netif_carrier_ok(tp->dev)) {
-               if (netif_msg_link(tp))
-                       printk(KERN_INFO PFX "%s: Link is down.\n",
-                              tp->dev->name);
-       } else if (netif_msg_link(tp)) {
-               printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
-                      tp->dev->name,
-                      (tp->link_config.active_speed == SPEED_1000 ?
-                       1000 :
-                       (tp->link_config.active_speed == SPEED_100 ?
-                        100 : 10)),
-                      (tp->link_config.active_duplex == DUPLEX_FULL ?
-                       "full" : "half"));
-
-               printk(KERN_INFO PFX
-                      "%s: Flow control is %s for TX and %s for RX.\n",
-                      tp->dev->name,
-                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
-                      "on" : "off",
-                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
-                      "on" : "off");
-       }
-}
-
-static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
-{
-       u8 cap = 0;
-
-       if (lcladv & ADVERTISE_PAUSE_CAP) {
-               if (lcladv & ADVERTISE_PAUSE_ASYM) {
-                       if (rmtadv & LPA_PAUSE_CAP)
-                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
-                       else if (rmtadv & LPA_PAUSE_ASYM)
-                               cap = TG3_FLOW_CTRL_RX;
-               } else {
-                       if (rmtadv & LPA_PAUSE_CAP)
-                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
-               }
-       } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
-               if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
-                       cap = TG3_FLOW_CTRL_TX;
-       }
-
-       return cap;
-}
-
-static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
-{
-       u8 cap = 0;
-
-       if (lcladv & ADVERTISE_1000XPAUSE) {
-               if (lcladv & ADVERTISE_1000XPSE_ASYM) {
-                       if (rmtadv & LPA_1000XPAUSE)
-                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
-                       else if (rmtadv & LPA_1000XPAUSE_ASYM)
-                               cap = TG3_FLOW_CTRL_RX;
-               } else {
-                       if (rmtadv & LPA_1000XPAUSE)
-                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
-               }
-       } else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
-               if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
-                       cap = TG3_FLOW_CTRL_TX;
-       }
-
-       return cap;
-}
-
-static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
-{
-       u8 new_tg3_flags = 0;
-       u32 old_rx_mode = tp->rx_mode;
-       u32 old_tx_mode = tp->tx_mode;
-
-       if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
-               if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
-                       new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
-                                                                  remote_adv);
-               else
-                       new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv,
-                                                                  remote_adv);
-       } else {
-               new_tg3_flags = tp->link_config.flowctrl;
-       }
-
-       tp->link_config.active_flowctrl = new_tg3_flags;
-
-       if (new_tg3_flags & TG3_FLOW_CTRL_RX)
-               tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
-       else
-               tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
-
-       if (old_rx_mode != tp->rx_mode) {
-               tw32_f(MAC_RX_MODE, tp->rx_mode);
-       }
-
-       if (new_tg3_flags & TG3_FLOW_CTRL_TX)
-               tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
-       else
-               tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
-
-       if (old_tx_mode != tp->tx_mode) {
-               tw32_f(MAC_TX_MODE, tp->tx_mode);
-       }
-}
-
 static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex)
 {
        switch (val & MII_TG3_AUX_STAT_SPDMASK) {
@@ -1738,7 +2287,7 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8
                *speed = SPEED_INVALID;
                *duplex = DUPLEX_INVALID;
                break;
-       };
+       }
 }
 
 static void tg3_phy_copper_begin(struct tg3 *tp)
@@ -1764,7 +2313,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                                ~(ADVERTISED_1000baseT_Half |
                                  ADVERTISED_1000baseT_Full);
 
-               new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+               new_adv = ADVERTISE_CSMA;
                if (tp->link_config.advertising & ADVERTISED_10baseT_Half)
                        new_adv |= ADVERTISE_10HALF;
                if (tp->link_config.advertising & ADVERTISED_10baseT_Full)
@@ -1773,6 +2322,9 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                        new_adv |= ADVERTISE_100HALF;
                if (tp->link_config.advertising & ADVERTISED_100baseT_Full)
                        new_adv |= ADVERTISE_100FULL;
+
+               new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+
                tg3_writephy(tp, MII_ADVERTISE, new_adv);
 
                if (tp->link_config.advertising &
@@ -1792,9 +2344,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                        tg3_writephy(tp, MII_TG3_CTRL, 0);
                }
        } else {
+               new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+               new_adv |= ADVERTISE_CSMA;
+
                /* Asking for a specific link mode. */
                if (tp->link_config.speed == SPEED_1000) {
-                       new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
                        tg3_writephy(tp, MII_ADVERTISE, new_adv);
 
                        if (tp->link_config.duplex == DUPLEX_FULL)
@@ -1805,11 +2359,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                            tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
                                new_adv |= (MII_TG3_CTRL_AS_MASTER |
                                            MII_TG3_CTRL_ENABLE_AS_MASTER);
-                       tg3_writephy(tp, MII_TG3_CTRL, new_adv);
                } else {
-                       tg3_writephy(tp, MII_TG3_CTRL, 0);
-
-                       new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
                        if (tp->link_config.speed == SPEED_100) {
                                if (tp->link_config.duplex == DUPLEX_FULL)
                                        new_adv |= ADVERTISE_100FULL;
@@ -1822,7 +2372,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                                        new_adv |= ADVERTISE_10HALF;
                        }
                        tg3_writephy(tp, MII_ADVERTISE, new_adv);
+
+                       new_adv = 0;
                }
+
+               tg3_writephy(tp, MII_TG3_CTRL, new_adv);
        }
 
        if (tp->link_config.autoneg == AUTONEG_DISABLE &&
@@ -1845,7 +2399,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                case SPEED_1000:
                        bmcr |= TG3_BMCR_SPEED1000;
                        break;
-               };
+               }
 
                if (tp->link_config.duplex == DUPLEX_FULL)
                        bmcr |= BMCR_FULLDPLX;
@@ -1938,10 +2492,44 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
        return 1;
 }
 
+static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv)
+{
+       u32 curadv, reqadv;
+
+       if (tg3_readphy(tp, MII_ADVERTISE, lcladv))
+               return 1;
+
+       curadv = *lcladv & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+       reqadv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+
+       if (tp->link_config.active_duplex == DUPLEX_FULL) {
+               if (curadv != reqadv)
+                       return 0;
+
+               if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)
+                       tg3_readphy(tp, MII_LPA, rmtadv);
+       } else {
+               /* Reprogram the advertisement register, even if it
+                * does not affect the current link.  If the link
+                * gets renegotiated in the future, we can save an
+                * additional renegotiation cycle by advertising
+                * it correctly in the first place.
+                */
+               if (curadv != reqadv) {
+                       *lcladv &= ~(ADVERTISE_PAUSE_CAP |
+                                    ADVERTISE_PAUSE_ASYM);
+                       tg3_writephy(tp, MII_ADVERTISE, *lcladv | reqadv);
+               }
+       }
+
+       return 1;
+}
+
 static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
 {
        int current_link_up;
        u32 bmsr, dummy;
+       u32 lcl_adv, rmt_adv;
        u16 current_speed;
        u8 current_duplex;
        int i, err;
@@ -1955,9 +2543,11 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
              MAC_STATUS_LNKSTATE_CHANGED));
        udelay(40);
 
-       tp->mi_mode = MAC_MI_MODE_BASE;
-       tw32_f(MAC_MI_MODE, tp->mi_mode);
-       udelay(80);
+       if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+               tw32_f(MAC_MI_MODE,
+                    (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+               udelay(80);
+       }
 
        tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
 
@@ -2084,56 +2674,35 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                        udelay(10);
                }
 
-               if (tp->link_config.autoneg == AUTONEG_ENABLE) {
-                       if (bmcr & BMCR_ANENABLE) {
-                               current_link_up = 1;
-
-                               /* Force autoneg restart if we are exiting
-                                * low power mode.
-                                */
-                               if (!tg3_copper_is_advertising_all(tp,
-                                               tp->link_config.advertising))
-                                       current_link_up = 0;
-                       } else {
-                               current_link_up = 0;
-                       }
-               } else {
-                       if (!(bmcr & BMCR_ANENABLE) &&
-                           tp->link_config.speed == current_speed &&
-                           tp->link_config.duplex == current_duplex) {
-                               current_link_up = 1;
-                       } else {
-                               current_link_up = 0;
-                       }
-               }
+               lcl_adv = 0;
+               rmt_adv = 0;
 
                tp->link_config.active_speed = current_speed;
                tp->link_config.active_duplex = current_duplex;
-       }
-
-       if (current_link_up == 1 &&
-           (tp->link_config.active_duplex == DUPLEX_FULL) &&
-           (tp->link_config.autoneg == AUTONEG_ENABLE)) {
-               u32 local_adv, remote_adv;
-
-               if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
-                       local_adv = 0;
-               local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
-
-               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,
-                * something is wrong.  Bring the link down and reconfigure.
-                */
-               if (local_adv != ADVERTISE_PAUSE_CAP) {
-                       current_link_up = 0;
+               if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+                       if ((bmcr & BMCR_ANENABLE) &&
+                           tg3_copper_is_advertising_all(tp,
+                                               tp->link_config.advertising)) {
+                               if (tg3_adv_1000T_flowctrl_ok(tp, &lcl_adv,
+                                                                 &rmt_adv))
+                                       current_link_up = 1;
+                       }
                } else {
-                       tg3_setup_flow_control(tp, local_adv, remote_adv);
+                       if (!(bmcr & BMCR_ANENABLE) &&
+                           tp->link_config.speed == current_speed &&
+                           tp->link_config.duplex == current_duplex &&
+                           tp->link_config.flowctrl ==
+                           tp->link_config.active_flowctrl) {
+                               current_link_up = 1;
+                       }
                }
+
+               if (current_link_up == 1 &&
+                   tp->link_config.active_duplex == DUPLEX_FULL)
+                       tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
        }
+
 relink:
        if (current_link_up == 0 || tp->link_config.phy_is_low_power) {
                u32 tmp;
@@ -2282,6 +2851,7 @@ struct tg3_fiber_aneginfo {
 static int tg3_fiber_aneg_smachine(struct tg3 *tp,
                                   struct tg3_fiber_aneginfo *ap)
 {
+       u16 flowctrl;
        unsigned long delta;
        u32 rx_cfg_reg;
        int ret;
@@ -2381,7 +2951,12 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
 
        case ANEG_STATE_ABILITY_DETECT_INIT:
                ap->flags &= ~(MR_TOGGLE_TX);
-               ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
+               ap->txconfig = ANEG_CFG_FD;
+               flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+               if (flowctrl & ADVERTISE_1000XPAUSE)
+                       ap->txconfig |= ANEG_CFG_PS1;
+               if (flowctrl & ADVERTISE_1000XPSE_ASYM)
+                       ap->txconfig |= ANEG_CFG_PS2;
                tw32(MAC_TX_AUTO_NEG, ap->txconfig);
                tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
                tw32_f(MAC_MODE, tp->mac_mode);
@@ -2522,12 +3097,12 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
        default:
                ret = ANEG_FAILED;
                break;
-       };
+       }
 
        return ret;
 }
 
-static int fiber_autoneg(struct tg3 *tp, u32 *flags)
+static int fiber_autoneg(struct tg3 *tp, u32 *txflags, u32 *rxflags)
 {
        int res = 0;
        struct tg3_fiber_aneginfo aninfo;
@@ -2561,7 +3136,8 @@ static int fiber_autoneg(struct tg3 *tp, u32 *flags)
        tw32_f(MAC_MODE, tp->mac_mode);
        udelay(40);
 
-       *flags = aninfo.flags;
+       *txflags = aninfo.txconfig;
+       *rxflags = aninfo.flags;
 
        if (status == ANEG_DONE &&
            (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK |
@@ -2623,6 +3199,7 @@ static void tg3_init_bcm8002(struct tg3 *tp)
 
 static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 {
+       u16 flowctrl;
        u32 sg_dig_ctrl, sg_dig_status;
        u32 serdes_cfg, expected_sg_dig_ctrl;
        int workaround, port_a;
@@ -2648,7 +3225,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
        sg_dig_ctrl = tr32(SG_DIG_CTRL);
 
        if (tp->link_config.autoneg != AUTONEG_ENABLE) {
-               if (sg_dig_ctrl & (1 << 31)) {
+               if (sg_dig_ctrl & SG_DIG_USING_HW_AUTONEG) {
                        if (workaround) {
                                u32 val = serdes_cfg;
 
@@ -2658,7 +3235,8 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
                                        val |= 0x4010000;
                                tw32_f(MAC_SERDES_CFG, val);
                        }
-                       tw32_f(SG_DIG_CTRL, 0x01388400);
+
+                       tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP);
                }
                if (mac_status & MAC_STATUS_PCS_SYNCED) {
                        tg3_setup_flow_control(tp, 0, 0);
@@ -2668,13 +3246,13 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
        }
 
        /* Want auto-negotiation.  */
-       expected_sg_dig_ctrl = 0x81388400;
-
-       /* Pause capability */
-       expected_sg_dig_ctrl |= (1 << 11);
+       expected_sg_dig_ctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_COMMON_SETUP;
 
-       /* Asymettric pause */
-       expected_sg_dig_ctrl |= (1 << 12);
+       flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+       if (flowctrl & ADVERTISE_1000XPAUSE)
+               expected_sg_dig_ctrl |= SG_DIG_PAUSE_CAP;
+       if (flowctrl & ADVERTISE_1000XPSE_ASYM)
+               expected_sg_dig_ctrl |= SG_DIG_ASYM_PAUSE;
 
        if (sg_dig_ctrl != expected_sg_dig_ctrl) {
                if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
@@ -2689,7 +3267,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 restart_autoneg:
                if (workaround)
                        tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
-               tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
+               tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | SG_DIG_SOFT_RESET);
                udelay(5);
                tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
 
@@ -2700,22 +3278,25 @@ restart_autoneg:
                sg_dig_status = tr32(SG_DIG_STATUS);
                mac_status = tr32(MAC_STATUS);
 
-               if ((sg_dig_status & (1 << 1)) &&
+               if ((sg_dig_status & SG_DIG_AUTONEG_COMPLETE) &&
                    (mac_status & MAC_STATUS_PCS_SYNCED)) {
-                       u32 local_adv, remote_adv;
+                       u32 local_adv = 0, remote_adv = 0;
 
-                       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;
+                       if (sg_dig_ctrl & SG_DIG_PAUSE_CAP)
+                               local_adv |= ADVERTISE_1000XPAUSE;
+                       if (sg_dig_ctrl & SG_DIG_ASYM_PAUSE)
+                               local_adv |= ADVERTISE_1000XPSE_ASYM;
+
+                       if (sg_dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE)
+                               remote_adv |= LPA_1000XPAUSE;
+                       if (sg_dig_status & SG_DIG_PARTNER_ASYM_PAUSE)
+                               remote_adv |= LPA_1000XPAUSE_ASYM;
 
                        tg3_setup_flow_control(tp, local_adv, remote_adv);
                        current_link_up = 1;
                        tp->serdes_counter = 0;
                        tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
-               } else if (!(sg_dig_status & (1 << 1))) {
+               } else if (!(sg_dig_status & SG_DIG_AUTONEG_COMPLETE)) {
                        if (tp->serdes_counter)
                                tp->serdes_counter--;
                        else {
@@ -2730,7 +3311,7 @@ restart_autoneg:
                                        tw32_f(MAC_SERDES_CFG, val);
                                }
 
-                               tw32_f(SG_DIG_CTRL, 0x01388400);
+                               tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP);
                                udelay(40);
 
                                /* Link parallel detection - link is up */
@@ -2766,18 +3347,21 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
                goto out;
 
        if (tp->link_config.autoneg == AUTONEG_ENABLE) {
-               u32 flags;
+               u32 txflags, rxflags;
                int i;
 
-               if (fiber_autoneg(tp, &flags)) {
-                       u32 local_adv, remote_adv;
+               if (fiber_autoneg(tp, &txflags, &rxflags)) {
+                       u32 local_adv = 0, remote_adv = 0;
+
+                       if (txflags & ANEG_CFG_PS1)
+                               local_adv |= ADVERTISE_1000XPAUSE;
+                       if (txflags & ANEG_CFG_PS2)
+                               local_adv |= ADVERTISE_1000XPSE_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;
+                       if (rxflags & MR_LP_ADV_SYM_PAUSE)
+                               remote_adv |= LPA_1000XPAUSE;
+                       if (rxflags & MR_LP_ADV_ASYM_PAUSE)
+                               remote_adv |= LPA_1000XPAUSE_ASYM;
 
                        tg3_setup_flow_control(tp, local_adv, remote_adv);
 
@@ -2801,6 +3385,8 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
                    !(mac_status & MAC_STATUS_RCVD_CFG))
                        current_link_up = 1;
        } else {
+               tg3_setup_flow_control(tp, 0, 0);
+
                /* Forcing 1000FD link up. */
                current_link_up = 1;
 
@@ -2929,6 +3515,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
        u32 bmsr, bmcr;
        u16 current_speed;
        u8 current_duplex;
+       u32 local_adv, remote_adv;
 
        tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
        tw32_f(MAC_MODE, tp->mac_mode);
@@ -2973,8 +3560,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                                  ADVERTISE_1000XPSE_ASYM |
                                  ADVERTISE_SLCT);
 
-               /* Always advertise symmetric PAUSE just like copper */
-               new_adv |= ADVERTISE_1000XPAUSE;
+               new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
 
                if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
                        new_adv |= ADVERTISE_1000XHALF;
@@ -3045,8 +3631,11 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                else
                        current_duplex = DUPLEX_HALF;
 
+               local_adv = 0;
+               remote_adv = 0;
+
                if (bmcr & BMCR_ANENABLE) {
-                       u32 local_adv, remote_adv, common;
+                       u32 common;
 
                        err |= tg3_readphy(tp, MII_ADVERTISE, &local_adv);
                        err |= tg3_readphy(tp, MII_LPA, &remote_adv);
@@ -3057,15 +3646,15 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                                        current_duplex = DUPLEX_FULL;
                                else
                                        current_duplex = DUPLEX_HALF;
-
-                               tg3_setup_flow_control(tp, local_adv,
-                                                      remote_adv);
                        }
                        else
                                current_link_up = 0;
                }
        }
 
+       if (current_link_up == 1 && current_duplex == DUPLEX_FULL)
+               tg3_setup_flow_control(tp, local_adv, remote_adv);
+
        tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
        if (tp->link_config.active_duplex == DUPLEX_HALF)
                tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
@@ -3349,7 +3938,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key,
 
        default:
                return -EINVAL;
-       };
+       }
 
        /* Do not overwrite any of the map or rp information
         * until we are sure we can commit to a new buffer.
@@ -3409,7 +3998,7 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key,
 
        default:
                return;
-       };
+       }
 
        dest_map->skb = src_map->skb;
        pci_unmap_addr_set(dest_map, mapping,
@@ -3619,7 +4208,15 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
                        sblk->status = SD_STATUS_UPDATED |
                                (sblk->status & ~SD_STATUS_LINK_CHG);
                        spin_lock(&tp->lock);
-                       tg3_setup_phy(tp, 0);
+                       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+                               tw32_f(MAC_STATUS,
+                                    (MAC_STATUS_SYNC_CHANGED |
+                                     MAC_STATUS_CFG_CHANGED |
+                                     MAC_STATUS_MI_COMPLETION |
+                                     MAC_STATUS_LNKSTATE_CHANGED));
+                               udelay(40);
+                       } else
+                               tg3_setup_phy(tp, 0);
                        spin_unlock(&tp->lock);
                }
        }
@@ -3875,6 +4472,8 @@ static int tg3_halt(struct tg3 *, int, int);
  * Invoked with tp->lock held.
  */
 static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+       __releases(tp->lock)
+       __acquires(tp->lock)
 {
        int err;
 
@@ -3905,6 +4504,7 @@ static void tg3_poll_controller(struct net_device *dev)
 static void tg3_reset_task(struct work_struct *work)
 {
        struct tg3 *tp = container_of(work, struct tg3, reset_task);
+       int err;
        unsigned int restart_timer;
 
        tg3_full_lock(tp, 0);
@@ -3916,6 +4516,8 @@ static void tg3_reset_task(struct work_struct *work)
 
        tg3_full_unlock(tp);
 
+       tg3_phy_stop(tp);
+
        tg3_netif_stop(tp);
 
        tg3_full_lock(tp, 1);
@@ -3931,7 +4533,8 @@ static void tg3_reset_task(struct work_struct *work)
        }
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
-       if (tg3_init_hw(tp, 1))
+       err = tg3_init_hw(tp, 1);
+       if (err)
                goto out;
 
        tg3_netif_start(tp);
@@ -3941,6 +4544,9 @@ static void tg3_reset_task(struct work_struct *work)
 
 out:
        tg3_full_unlock(tp);
+
+       if (!err)
+               tg3_phy_start(tp);
 }
 
 static void tg3_dump_short_state(struct tg3 *tp)
@@ -3993,11 +4599,21 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
                                       u32 last_plus_one, u32 *start,
                                       u32 base_flags, u32 mss)
 {
-       struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC);
+       struct sk_buff *new_skb;
        dma_addr_t new_addr = 0;
        u32 entry = *start;
        int i, ret = 0;
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+               new_skb = skb_copy(skb, GFP_ATOMIC);
+       else {
+               int more_headroom = 4 - ((unsigned long)skb->data & 3);
+
+               new_skb = skb_copy_expand(skb,
+                                         skb_headroom(skb) + more_headroom,
+                                         skb_tailroom(skb), GFP_ATOMIC);
+       }
+
        if (!new_skb) {
                ret = -1;
        } else {
@@ -4207,7 +4823,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
        }
 
        segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
-       if (unlikely(IS_ERR(segs)))
+       if (IS_ERR(segs))
                goto tg3_tso_bug_end;
 
        do {
@@ -4320,7 +4936,9 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
 
        would_hit_hwbug = 0;
 
-       if (tg3_4g_overflow_test(mapping, len))
+       if (tp->tg3_flags3 & TG3_FLG3_5701_DMA_BUG)
+               would_hit_hwbug = 1;
+       else if (tg3_4g_overflow_test(mapping, len))
                would_hit_hwbug = 1;
 
        tg3_set_txd(tp, entry, mapping, len, base_flags,
@@ -4432,6 +5050,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
                return 0;
        }
 
+       tg3_phy_stop(tp);
+
        tg3_netif_stop(tp);
 
        tg3_full_lock(tp, 1);
@@ -4447,6 +5067,9 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 
        tg3_full_unlock(tp);
 
+       if (!err)
+               tg3_phy_start(tp);
+
        return err;
 }
 
@@ -4738,7 +5361,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int
 
                default:
                        break;
-               };
+               }
        }
 
        val = tr32(ofs);
@@ -4980,7 +5603,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
 
                default:
                        break;
-               };
+               }
        }
 
        if (kind == RESET_KIND_INIT ||
@@ -5005,7 +5628,7 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
 
                default:
                        break;
-               };
+               }
        }
 
        if (kind == RESET_KIND_SHUTDOWN)
@@ -5034,7 +5657,7 @@ static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
 
                default:
                        break;
-               };
+               }
        }
 }
 
@@ -5156,6 +5779,8 @@ static int tg3_chip_reset(struct tg3 *tp)
 
        tg3_nvram_lock(tp);
 
+       tg3_mdio_stop(tp);
+
        /* No matching tg3_nvram_unlock() after this because
         * chip reset below will undo the nvram lock.
         */
@@ -5171,7 +5796,8 @@ static int tg3_chip_reset(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                tw32(GRC_FASTBOOT_PC, 0);
 
        /*
@@ -5307,6 +5933,8 @@ static int tg3_chip_reset(struct tg3 *tp)
                tw32_f(MAC_MODE, 0);
        udelay(40);
 
+       tg3_mdio_start(tp);
+
        err = tg3_poll_fw(tp);
        if (err)
                return err;
@@ -5342,19 +5970,17 @@ static void tg3_stop_fw(struct tg3 *tp)
        if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
           !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
                u32 val;
-               int i;
+
+               /* Wait for RX cpu to ACK the previous event. */
+               tg3_wait_for_event_ack(tp);
 
                tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
                val = tr32(GRC_RX_CPU_EVENT);
-               val |= (1 << 14);
+               val |= GRC_RX_CPU_DRIVER_EVENT;
                tw32(GRC_RX_CPU_EVENT, val);
 
-               /* Wait for RX cpu to ACK the event.  */
-               for (i = 0; i < 100; i++) {
-                       if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14)))
-                               break;
-                       udelay(1);
-               }
+               /* Wait for RX cpu to ACK this event. */
+               tg3_wait_for_event_ack(tp);
        }
 }
 
@@ -6388,7 +7014,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tg3_abort_hw(tp, 1);
        }
 
-       if (reset_phy)
+       if (reset_phy &&
+           !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB))
                tg3_phy_reset(tp);
 
        err = tg3_chip_reset(tp);
@@ -6464,7 +7091,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                return err;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) {
                /* This value is determined during the probe time DMA
                 * engine test, tg3_test_dma.
                 */
@@ -6703,7 +7331,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                      RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
                      RDMAC_MODE_LNGREAD_ENAB);
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
                              RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
                              RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
@@ -6871,8 +7500,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) ||
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) ||
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ||
-           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761))
-               val |= (1 << 29);
+           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) ||
+           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785))
+               val |= WDMAC_MODE_STATUS_TAG_FIX;
 
        tw32_f(WDMAC_MODE, val);
        udelay(40);
@@ -6933,23 +7563,14 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 
        tp->rx_mode = RX_MODE_ENABLE;
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
 
        tw32_f(MAC_RX_MODE, tp->rx_mode);
        udelay(10);
 
-       if (tp->link_config.phy_is_low_power) {
-               tp->link_config.phy_is_low_power = 0;
-               tp->link_config.speed = tp->link_config.orig_speed;
-               tp->link_config.duplex = tp->link_config.orig_duplex;
-               tp->link_config.autoneg = tp->link_config.orig_autoneg;
-       }
-
-       tp->mi_mode = MAC_MI_MODE_BASE;
-       tw32_f(MAC_MI_MODE, tp->mi_mode);
-       udelay(80);
-
        tw32(MAC_LED_CTRL, tp->led_ctrl);
 
        tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
@@ -6996,19 +7617,28 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
        }
 
-       err = tg3_setup_phy(tp, 0);
-       if (err)
-               return err;
+       if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
+               if (tp->link_config.phy_is_low_power) {
+                       tp->link_config.phy_is_low_power = 0;
+                       tp->link_config.speed = tp->link_config.orig_speed;
+                       tp->link_config.duplex = tp->link_config.orig_duplex;
+                       tp->link_config.autoneg = tp->link_config.orig_autoneg;
+               }
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
-               u32 tmp;
+               err = tg3_setup_phy(tp, 0);
+               if (err)
+                       return err;
 
-               /* Clear CRC stats. */
-               if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
-                       tg3_writephy(tp, MII_TG3_TEST1,
-                                    tmp | MII_TG3_TEST1_CRC_EN);
-                       tg3_readphy(tp, 0x14, &tmp);
+               if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+                   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
+                       u32 tmp;
+
+                       /* Clear CRC stats. */
+                       if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
+                               tg3_writephy(tp, MII_TG3_TEST1,
+                                            tmp | MII_TG3_TEST1_CRC_EN);
+                               tg3_readphy(tp, 0x14, &tmp);
+                       }
                }
        }
 
@@ -7061,7 +7691,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 
        default:
                break;
-       };
+       }
 
        if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
                /* Write our heartbeat update interval to APE. */
@@ -7244,14 +7874,16 @@ static void tg3_timer(unsigned long __opaque)
                if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
                        u32 val;
 
+                       tg3_wait_for_event_ack(tp);
+
                        tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
                                      FWCMD_NICDRV_ALIVE3);
                        tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
                        /* 5 seconds timeout */
                        tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
                        val = tr32(GRC_RX_CPU_EVENT);
-                       val |= (1 << 14);
-                       tw32(GRC_RX_CPU_EVENT, val);
+                       val |= GRC_RX_CPU_DRIVER_EVENT;
+                       tw32_f(GRC_RX_CPU_EVENT, val);
                }
                tp->asf_counter = tp->asf_multiplier;
        }
@@ -7521,6 +8153,8 @@ static int tg3_open(struct net_device *dev)
                }
        }
 
+       tg3_phy_start(tp);
+
        tg3_full_lock(tp, 0);
 
        add_timer(&tp->timer);
@@ -8322,7 +8956,13 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 
 static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct tg3 *tp = netdev_priv(dev);
+       struct tg3 *tp = netdev_priv(dev);
+
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
+               return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
+       }
 
        cmd->supported = (SUPPORTED_Autoneg);
 
@@ -8359,6 +8999,12 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct tg3 *tp = netdev_priv(dev);
 
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
+               return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
+       }
+
        if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
                /* These are the only valid advertisement bits allowed.  */
                if (cmd->autoneg == AUTONEG_ENABLE &&
@@ -8376,7 +9022,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                   (cmd->speed == SPEED_1000))
                return -EINVAL;
        else if ((cmd->speed == SPEED_1000) &&
-                (tp->tg3_flags2 & TG3_FLAG_10_100_ONLY))
+                (tp->tg3_flags & TG3_FLAG_10_100_ONLY))
                return -EINVAL;
 
        tg3_full_lock(tp, 0);
@@ -8391,7 +9037,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                tp->link_config.advertising = 0;
                tp->link_config.speed = cmd->speed;
                tp->link_config.duplex = cmd->duplex;
-       }
+       }
 
        tp->link_config.orig_speed = tp->link_config.speed;
        tp->link_config.orig_duplex = tp->link_config.duplex;
@@ -8474,7 +9120,10 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
            (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
                if (value) {
                        dev->features |= NETIF_F_TSO6;
-                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+                            GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
+                           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                                dev->features |= NETIF_F_TSO_ECN;
                } else
                        dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
@@ -8485,7 +9134,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
 static int tg3_nway_reset(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
-       u32 bmcr;
        int r;
 
        if (!netif_running(dev))
@@ -8494,17 +9142,25 @@ static int tg3_nway_reset(struct net_device *dev)
        if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                return -EINVAL;
 
-       spin_lock_bh(&tp->lock);
-       r = -EINVAL;
-       tg3_readphy(tp, MII_BMCR, &bmcr);
-       if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
-           ((bmcr & BMCR_ANENABLE) ||
-            (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
-               tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
-                                          BMCR_ANENABLE);
-               r = 0;
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
+               r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]);
+       } else {
+               u32 bmcr;
+
+               spin_lock_bh(&tp->lock);
+               r = -EINVAL;
+               tg3_readphy(tp, MII_BMCR, &bmcr);
+               if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
+                   ((bmcr & BMCR_ANENABLE) ||
+                    (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
+                       tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
+                                                  BMCR_ANENABLE);
+                       r = 0;
+               }
+               spin_unlock_bh(&tp->lock);
        }
-       spin_unlock_bh(&tp->lock);
 
        return r;
 }
@@ -8546,6 +9202,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
                return -EINVAL;
 
        if (netif_running(dev)) {
+               tg3_phy_stop(tp);
                tg3_netif_stop(tp);
                irq_sync = 1;
        }
@@ -8569,6 +9226,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
 
        tg3_full_unlock(tp);
 
+       if (irq_sync && !err)
+               tg3_phy_start(tp);
+
        return err;
 }
 
@@ -8592,36 +9252,92 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
        struct tg3 *tp = netdev_priv(dev);
-       int irq_sync = 0, err = 0;
+       int err = 0;
 
-       if (netif_running(dev)) {
-               tg3_netif_stop(tp);
-               irq_sync = 1;
-       }
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
 
-       tg3_full_lock(tp, irq_sync);
+               if (epause->autoneg) {
+                       u32 newadv;
+                       struct phy_device *phydev;
 
-       if (epause->autoneg)
-               tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
-       else
-               tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
-       if (epause->rx_pause)
-               tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
-       else
-               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
-       if (epause->tx_pause)
-               tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
-       else
-               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+                       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
 
-       if (netif_running(dev)) {
-               tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               err = tg3_restart_hw(tp, 1);
-               if (!err)
-                       tg3_netif_start(tp);
-       }
+                       if (epause->rx_pause) {
+                               if (epause->tx_pause)
+                                       newadv = ADVERTISED_Pause;
+                               else
+                                       newadv = ADVERTISED_Pause |
+                                                ADVERTISED_Asym_Pause;
+                       } else if (epause->tx_pause) {
+                               newadv = ADVERTISED_Asym_Pause;
+                       } else
+                               newadv = 0;
+
+                       if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+                               u32 oldadv = phydev->advertising &
+                                            (ADVERTISED_Pause |
+                                             ADVERTISED_Asym_Pause);
+                               if (oldadv != newadv) {
+                                       phydev->advertising &=
+                                               ~(ADVERTISED_Pause |
+                                                 ADVERTISED_Asym_Pause);
+                                       phydev->advertising |= newadv;
+                                       err = phy_start_aneg(phydev);
+                               }
+                       } else {
+                               tp->link_config.advertising &=
+                                               ~(ADVERTISED_Pause |
+                                                 ADVERTISED_Asym_Pause);
+                               tp->link_config.advertising |= newadv;
+                       }
+               } else {
+                       if (epause->rx_pause)
+                               tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
+                       else
+                               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
 
-       tg3_full_unlock(tp);
+                       if (epause->tx_pause)
+                               tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
+                       else
+                               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+
+                       if (netif_running(dev))
+                               tg3_setup_flow_control(tp, 0, 0);
+               }
+       } else {
+               int irq_sync = 0;
+
+               if (netif_running(dev)) {
+                       tg3_netif_stop(tp);
+                       irq_sync = 1;
+               }
+
+               tg3_full_lock(tp, irq_sync);
+
+               if (epause->autoneg)
+                       tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+               else
+                       tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
+               if (epause->rx_pause)
+                       tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
+               else
+                       tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
+               if (epause->tx_pause)
+                       tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
+               else
+                       tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+
+               if (netif_running(dev)) {
+                       tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+                       err = tg3_restart_hw(tp, 1);
+                       if (!err)
+                               tg3_netif_start(tp);
+               }
+
+               tg3_full_unlock(tp);
+       }
 
        return err;
 }
@@ -8665,7 +9381,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                ethtool_op_set_tx_ipv6_csum(dev, data);
        else
                ethtool_op_set_tx_csum(dev, data);
@@ -8709,7 +9426,7 @@ static int tg3_phys_id(struct net_device *dev, u32 data)
                return -EAGAIN;
 
        if (data == 0)
-               data = 2;
+               data = UINT_MAX / 2;
 
        for (i = 0; i < (data * 2); i++) {
                if ((i % 2) == 0)
@@ -9186,7 +9903,8 @@ static int tg3_test_memory(struct tg3 *tp)
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                        mem_tbl = mem_tbl_5755;
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                        mem_tbl = mem_tbl_5906;
@@ -9392,7 +10110,9 @@ static int tg3_test_loopback(struct tg3 *tp)
        if (err)
                return TG3_LOOPBACK_FAILED;
 
-       if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
                int i;
                u32 status;
 
@@ -9409,7 +10129,7 @@ static int tg3_test_loopback(struct tg3 *tp)
                if (status != CPMU_MUTEX_GNT_DRIVER)
                        return TG3_LOOPBACK_FAILED;
 
-               /* Turn off power management based on link speed. */
+               /* Turn off link-based power management. */
                cpmuctrl = tr32(TG3_CPMU_CTRL);
                tw32(TG3_CPMU_CTRL,
                     cpmuctrl & ~(CPMU_CTRL_LINK_SPEED_MODE |
@@ -9419,14 +10139,17 @@ static int tg3_test_loopback(struct tg3 *tp)
        if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
                err |= TG3_MAC_LOOPBACK_FAILED;
 
-       if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
                tw32(TG3_CPMU_CTRL, cpmuctrl);
 
                /* Release the mutex */
                tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
        }
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+           !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
                if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
                        err |= TG3_PHY_LOOPBACK_FAILED;
        }
@@ -9453,9 +10176,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                data[1] = 1;
        }
        if (etest->flags & ETH_TEST_FL_OFFLINE) {
-               int err, irq_sync = 0;
+               int err, err2 = 0, irq_sync = 0;
 
                if (netif_running(dev)) {
+                       tg3_phy_stop(tp);
                        tg3_netif_stop(tp);
                        irq_sync = 1;
                }
@@ -9496,11 +10220,15 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
                if (netif_running(dev)) {
                        tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-                       if (!tg3_restart_hw(tp, 1))
+                       err2 = tg3_restart_hw(tp, 1);
+                       if (!err2)
                                tg3_netif_start(tp);
                }
 
                tg3_full_unlock(tp);
+
+               if (irq_sync && !err2)
+                       tg3_phy_start(tp);
        }
        if (tp->link_config.phy_is_low_power)
                tg3_set_power_state(tp, PCI_D3hot);
@@ -9513,6 +10241,12 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        struct tg3 *tp = netdev_priv(dev);
        int err;
 
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
+               return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd);
+       }
+
        switch(cmd) {
        case SIOCGMIIPHY:
                data->phy_id = PHY_ADDR;
@@ -9729,7 +10463,7 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
                        return;
                }
        }
-       tp->nvram_size = 0x80000;
+       tp->nvram_size = TG3_NVRAM_SIZE_512KB;
 }
 
 static void __devinit tg3_get_nvram_info(struct tg3 *tp)
@@ -9870,11 +10604,14 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
                        tp->nvram_pagesize = 264;
                        if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 ||
                            nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5)
-                               tp->nvram_size = (protect ? 0x3e200 : 0x80000);
+                               tp->nvram_size = (protect ? 0x3e200 :
+                                                 TG3_NVRAM_SIZE_512KB);
                        else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2)
-                               tp->nvram_size = (protect ? 0x1f200 : 0x40000);
+                               tp->nvram_size = (protect ? 0x1f200 :
+                                                 TG3_NVRAM_SIZE_256KB);
                        else
-                               tp->nvram_size = (protect ? 0x1f200 : 0x20000);
+                               tp->nvram_size = (protect ? 0x1f200 :
+                                                 TG3_NVRAM_SIZE_128KB);
                        break;
                case FLASH_5752VENDOR_ST_M45PE10:
                case FLASH_5752VENDOR_ST_M45PE20:
@@ -9884,11 +10621,17 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
                        tp->tg3_flags2 |= TG3_FLG2_FLASH;
                        tp->nvram_pagesize = 256;
                        if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10)
-                               tp->nvram_size = (protect ? 0x10000 : 0x20000);
+                               tp->nvram_size = (protect ?
+                                                 TG3_NVRAM_SIZE_64KB :
+                                                 TG3_NVRAM_SIZE_128KB);
                        else if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE20)
-                               tp->nvram_size = (protect ? 0x10000 : 0x40000);
+                               tp->nvram_size = (protect ?
+                                                 TG3_NVRAM_SIZE_64KB :
+                                                 TG3_NVRAM_SIZE_256KB);
                        else
-                               tp->nvram_size = (protect ? 0x20000 : 0x80000);
+                               tp->nvram_size = (protect ?
+                                                 TG3_NVRAM_SIZE_128KB :
+                                                 TG3_NVRAM_SIZE_512KB);
                        break;
        }
 }
@@ -9982,25 +10725,25 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp)
                        case FLASH_5761VENDOR_ATMEL_MDB161D:
                        case FLASH_5761VENDOR_ST_A_M45PE16:
                        case FLASH_5761VENDOR_ST_M_M45PE16:
-                               tp->nvram_size = 0x100000;
+                               tp->nvram_size = TG3_NVRAM_SIZE_2MB;
                                break;
                        case FLASH_5761VENDOR_ATMEL_ADB081D:
                        case FLASH_5761VENDOR_ATMEL_MDB081D:
                        case FLASH_5761VENDOR_ST_A_M45PE80:
                        case FLASH_5761VENDOR_ST_M_M45PE80:
-                               tp->nvram_size = 0x80000;
+                               tp->nvram_size = TG3_NVRAM_SIZE_1MB;
                                break;
                        case FLASH_5761VENDOR_ATMEL_ADB041D:
                        case FLASH_5761VENDOR_ATMEL_MDB041D:
                        case FLASH_5761VENDOR_ST_A_M45PE40:
                        case FLASH_5761VENDOR_ST_M_M45PE40:
-                               tp->nvram_size = 0x40000;
+                               tp->nvram_size = TG3_NVRAM_SIZE_512KB;
                                break;
                        case FLASH_5761VENDOR_ATMEL_ADB021D:
                        case FLASH_5761VENDOR_ATMEL_MDB021D:
                        case FLASH_5761VENDOR_ST_A_M45PE20:
                        case FLASH_5761VENDOR_ST_M_M45PE20:
-                               tp->nvram_size = 0x20000;
+                               tp->nvram_size = TG3_NVRAM_SIZE_256KB;
                                break;
                }
        }
@@ -10046,7 +10789,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
                        tg3_get_5755_nvram_info(tp);
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-                        GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+                        GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+                        GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                        tg3_get_5787_nvram_info(tp);
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
                        tg3_get_5761_nvram_info(tp);
@@ -10377,6 +11121,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) &&
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) &&
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) &&
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) &&
                    (tp->nvram_jedecnum == JEDEC_ST) &&
                    (nvram_cmd & NVRAM_CMD_FIRST)) {
 
@@ -10559,7 +11304,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
        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, eeprom_phy_id;
+               u32 nic_phy_id, ver, cfg2 = 0, cfg4 = 0, eeprom_phy_id;
                int eeprom_phy_serdes = 0;
 
                tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
@@ -10573,6 +11318,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                    (ver > 0) && (ver < 0x100))
                        tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
 
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+                       tg3_read_mem(tp, NIC_SRAM_DATA_CFG_4, &cfg4);
+
                if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
                    NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER)
                        eeprom_phy_serdes = 1;
@@ -10645,16 +11393,15 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                                                 LED_CTRL_MODE_PHY_2);
                        break;
 
-               };
+               }
 
                if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
                     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) &&
                    tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
                        tp->led_ctrl = LED_CTRL_MODE_PHY_2;
 
-               if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
-                   tp->pci_chip_rev_id == CHIPREV_ID_5784_A1)
-                       tp->led_ctrl = LED_CTRL_MODE_MAC;
+               if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX)
+                       tp->led_ctrl = LED_CTRL_MODE_PHY_1;
 
                if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) {
                        tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
@@ -10698,7 +11445,63 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                        if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE)
                                tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
                }
+
+               if (cfg4 & NIC_SRAM_RGMII_STD_IBND_DISABLE)
+                       tp->tg3_flags3 |= TG3_FLG3_RGMII_STD_IBND_DISABLE;
+               if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN)
+                       tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_RX_EN;
+               if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN)
+                       tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN;
+       }
+}
+
+static int __devinit tg3_issue_otp_command(struct tg3 *tp, u32 cmd)
+{
+       int i;
+       u32 val;
+
+       tw32(OTP_CTRL, cmd | OTP_CTRL_OTP_CMD_START);
+       tw32(OTP_CTRL, cmd);
+
+       /* Wait for up to 1 ms for command to execute. */
+       for (i = 0; i < 100; i++) {
+               val = tr32(OTP_STATUS);
+               if (val & OTP_STATUS_CMD_DONE)
+                       break;
+               udelay(10);
        }
+
+       return (val & OTP_STATUS_CMD_DONE) ? 0 : -EBUSY;
+}
+
+/* Read the gphy configuration from the OTP region of the chip.  The gphy
+ * configuration is a 32-bit value that straddles the alignment boundary.
+ * We do two 32-bit reads and then shift and merge the results.
+ */
+static u32 __devinit tg3_read_otp_phycfg(struct tg3 *tp)
+{
+       u32 bhalf_otp, thalf_otp;
+
+       tw32(OTP_MODE, OTP_MODE_OTP_THRU_GRC);
+
+       if (tg3_issue_otp_command(tp, OTP_CTRL_OTP_CMD_INIT))
+               return 0;
+
+       tw32(OTP_ADDRESS, OTP_ADDRESS_MAGIC1);
+
+       if (tg3_issue_otp_command(tp, OTP_CTRL_OTP_CMD_READ))
+               return 0;
+
+       thalf_otp = tr32(OTP_READ_DATA);
+
+       tw32(OTP_ADDRESS, OTP_ADDRESS_MAGIC2);
+
+       if (tg3_issue_otp_command(tp, OTP_CTRL_OTP_CMD_READ))
+               return 0;
+
+       bhalf_otp = tr32(OTP_READ_DATA);
+
+       return ((thalf_otp & 0x0000ffff) << 16) | (bhalf_otp >> 16);
 }
 
 static int __devinit tg3_phy_probe(struct tg3 *tp)
@@ -10707,6 +11510,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
        u32 hw_phy_id, hw_phy_id_masked;
        int err;
 
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
+               return tg3_phy_init(tp);
+
        /* Reading the PHY ID register can conflict with ASF
         * firwmare access to the PHY hardware.
         */
@@ -11142,6 +11948,38 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                }
        }
 
+       if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
+               static struct tg3_dev_id {
+                       u32     vendor;
+                       u32     device;
+               } bridge_chipsets[] = {
+                       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0 },
+                       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1 },
+                       { },
+               };
+               struct tg3_dev_id *pci_id = &bridge_chipsets[0];
+               struct pci_dev *bridge = NULL;
+
+               while (pci_id->vendor != 0) {
+                       bridge = pci_get_device(pci_id->vendor,
+                                               pci_id->device,
+                                               bridge);
+                       if (!bridge) {
+                               pci_id++;
+                               continue;
+                       }
+                       if (bridge->subordinate &&
+                           (bridge->subordinate->number <=
+                            tp->pdev->bus->number) &&
+                           (bridge->subordinate->subordinate >=
+                            tp->pdev->bus->number)) {
+                               tp->tg3_flags3 |= TG3_FLG3_5701_DMA_BUG;
+                               pci_dev_put(bridge);
+                               break;
+                       }
+               }
+       }
+
        /* The EPB bridge inside 5714, 5715, and 5780 cannot support
         * DMA addresses > 40-bit. This bridge may have other additional
         * 57xx devices behind it in some 4-port NIC designs for example.
@@ -11197,6 +12035,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
            (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
                tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
@@ -11218,6 +12057,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
                        tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
                        tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
@@ -11230,14 +12070,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                }
        }
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+            (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
                tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
 
        pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
@@ -11426,7 +12260,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
                tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
 
                if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
@@ -11454,6 +12289,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
                tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
 
+       if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) {
+               /* Turn off the debug UART. */
+               tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
+               if (tp->tg3_flags2 & TG3_FLG2_IS_NIC)
+                       /* Keep VMain power. */
+                       tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 |
+                                             GRC_LCLCTRL_GPIO_OUTPUT0;
+       }
+
        /* Force the chip into D0. */
        err = tg3_set_power_state(tp, PCI_D0);
        if (err) {
@@ -11510,18 +12354,34 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                                tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
                        if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M)
                                tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM;
-               } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+               } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 &&
+                          GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785)
                        tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
        }
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+           GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) {
+               tp->phy_otp = tg3_read_otp_phycfg(tp);
+               if (tp->phy_otp == 0)
+                       tp->phy_otp = TG3_OTP_DEFAULT;
+       }
+
+       if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)
+               tp->mi_mode = MAC_MI_MODE_500KHZ_CONST;
+       else
+               tp->mi_mode = MAC_MI_MODE_BASE;
+
        tp->coalesce_mode = 0;
        if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
            GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
                tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
 
-       /* Initialize MAC MI mode, polling disabled. */
-       tw32_f(MAC_MI_MODE, tp->mi_mode);
-       udelay(80);
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+               tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB;
+
+       err = tg3_mdio_init(tp);
+       if (err)
+               return err;
 
        /* Initialize data/descriptor byte/word swapping. */
        val = tr32(GRC_MODE);
@@ -11602,6 +12462,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n",
                       pci_name(tp->pdev), err);
                /* ... but do not return immediately ... */
+               tg3_mdio_fini(tp);
        }
 
        tg3_read_partno(tp);
@@ -11649,6 +12510,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                tp->dev->hard_start_xmit = tg3_start_xmit;
        else
@@ -11769,7 +12631,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
        }
 
        if (!is_valid_ether_addr(&dev->dev_addr[0])) {
-#ifdef CONFIG_SPARC64
+#ifdef CONFIG_SPARC
                if (!tg3_get_default_macaddr_sparc(tp))
                        return 0;
 #endif
@@ -11851,7 +12713,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
                        val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX |
                                DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
                        break;
-               };
+               }
        } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
                switch (cacheline_size) {
                case 16:
@@ -11868,7 +12730,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
                        val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
                        val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE;
                        break;
-               };
+               }
        } else {
                switch (cacheline_size) {
                case 16:
@@ -11912,7 +12774,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
                        val |= (DMA_RWCTRL_READ_BNDRY_1024 |
                                DMA_RWCTRL_WRITE_BNDRY_1024);
                        break;
-               };
+               }
        }
 
 out:
@@ -12272,7 +13134,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
        case PHY_ID_BCM8002:    return "8002/serdes";
        case 0:                 return "serdes";
        default:                return "unknown";
-       };
+       }
 }
 
 static char * __devinit tg3_bus_string(struct tg3 *tp, char *str)
@@ -12374,7 +13236,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                                  const struct pci_device_id *ent)
 {
        static int tg3_version_printed = 0;
-       unsigned long tg3reg_base, tg3reg_len;
+       resource_size_t tg3reg_base;
+       unsigned long tg3reg_len;
        struct net_device *dev;
        struct tg3 *tp;
        int err, pm_cap;
@@ -12441,7 +13304,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        tp->mac_mode = TG3_DEF_MAC_MODE;
        tp->rx_mode = TG3_DEF_RX_MODE;
        tp->tx_mode = TG3_DEF_TX_MODE;
-       tp->mi_mode = MAC_MI_MODE_BASE;
+
        if (tg3_debug > 0)
                tp->msg_enable = tg3_debug;
        else
@@ -12572,7 +13435,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
                        dev->features |= NETIF_F_TSO6;
-               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+                    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
+                       GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                        dev->features |= NETIF_F_TSO_ECN;
        }
 
@@ -12603,7 +13469,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                tg3reg_len = pci_resource_len(pdev, 2);
 
                tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len);
-               if (tp->aperegs == 0UL) {
+               if (!tp->aperegs) {
                        printk(KERN_ERR PFX "Cannot map APE registers, "
                               "aborting.\n");
                        err = -ENOMEM;
@@ -12638,7 +13504,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                        dev->features |= NETIF_F_IPV6_CSUM;
 
                tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
@@ -12720,6 +13587,12 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
                struct tg3 *tp = netdev_priv(dev);
 
                flush_scheduled_work();
+
+               if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+                       tg3_phy_fini(tp);
+                       tg3_mdio_fini(tp);
+               }
+
                unregister_netdev(dev);
                if (tp->aperegs) {
                        iounmap(tp->aperegs);
@@ -12752,6 +13625,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
                return 0;
 
        flush_scheduled_work();
+       tg3_phy_stop(tp);
        tg3_netif_stop(tp);
 
        del_timer_sync(&tp->timer);
@@ -12769,10 +13643,13 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
 
        err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
        if (err) {
+               int err2;
+
                tg3_full_lock(tp, 0);
 
                tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-               if (tg3_restart_hw(tp, 1))
+               err2 = tg3_restart_hw(tp, 1);
+               if (err2)
                        goto out;
 
                tp->timer.expires = jiffies + tp->timer_offset;
@@ -12783,6 +13660,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
 
 out:
                tg3_full_unlock(tp);
+
+               if (!err2)
+                       tg3_phy_start(tp);
        }
 
        return err;
@@ -12820,6 +13700,9 @@ static int tg3_resume(struct pci_dev *pdev)
 out:
        tg3_full_unlock(tp);
 
+       if (!err)
+               tg3_phy_start(tp);
+
        return err;
 }