]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/broadcom/tg3.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[karo-tx-linux.git] / drivers / net / ethernet / broadcom / tg3.c
index cc092170dfa3c1f78924fed845cbd64388650df2..b0657466041d733900199124ffab0f6dbaf088af 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
  * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
  * Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2005-2011 Broadcom Corporation.
+ * Copyright (C) 2005-2012 Broadcom Corporation.
  *
  * Firmware is:
  *     Derived from proprietary unpublished source code,
@@ -204,6 +204,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 #define TG3_RAW_IP_ALIGN 2
 
 #define TG3_FW_UPDATE_TIMEOUT_SEC      5
+#define TG3_FW_UPDATE_FREQ_SEC         (TG3_FW_UPDATE_TIMEOUT_SEC / 2)
 
 #define FIRMWARE_TG3           "tigon/tg3.bin"
 #define FIRMWARE_TG3TSO                "tigon/tg3_tso.bin"
@@ -1453,33 +1454,23 @@ static void tg3_wait_for_event_ack(struct tg3 *tp)
 }
 
 /* tp->lock is held. */
-static void tg3_ump_link_report(struct tg3 *tp)
+static void tg3_phy_gather_ump_data(struct tg3 *tp, u32 *data)
 {
-       u32 reg;
-       u32 val;
-
-       if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, 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);
+       u32 reg, val;
 
        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);
+       *data++ = 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);
+       *data++ = val;
 
        val = 0;
        if (!(tp->phy_flags & TG3_PHYFLG_MII_SERDES)) {
@@ -1488,13 +1479,33 @@ static void tg3_ump_link_report(struct tg3 *tp)
                if (!tg3_readphy(tp, MII_STAT1000, &reg))
                        val |= (reg & 0xffff);
        }
-       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
+       *data++ = 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);
+       *data++ = val;
+}
+
+/* tp->lock is held. */
+static void tg3_ump_link_report(struct tg3 *tp)
+{
+       u32 data[4];
+
+       if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF))
+               return;
+
+       tg3_phy_gather_ump_data(tp, data);
+
+       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);
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x0, data[0]);
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x4, data[1]);
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x8, data[2]);
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0xc, data[3]);
 
        tg3_generate_fw_event(tp);
 }
@@ -1809,13 +1820,13 @@ static void tg3_adjust_link(struct net_device *dev)
                      (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) ||
+       if (phydev->link != tp->old_link ||
            phydev->speed != tp->link_config.active_speed ||
            phydev->duplex != tp->link_config.active_duplex ||
            oldflowctrl != tp->link_config.active_flowctrl)
                linkmesg = 1;
 
+       tp->old_link = phydev->link;
        tp->link_config.active_speed = phydev->speed;
        tp->link_config.active_duplex = phydev->duplex;
 
@@ -1884,10 +1895,10 @@ static void tg3_phy_start(struct tg3 *tp)
 
        if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
                tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
-               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;
+               phydev->speed = tp->link_config.speed;
+               phydev->duplex = tp->link_config.duplex;
+               phydev->autoneg = tp->link_config.autoneg;
+               phydev->advertising = tp->link_config.advertising;
        }
 
        phy_start(phydev);
@@ -2709,9 +2720,6 @@ static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed)
        return 0;
 }
 
-static int tg3_setup_phy(struct tg3 *, int);
-static int tg3_halt_cpu(struct tg3 *, u32);
-
 static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
 {
        u32 val;
@@ -3143,8 +3151,6 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
 
                phy_addr = tg3_nvram_phys_addr(tp, offset);
 
-               tw32(NVRAM_ADDR, phy_addr);
-
                nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR;
 
                if (page_off == 0 || i == 0)
@@ -3155,6 +3161,11 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
                if (i == (len - 4))
                        nvram_cmd |= NVRAM_CMD_LAST;
 
+               if ((nvram_cmd & NVRAM_CMD_FIRST) ||
+                   !tg3_flag(tp, FLASH) ||
+                   !tg3_flag(tp, 57765_PLUS))
+                       tw32(NVRAM_ADDR, phy_addr);
+
                if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
                    !tg3_flag(tp, 5755_PLUS) &&
                    (tp->nvram_jedecnum == JEDEC_ST) &&
@@ -3514,6 +3525,8 @@ static int tg3_power_up(struct tg3 *tp)
        return err;
 }
 
+static int tg3_setup_phy(struct tg3 *, int);
+
 static int tg3_power_down_prepare(struct tg3 *tp)
 {
        u32 misc_host_ctrl;
@@ -3552,10 +3565,10 @@ static int tg3_power_down_prepare(struct tg3 *tp)
 
                        tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
 
-                       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;
+                       tp->link_config.speed = phydev->speed;
+                       tp->link_config.duplex = phydev->duplex;
+                       tp->link_config.autoneg = phydev->autoneg;
+                       tp->link_config.advertising = phydev->advertising;
 
                        advertising = ADVERTISED_TP |
                                      ADVERTISED_Pause |
@@ -3588,19 +3601,11 @@ static int tg3_power_down_prepare(struct tg3 *tp)
        } else {
                do_low_power = true;
 
-               if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
+               if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER))
                        tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
