Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6.git] / drivers / net / tg3.c
index bf376b3..eb9f8f3 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.91"
-#define DRV_MODULE_RELDATE     "April 18, 2008"
+#define DRV_MODULE_VERSION     "3.94"
+#define DRV_MODULE_RELDATE     "August 14, 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)},
@@ -533,6 +536,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
                return 0;
 
        switch (locknum) {
+               case TG3_APE_LOCK_GRC:
                case TG3_APE_LOCK_MEM:
                        break;
                default:
@@ -570,6 +574,7 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
                return;
 
        switch (locknum) {
+               case TG3_APE_LOCK_GRC:
                case TG3_APE_LOCK_MEM:
                        break;
                default:
@@ -804,6 +809,597 @@ 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;
+
+       tg3_mdio_start(tp);
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) ||
+           (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED))
+               return 0;
+
+       tp->mdio_bus = mdiobus_alloc();
+       if (tp->mdio_bus == NULL)
+               return -ENOMEM;
+
+       tp->mdio_bus->name     = "tg3 mdio bus";
+       snprintf(tp->mdio_bus->id, MII_BUS_ID_SIZE, "%x",
+                (tp->pdev->bus->number << 8) | tp->pdev->devfn);
+       tp->mdio_bus->priv     = tp;
+       tp->mdio_bus->parent   = &tp->pdev->dev;
+       tp->mdio_bus->read     = &tg3_mdio_read;
+       tp->mdio_bus->write    = &tg3_mdio_write;
+       tp->mdio_bus->reset    = &tg3_mdio_reset;
+       tp->mdio_bus->phy_mask = ~(1 << PHY_ADDR);
+       tp->mdio_bus->irq      = &tp->mdio_irq[0];
+
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               tp->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(tp->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);
+               mdiobus_free(tp->mdio_bus);
+               tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
+       }
+}
+
+/* tp->lock is held. */
+static inline void tg3_generate_fw_event(struct tg3 *tp)
+{
+       u32 val;
+
+       val = tr32(GRC_RX_CPU_EVENT);
+       val |= GRC_RX_CPU_DRIVER_EVENT;
+       tw32_f(GRC_RX_CPU_EVENT, val);
+
+       tp->last_event_jiffies = jiffies;
+}
+
+#define TG3_FW_EVENT_TIMEOUT_USEC 2500
+
+/* tp->lock is held. */
+static void tg3_wait_for_event_ack(struct tg3 *tp)
+{
+       int i;
+       unsigned int delay_cnt;
+       long time_remain;
+
+       /* If enough time has passed, no wait is necessary. */
+       time_remain = (long)(tp->last_event_jiffies + 1 +
+                     usecs_to_jiffies(TG3_FW_EVENT_TIMEOUT_USEC)) -
+                     (long)jiffies;
+       if (time_remain < 0)
+               return;
+
+       /* Check if we can shorten the wait time. */
+       delay_cnt = jiffies_to_usecs(time_remain);
+       if (delay_cnt > TG3_FW_EVENT_TIMEOUT_USEC)
+               delay_cnt = TG3_FW_EVENT_TIMEOUT_USEC;
+       delay_cnt = (delay_cnt >> 3) + 1;
+
+       for (i = 0; i < delay_cnt; i++) {
+               if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
+                       break;
+               udelay(8);
+       }
+}
+
+/* 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);
+
+       tg3_generate_fw_event(tp);
+}
+
+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);
@@ -861,37 +1457,6 @@ static void tg3_phy_set_wirespeed(struct tg3 *tp)
                             (val | (1 << 15) | (1 << 4)));
 }
 
-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 void tg3_phy_apply_otp(struct tg3 *tp)
 {
        u32 otp, phy;
@@ -1115,8 +1680,6 @@ 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.
  */