-                       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->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
-                       tp->link_config.speed = SPEED_10;
-                       tp->link_config.duplex = DUPLEX_HALF;
-                       tp->link_config.autoneg = AUTONEG_ENABLE;
+               if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
                        tg3_setup_phy(tp, 0);
-               }
        }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
@@ -3809,8 +3814,8 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8
                                  DUPLEX_HALF;
                        break;
                }
-               *speed = SPEED_INVALID;
-               *duplex = DUPLEX_INVALID;
+               *speed = SPEED_UNKNOWN;
+               *duplex = DUPLEX_UNKNOWN;
                break;
        }
 }
@@ -3890,51 +3895,33 @@ done:
 
 static void tg3_phy_copper_begin(struct tg3 *tp)
 {
-       u32 new_adv;
-       int i;
+       if (tp->link_config.autoneg == AUTONEG_ENABLE ||
+           (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
+               u32 adv, fc;
 
-       if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
-               new_adv = ADVERTISED_10baseT_Half |
-                         ADVERTISED_10baseT_Full;
-               if (tg3_flag(tp, WOL_SPEED_100MB))
-                       new_adv |= ADVERTISED_100baseT_Half |
-                                  ADVERTISED_100baseT_Full;
-
-               tg3_phy_autoneg_cfg(tp, new_adv,
-                                   FLOW_CTRL_TX | FLOW_CTRL_RX);
-       } else if (tp->link_config.speed == SPEED_INVALID) {
-               if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
-                       tp->link_config.advertising &=
-                               ~(ADVERTISED_1000baseT_Half |
-                                 ADVERTISED_1000baseT_Full);
+               if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+                       adv = ADVERTISED_10baseT_Half |
+                             ADVERTISED_10baseT_Full;
+                       if (tg3_flag(tp, WOL_SPEED_100MB))
+                               adv |= ADVERTISED_100baseT_Half |
+                                      ADVERTISED_100baseT_Full;
 
-               tg3_phy_autoneg_cfg(tp, tp->link_config.advertising,
-                                   tp->link_config.flowctrl);
-       } else {
-               /* Asking for a specific link mode. */
-               if (tp->link_config.speed == SPEED_1000) {
-                       if (tp->link_config.duplex == DUPLEX_FULL)
-                               new_adv = ADVERTISED_1000baseT_Full;
-                       else
-                               new_adv = ADVERTISED_1000baseT_Half;
-               } else if (tp->link_config.speed == SPEED_100) {
-                       if (tp->link_config.duplex == DUPLEX_FULL)
-                               new_adv = ADVERTISED_100baseT_Full;
-                       else
-                               new_adv = ADVERTISED_100baseT_Half;
+                       fc = FLOW_CTRL_TX | FLOW_CTRL_RX;
                } else {
-                       if (tp->link_config.duplex == DUPLEX_FULL)
-                               new_adv = ADVERTISED_10baseT_Full;
-                       else
-                               new_adv = ADVERTISED_10baseT_Half;
+                       adv = tp->link_config.advertising;
+                       if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
+                               adv &= ~(ADVERTISED_1000baseT_Half |
+                                        ADVERTISED_1000baseT_Full);
+
+                       fc = tp->link_config.flowctrl;
                }
 
-               tg3_phy_autoneg_cfg(tp, new_adv,
-                                   tp->link_config.flowctrl);
-       }
+               tg3_phy_autoneg_cfg(tp, adv, fc);
 
-       if (tp->link_config.autoneg == AUTONEG_DISABLE &&
-           tp->link_config.speed != SPEED_INVALID) {
+               tg3_writephy(tp, MII_BMCR,
+                            BMCR_ANENABLE | BMCR_ANRESTART);
+       } else {
+               int i;
                u32 bmcr, orig_bmcr;
 
                tp->link_config.active_speed = tp->link_config.speed;
@@ -3976,9 +3963,6 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                        tg3_writephy(tp, MII_BMCR, bmcr);
                        udelay(40);
                }
-       } else {
-               tg3_writephy(tp, MII_BMCR,
-                            BMCR_ANENABLE | BMCR_ANRESTART);
        }
 }
 
@@ -4028,7 +4012,16 @@ static bool tg3_phy_copper_an_config_ok(struct tg3 *tp, u32 *lcladv)
                if (tg3_readphy(tp, MII_CTRL1000, &tg3_ctrl))
                        return false;
 
-               tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+               if (tgtadv &&
+                   (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+                    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) {
+                       tgtadv |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
+                       tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL |
+                                    CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER);
+               } else {
+                       tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+               }
+
                if (tg3_ctrl != tgtadv)
                        return false;
        }
@@ -4159,8 +4152,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
        }
 
        current_link_up = 0;
-       current_speed = SPEED_INVALID;
-       current_duplex = DUPLEX_INVALID;
+       current_speed = SPEED_UNKNOWN;
+       current_duplex = DUPLEX_UNKNOWN;
        tp->phy_flags &= ~TG3_PHYFLG_MDIX_STATE;
        tp->link_config.rmt_adv = 0;
 
@@ -5056,8 +5049,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
                                    LED_CTRL_LNKLED_OVERRIDE |
                                    LED_CTRL_1000MBPS_ON));
        } else {
-               tp->link_config.active_speed = SPEED_INVALID;
-               tp->link_config.active_duplex = DUPLEX_INVALID;
+               tp->link_config.active_speed = SPEED_UNKNOWN;
+               tp->link_config.active_duplex = DUPLEX_UNKNOWN;
                tw32(MAC_LED_CTRL, (tp->led_ctrl |
                                    LED_CTRL_LNKLED_OVERRIDE |
                                    LED_CTRL_TRAFFIC_OVERRIDE));
@@ -5105,8 +5098,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                tg3_phy_reset(tp);
 
        current_link_up = 0;
-       current_speed = SPEED_INVALID;
-       current_duplex = DUPLEX_INVALID;
+       current_speed = SPEED_UNKNOWN;
+       current_duplex = DUPLEX_UNKNOWN;
        tp->link_config.rmt_adv = 0;
 
        err |= tg3_readphy(tp, MII_BMSR, &bmsr);
@@ -5602,7 +5595,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
                }
        }
 
-       netdev_completed_queue(tp->dev, pkts_compl, bytes_compl);
+       netdev_tx_completed_queue(txq, pkts_compl, bytes_compl);
 
        tnapi->tx_cons = sw_idx;
 
@@ -5935,6 +5928,9 @@ next_pkt_nopost:
 
        /* Refill RX ring(s). */
        if (!tg3_flag(tp, ENABLE_RSS)) {
+               /* Sync BD data before updating mailbox */
+               wmb();
+
                if (work_mask & RXD_OPAQUE_RING_STD) {
                        tpr->rx_std_prod_idx = std_prod_idx &
                                               tp->rx_std_ring_mask;
@@ -6171,6 +6167,7 @@ static inline void tg3_reset_task_cancel(struct tg3 *tp)
 {
        cancel_work_sync(&tp->reset_task);
        tg3_flag_clear(tp, RESET_TASK_PENDING);
+       tg3_flag_clear(tp, TX_RECOVERY_PENDING);
 }
 
 static int tg3_poll_msix(struct napi_struct *napi, int budget)
@@ -6924,7 +6921,6 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                          ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0),
                            mss, vlan)) {
                would_hit_hwbug = 1;
-       /* Now loop through additional data fragments, and queue them. */
        } else if (skb_shinfo(skb)->nr_frags > 0) {
                u32 tmp_mss = mss;
 
@@ -6933,6 +6929,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                    !tg3_flag(tp, HW_TSO_3))
                        tmp_mss = 0;
 
+               /* Now loop through additional data
+                * fragments, and queue them.
+                */
                last = skb_shinfo(skb)->nr_frags - 1;
                for (i = 0; i <= last; i++) {
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -6972,7 +6971,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        skb_tx_timestamp(skb);
-       netdev_sent_queue(tp->dev, skb->len);
+       netdev_tx_sent_queue(txq, skb->len);
+
+       /* Sync BD data before updating mailbox */
+       wmb();
 
        /* Packets are ready, update Tx producer idx local and on card. */
        tw32_tx_mbox(tnapi->prodmbox, entry);
@@ -7394,8 +7396,8 @@ static void tg3_free_rings(struct tg3 *tp)
 
                        dev_kfree_skb_any(skb);
                }
+               netdev_tx_reset_queue(netdev_get_tx_queue(tp->dev, j));
        }
-       netdev_reset_queue(tp->dev);
 }
 
 /* Initialize tx/rx rings for packet processing.
@@ -8005,10 +8007,8 @@ static int tg3_chip_reset(struct tg3 *tp)
        return 0;
 }
 
-static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *,
-                                                struct rtnl_link_stats64 *);
-static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *,
-                                               struct tg3_ethtool_stats *);
+static void tg3_get_nstats(struct tg3 *, struct rtnl_link_stats64 *);
+static void tg3_get_estats(struct tg3 *, struct tg3_ethtool_stats *);
 
 /* tp->lock is held. */
 static int tg3_halt(struct tg3 *tp, int kind, int silent)
@@ -8029,7 +8029,7 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent)
 
        if (tp->hw_stats) {
                /* Save the stats across chip resets... */
-               tg3_get_stats64(tp->dev, &tp->net_stats_prev),
+               tg3_get_nstats(tp, &tp->net_stats_prev);
                tg3_get_estats(tp, &tp->estats_prev);
 
                /* And make sure the next sample is new data */
@@ -8049,7 +8049,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
        int err = 0, skip_mac_1 = 0;
 
        if (!is_valid_ether_addr(addr->sa_data))
-               return -EINVAL;
+               return -EADDRNOTAVAIL;
 
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
@@ -8895,9 +8895,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        if (tg3_flag(tp, PCI_EXPRESS))
                rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
-               rdmac_mode |= RDMAC_MODE_JMB_2K_MMRR;
-
        if (tg3_flag(tp, HW_TSO_1) ||
            tg3_flag(tp, HW_TSO_2) ||
            tg3_flag(tp, HW_TSO_3))
@@ -9244,12 +9241,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        }
 
        if (!tg3_flag(tp, USE_PHYLIB)) {
-               if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+               if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
                        tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
-                       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;
-               }
 
                err = tg3_setup_phy(tp, 0);
                if (err)