@@ -1295,6 +1858,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;
@@ -1406,7 +1984,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);
@@ -1434,8 +2012,6 @@ static void tg3_power_down_phy(struct tg3 *tp)
 static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
 {
        u32 misc_host_ctrl;
-       u16 power_control, power_caps;
-       int pm = tp->pm_cap;
 
        /* Make sure register accesses (indirect or otherwise)
         * will function correctly.
@@ -1444,18 +2020,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                               TG3PCI_MISC_HOST_CTRL,
                               tp->misc_host_ctrl);
 
-       pci_read_config_word(tp->pdev,
-                            pm + PCI_PM_CTRL,
-                            &power_control);
-       power_control |= PCI_PM_CTRL_PME_STATUS;
-       power_control &= ~(PCI_PM_CTRL_STATE_MASK);
        switch (state) {
        case PCI_D0:
-               power_control |= 0;
-               pci_write_config_word(tp->pdev,
-                                     pm + PCI_PM_CTRL,
-                                     power_control);
-               udelay(100);    /* Delay after power state change */
+               pci_enable_wake(tp->pdev, state, false);
+               pci_set_power_state(tp->pdev, PCI_D0);
 
                /* Switch out of Vaux if it is a NIC */
                if (tp->tg3_flags2 & TG3_FLG2_IS_NIC)
@@ -1464,42 +2032,68 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                return 0;
 
        case PCI_D1:
-               power_control |= 1;
-               break;
-
        case PCI_D2:
-               power_control |= 2;
-               break;
-
        case PCI_D3hot:
-               power_control |= 3;
                break;
 
        default:
-               printk(KERN_WARNING PFX "%s: Invalid power state (%d) "
-                      "requested.\n",
-                      tp->dev->name, state);
+               printk(KERN_ERR PFX "%s: Invalid power state (D%d) requested\n",
+                       tp->dev->name, state);
                return -EINVAL;
-       };
-
-       power_control |= PCI_PM_CTRL_PME_ENABLE;
-
+       }
        misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
        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) {
@@ -1524,14 +2118,14 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                                                     WOL_DRV_WOL |
                                                     WOL_SET_MAGIC_PKT);
 
-       pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps);
-
        if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) {
                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;
@@ -1556,10 +2150,17 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
                        tw32(MAC_LED_CTRL, tp->led_ctrl);
 
-               if (((power_caps & PCI_PM_CAP_PME_D3cold) &&
-                    (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)))
+               if (pci_pme_capable(tp->pdev, state) &&
+                    (tp->tg3_flags & TG3_FLAG_WOL_ENABLE))
                        mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE;
 
+               if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+                       mac_mode |= tp->mac_mode &
+                                   (MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN);
+                       if (mac_mode & MAC_MODE_APE_TX_EN)
+                               mac_mode |= MAC_MODE_TDE_ENABLE;
+               }
+
                tw32_f(MAC_MODE, mac_mode);
                udelay(100);
 
@@ -1649,154 +2250,15 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
 
        tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
 
+       if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
+               pci_enable_wake(tp->pdev, state, true);
+
        /* Finally, set the new power state. */
-       pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
-       udelay(100);    /* Delay after power state change */
+       pci_set_power_state(tp->pdev, 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 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 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->link_config.autoneg == AUTONEG_ENABLE &&
-           (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
-               if (tp->tg3_flags2 & TG3_FLG2_ANY_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) {
@@ -1841,7 +2303,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)
@@ -1953,7 +2415,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;
@@ -2651,7 +3113,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
        default:
                ret = ANEG_FAILED;
                break;
-       };
+       }
 
        return ret;
 }
@@ -3103,8 +3565,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
        err |= tg3_readphy(tp, MII_BMCR, &bmcr);
 
        if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset &&
-           (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
-            tp->link_config.flowctrl == tp->link_config.active_flowctrl) {
+           (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
                /* do nothing, just check for link up at the end */
        } else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
                u32 adv, new_adv;
@@ -3402,10 +3863,7 @@ static void tg3_tx(struct tg3 *tp)
                        return;
                }
 
-               pci_unmap_single(tp->pdev,
-                                pci_unmap_addr(ri, mapping),
-                                skb_headlen(skb),
-                                PCI_DMA_TODEVICE);
+               skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE);
 
                ri->skb = NULL;
 
@@ -3415,12 +3873,6 @@ static void tg3_tx(struct tg3 *tp)
                        ri = &tp->tx_buffers[sw_idx];
                        if (unlikely(ri->skb != NULL || sw_idx == hw_idx))
                                tx_bug = 1;
-
-                       pci_unmap_page(tp->pdev,
-                                      pci_unmap_addr(ri, mapping),
-                                      skb_shinfo(skb)->frags[i].size,
-                                      PCI_DMA_TODEVICE);
-
                        sw_idx = NEXT_TX(sw_idx);
                }
 
@@ -3493,7 +3945,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.
@@ -3553,7 +4005,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,
@@ -3763,7 +4215,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);
                }
        }
@@ -4051,6 +4511,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);
@@ -4062,6 +4523,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);
@@ -4077,7 +4540,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);
@@ -4087,6 +4551,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)
@@ -4159,12 +4626,16 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
        } else {
                /* New SKB is guaranteed to be linear. */
                entry = *start;
-               new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
-                                         PCI_DMA_TODEVICE);
+               ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE);
+               new_addr = skb_shinfo(new_skb)->dma_maps[0];
+
                /* Make sure new skb does not cross any 4G boundaries.
                 * Drop the packet if it does.
                 */
-               if (tg3_4g_overflow_test(new_addr, new_skb->len)) {
+               if (ret || tg3_4g_overflow_test(new_addr, new_skb->len)) {
+                       if (!ret)
+                               skb_dma_unmap(&tp->pdev->dev, new_skb,
+                                             DMA_TO_DEVICE);
                        ret = -1;
                        dev_kfree_skb(new_skb);
                        new_skb = NULL;
@@ -4178,18 +4649,8 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
        /* Now clean up the sw ring entries. */
        i = 0;
        while (entry != last_plus_one) {
-               int len;
-
-               if (i == 0)
-                       len = skb_headlen(skb);
-               else
-                       len = skb_shinfo(skb)->frags[i-1].size;
-               pci_unmap_single(tp->pdev,
-                                pci_unmap_addr(&tp->tx_buffers[entry], mapping),
-                                len, PCI_DMA_TODEVICE);
                if (i == 0) {
                        tp->tx_buffers[entry].skb = new_skb;
-                       pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, new_addr);
                } else {
                        tp->tx_buffers[entry].skb = NULL;
                }
@@ -4197,6 +4658,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
                i++;
        }
 
+       skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE);
        dev_kfree_skb(skb);
 
        return ret;
@@ -4231,8 +4693,9 @@ static void tg3_set_txd(struct tg3 *tp, int entry,
 static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
-       dma_addr_t mapping;
        u32 len, entry, base_flags, mss;
+       struct skb_shared_info *sp;
+       dma_addr_t mapping;
 
        len = skb_headlen(skb);
 
@@ -4291,11 +4754,16 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                               (vlan_tx_tag_get(skb) << 16));
 #endif
 
-       /* Queue skb data, a.k.a. the main skb fragment. */
-       mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+       if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) {
+               dev_kfree_skb(skb);
+               goto out_unlock;
+       }
+
+       sp = skb_shinfo(skb);
+
+       mapping = sp->dma_maps[0];
 
        tp->tx_buffers[entry].skb = skb;
-       pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
        tg3_set_txd(tp, entry, mapping, len, base_flags,
                    (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
@@ -4311,13 +4779,8 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
                        len = frag->size;
-                       mapping = pci_map_page(tp->pdev,
-                                              frag->page,
-                                              frag->page_offset,
-                                              len, PCI_DMA_TODEVICE);
-
+                       mapping = sp->dma_maps[i + 1];
                        tp->tx_buffers[entry].skb = NULL;
-                       pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
                        tg3_set_txd(tp, entry, mapping, len,
                                    base_flags, (i == last) | (mss << 1));
@@ -4385,9 +4848,10 @@ tg3_tso_bug_end:
 static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
-       dma_addr_t mapping;
        u32 len, entry, base_flags, mss;
+       struct skb_shared_info *sp;
        int would_hit_hwbug;
+       dma_addr_t mapping;
 
        len = skb_headlen(skb);
 
@@ -4468,11 +4932,16 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
                               (vlan_tx_tag_get(skb) << 16));
 #endif
 
-       /* Queue skb data, a.k.a. the main skb fragment. */
-       mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+       if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) {
+               dev_kfree_skb(skb);
+               goto out_unlock;
+       }
+
+       sp = skb_shinfo(skb);
+
+       mapping = sp->dma_maps[0];
 
        tp->tx_buffers[entry].skb = skb;
-       pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
        would_hit_hwbug = 0;
 
@@ -4495,13 +4964,9 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
                        len = frag->size;