@@ -9340,74 +9333,6 @@ static int tg3_init_hw(struct tg3 *tp, int reset_phy)
        return tg3_reset_hw(tp, reset_phy);
 }
 
-/* Restart hardware after configuration changes, self-test, etc.
- * Invoked with tp->lock held.
- */
-static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
-       __releases(tp->lock)
-       __acquires(tp->lock)
-{
-       int err;
-
-       err = tg3_init_hw(tp, reset_phy);
-       if (err) {
-               netdev_err(tp->dev,
-                          "Failed to re-initialize device, aborting\n");
-               tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               tg3_full_unlock(tp);
-               del_timer_sync(&tp->timer);
-               tp->irq_sync = 0;
-               tg3_napi_enable(tp);
-               dev_close(tp->dev);
-               tg3_full_lock(tp, 0);
-       }
-       return err;
-}
-
-static void tg3_reset_task(struct work_struct *work)
-{
-       struct tg3 *tp = container_of(work, struct tg3, reset_task);
-       int err;
-
-       tg3_full_lock(tp, 0);
-
-       if (!netif_running(tp->dev)) {
-               tg3_flag_clear(tp, RESET_TASK_PENDING);
-               tg3_full_unlock(tp);
-               return;
-       }
-
-       tg3_full_unlock(tp);
-
-       tg3_phy_stop(tp);
-
-       tg3_netif_stop(tp);
-
-       tg3_full_lock(tp, 1);
-
-       if (tg3_flag(tp, TX_RECOVERY_PENDING)) {
-               tp->write32_tx_mbox = tg3_write32_tx_mbox;
-               tp->write32_rx_mbox = tg3_write_flush_reg32;
-               tg3_flag_set(tp, MBOX_WRITE_REORDER);
-               tg3_flag_clear(tp, TX_RECOVERY_PENDING);
-       }
-
-       tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
-       err = tg3_init_hw(tp, 1);
-       if (err)
-               goto out;
-
-       tg3_netif_start(tp);
-
-out:
-       tg3_full_unlock(tp);
-
-       if (!err)
-               tg3_phy_start(tp);
-
-       tg3_flag_clear(tp, RESET_TASK_PENDING);
-}
-
 #define TG3_STAT_ADD32(PSTAT, REG) \
 do {   u32 __val = tr32(REG); \
        (PSTAT)->low += __val; \
@@ -9620,6 +9545,108 @@ restart_timer:
        add_timer(&tp->timer);
 }
 
+static void __devinit tg3_timer_init(struct tg3 *tp)
+{
+       if (tg3_flag(tp, TAGGED_STATUS) &&
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+           !tg3_flag(tp, 57765_CLASS))
+               tp->timer_offset = HZ;
+       else
+               tp->timer_offset = HZ / 10;
+
+       BUG_ON(tp->timer_offset > HZ);
+
+       tp->timer_multiplier = (HZ / tp->timer_offset);
+       tp->asf_multiplier = (HZ / tp->timer_offset) *
+                            TG3_FW_UPDATE_FREQ_SEC;
+
+       init_timer(&tp->timer);
+       tp->timer.data = (unsigned long) tp;
+       tp->timer.function = tg3_timer;
+}
+
+static void tg3_timer_start(struct tg3 *tp)
+{
+       tp->asf_counter   = tp->asf_multiplier;
+       tp->timer_counter = tp->timer_multiplier;
+
+       tp->timer.expires = jiffies + tp->timer_offset;
+       add_timer(&tp->timer);
+}
+
+static void tg3_timer_stop(struct tg3 *tp)
+{
+       del_timer_sync(&tp->timer);
+}
+
+/* Restart hardware after configuration changes, self-test, etc.
+ * Invoked with tp->lock held.
+ */
+static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+       __releases(tp->lock)
+       __acquires(tp->lock)
+{
+       int err;
+
+       err = tg3_init_hw(tp, reset_phy);
+       if (err) {
+               netdev_err(tp->dev,
+                          "Failed to re-initialize device, aborting\n");
+               tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+               tg3_full_unlock(tp);
+               tg3_timer_stop(tp);
+               tp->irq_sync = 0;
+               tg3_napi_enable(tp);
+               dev_close(tp->dev);
+               tg3_full_lock(tp, 0);
+       }
+       return err;
+}
+
+static void tg3_reset_task(struct work_struct *work)
+{
+       struct tg3 *tp = container_of(work, struct tg3, reset_task);
+       int err;
+
+       tg3_full_lock(tp, 0);
+
+       if (!netif_running(tp->dev)) {
+               tg3_flag_clear(tp, RESET_TASK_PENDING);
+               tg3_full_unlock(tp);
+               return;
+       }
+
+       tg3_full_unlock(tp);
+
+       tg3_phy_stop(tp);
+
+       tg3_netif_stop(tp);
+
+       tg3_full_lock(tp, 1);
+
+       if (tg3_flag(tp, TX_RECOVERY_PENDING)) {
+               tp->write32_tx_mbox = tg3_write32_tx_mbox;
+               tp->write32_rx_mbox = tg3_write_flush_reg32;
+               tg3_flag_set(tp, MBOX_WRITE_REORDER);
+               tg3_flag_clear(tp, TX_RECOVERY_PENDING);
+       }
+
+       tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
+       err = tg3_init_hw(tp, 1);
+       if (err)
+               goto out;
+
+       tg3_netif_start(tp);
+
+out:
+       tg3_full_unlock(tp);
+
+       if (!err)
+               tg3_phy_start(tp);
+
+       tg3_flag_clear(tp, RESET_TASK_PENDING);
+}
+
 static int tg3_request_irq(struct tg3 *tp, int irq_num)
 {
        irq_handler_t fn;
@@ -9674,7 +9701,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
        }
 
        err = request_irq(tnapi->irq_vec, tg3_test_isr,
-                         IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi);
+                         IRQF_SHARED, dev->name, tnapi);
        if (err)
                return err;
 