-                       mapping = pci_map_page(tp->pdev,
-                                              frag->page,
-                                              frag->page_offset,
-                                              len, PCI_DMA_TODEVICE);
+                       mapping = sp->dma_maps[i + 1];
 
                        tp->tx_buffers[entry].skb = NULL;
-                       pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
                        if (tg3_4g_overflow_test(mapping, len))
                                would_hit_hwbug = 1;
@@ -4590,6 +5055,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);
@@ -4605,6 +5072,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;
 }
 
@@ -4649,7 +5119,6 @@ static void tg3_free_rings(struct tg3 *tp)
        for (i = 0; i < TG3_TX_RING_SIZE; ) {
                struct tx_ring_info *txp;
                struct sk_buff *skb;
-               int j;
 
                txp = &tp->tx_buffers[i];
                skb = txp->skb;
@@ -4659,22 +5128,11 @@ static void tg3_free_rings(struct tg3 *tp)
                        continue;
                }
 
-               pci_unmap_single(tp->pdev,
-                                pci_unmap_addr(txp, mapping),
-                                skb_headlen(skb),
-                                PCI_DMA_TODEVICE);
-               txp->skb = NULL;
+               skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE);
 
-               i++;
+               txp->skb = NULL;
 
-               for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) {
-                       txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)];
-                       pci_unmap_page(tp->pdev,
-                                      pci_unmap_addr(txp, mapping),
-                                      skb_shinfo(skb)->frags[j].size,
-                                      PCI_DMA_TODEVICE);
-                       i++;
-               }
+               i += skb_shinfo(skb)->nr_frags + 1;
 
                dev_kfree_skb_any(skb);
        }
@@ -4896,7 +5354,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int
 
                default:
                        break;
-               };
+               }
        }
 
        val = tr32(ofs);
@@ -5049,7 +5507,7 @@ static void tg3_ape_send_event(struct tg3 *tp, u32 event)
                return;
 
        apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
-       if (apedata != APE_FW_STATUS_READY)
+       if (!(apedata & APE_FW_STATUS_READY))
                return;
 
        /* Wait for up to 1 millisecond for APE to service previous event. */
@@ -5138,7 +5596,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
 
                default:
                        break;
-               };
+               }
        }
 
        if (kind == RESET_KIND_INIT ||
@@ -5163,7 +5621,7 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
 
                default:
                        break;
-               };
+               }
        }
 
        if (kind == RESET_KIND_SHUTDOWN)
@@ -5192,7 +5650,7 @@ static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
 
                default:
                        break;
-               };
+               }
        }
 }
 
@@ -5314,6 +5772,10 @@ static int tg3_chip_reset(struct tg3 *tp)
 
        tg3_nvram_lock(tp);
 
+       tg3_mdio_stop(tp);
+
+       tg3_ape_lock(tp, TG3_APE_LOCK_GRC);
+
        /* No matching tg3_nvram_unlock() after this because
         * chip reset below will undo the nvram lock.
         */
@@ -5329,7 +5791,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);
 
        /*
@@ -5461,10 +5924,19 @@ static int tg3_chip_reset(struct tg3 *tp)
        } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
                tp->mac_mode = MAC_MODE_PORT_MODE_GMII;
                tw32_f(MAC_MODE, tp->mac_mode);
+       } else if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+               tp->mac_mode &= (MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN);
+               if (tp->mac_mode & MAC_MODE_APE_TX_EN)
+                       tp->mac_mode |= MAC_MODE_TDE_ENABLE;
+               tw32_f(MAC_MODE, tp->mac_mode);
        } else
                tw32_f(MAC_MODE, 0);
        udelay(40);
 
+       tg3_mdio_start(tp);
+
+       tg3_ape_unlock(tp, TG3_APE_LOCK_GRC);
+
        err = tg3_poll_fw(tp);
        if (err)
                return err;
@@ -5486,6 +5958,7 @@ static int tg3_chip_reset(struct tg3 *tp)
                tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
                if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
                        tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
+                       tp->last_event_jiffies = jiffies;
                        if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
                                tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
                }
@@ -5499,20 +5972,15 @@ 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);
-               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);
-               }
+               tg3_generate_fw_event(tp);
+
+               /* Wait for RX cpu to ACK this event. */
+               tg3_wait_for_event_ack(tp);
        }
 }
 
@@ -6546,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);
@@ -6622,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.
                 */
@@ -6861,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;
@@ -6956,7 +7427,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                udelay(10);
        }
 
-       tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
+       if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+               tp->mac_mode &= MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
+       else
+               tp->mac_mode = 0;
+       tp->mac_mode |= MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
                MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
        if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
            !(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
@@ -7029,8 +7504,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);
@@ -7091,23 +7567,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_AUTO_POLL;
-       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);
@@ -7154,19 +7621,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);
+                       }
                }
        }
 
@@ -7219,7 +7695,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. */
@@ -7236,21 +7712,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
  */
 static int tg3_init_hw(struct tg3 *tp, int reset_phy)
 {
-       int err;
-
-       /* Force the chip into D0. */
-       err = tg3_set_power_state(tp, PCI_D0);
-       if (err)
-               goto out;
-
        tg3_switch_clocks(tp);
 
        tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
 
-       err = tg3_reset_hw(tp, reset_phy);
-
-out:
-       return err;
+       return tg3_reset_hw(tp, reset_phy);
 }
 
 #define TG3_STAT_ADD32(PSTAT, REG) \
@@ -7399,17 +7865,17 @@ static void tg3_timer(unsigned long __opaque)
         * resets.
         */
        if (!--tp->asf_counter) {
-               if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
-                       u32 val;
+               if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+                   !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
+                       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);
+
+                       tg3_generate_fw_event(tp);
                }
                tp->asf_counter = tp->asf_multiplier;
        }
@@ -7563,13 +8029,11 @@ static int tg3_open(struct net_device *dev)
 
        netif_carrier_off(tp->dev);
 
-       tg3_full_lock(tp, 0);
-
        err = tg3_set_power_state(tp, PCI_D0);
-       if (err) {
-               tg3_full_unlock(tp);
+       if (err)
                return err;
-       }
+
+       tg3_full_lock(tp, 0);
 
        tg3_disable_ints(tp);
        tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
@@ -7679,6 +8143,8 @@ static int tg3_open(struct net_device *dev)
                }
        }
 
+       tg3_phy_start(tp);
+
        tg3_full_lock(tp, 0);
 
        add_timer(&tp->timer);
@@ -7979,6 +8445,11 @@ static inline unsigned long get_stat64(tg3_stat64_t *val)
        return ret;
 }
 
+static inline u64 get_estat64(tg3_stat64_t *val)
+{
+       return ((u64)val->high << 32) | ((u64)val->low);
+}
+
 static unsigned long calc_crc_errors(struct tg3 *tp)
 {
        struct tg3_hw_stats *hw_stats = tp->hw_stats;
@@ -8007,7 +8478,7 @@ static unsigned long calc_crc_errors(struct tg3 *tp)
 
 #define ESTAT_ADD(member) \
        estats->member =        old_estats->member + \
-                               get_stat64(&hw_stats->member)
+                               get_estat64(&hw_stats->member)
 
 static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp)
 {
@@ -8480,7 +8951,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);
 
@@ -8517,6 +8994,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 &&
@@ -8534,7 +9017,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);
@@ -8549,7 +9032,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;
@@ -8577,7 +9060,8 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct tg3 *tp = netdev_priv(dev);
 
-       if (tp->tg3_flags & TG3_FLAG_WOL_CAP)
+       if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) &&
+           device_can_wakeup(&tp->pdev->dev))
                wol->supported = WAKE_MAGIC;
        else
                wol->supported = 0;
@@ -8590,18 +9074,22 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct tg3 *tp = netdev_priv(dev);
+       struct device *dp = &tp->pdev->dev;
 
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EINVAL;
        if ((wol->wolopts & WAKE_MAGIC) &&
-           !(tp->tg3_flags & TG3_FLAG_WOL_CAP))
+           !((tp->tg3_flags & TG3_FLAG_WOL_CAP) && device_can_wakeup(dp)))
                return -EINVAL;
 
        spin_lock_bh(&tp->lock);
-       if (wol->wolopts & WAKE_MAGIC)
+       if (wol->wolopts & WAKE_MAGIC) {
                tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
-       else
+               device_set_wakeup_enable(dp, true);
+       } else {
                tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
+               device_set_wakeup_enable(dp, false);
+       }
        spin_unlock_bh(&tp->lock);
 
        return 0;