@@ -9985,24 +10012,6 @@ static int tg3_open(struct net_device *dev)
        if (err) {
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
                tg3_free_rings(tp);
-       } else {
-               if (tg3_flag(tp, TAGGED_STATUS) &&
-                   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
-                   !tg3_flag(tp, 57765_CLASS))
-                       tp->timer_offset = HZ;
-               else
-                       tp->timer_offset = HZ / 10;
-
-               BUG_ON(tp->timer_offset > HZ);
-               tp->timer_counter = tp->timer_multiplier =
-                       (HZ / tp->timer_offset);
-               tp->asf_counter = tp->asf_multiplier =
-                       ((HZ / tp->timer_offset) * 2);
-
-               init_timer(&tp->timer);
-               tp->timer.expires = jiffies + tp->timer_offset;
-               tp->timer.data = (unsigned long) tp;
-               tp->timer.function = tg3_timer;
        }
 
        tg3_full_unlock(tp);
@@ -10034,7 +10043,7 @@ static int tg3_open(struct net_device *dev)
 
        tg3_full_lock(tp, 0);
 
-       add_timer(&tp->timer);
+       tg3_timer_start(tp);
        tg3_flag_set(tp, INIT_COMPLETE);
        tg3_enable_ints(tp);
 
@@ -10079,7 +10088,7 @@ static int tg3_close(struct net_device *dev)
 
        netif_tx_stop_all_queues(dev);
 
-       del_timer_sync(&tp->timer);
+       tg3_timer_stop(tp);
 
        tg3_phy_stop(tp);
 
@@ -10120,7 +10129,7 @@ static inline u64 get_stat64(tg3_stat64_t *val)
        return ((u64)val->high << 32) | ((u64)val->low);
 }
 
-static u64 calc_crc_errors(struct tg3 *tp)
+static u64 tg3_calc_crc_errors(struct tg3 *tp)
 {
        struct tg3_hw_stats *hw_stats = tp->hw_stats;
 
@@ -10129,14 +10138,12 @@ static u64 calc_crc_errors(struct tg3 *tp)
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
                u32 val;
 
-               spin_lock_bh(&tp->lock);
                if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) {
                        tg3_writephy(tp, MII_TG3_TEST1,
                                     val | MII_TG3_TEST1_CRC_EN);
                        tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val);
                } else
                        val = 0;
-               spin_unlock_bh(&tp->lock);
 
                tp->phy_crc_errors += val;
 
@@ -10150,15 +10157,11 @@ static u64 calc_crc_errors(struct tg3 *tp)
        estats->member =        old_estats->member + \
                                get_stat64(&hw_stats->member)
 
-static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp,
-                                              struct tg3_ethtool_stats *estats)
+static void tg3_get_estats(struct tg3 *tp, struct tg3_ethtool_stats *estats)
 {
        struct tg3_ethtool_stats *old_estats = &tp->estats_prev;
        struct tg3_hw_stats *hw_stats = tp->hw_stats;
 
-       if (!hw_stats)
-               return old_estats;
-
        ESTAT_ADD(rx_octets);
        ESTAT_ADD(rx_fragments);
        ESTAT_ADD(rx_ucast_packets);
@@ -10236,20 +10239,13 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp,
        ESTAT_ADD(nic_tx_threshold_hit);
 
        ESTAT_ADD(mbuf_lwm_thresh_hit);
-
-       return estats;
 }
 