@@ -8632,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);
@@ -8643,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))
@@ -8652,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;
 }
@@ -8704,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;
        }
@@ -8727,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;
 }
 
@@ -8750,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;
 }
@@ -8823,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);
@@ -9344,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;
@@ -9551,7 +10111,8 @@ static int tg3_test_loopback(struct tg3 *tp)
                return TG3_LOOPBACK_FAILED;
 
        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) {
                int i;
                u32 status;
 
@@ -9579,14 +10140,16 @@ static int tg3_test_loopback(struct tg3 *tp)
                err |= TG3_MAC_LOOPBACK_FAILED;
 
        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) {
                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;
        }
@@ -9613,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;
                }
@@ -9656,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);
@@ -9673,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;
@@ -10215,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);
@@ -10546,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)) {
 
@@ -10720,7 +11296,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                if (val & VCPU_CFGSHDW_ASPM_DBNC)
                        tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
                if ((val & VCPU_CFGSHDW_WOL_ENABLE) &&
-                   (val & VCPU_CFGSHDW_WOL_MAGPKT))
+                   (val & VCPU_CFGSHDW_WOL_MAGPKT) &&
+                   device_may_wakeup(&tp->pdev->dev))
                        tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
                return;
        }
@@ -10728,7 +11305,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);
@@ -10742,6 +11319,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;
@@ -10814,7 +11394,7 @@ 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) &&
@@ -10847,8 +11427,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                    !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
                        tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
 
-               if (tp->tg3_flags & TG3_FLAG_WOL_CAP &&
-                   nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)
+               if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) &&
+                   (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE) &&
+                   device_may_wakeup(&tp->pdev->dev))
                        tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
 
                if (cfg2 & (1 << 17))
@@ -10866,6 +11447,13 @@ 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;
        }
 }
 
@@ -10924,6 +11512,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.
         */
@@ -11446,6 +12037,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;
@@ -11467,6 +12059,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;
@@ -11479,14 +12072,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);
@@ -11675,7 +12262,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 ||
@@ -11703,6 +12291,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) {
@@ -11759,7 +12356,8 @@ 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;
        }
 
@@ -11770,8 +12368,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                        tp->phy_otp = TG3_OTP_DEFAULT;
        }
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+       if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)
                tp->mi_mode = MAC_MI_MODE_500KHZ_CONST;
        else
                tp->mi_mode = MAC_MI_MODE_BASE;
@@ -11781,9 +12378,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            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);
@@ -11844,6 +12444,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                                       tp->misc_host_ctrl);
        }
 
+       /* Preserve the APE MAC_MODE bits */
+       if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+               tp->mac_mode = tr32(MAC_MODE) |
+                              MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
+       else
+               tp->mac_mode = TG3_DEF_MAC_MODE;
+
        /* these are limited to 10/100 only */
        if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
             (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
@@ -11864,6 +12471,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);
@@ -11911,6 +12519,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
@@ -12113,7 +12722,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:
@@ -12130,7 +12739,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:
@@ -12174,7 +12783,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:
@@ -12534,7 +13143,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)
@@ -12701,7 +13310,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        tp->pdev = pdev;
        tp->dev = dev;
        tp->pm_cap = pm_cap;
-       tp->mac_mode = TG3_DEF_MAC_MODE;
        tp->rx_mode = TG3_DEF_RX_MODE;
        tp->tx_mode = TG3_DEF_TX_MODE;
 
@@ -12835,7 +13443,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;
        }
 
@@ -12901,7 +13512,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;
@@ -12983,6 +13595,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);
@@ -13003,6 +13621,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct tg3 *tp = netdev_priv(dev);
+       pci_power_t target_state;
        int err;
 
        /* PCI register 4 needs to be saved whether netif_running() or not.
@@ -13015,6 +13634,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);
@@ -13030,12 +13650,17 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
        tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
        tg3_full_unlock(tp);
 
-       err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
+       target_state = pdev->pm_cap ? pci_target_state(pdev) : PCI_D3hot;
+
+       err = tg3_set_power_state(tp, target_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;
@@ -13046,6 +13671,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;
@@ -13083,6 +13711,9 @@ static int tg3_resume(struct pci_dev *pdev)
 out:
        tg3_full_unlock(tp);
 
+       if (!err)
+               tg3_phy_start(tp);
+
        return err;
 }