-static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
-                                                struct rtnl_link_stats64 *stats)
+static void tg3_get_nstats(struct tg3 *tp, struct rtnl_link_stats64 *stats)
 {
-       struct tg3 *tp = netdev_priv(dev);
        struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev;
        struct tg3_hw_stats *hw_stats = tp->hw_stats;
 
-       if (!hw_stats)
-               return old_stats;
-
        stats->rx_packets = old_stats->rx_packets +
                get_stat64(&hw_stats->rx_ucast_packets) +
                get_stat64(&hw_stats->rx_mcast_packets) +
@@ -10292,15 +10288,13 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
                get_stat64(&hw_stats->tx_carrier_sense_errors);
 
        stats->rx_crc_errors = old_stats->rx_crc_errors +
-               calc_crc_errors(tp);
+               tg3_calc_crc_errors(tp);
 
        stats->rx_missed_errors = old_stats->rx_missed_errors +
                get_stat64(&hw_stats->rx_discards);
 
        stats->rx_dropped = tp->rx_dropped;
        stats->tx_dropped = tp->tx_dropped;
-
-       return stats;
 }
 
 static int tg3_get_regs_len(struct net_device *dev)
@@ -10510,8 +10504,8 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                cmd->eth_tp_mdix = ETH_TP_MDI;
                }
        } else {
-               ethtool_cmd_speed_set(cmd, SPEED_INVALID);
-               cmd->duplex = DUPLEX_INVALID;
+               ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+               cmd->duplex = DUPLEX_UNKNOWN;
                cmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
        }
        cmd->phy_address = tp->phy_addr;
@@ -10593,18 +10587,14 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        if (cmd->autoneg == AUTONEG_ENABLE) {
                tp->link_config.advertising = (cmd->advertising |
                                              ADVERTISED_Autoneg);
-               tp->link_config.speed = SPEED_INVALID;
-               tp->link_config.duplex = DUPLEX_INVALID;
+               tp->link_config.speed = SPEED_UNKNOWN;
+               tp->link_config.duplex = DUPLEX_UNKNOWN;
        } else {
                tp->link_config.advertising = 0;
                tp->link_config.speed = 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;
-       tp->link_config.orig_autoneg = tp->link_config.autoneg;
-
        if (netif_running(dev))
                tg3_setup_phy(tp, 1);
 
@@ -10851,10 +10841,10 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
                        if (!epause->autoneg)
                                tg3_setup_flow_control(tp, 0, 0);
                } else {
-                       tp->link_config.orig_advertising &=
+                       tp->link_config.advertising &=
                                        ~(ADVERTISED_Pause |
                                          ADVERTISED_Asym_Pause);
-                       tp->link_config.orig_advertising |= newadv;
+                       tp->link_config.advertising |= newadv;
                }
        } else {
                int irq_sync = 0;
@@ -11031,7 +11021,10 @@ static void tg3_get_ethtool_stats(struct net_device *dev,
 {
        struct tg3 *tp = netdev_priv(dev);
 
-       tg3_get_estats(tp, (struct tg3_ethtool_stats *)tmp_stats);
+       if (tp->hw_stats)
+               tg3_get_estats(tp, (struct tg3_ethtool_stats *)tmp_stats);
+       else
+               memset(tmp_stats, 0, sizeof(struct tg3_ethtool_stats));
 }
 
 static __be32 *tg3_vpd_readblock(struct tg3 *tp, u32 *vpdlen)
@@ -11740,6 +11733,10 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback)
        } else {
                num_pkts = 1;
                data_off = ETH_HLEN;
+
+               if (tg3_flag(tp, USE_JUMBO_BDFLAG) &&
+                   tx_len > VLAN_ETH_FRAME_LEN)
+                       base_flags |= TXD_FLAG_JMB_PKT;
        }
 
        for (i = data_off; i < tx_len; i++)
@@ -11772,6 +11769,9 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback)
 
        tnapi->tx_prod++;
 
+       /* Sync BD data before updating mailbox */
+       wmb();
+
        tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod);
        tr32_mailbox(tnapi->prodmbox);
 
@@ -11870,6 +11870,10 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
 {
        int err = -EIO;
        u32 eee_cap;
+       u32 jmb_pkt_sz = 9000;
+
+       if (tp->dma_limit)
+               jmb_pkt_sz = tp->dma_limit - ETH_HLEN;
 
        eee_cap = tp->phy_flags & TG3_PHYFLG_EEE_CAP;
        tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP;
@@ -11913,7 +11917,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
                        data[0] |= TG3_STD_LOOPBACK_FAILED;
 
                if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
-                   tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
+                   tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
                        data[0] |= TG3_JMB_LOOPBACK_FAILED;
 
                tg3_mac_loopback(tp, false);
@@ -11938,7 +11942,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
                    tg3_run_loopback(tp, ETH_FRAME_LEN, true))
                        data[1] |= TG3_TSO_LOOPBACK_FAILED;
                if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
-                   tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
+                   tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
                        data[1] |= TG3_JMB_LOOPBACK_FAILED;
 
                if (do_extlpbk) {
@@ -11956,7 +11960,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
                            tg3_run_loopback(tp, ETH_FRAME_LEN, true))
                                data[2] |= TG3_TSO_LOOPBACK_FAILED;
                        if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
-                           tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
+                           tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false))
                                data[2] |= TG3_JMB_LOOPBACK_FAILED;
                }
 
@@ -12212,6 +12216,21 @@ static const struct ethtool_ops tg3_ethtool_ops = {
        .set_rxfh_indir         = tg3_set_rxfh_indir,
 };
 
+static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
+                                               struct rtnl_link_stats64 *stats)
+{
+       struct tg3 *tp = netdev_priv(dev);
+
+       if (!tp->hw_stats)
+               return &tp->net_stats_prev;
+
+       spin_lock_bh(&tp->lock);
+       tg3_get_nstats(tp, stats);
+       spin_unlock_bh(&tp->lock);
+
+       return stats;
+}
+
 static void tg3_set_rx_mode(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
@@ -12248,7 +12267,7 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
 static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct tg3 *tp = netdev_priv(dev);
-       int err;
+       int err, reset_phy = 0;
 
        if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
                return -EINVAL;
@@ -12271,7 +12290,13 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 
        tg3_set_mtu(dev, tp, new_mtu);
 
-       err = tg3_restart_hw(tp, 0);
+       /* Reset PHY, otherwise the read DMA engine will be in a mode that
+        * breaks all requests to 256 bytes.
+        */
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
+               reset_phy = 1;
+
+       err = tg3_restart_hw(tp, reset_phy);
 
        if (!err)
                tg3_netif_start(tp);
@@ -13343,14 +13368,13 @@ static void __devinit tg3_phy_init_link_config(struct tg3 *tp)
                adv |= ADVERTISED_FIBRE;
 
        tp->link_config.advertising = adv;
-       tp->link_config.speed = SPEED_INVALID;
-       tp->link_config.duplex = DUPLEX_INVALID;
+       tp->link_config.speed = SPEED_UNKNOWN;
+       tp->link_config.duplex = DUPLEX_UNKNOWN;
        tp->link_config.autoneg = AUTONEG_ENABLE;
-       tp->link_config.active_speed = SPEED_INVALID;
-       tp->link_config.active_duplex = DUPLEX_INVALID;
-       tp->link_config.orig_speed = SPEED_INVALID;
-       tp->link_config.orig_duplex = DUPLEX_INVALID;
-       tp->link_config.orig_autoneg = AUTONEG_INVALID;
+       tp->link_config.active_speed = SPEED_UNKNOWN;
+       tp->link_config.active_duplex = DUPLEX_UNKNOWN;
+
+       tp->old_link = -1;
 }
 
 static int __devinit tg3_phy_probe(struct tg3 *tp)
@@ -13892,6 +13916,83 @@ static struct pci_dev * __devinit tg3_find_peer(struct tg3 *tp)
        return peer;
 }
 
+static void __devinit tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
+{
+       tp->pci_chip_rev_id = misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT;
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
+               u32 reg;
+
+               /* All devices that use the alternate
+                * ASIC REV location have a CPMU.
+                */
+               tg3_flag_set(tp, CPMU_PRESENT);
+
+               if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
+                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
+                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
+                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
+                       reg = TG3PCI_GEN2_PRODID_ASICREV;
+               else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 ||
+                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 ||
+                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761 ||
+                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765 ||
+                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
+                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795 ||
+                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57762 ||
+                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57766 ||
+                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57782 ||
+                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57786)
+                       reg = TG3PCI_GEN15_PRODID_ASICREV;
+               else
+                       reg = TG3PCI_PRODID_ASICREV;
+
+               pci_read_config_dword(tp->pdev, reg, &tp->pci_chip_rev_id);
+       }
+
+       /* Wrong chip ID in 5752 A0. This code can be removed later
+        * as A0 is not in production.
+        */
+       if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
+               tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+               tg3_flag_set(tp, 5717_PLUS);
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
+               tg3_flag_set(tp, 57765_CLASS);
+
+       if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS))
+               tg3_flag_set(tp, 57765_PLUS);
+
+       /* Intentionally exclude ASIC_REV_5906 */
+       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_5785 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+           tg3_flag(tp, 57765_PLUS))
+               tg3_flag_set(tp, 5755_PLUS);
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
+               tg3_flag_set(tp, 5780_CLASS);
+
+       if (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_5906 ||
+           tg3_flag(tp, 5755_PLUS) ||
+           tg3_flag(tp, 5780_CLASS))
+               tg3_flag_set(tp, 5750_PLUS);
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+           tg3_flag(tp, 5750_PLUS))
+               tg3_flag_set(tp, 5705_PLUS);
+}
+
 static int __devinit tg3_get_invariants(struct tg3 *tp)
 {
        u32 misc_ctrl_reg;
@@ -13923,43 +14024,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
                               tp->misc_host_ctrl);
 
-       tp->pci_chip_rev_id = (misc_ctrl_reg >>
-                              MISC_HOST_CTRL_CHIPREV_SHIFT);
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
-               u32 prod_id_asic_rev;
-
-               if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
-                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
-                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
-                   tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
-                       pci_read_config_dword(tp->pdev,
-                                             TG3PCI_GEN2_PRODID_ASICREV,
-                                             &prod_id_asic_rev);
-               else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 ||
-                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 ||
-                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761 ||
-                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765 ||
-                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
-                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795 ||
-                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57762 ||
-                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57766 ||
-                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57782 ||
-                        tp->pdev->device == TG3PCI_DEVICE_TIGON3_57786)
-                       pci_read_config_dword(tp->pdev,
-                                             TG3PCI_GEN15_PRODID_ASICREV,
-                                             &prod_id_asic_rev);
-               else
-                       pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV,
-                                             &prod_id_asic_rev);
-
-               tp->pci_chip_rev_id = prod_id_asic_rev;
-       }
-
-       /* Wrong chip ID in 5752 A0. This code can be removed later
-        * as A0 is not in production.
-        */
-       if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
-               tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
+       tg3_detect_asic_rev(tp, misc_ctrl_reg);
 
        /* If we have 5702/03 A1 or A2 on certain ICH chipsets,
         * we need to disable memory and use config. cycles
@@ -14057,9 +14122,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
         * Any tg3 device found behind the bridge will also need the 40-bit
         * DMA workaround.
         */
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
-               tg3_flag_set(tp, 5780_CLASS);
+       if (tg3_flag(tp, 5780_CLASS)) {
                tg3_flag_set(tp, 40BIT_DMA_BUG);
                tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI);
        } else {
@@ -14085,39 +14148,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
                tp->pdev_peer = tg3_find_peer(tp);
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
-               tg3_flag_set(tp, 5717_PLUS);
-
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
-               tg3_flag_set(tp, 57765_CLASS);
-
-       if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS))
-               tg3_flag_set(tp, 57765_PLUS);
-
-       /* Intentionally exclude ASIC_REV_5906 */
-       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_5785 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
-           tg3_flag(tp, 57765_PLUS))
-               tg3_flag_set(tp, 5755_PLUS);
-
-       if (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_5906 ||
-           tg3_flag(tp, 5755_PLUS) ||
-           tg3_flag(tp, 5780_CLASS))
-               tg3_flag_set(tp, 5750_PLUS);
-
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-           tg3_flag(tp, 5750_PLUS))
-               tg3_flag_set(tp, 5705_PLUS);
-
        /* Determine TSO capabilities */
        if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0)
                ; /* Do nothing. HW bug. */
@@ -14189,8 +14219,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
                tp->dma_limit = TG3_TX_BD_DMA_MAX_4K;
-       else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
-               tp->dma_limit = TG3_TX_BD_DMA_MAX_2K;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
@@ -14214,12 +14242,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 
                tg3_flag_set(tp, PCI_EXPRESS);
 
-               if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) {
-                       int readrq = pcie_get_readrq(tp->pdev);
-                       if (readrq > 2048)
-                               pcie_set_readrq(tp->pdev, 2048);
-               }
-
                pci_read_config_word(tp->pdev,
                                     pci_pcie_cap(tp->pdev) + PCI_EXP_LNKCTL,
                                     &lnkctl);
@@ -14449,13 +14471,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                tg3_ape_lock_init(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_5785 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
-           tg3_flag(tp, 57765_PLUS))
-               tg3_flag_set(tp, CPMU_PRESENT);
-
        /* Set up tp->grc_local_ctrl before calling
         * tg3_pwrsrc_switch_to_vmain().  GPIO1 driven high
         * will bring 5700's external PHY out of reset.
@@ -15721,6 +15736,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                tg3_frob_aux_power(tp, false);
        }
 
+       tg3_timer_init(tp);
+
        err = register_netdev(dev);
        if (err) {
                dev_err(&pdev->dev, "Cannot register net device, aborting\n");
@@ -15846,7 +15863,7 @@ static int tg3_suspend(struct device *device)
        tg3_phy_stop(tp);
        tg3_netif_stop(tp);
 
-       del_timer_sync(&tp->timer);
+       tg3_timer_stop(tp);
 
        tg3_full_lock(tp, 1);
        tg3_disable_ints(tp);
@@ -15870,8 +15887,7 @@ static int tg3_suspend(struct device *device)
                if (err2)
                        goto out;
 
-               tp->timer.expires = jiffies + tp->timer_offset;
-               add_timer(&tp->timer);
+               tg3_timer_start(tp);
 
                netif_device_attach(dev);
                tg3_netif_start(tp);
@@ -15905,8 +15921,7 @@ static int tg3_resume(struct device *device)
        if (err)
                goto out;
 
-       tp->timer.expires = jiffies + tp->timer_offset;
-       add_timer(&tp->timer);
+       tg3_timer_start(tp);
 
        tg3_netif_start(tp);
 
@@ -15954,11 +15969,10 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
 
        tg3_netif_stop(tp);
 
-       del_timer_sync(&tp->timer);
+       tg3_timer_stop(tp);
 
        /* Want to make sure that the reset task doesn't run */
        tg3_reset_task_cancel(tp);
-       tg3_flag_clear(tp, TX_RECOVERY_PENDING);
 
        netif_device_detach(netdev);
 
@@ -16051,8 +16065,7 @@ static void tg3_io_resume(struct pci_dev *pdev)
 
        netif_device_attach(netdev);
 
-       tp->timer.expires = jiffies + tp->timer_offset;
-       add_timer(&tp->timer);
+       tg3_timer_start(tp);
 
        tg3_netif_start(tp);