]> Pileus Git - ~andy/linux/blobdiff - drivers/net/ethernet/broadcom/tg3.c
tg3: fix to append hardware time stamping flags
[~andy/linux] / drivers / net / ethernet / broadcom / tg3.c
index 17a972734ba746d9218df4bf025218a91ebee947..728d42ab2a7636e4656a28174ac2b8c9159c60f0 100644 (file)
@@ -94,10 +94,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 
 #define DRV_MODULE_NAME                "tg3"
 #define TG3_MAJ_NUM                    3
-#define TG3_MIN_NUM                    130
+#define TG3_MIN_NUM                    131
 #define DRV_MODULE_VERSION     \
        __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE     "February 14, 2013"
+#define DRV_MODULE_RELDATE     "April 09, 2013"
 
 #define RESET_KIND_SHUTDOWN    0
 #define RESET_KIND_INIT                1
@@ -212,6 +212,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 #define TG3_FW_UPDATE_FREQ_SEC         (TG3_FW_UPDATE_TIMEOUT_SEC / 2)
 
 #define FIRMWARE_TG3           "tigon/tg3.bin"
+#define FIRMWARE_TG357766      "tigon/tg357766.bin"
 #define FIRMWARE_TG3TSO                "tigon/tg3_tso.bin"
 #define FIRMWARE_TG3TSO5       "tigon/tg3_tso5.bin"
 
@@ -1873,6 +1874,20 @@ static void tg3_link_report(struct tg3 *tp)
        tp->link_up = netif_carrier_ok(tp->dev);
 }
 
+static u32 tg3_decode_flowctrl_1000T(u32 adv)
+{
+       u32 flowctrl = 0;
+
+       if (adv & ADVERTISE_PAUSE_CAP) {
+               flowctrl |= FLOW_CTRL_RX;
+               if (!(adv & ADVERTISE_PAUSE_ASYM))
+                       flowctrl |= FLOW_CTRL_TX;
+       } else if (adv & ADVERTISE_PAUSE_ASYM)
+               flowctrl |= FLOW_CTRL_TX;
+
+       return flowctrl;
+}
+
 static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
 {
        u16 miireg;
@@ -1889,6 +1904,20 @@ static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
        return miireg;
 }
 
+static u32 tg3_decode_flowctrl_1000X(u32 adv)
+{
+       u32 flowctrl = 0;
+
+       if (adv & ADVERTISE_1000XPAUSE) {
+               flowctrl |= FLOW_CTRL_RX;
+               if (!(adv & ADVERTISE_1000XPSE_ASYM))
+                       flowctrl |= FLOW_CTRL_TX;
+       } else if (adv & ADVERTISE_1000XPSE_ASYM)
+               flowctrl |= FLOW_CTRL_TX;
+
+       return flowctrl;
+}
+
 static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
 {
        u8 cap = 0;
@@ -2199,7 +2228,7 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable)
        tg3_writephy(tp, MII_TG3_MISC_SHDW, reg);
 }
 
-static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
+static void tg3_phy_toggle_automdix(struct tg3 *tp, bool enable)
 {
        u32 phy;
 
@@ -2291,7 +2320,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
        tg3_phy_toggle_auxctl_smdsp(tp, false);
 }
 
-static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
+static void tg3_phy_eee_adjust(struct tg3 *tp, bool current_link_up)
 {
        u32 val;
 
@@ -2301,7 +2330,7 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
        tp->setlpicnt = 0;
 
        if (tp->link_config.autoneg == AUTONEG_ENABLE &&
-           current_link_up == 1 &&
+           current_link_up &&
            tp->link_config.active_duplex == DUPLEX_FULL &&
            (tp->link_config.active_speed == SPEED_100 ||
             tp->link_config.active_speed == SPEED_1000)) {
@@ -2323,7 +2352,7 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
        }
 
        if (!tp->setlpicnt) {
-               if (current_link_up == 1 &&
+               if (current_link_up &&
                   !tg3_phy_toggle_auxctl_smdsp(tp, true)) {
                        tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000);
                        tg3_phy_toggle_auxctl_smdsp(tp, false);
@@ -2530,6 +2559,13 @@ static void tg3_carrier_off(struct tg3 *tp)
        tp->link_up = false;
 }
 
+static void tg3_warn_mgmt_link_flap(struct tg3 *tp)
+{
+       if (tg3_flag(tp, ENABLE_ASF))
+               netdev_warn(tp->dev,
+                           "Management side-band traffic will be interrupted during phy settings change\n");
+}
+
 /* This will reset the tigon3 PHY if there is no valid
  * link unless the FORCE argument is non-zero.
  */
@@ -2669,7 +2705,7 @@ out:
        if (tg3_chip_rev_id(tp) == CHIPREV_ID_5762_A0)
                tg3_phydsp_write(tp, 0xffb, 0x4000);
 
-       tg3_phy_toggle_automdix(tp, 1);
+       tg3_phy_toggle_automdix(tp, true);
        tg3_phy_set_wirespeed(tp);
        return 0;
 }
@@ -2925,6 +2961,9 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
 {
        u32 val;
 
+       if (tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN)
+               return;
+
        if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
                if (tg3_asic_rev(tp) == ASIC_REV_5704) {
                        u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
@@ -3448,11 +3487,58 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
 #define TX_CPU_SCRATCH_SIZE    0x04000
 
 /* tp->lock is held. */
-static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
+static int tg3_pause_cpu(struct tg3 *tp, u32 cpu_base)
 {
        int i;
+       const int iters = 10000;
+
+       for (i = 0; i < iters; i++) {
+               tw32(cpu_base + CPU_STATE, 0xffffffff);
+               tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
+               if (tr32(cpu_base + CPU_MODE) & CPU_MODE_HALT)
+                       break;
+       }
+
+       return (i == iters) ? -EBUSY : 0;
+}
+
+/* tp->lock is held. */
+static int tg3_rxcpu_pause(struct tg3 *tp)
+{
+       int rc = tg3_pause_cpu(tp, RX_CPU_BASE);
+
+       tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+       tw32_f(RX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
+       udelay(10);
+
+       return rc;
+}
+
+/* tp->lock is held. */
+static int tg3_txcpu_pause(struct tg3 *tp)
+{
+       return tg3_pause_cpu(tp, TX_CPU_BASE);
+}
+
+/* tp->lock is held. */
+static void tg3_resume_cpu(struct tg3 *tp, u32 cpu_base)
+{
+       tw32(cpu_base + CPU_STATE, 0xffffffff);
+       tw32_f(cpu_base + CPU_MODE,  0x00000000);
+}
 
-       BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
+/* tp->lock is held. */
+static void tg3_rxcpu_resume(struct tg3 *tp)
+{
+       tg3_resume_cpu(tp, RX_CPU_BASE);
+}
+
+/* tp->lock is held. */
+static int tg3_halt_cpu(struct tg3 *tp, u32 cpu_base)
+{
+       int rc;
+
+       BUG_ON(cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
 
        if (tg3_asic_rev(tp) == ASIC_REV_5906) {
                u32 val = tr32(GRC_VCPU_EXT_CTRL);
@@ -3460,17 +3546,8 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
                tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
                return 0;
        }
-       if (offset == RX_CPU_BASE) {
-               for (i = 0; i < 10000; i++) {
-                       tw32(offset + CPU_STATE, 0xffffffff);
-                       tw32(offset + CPU_MODE,  CPU_MODE_HALT);
-                       if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
-                               break;
-               }
-
-               tw32(offset + CPU_STATE, 0xffffffff);
-               tw32_f(offset + CPU_MODE,  CPU_MODE_HALT);
-               udelay(10);
+       if (cpu_base == RX_CPU_BASE) {
+               rc = tg3_rxcpu_pause(tp);
        } else {
                /*
                 * There is only an Rx CPU for the 5750 derivative in the
@@ -3479,17 +3556,12 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
                if (tg3_flag(tp, IS_SSB_CORE))
                        return 0;
 
-               for (i = 0; i < 10000; i++) {
-                       tw32(offset + CPU_STATE, 0xffffffff);
-                       tw32(offset + CPU_MODE,  CPU_MODE_HALT);
-                       if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
-                               break;
-               }
+               rc = tg3_txcpu_pause(tp);
        }
 
-       if (i >= 10000) {
+       if (rc) {
                netdev_err(tp->dev, "%s timed out, %s CPU\n",
-                          __func__, offset == RX_CPU_BASE ? "RX" : "TX");
+                          __func__, cpu_base == RX_CPU_BASE ? "RX" : "TX");
                return -ENODEV;
        }
 
@@ -3499,19 +3571,41 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
        return 0;
 }
 
-struct fw_info {
-       unsigned int fw_base;
-       unsigned int fw_len;
-       const __be32 *fw_data;
-};
+static int tg3_fw_data_len(struct tg3 *tp,
+                          const struct tg3_firmware_hdr *fw_hdr)
+{
+       int fw_len;
+
+       /* Non fragmented firmware have one firmware header followed by a
+        * contiguous chunk of data to be written. The length field in that
+        * header is not the length of data to be written but the complete
+        * length of the bss. The data length is determined based on
+        * tp->fw->size minus headers.
+        *
+        * Fragmented firmware have a main header followed by multiple
+        * fragments. Each fragment is identical to non fragmented firmware
+        * with a firmware header followed by a contiguous chunk of data. In
+        * the main header, the length field is unused and set to 0xffffffff.
+        * In each fragment header the length is the entire size of that
+        * fragment i.e. fragment data + header length. Data length is
+        * therefore length field in the header minus TG3_FW_HDR_LEN.
+        */
+       if (tp->fw_len == 0xffffffff)
+               fw_len = be32_to_cpu(fw_hdr->len);
+       else
+               fw_len = tp->fw->size;
+
+       return (fw_len - TG3_FW_HDR_LEN) / sizeof(u32);
+}
 
 /* tp->lock is held. */
 static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
                                 u32 cpu_scratch_base, int cpu_scratch_size,
-                                struct fw_info *info)
+                                const struct tg3_firmware_hdr *fw_hdr)
 {
-       int err, lock_err, i;
+       int err, i;
        void (*write_op)(struct tg3 *, u32, u32);
+       int total_len = tp->fw->size;
 
        if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
                netdev_err(tp->dev,
@@ -3520,30 +3614,49 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
                return -EINVAL;
        }
 
-       if (tg3_flag(tp, 5705_PLUS))
+       if (tg3_flag(tp, 5705_PLUS) && tg3_asic_rev(tp) != ASIC_REV_57766)
                write_op = tg3_write_mem;
        else
                write_op = tg3_write_indirect_reg32;
 
-       /* It is possible that bootcode is still loading at this point.
-        * Get the nvram lock first before halting the cpu.
-        */
-       lock_err = tg3_nvram_lock(tp);
-       err = tg3_halt_cpu(tp, cpu_base);
-       if (!lock_err)
-               tg3_nvram_unlock(tp);
-       if (err)
-               goto out;
+       if (tg3_asic_rev(tp) != ASIC_REV_57766) {
+               /* It is possible that bootcode is still loading at this point.
+                * Get the nvram lock first before halting the cpu.
+                */
+               int lock_err = tg3_nvram_lock(tp);
+               err = tg3_halt_cpu(tp, cpu_base);
+               if (!lock_err)
+                       tg3_nvram_unlock(tp);
+               if (err)
+                       goto out;
 
-       for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
-               write_op(tp, cpu_scratch_base + i, 0);
-       tw32(cpu_base + CPU_STATE, 0xffffffff);
-       tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
-       for (i = 0; i < (info->fw_len / sizeof(u32)); i++)
-               write_op(tp, (cpu_scratch_base +
-                             (info->fw_base & 0xffff) +
-                             (i * sizeof(u32))),
-                             be32_to_cpu(info->fw_data[i]));
+               for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
+                       write_op(tp, cpu_scratch_base + i, 0);
+               tw32(cpu_base + CPU_STATE, 0xffffffff);
+               tw32(cpu_base + CPU_MODE,
+                    tr32(cpu_base + CPU_MODE) | CPU_MODE_HALT);
+       } else {
+               /* Subtract additional main header for fragmented firmware and
+                * advance to the first fragment
+                */
+               total_len -= TG3_FW_HDR_LEN;
+               fw_hdr++;
+       }
+
+       do {
+               u32 *fw_data = (u32 *)(fw_hdr + 1);
+               for (i = 0; i < tg3_fw_data_len(tp, fw_hdr); i++)
+                       write_op(tp, cpu_scratch_base +
+                                    (be32_to_cpu(fw_hdr->base_addr) & 0xffff) +
+                                    (i * sizeof(u32)),
+                                be32_to_cpu(fw_data[i]));
+
+               total_len -= be32_to_cpu(fw_hdr->len);
+
+               /* Advance to next fragment */
+               fw_hdr = (struct tg3_firmware_hdr *)
+                        ((void *)fw_hdr + be32_to_cpu(fw_hdr->len));
+       } while (total_len > 0);
 
        err = 0;
 
@@ -3551,14 +3664,34 @@ out:
        return err;
 }
 
+/* tp->lock is held. */
+static int tg3_pause_cpu_and_set_pc(struct tg3 *tp, u32 cpu_base, u32 pc)
+{
+       int i;
+       const int iters = 5;
+
+       tw32(cpu_base + CPU_STATE, 0xffffffff);
+       tw32_f(cpu_base + CPU_PC, pc);
+
+       for (i = 0; i < iters; i++) {
+               if (tr32(cpu_base + CPU_PC) == pc)
+                       break;
+               tw32(cpu_base + CPU_STATE, 0xffffffff);
+               tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
+               tw32_f(cpu_base + CPU_PC, pc);
+               udelay(1000);
+       }
+
+       return (i == iters) ? -EBUSY : 0;
+}
+
 /* tp->lock is held. */
 static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 {
-       struct fw_info info;
-       const __be32 *fw_data;
-       int err, i;
+       const struct tg3_firmware_hdr *fw_hdr;
+       int err;
 
-       fw_data = (void *)tp->fw->data;
+       fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
 
        /* Firmware blob starts with version numbers, followed by
           start address and length. We are setting complete length.
@@ -3566,60 +3699,117 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
           Remainder is the blob to be loaded contiguously
           from start address. */
 
-       info.fw_base = be32_to_cpu(fw_data[1]);
-       info.fw_len = tp->fw->size - 12;
-       info.fw_data = &fw_data[3];
-
        err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
                                    RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
-                                   &info);
+                                   fw_hdr);
        if (err)
                return err;
 
        err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
                                    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
-                                   &info);
+                                   fw_hdr);
        if (err)
                return err;
 
        /* Now startup only the RX cpu. */
-       tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
-       tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
-
-       for (i = 0; i < 5; i++) {
-               if (tr32(RX_CPU_BASE + CPU_PC) == info.fw_base)
-                       break;
-               tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
-               tw32(RX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
-               tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
-               udelay(1000);
-       }
-       if (i >= 5) {
+       err = tg3_pause_cpu_and_set_pc(tp, RX_CPU_BASE,
+                                      be32_to_cpu(fw_hdr->base_addr));
+       if (err) {
                netdev_err(tp->dev, "%s fails to set RX CPU PC, is %08x "
                           "should be %08x\n", __func__,
-                          tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
+                          tr32(RX_CPU_BASE + CPU_PC),
+                               be32_to_cpu(fw_hdr->base_addr));
                return -ENODEV;
        }
-       tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
-       tw32_f(RX_CPU_BASE + CPU_MODE,  0x00000000);
+
+       tg3_rxcpu_resume(tp);
 
        return 0;
 }
 
+static int tg3_validate_rxcpu_state(struct tg3 *tp)
+{
+       const int iters = 1000;
+       int i;
+       u32 val;
+
+       /* Wait for boot code to complete initialization and enter service
+        * loop. It is then safe to download service patches
+        */
+       for (i = 0; i < iters; i++) {
+               if (tr32(RX_CPU_HWBKPT) == TG3_SBROM_IN_SERVICE_LOOP)
+                       break;
+
+               udelay(10);
+       }
+
+       if (i == iters) {
+               netdev_err(tp->dev, "Boot code not ready for service patches\n");
+               return -EBUSY;
+       }
+
+       val = tg3_read_indirect_reg32(tp, TG3_57766_FW_HANDSHAKE);
+       if (val & 0xff) {
+               netdev_warn(tp->dev,
+                           "Other patches exist. Not downloading EEE patch\n");
+               return -EEXIST;
+       }
+
+       return 0;
+}
+
+/* tp->lock is held. */
+static void tg3_load_57766_firmware(struct tg3 *tp)
+{
+       struct tg3_firmware_hdr *fw_hdr;
+
+       if (!tg3_flag(tp, NO_NVRAM))
+               return;
+
+       if (tg3_validate_rxcpu_state(tp))
+               return;
+
+       if (!tp->fw)
+               return;
+
+       /* This firmware blob has a different format than older firmware
+        * releases as given below. The main difference is we have fragmented
+        * data to be written to non-contiguous locations.
+        *
+        * In the beginning we have a firmware header identical to other
+        * firmware which consists of version, base addr and length. The length
+        * here is unused and set to 0xffffffff.
+        *
+        * This is followed by a series of firmware fragments which are
+        * individually identical to previous firmware. i.e. they have the
+        * firmware header and followed by data for that fragment. The version
+        * field of the individual fragment header is unused.
+        */
+
+       fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
+       if (be32_to_cpu(fw_hdr->base_addr) != TG3_57766_FW_BASE_ADDR)
+               return;
+
+       if (tg3_rxcpu_pause(tp))
+               return;
+
+       /* tg3_load_firmware_cpu() will always succeed for the 57766 */
+       tg3_load_firmware_cpu(tp, 0, TG3_57766_FW_BASE_ADDR, 0, fw_hdr);
+
+       tg3_rxcpu_resume(tp);
+}
+
 /* tp->lock is held. */
 static int tg3_load_tso_firmware(struct tg3 *tp)
 {
-       struct fw_info info;
-       const __be32 *fw_data;
+       const struct tg3_firmware_hdr *fw_hdr;
        unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
-       int err, i;
+       int err;
 
-       if (tg3_flag(tp, HW_TSO_1) ||
-           tg3_flag(tp, HW_TSO_2) ||
-           tg3_flag(tp, HW_TSO_3))
+       if (!tg3_flag(tp, FW_TSO))
                return 0;
 
-       fw_data = (void *)tp->fw->data;
+       fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
 
        /* Firmware blob starts with version numbers, followed by
           start address and length. We are setting complete length.
@@ -3627,10 +3817,7 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
           Remainder is the blob to be loaded contiguously
           from start address. */
 
-       info.fw_base = be32_to_cpu(fw_data[1]);
        cpu_scratch_size = tp->fw_len;
-       info.fw_len = tp->fw->size - 12;
-       info.fw_data = &fw_data[3];
 
        if (tg3_asic_rev(tp) == ASIC_REV_5705) {
                cpu_base = RX_CPU_BASE;
@@ -3643,36 +3830,28 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
 
        err = tg3_load_firmware_cpu(tp, cpu_base,
                                    cpu_scratch_base, cpu_scratch_size,
-                                   &info);
+                                   fw_hdr);
        if (err)
                return err;
 
        /* Now startup the cpu. */
-       tw32(cpu_base + CPU_STATE, 0xffffffff);
-       tw32_f(cpu_base + CPU_PC, info.fw_base);
-
-       for (i = 0; i < 5; i++) {
-               if (tr32(cpu_base + CPU_PC) == info.fw_base)
-                       break;
-               tw32(cpu_base + CPU_STATE, 0xffffffff);
-               tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
-               tw32_f(cpu_base + CPU_PC, info.fw_base);
-               udelay(1000);
-       }
-       if (i >= 5) {
+       err = tg3_pause_cpu_and_set_pc(tp, cpu_base,
+                                      be32_to_cpu(fw_hdr->base_addr));
+       if (err) {
                netdev_err(tp->dev,
                           "%s fails to set CPU PC, is %08x should be %08x\n",
-                          __func__, tr32(cpu_base + CPU_PC), info.fw_base);
+                          __func__, tr32(cpu_base + CPU_PC),
+                          be32_to_cpu(fw_hdr->base_addr));
                return -ENODEV;
        }
-       tw32(cpu_base + CPU_STATE, 0xffffffff);
-       tw32_f(cpu_base + CPU_MODE,  0x00000000);
+
+       tg3_resume_cpu(tp, cpu_base);
        return 0;
 }
 
 
 /* tp->lock is held. */
-static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
+static void __tg3_set_mac_addr(struct tg3 *tp, bool skip_mac_1)
 {
        u32 addr_high, addr_low;
        int i;
@@ -3735,7 +3914,7 @@ static int tg3_power_up(struct tg3 *tp)
        return err;
 }
 
-static int tg3_setup_phy(struct tg3 *, int);
+static int tg3_setup_phy(struct tg3 *, bool);
 
 static int tg3_power_down_prepare(struct tg3 *tp)
 {
@@ -3807,7 +3986,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
                        tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
 
                if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
-                       tg3_setup_phy(tp, 0);
+                       tg3_setup_phy(tp, false);
        }
 
        if (tg3_asic_rev(tp) == ASIC_REV_5906) {
@@ -3848,7 +4027,13 @@ static int tg3_power_down_prepare(struct tg3 *tp)
 
                        if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
                                mac_mode = MAC_MODE_PORT_MODE_GMII;
-                       else
+                       else if (tp->phy_flags &
+                                TG3_PHYFLG_KEEP_LINK_ON_PWRDN) {
+                               if (tp->link_config.active_speed == SPEED_1000)
+                                       mac_mode = MAC_MODE_PORT_MODE_GMII;
+                               else
+                                       mac_mode = MAC_MODE_PORT_MODE_MII;
+                       } else
                                mac_mode = MAC_MODE_PORT_MODE_MII;
 
                        mac_mode |= tp->mac_mode & MAC_MODE_LINK_POLARITY;
@@ -4102,12 +4287,16 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
            (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
                u32 adv, fc;
 
-               if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+               if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) &&
+                   !(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN)) {
                        adv = ADVERTISED_10baseT_Half |
                              ADVERTISED_10baseT_Full;
                        if (tg3_flag(tp, WOL_SPEED_100MB))
                                adv |= ADVERTISED_100baseT_Half |
                                       ADVERTISED_100baseT_Full;
+                       if (tp->phy_flags & TG3_PHYFLG_1G_ON_VAUX_OK)
+                               adv |= ADVERTISED_1000baseT_Half |
+                                      ADVERTISED_1000baseT_Full;
 
                        fc = FLOW_CTRL_TX | FLOW_CTRL_RX;
                } else {
@@ -4121,6 +4310,15 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
 
                tg3_phy_autoneg_cfg(tp, adv, fc);
 
+               if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) &&
+                   (tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN)) {
+                       /* Normally during power down we want to autonegotiate
+                        * the lowest possible speed for WOL. However, to avoid
+                        * link flap, we leave it untouched.
+                        */
+                       return;
+               }
+
                tg3_writephy(tp, MII_BMCR,
                             BMCR_ANENABLE | BMCR_ANRESTART);
        } else {
@@ -4177,6 +4375,103 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
        }
 }
 
+static int tg3_phy_pull_config(struct tg3 *tp)
+{
+       int err;
+       u32 val;
+
+       err = tg3_readphy(tp, MII_BMCR, &val);
+       if (err)
+               goto done;
+
+       if (!(val & BMCR_ANENABLE)) {
+               tp->link_config.autoneg = AUTONEG_DISABLE;
+               tp->link_config.advertising = 0;
+               tg3_flag_clear(tp, PAUSE_AUTONEG);
+
+               err = -EIO;
+
+               switch (val & (BMCR_SPEED1000 | BMCR_SPEED100)) {
+               case 0:
+                       if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
+                               goto done;
+
+                       tp->link_config.speed = SPEED_10;
+                       break;
+               case BMCR_SPEED100:
+                       if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
+                               goto done;
+
+                       tp->link_config.speed = SPEED_100;
+                       break;
+               case BMCR_SPEED1000:
+                       if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
+                               tp->link_config.speed = SPEED_1000;
+                               break;
+                       }
+                       /* Fall through */
+               default:
+                       goto done;
+               }
+
+               if (val & BMCR_FULLDPLX)
+                       tp->link_config.duplex = DUPLEX_FULL;
+               else
+                       tp->link_config.duplex = DUPLEX_HALF;
+
+               tp->link_config.flowctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
+
+               err = 0;
+               goto done;
+       }
+
+       tp->link_config.autoneg = AUTONEG_ENABLE;
+       tp->link_config.advertising = ADVERTISED_Autoneg;
+       tg3_flag_set(tp, PAUSE_AUTONEG);
+
+       if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
+               u32 adv;
+
+               err = tg3_readphy(tp, MII_ADVERTISE, &val);
+               if (err)
+                       goto done;
+
+               adv = mii_adv_to_ethtool_adv_t(val & ADVERTISE_ALL);
+               tp->link_config.advertising |= adv | ADVERTISED_TP;
+
+               tp->link_config.flowctrl = tg3_decode_flowctrl_1000T(val);
+       } else {
+               tp->link_config.advertising |= ADVERTISED_FIBRE;
+       }
+
+       if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
+               u32 adv;
+
+               if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
+                       err = tg3_readphy(tp, MII_CTRL1000, &val);
+                       if (err)
+                               goto done;
+
+                       adv = mii_ctrl1000_to_ethtool_adv_t(val);
+               } else {
+                       err = tg3_readphy(tp, MII_ADVERTISE, &val);
+                       if (err)
+                               goto done;
+
+                       adv = tg3_decode_flowctrl_1000X(val);
+                       tp->link_config.flowctrl = adv;
+
+                       val &= (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL);
+                       adv = mii_adv_to_ethtool_adv_x(val);
+               }
+
+               tp->link_config.advertising |= adv;
+       }
+
+done:
+       return err;
+}
+
 static int tg3_init_5401phy_dsp(struct tg3 *tp)
 {
        int err;
@@ -4196,6 +4491,32 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp)
        return err;
 }
 
+static bool tg3_phy_eee_config_ok(struct tg3 *tp)
+{
+       u32 val;
+       u32 tgtadv = 0;
+       u32 advertising = tp->link_config.advertising;
+
+       if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
+               return true;
+
+       if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val))
+               return false;
+
+       val &= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
+
+
+       if (advertising & ADVERTISED_100baseT_Full)
+               tgtadv |= MDIO_AN_EEE_ADV_100TX;
+       if (advertising & ADVERTISED_1000baseT_Full)
+               tgtadv |= MDIO_AN_EEE_ADV_1000T;
+
+       if (val != tgtadv)
+               return false;
+
+       return true;
+}
+
 static bool tg3_phy_copper_an_config_ok(struct tg3 *tp, u32 *lcladv)
 {
        u32 advmsk, tgtadv, advertising;
@@ -4262,7 +4583,7 @@ static bool tg3_phy_copper_fetch_rmtadv(struct tg3 *tp, u32 *rmtadv)
        return true;
 }
 
-static bool tg3_test_and_report_link_chg(struct tg3 *tp, int curr_link_up)
+static bool tg3_test_and_report_link_chg(struct tg3 *tp, bool curr_link_up)
 {
        if (curr_link_up != tp->link_up) {
                if (curr_link_up) {
@@ -4280,23 +4601,28 @@ static bool tg3_test_and_report_link_chg(struct tg3 *tp, int curr_link_up)
        return false;
 }
 
-static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
+static void tg3_clear_mac_status(struct tg3 *tp)
 {
-       int current_link_up;
+       tw32(MAC_EVENT, 0);
+
+       tw32_f(MAC_STATUS,
+              MAC_STATUS_SYNC_CHANGED |
+              MAC_STATUS_CFG_CHANGED |
+              MAC_STATUS_MI_COMPLETION |
+              MAC_STATUS_LNKSTATE_CHANGED);
+       udelay(40);
+}
+
+static int tg3_setup_copper_phy(struct tg3 *tp, bool force_reset)
+{
+       bool current_link_up;
        u32 bmsr, val;
        u32 lcl_adv, rmt_adv;
        u16 current_speed;
        u8 current_duplex;
        int i, err;
 
-       tw32(MAC_EVENT, 0);
-
-       tw32_f(MAC_STATUS,
-            (MAC_STATUS_SYNC_CHANGED |
-             MAC_STATUS_CFG_CHANGED |
-             MAC_STATUS_MI_COMPLETION |
-             MAC_STATUS_LNKSTATE_CHANGED));
-       udelay(40);
+       tg3_clear_mac_status(tp);
 
        if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
                tw32_f(MAC_MI_MODE,
@@ -4316,7 +4642,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                tg3_readphy(tp, MII_BMSR, &bmsr);
                if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
                    !(bmsr & BMSR_LSTATUS))
-                       force_reset = 1;
+                       force_reset = true;
        }
        if (force_reset)
                tg3_phy_reset(tp);
@@ -4380,7 +4706,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                        tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
        }
 
-       current_link_up = 0;
+       current_link_up = false;
        current_speed = SPEED_UNKNOWN;
        current_duplex = DUPLEX_UNKNOWN;
        tp->phy_flags &= ~TG3_PHYFLG_MDIX_STATE;
@@ -4439,21 +4765,31 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                tp->link_config.active_duplex = current_duplex;
 
                if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+                       bool eee_config_ok = tg3_phy_eee_config_ok(tp);
+
                        if ((bmcr & BMCR_ANENABLE) &&
+                           eee_config_ok &&
                            tg3_phy_copper_an_config_ok(tp, &lcl_adv) &&
                            tg3_phy_copper_fetch_rmtadv(tp, &rmt_adv))
-                               current_link_up = 1;
+                               current_link_up = true;
+
+                       /* EEE settings changes take effect only after a phy
+                        * reset.  If we have skipped a reset due to Link Flap
+                        * Avoidance being enabled, do it now.
+                        */
+                       if (!eee_config_ok &&
+                           (tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
+                           !force_reset)
+                               tg3_phy_reset(tp);
                } else {
                        if (!(bmcr & BMCR_ANENABLE) &&
                            tp->link_config.speed == current_speed &&
-                           tp->link_config.duplex == current_duplex &&
-                           tp->link_config.flowctrl ==
-                           tp->link_config.active_flowctrl) {
-                               current_link_up = 1;
+                           tp->link_config.duplex == current_duplex) {
+                               current_link_up = true;
                        }
                }
 
-               if (current_link_up == 1 &&
+               if (current_link_up &&
                    tp->link_config.active_duplex == DUPLEX_FULL) {
                        u32 reg, bit;
 
@@ -4473,11 +4809,11 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
        }
 
 relink:
-       if (current_link_up == 0 || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
+       if (!current_link_up || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
                tg3_phy_copper_begin(tp);
 
                if (tg3_flag(tp, ROBOSWITCH)) {
-                       current_link_up = 1;
+                       current_link_up = true;
                        /* FIXME: when BCM5325 switch is used use 100 MBit/s */
                        current_speed = SPEED_1000;
                        current_duplex = DUPLEX_FULL;
@@ -4488,11 +4824,11 @@ relink:
                tg3_readphy(tp, MII_BMSR, &bmsr);
                if ((!tg3_readphy(tp, MII_BMSR, &bmsr) && (bmsr & BMSR_LSTATUS)) ||
                    (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK))
-                       current_link_up = 1;
+                       current_link_up = true;
        }
 
        tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
-       if (current_link_up == 1) {
+       if (current_link_up) {
                if (tp->link_config.active_speed == SPEED_100 ||
                    tp->link_config.active_speed == SPEED_10)
                        tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
@@ -4528,7 +4864,7 @@ relink:
                tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
 
        if (tg3_asic_rev(tp) == ASIC_REV_5700) {
-               if (current_link_up == 1 &&
+               if (current_link_up &&
                    tg3_5700_link_polarity(tp, tp->link_config.active_speed))
                        tp->mac_mode |= MAC_MODE_LINK_POLARITY;
                else
@@ -4559,7 +4895,7 @@ relink:
        udelay(40);
 
        if (tg3_asic_rev(tp) == ASIC_REV_5700 &&
-           current_link_up == 1 &&
+           current_link_up &&
            tp->link_config.active_speed == SPEED_1000 &&
            (tg3_flag(tp, PCIX_MODE) || tg3_flag(tp, PCI_HIGH_SPEED))) {
                udelay(120);
@@ -4999,19 +5335,19 @@ static void tg3_init_bcm8002(struct tg3 *tp)
        tg3_writephy(tp, 0x10, 0x8011);
 }
 
-static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
+static bool tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 {
        u16 flowctrl;
+       bool current_link_up;
        u32 sg_dig_ctrl, sg_dig_status;
        u32 serdes_cfg, expected_sg_dig_ctrl;
        int workaround, port_a;
-       int current_link_up;
 
        serdes_cfg = 0;
        expected_sg_dig_ctrl = 0;
        workaround = 0;
        port_a = 1;
-       current_link_up = 0;
+       current_link_up = false;
 
        if (tg3_chip_rev_id(tp) != CHIPREV_ID_5704_A0 &&
            tg3_chip_rev_id(tp) != CHIPREV_ID_5704_A1) {
@@ -5042,7 +5378,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
                }
                if (mac_status & MAC_STATUS_PCS_SYNCED) {
                        tg3_setup_flow_control(tp, 0, 0);
-                       current_link_up = 1;
+                       current_link_up = true;
                }
                goto out;
        }
@@ -5063,7 +5399,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
                                    MAC_STATUS_RCVD_CFG)) ==
                     MAC_STATUS_PCS_SYNCED)) {
                        tp->serdes_counter--;
-                       current_link_up = 1;
+                       current_link_up = true;
                        goto out;
                }
 restart_autoneg:
@@ -5098,7 +5434,7 @@ restart_autoneg:
                                           mii_adv_to_ethtool_adv_x(remote_adv);
 
                        tg3_setup_flow_control(tp, local_adv, remote_adv);
-                       current_link_up = 1;
+                       current_link_up = true;
                        tp->serdes_counter = 0;
                        tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
                } else if (!(sg_dig_status & SG_DIG_AUTONEG_COMPLETE)) {
@@ -5126,7 +5462,7 @@ restart_autoneg:
                                if ((mac_status & MAC_STATUS_PCS_SYNCED) &&
                                    !(mac_status & MAC_STATUS_RCVD_CFG)) {
                                        tg3_setup_flow_control(tp, 0, 0);
-                                       current_link_up = 1;
+                                       current_link_up = true;
                                        tp->phy_flags |=
                                                TG3_PHYFLG_PARALLEL_DETECT;
                                        tp->serdes_counter =
@@ -5144,9 +5480,9 @@ out:
        return current_link_up;
 }
 
-static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
+static bool tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
 {
-       int current_link_up = 0;
+       bool current_link_up = false;
 
        if (!(mac_status & MAC_STATUS_PCS_SYNCED))
                goto out;
@@ -5173,7 +5509,7 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
 
                        tg3_setup_flow_control(tp, local_adv, remote_adv);
 
-                       current_link_up = 1;
+                       current_link_up = true;
                }
                for (i = 0; i < 30; i++) {
                        udelay(20);
@@ -5188,15 +5524,15 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
                }
 
                mac_status = tr32(MAC_STATUS);
-               if (current_link_up == 0 &&
+               if (!current_link_up &&
                    (mac_status & MAC_STATUS_PCS_SYNCED) &&
                    !(mac_status & MAC_STATUS_RCVD_CFG))
-                       current_link_up = 1;
+                       current_link_up = true;
        } else {
                tg3_setup_flow_control(tp, 0, 0);
 
                /* Forcing 1000FD link up. */
-               current_link_up = 1;
+               current_link_up = true;
 
                tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS));
                udelay(40);
@@ -5209,13 +5545,13 @@ out:
        return current_link_up;
 }
 
-static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
+static int tg3_setup_fiber_phy(struct tg3 *tp, bool force_reset)
 {
        u32 orig_pause_cfg;
        u16 orig_active_speed;
        u8 orig_active_duplex;
        u32 mac_status;
-       int current_link_up;
+       bool current_link_up;
        int i;
 
        orig_pause_cfg = tp->link_config.active_flowctrl;
@@ -5252,7 +5588,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
        tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
        udelay(40);
 
-       current_link_up = 0;
+       current_link_up = false;
        tp->link_config.rmt_adv = 0;
        mac_status = tr32(MAC_STATUS);
 
@@ -5277,7 +5613,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
 
        mac_status = tr32(MAC_STATUS);
        if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
-               current_link_up = 0;
+               current_link_up = false;
                if (tp->link_config.autoneg == AUTONEG_ENABLE &&
                    tp->serdes_counter == 0) {
                        tw32_f(MAC_MODE, (tp->mac_mode |
@@ -5287,7 +5623,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
                }
        }
 
-       if (current_link_up == 1) {
+       if (current_link_up) {
                tp->link_config.active_speed = SPEED_1000;
                tp->link_config.active_duplex = DUPLEX_FULL;
                tw32(MAC_LED_CTRL, (tp->led_ctrl |
@@ -5312,33 +5648,63 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
        return 0;
 }
 
-static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
+static int tg3_setup_fiber_mii_phy(struct tg3 *tp, bool force_reset)
 {
-       int current_link_up, err = 0;
+       int err = 0;
        u32 bmsr, bmcr;
-       u16 current_speed;
-       u8 current_duplex;
-       u32 local_adv, remote_adv;
+       u16 current_speed = SPEED_UNKNOWN;
+       u8 current_duplex = DUPLEX_UNKNOWN;
+       bool current_link_up = false;
+       u32 local_adv, remote_adv, sgsr;
+
+       if ((tg3_asic_rev(tp) == ASIC_REV_5719 ||
+            tg3_asic_rev(tp) == ASIC_REV_5720) &&
+            !tg3_readphy(tp, SERDES_TG3_1000X_STATUS, &sgsr) &&
+            (sgsr & SERDES_TG3_SGMII_MODE)) {
+
+               if (force_reset)
+                       tg3_phy_reset(tp);
+
+               tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
+
+               if (!(sgsr & SERDES_TG3_LINK_UP)) {
+                       tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+               } else {
+                       current_link_up = true;
+                       if (sgsr & SERDES_TG3_SPEED_1000) {
+                               current_speed = SPEED_1000;
+                               tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+                       } else if (sgsr & SERDES_TG3_SPEED_100) {
+                               current_speed = SPEED_100;
+                               tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
+                       } else {
+                               current_speed = SPEED_10;
+                               tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
+                       }
+
+                       if (sgsr & SERDES_TG3_FULL_DUPLEX)
+                               current_duplex = DUPLEX_FULL;
+                       else
+                               current_duplex = DUPLEX_HALF;
+               }
+
+               tw32_f(MAC_MODE, tp->mac_mode);
+               udelay(40);
+
+               tg3_clear_mac_status(tp);
+
+               goto fiber_setup_done;
+       }
 
        tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
        tw32_f(MAC_MODE, tp->mac_mode);
        udelay(40);
 
-       tw32(MAC_EVENT, 0);
-
-       tw32_f(MAC_STATUS,
-            (MAC_STATUS_SYNC_CHANGED |
-             MAC_STATUS_CFG_CHANGED |
-             MAC_STATUS_MI_COMPLETION |
-             MAC_STATUS_LNKSTATE_CHANGED));
-       udelay(40);
+       tg3_clear_mac_status(tp);
 
        if (force_reset)
                tg3_phy_reset(tp);
 
-       current_link_up = 0;
-       current_speed = SPEED_UNKNOWN;
-       current_duplex = DUPLEX_UNKNOWN;
        tp->link_config.rmt_adv = 0;
 
        err |= tg3_readphy(tp, MII_BMSR, &bmsr);
@@ -5424,7 +5790,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
 
        if (bmsr & BMSR_LSTATUS) {
                current_speed = SPEED_1000;
-               current_link_up = 1;
+               current_link_up = true;
                if (bmcr & BMCR_FULLDPLX)
                        current_duplex = DUPLEX_FULL;
                else
@@ -5451,12 +5817,13 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                        } else if (!tg3_flag(tp, 5780_CLASS)) {
                                /* Link is up via parallel detect */
                        } else {
-                               current_link_up = 0;
+                               current_link_up = false;
                        }
                }
        }
 
-       if (current_link_up == 1 && current_duplex == DUPLEX_FULL)
+fiber_setup_done:
+       if (current_link_up && current_duplex == DUPLEX_FULL)
                tg3_setup_flow_control(tp, local_adv, remote_adv);
 
        tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
@@ -5535,7 +5902,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
        }
 }
 
-static int tg3_setup_phy(struct tg3 *tp, int force_reset)
+static int tg3_setup_phy(struct tg3 *tp, bool force_reset)
 {
        u32 val;
        int err;
@@ -5625,10 +5992,13 @@ static int tg3_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
 
        info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
                                SOF_TIMESTAMPING_RX_SOFTWARE |
-                               SOF_TIMESTAMPING_SOFTWARE    |
-                               SOF_TIMESTAMPING_TX_HARDWARE |
-                               SOF_TIMESTAMPING_RX_HARDWARE |
-                               SOF_TIMESTAMPING_RAW_HARDWARE;
+                               SOF_TIMESTAMPING_SOFTWARE;
+
+       if (tg3_flag(tp, PTP_CAPABLE)) {
+               info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
+                                       SOF_TIMESTAMPING_RX_HARDWARE |
+                                       SOF_TIMESTAMPING_RAW_HARDWARE;
+       }
 
        if (tp->ptp_clock)
                info->phc_index = ptp_clock_index(tp->ptp_clock);
@@ -6348,7 +6718,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
 
                if (desc->type_flags & RXD_FLAG_VLAN &&
                    !(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG))
-                       __vlan_hwaccel_put_tag(skb,
+                       __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
                                               desc->err_vlan & RXD_VLAN_MASK);
 
                napi_gro_receive(&tnapi->napi, skb);
@@ -6436,7 +6806,7 @@ static void tg3_poll_link(struct tg3 *tp)
                                      MAC_STATUS_LNKSTATE_CHANGED));
                                udelay(40);
                        } else
-                               tg3_setup_phy(tp, 0);
+                               tg3_setup_phy(tp, false);
                        spin_unlock(&tp->lock);
                }
        }
@@ -7533,7 +7903,7 @@ static int tg3_phy_lpbk_set(struct tg3 *tp, u32 speed, bool extlpbk)
        u32 val, bmcr, mac_mode, ptest = 0;
 
        tg3_phy_toggle_apd(tp, false);
-       tg3_phy_toggle_automdix(tp, 0);
+       tg3_phy_toggle_automdix(tp, false);
 
        if (extlpbk && tg3_phy_set_extloopbk(tp))
                return -EIO;
@@ -7641,7 +8011,7 @@ static void tg3_set_loopback(struct net_device *dev, netdev_features_t features)
                spin_lock_bh(&tp->lock);
                tg3_mac_loopback(tp, false);
                /* Force link status check */
-               tg3_setup_phy(tp, 1);
+               tg3_setup_phy(tp, true);
                spin_unlock_bh(&tp->lock);
                netdev_info(dev, "Internal MAC loopback mode disabled.\n");
        }
@@ -8039,11 +8409,9 @@ static int tg3_mem_rx_acquire(struct tg3 *tp)
                tnapi->rx_rcb = dma_alloc_coherent(&tp->pdev->dev,
                                                   TG3_RX_RCB_RING_BYTES(tp),
                                                   &tnapi->rx_rcb_mapping,
-                                                  GFP_KERNEL);
+                                                  GFP_KERNEL | __GFP_ZERO);
                if (!tnapi->rx_rcb)
                        goto err_out;
-
-               memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
        }
 
        return 0;
@@ -8093,12 +8461,10 @@ static int tg3_alloc_consistent(struct tg3 *tp)
        tp->hw_stats = dma_alloc_coherent(&tp->pdev->dev,
                                          sizeof(struct tg3_hw_stats),
                                          &tp->stats_mapping,
-                                         GFP_KERNEL);
+                                         GFP_KERNEL | __GFP_ZERO);
        if (!tp->hw_stats)
                goto err_out;
 
-       memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats));
-
        for (i = 0; i < tp->irq_cnt; i++) {
                struct tg3_napi *tnapi = &tp->napi[i];
                struct tg3_hw_status *sblk;
@@ -8106,11 +8472,10 @@ static int tg3_alloc_consistent(struct tg3 *tp)
                tnapi->hw_status = dma_alloc_coherent(&tp->pdev->dev,
                                                      TG3_HW_STATUS_SIZE,
                                                      &tnapi->status_mapping,
-                                                     GFP_KERNEL);
+                                                     GFP_KERNEL | __GFP_ZERO);
                if (!tnapi->hw_status)
                        goto err_out;
 
-               memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE);
                sblk = tnapi->hw_status;
 
                if (tg3_flag(tp, ENABLE_RSS)) {
@@ -8157,7 +8522,7 @@ err_out:
 /* To stop a block, clear the enable bit and poll till it
  * clears.  tp->lock is held.
  */
-static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int silent)
+static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, bool silent)
 {
        unsigned int i;
        u32 val;
@@ -8201,7 +8566,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int
 }
 
 /* tp->lock is held. */
-static int tg3_abort_hw(struct tg3 *tp, int silent)
+static int tg3_abort_hw(struct tg3 *tp, bool silent)
 {
        int i, err;
 
@@ -8561,6 +8926,9 @@ static int tg3_chip_reset(struct tg3 *tp)
 
        /* Reprobe ASF enable state.  */
        tg3_flag_clear(tp, ENABLE_ASF);
+       tp->phy_flags &= ~(TG3_PHYFLG_1G_ON_VAUX_OK |
+                          TG3_PHYFLG_KEEP_LINK_ON_PWRDN);
+
        tg3_flag_clear(tp, ASF_NEW_HANDSHAKE);
        tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
        if (val == NIC_SRAM_DATA_SIG_MAGIC) {
@@ -8572,6 +8940,12 @@ static int tg3_chip_reset(struct tg3 *tp)
                        tp->last_event_jiffies = jiffies;
                        if (tg3_flag(tp, 5750_PLUS))
                                tg3_flag_set(tp, ASF_NEW_HANDSHAKE);
+
+                       tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &nic_cfg);
+                       if (nic_cfg & NIC_SRAM_1G_ON_VAUX_OK)
+                               tp->phy_flags |= TG3_PHYFLG_1G_ON_VAUX_OK;
+                       if (nic_cfg & NIC_SRAM_LNK_FLAP_AVOID)
+                               tp->phy_flags |= TG3_PHYFLG_KEEP_LINK_ON_PWRDN;
                }
        }
 
@@ -8582,7 +8956,7 @@ 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)
+static int tg3_halt(struct tg3 *tp, int kind, bool silent)
 {
        int err;
 
@@ -8593,7 +8967,7 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent)
        tg3_abort_hw(tp, silent);
        err = tg3_chip_reset(tp);
 
-       __tg3_set_mac_addr(tp, 0);
+       __tg3_set_mac_addr(tp, false);
 
        tg3_write_sig_legacy(tp, kind);
        tg3_write_sig_post_reset(tp, kind);
@@ -8617,7 +8991,8 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
 {
        struct tg3 *tp = netdev_priv(dev);
        struct sockaddr *addr = p;
-       int err = 0, skip_mac_1 = 0;
+       int err = 0;
+       bool skip_mac_1 = false;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
@@ -8638,7 +9013,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
                /* Skip MAC addr 1 if ASF is using it. */
                if ((addr0_high != addr1_high || addr0_low != addr1_low) &&
                    !(addr1_high == 0 && addr1_low == 0))
-                       skip_mac_1 = 1;
+                       skip_mac_1 = true;
        }
        spin_lock_bh(&tp->lock);
        __tg3_set_mac_addr(tp, skip_mac_1);
@@ -9057,7 +9432,7 @@ static void tg3_rss_write_indir_tbl(struct tg3 *tp)
 }
 
 /* tp->lock is held. */
-static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
+static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
 {
        u32 val, rdmac_mode;
        int i, err, limit;
@@ -9106,6 +9481,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                       TG3_CPMU_DBTMR2_TXIDXEQ_2047US);
        }
 
+       if ((tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
+           !(tp->phy_flags & TG3_PHYFLG_USER_CONFIGURED)) {
+               tg3_phy_pull_config(tp);
+               tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
+       }
+
        if (reset_phy)
                tg3_phy_reset(tp);
 
@@ -9444,7 +9825,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        tg3_rings_reset(tp);
 
        /* Initialize MAC address and backoff seed. */
-       __tg3_set_mac_addr(tp, 0);
+       __tg3_set_mac_addr(tp, false);
 
        /* MTU + ethernet header + FCS + optional VLAN tag */
        tw32(MAC_RX_MTU_SIZE,
@@ -9781,6 +10162,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                        return err;
        }
 
+       if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+               /* Ignore any errors for the firmware download. If download
+                * fails, the device will operate with EEE disabled
+                */
+               tg3_load_57766_firmware(tp);
+       }
+
        if (tg3_flag(tp, TSO_CAPABLE)) {
                err = tg3_load_tso_firmware(tp);
                if (err)
@@ -9888,7 +10276,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
                        tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
 
-               err = tg3_setup_phy(tp, 0);
+               err = tg3_setup_phy(tp, false);
                if (err)
                        return err;
 
@@ -9968,7 +10356,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 /* Called at device open time to get the chip ready for
  * packet processing.  Invoked with tp->lock held.
  */
-static int tg3_init_hw(struct tg3 *tp, int reset_phy)
+static int tg3_init_hw(struct tg3 *tp, bool reset_phy)
 {
        tg3_switch_clocks(tp);
 
@@ -10229,7 +10617,7 @@ static void tg3_timer(unsigned long __opaque)
                                phy_event = 1;
 
                        if (phy_event)
-                               tg3_setup_phy(tp, 0);
+                               tg3_setup_phy(tp, false);
                } else if (tg3_flag(tp, POLL_SERDES)) {
                        u32 mac_stat = tr32(MAC_STATUS);
                        int need_setup = 0;
@@ -10252,7 +10640,7 @@ static void tg3_timer(unsigned long __opaque)
                                        tw32_f(MAC_MODE, tp->mac_mode);
                                        udelay(40);
                                }
-                               tg3_setup_phy(tp, 0);
+                               tg3_setup_phy(tp, false);
                        }
                } else if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
                           tg3_flag(tp, 5780_CLASS)) {
@@ -10338,7 +10726,7 @@ static void tg3_timer_stop(struct tg3 *tp)
 /* Restart hardware after configuration changes, self-test, etc.
  * Invoked with tp->lock held.
  */
-static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+static int tg3_restart_hw(struct tg3 *tp, bool reset_phy)
        __releases(tp->lock)
        __acquires(tp->lock)
 {
@@ -10388,7 +10776,7 @@ static void tg3_reset_task(struct work_struct *work)
        }
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
-       err = tg3_init_hw(tp, 1);
+       err = tg3_init_hw(tp, true);
        if (err)
                goto out;
 
@@ -10558,7 +10946,7 @@ static int tg3_test_msi(struct tg3 *tp)
        tg3_full_lock(tp, 1);
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-       err = tg3_init_hw(tp, 1);
+       err = tg3_init_hw(tp, true);
 
        tg3_full_unlock(tp);
 
@@ -10570,7 +10958,7 @@ static int tg3_test_msi(struct tg3 *tp)
 
 static int tg3_request_firmware(struct tg3 *tp)
 {
-       const __be32 *fw_data;
+       const struct tg3_firmware_hdr *fw_hdr;
 
        if (request_firmware(&tp->fw, tp->fw_needed, &tp->pdev->dev)) {
                netdev_err(tp->dev, "Failed to load firmware \"%s\"\n",
@@ -10578,15 +10966,15 @@ static int tg3_request_firmware(struct tg3 *tp)
                return -ENOENT;
        }
 
-       fw_data = (void *)tp->fw->data;
+       fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
 
        /* Firmware blob starts with version numbers, followed by
         * start address and _full_ length including BSS sections
         * (which must be longer than the actual data, of course
         */
 
-       tp->fw_len = be32_to_cpu(fw_data[2]);   /* includes bss */
-       if (tp->fw_len < (tp->fw->size - 12)) {
+       tp->fw_len = be32_to_cpu(fw_hdr->len);  /* includes bss */
+       if (tp->fw_len < (tp->fw->size - TG3_FW_HDR_LEN)) {
                netdev_err(tp->dev, "bogus length %d in \"%s\"\n",
                           tp->fw_len, tp->fw_needed);
                release_firmware(tp->fw);
@@ -10885,7 +11273,15 @@ static int tg3_open(struct net_device *dev)
 
        if (tp->fw_needed) {
                err = tg3_request_firmware(tp);
-               if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
+               if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+                       if (err) {
+                               netdev_warn(tp->dev, "EEE capability disabled\n");
+                               tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP;
+                       } else if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
+                               netdev_warn(tp->dev, "EEE capability restored\n");
+                               tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
+                       }
+               } else if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
                        if (err)
                                return err;
                } else if (err) {
@@ -10910,7 +11306,9 @@ static int tg3_open(struct net_device *dev)
 
        tg3_full_unlock(tp);
 
-       err = tg3_start(tp, true, true, true);
+       err = tg3_start(tp,
+                       !(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN),
+                       true, true);
        if (err) {
                tg3_frob_aux_power(tp, false);
                pci_set_power_state(tp->pdev, PCI_D3hot);
@@ -11416,8 +11814,12 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                tp->link_config.duplex = cmd->duplex;
        }
 
+       tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
+
+       tg3_warn_mgmt_link_flap(tp);
+
        if (netif_running(dev))
-               tg3_setup_phy(tp, 1);
+               tg3_setup_phy(tp, true);
 
        tg3_full_unlock(tp);
 
@@ -11494,6 +11896,8 @@ static int tg3_nway_reset(struct net_device *dev)
        if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
                return -EINVAL;
 
+       tg3_warn_mgmt_link_flap(tp);
+
        if (tg3_flag(tp, USE_PHYLIB)) {
                if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
                        return -EAGAIN;
@@ -11571,7 +11975,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
 
        if (netif_running(dev)) {
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               err = tg3_restart_hw(tp, 1);
+               err = tg3_restart_hw(tp, false);
                if (!err)
                        tg3_netif_start(tp);
        }
@@ -11606,6 +12010,9 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
        struct tg3 *tp = netdev_priv(dev);
        int err = 0;
 
+       if (tp->link_config.autoneg == AUTONEG_ENABLE)
+               tg3_warn_mgmt_link_flap(tp);
+
        if (tg3_flag(tp, USE_PHYLIB)) {
                u32 newadv;
                struct phy_device *phydev;
@@ -11692,7 +12099,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 
                if (netif_running(dev)) {
                        tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-                       err = tg3_restart_hw(tp, 1);
+                       err = tg3_restart_hw(tp, false);
                        if (!err)
                                tg3_netif_start(tp);
                }
@@ -11700,6 +12107,8 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
                tg3_full_unlock(tp);
        }
 
+       tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
+
        return err;
 }
 
@@ -12760,7 +13169,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
                goto done;
        }
 
-       err = tg3_reset_hw(tp, 1);
+       err = tg3_reset_hw(tp, true);
        if (err) {
                data[TG3_MAC_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
                data[TG3_PHY_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
@@ -12927,7 +13336,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
                if (netif_running(dev)) {
                        tg3_flag_set(tp, INIT_COMPLETE);
-                       err2 = tg3_restart_hw(tp, 1);
+                       err2 = tg3_restart_hw(tp, true);
                        if (!err2)
                                tg3_netif_start(tp);
                }
@@ -13244,7 +13653,8 @@ 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, reset_phy = 0;
+       int err;
+       bool reset_phy = false;
 
        if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
                return -EINVAL;
@@ -13271,7 +13681,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
         * breaks all requests to 256 bytes.
         */
        if (tg3_asic_rev(tp) == ASIC_REV_57766)
-               reset_phy = 1;
+               reset_phy = true;
 
        err = tg3_restart_hw(tp, reset_phy);
 
@@ -13837,6 +14247,12 @@ static void tg3_get_5720_nvram_info(struct tg3 *tp)
                case FLASH_5762_EEPROM_LD:
                        nvmpinstrp = FLASH_5720_EEPROM_LD;
                        break;
+               case FLASH_5720VENDOR_M_ST_M45PE20:
+                       /* This pinstrap supports multiple sizes, so force it
+                        * to read the actual size from location 0xf0.
+                        */
+                       nvmpinstrp = FLASH_5720VENDOR_ST_45USPT;
+                       break;
                }
        }
 
@@ -14289,14 +14705,18 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                    (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN))
                        tp->phy_flags |= TG3_PHYFLG_ENABLE_APD;
 
-               if (tg3_flag(tp, PCI_EXPRESS) &&
-                   tg3_asic_rev(tp) != ASIC_REV_5785 &&
-                   !tg3_flag(tp, 57765_PLUS)) {
+               if (tg3_flag(tp, PCI_EXPRESS)) {
                        u32 cfg3;
 
                        tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3);
-                       if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE)
+                       if (tg3_asic_rev(tp) != ASIC_REV_5785 &&
+                           !tg3_flag(tp, 57765_PLUS) &&
+                           (cfg3 & NIC_SRAM_ASPM_DEBOUNCE))
                                tg3_flag_set(tp, ASPM_WORKAROUND);
+                       if (cfg3 & NIC_SRAM_LNK_FLAP_AVOID)
+                               tp->phy_flags |= TG3_PHYFLG_KEEP_LINK_ON_PWRDN;
+                       if (cfg3 & NIC_SRAM_1G_ON_VAUX_OK)
+                               tp->phy_flags |= TG3_PHYFLG_1G_ON_VAUX_OK;
                }
 
                if (cfg4 & NIC_SRAM_RGMII_INBAND_DISABLE)
@@ -14450,6 +14870,12 @@ static int tg3_phy_probe(struct tg3 *tp)
                }
        }
 
+       if (!tg3_flag(tp, ENABLE_ASF) &&
+           !(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
+           !(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
+               tp->phy_flags &= ~(TG3_PHYFLG_1G_ON_VAUX_OK |
+                                  TG3_PHYFLG_KEEP_LINK_ON_PWRDN);
+
        if (tg3_flag(tp, USE_PHYLIB))
                return tg3_phy_init(tp);
 
@@ -14515,6 +14941,7 @@ static int tg3_phy_probe(struct tg3 *tp)
        if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
            (tg3_asic_rev(tp) == ASIC_REV_5719 ||
             tg3_asic_rev(tp) == ASIC_REV_5720 ||
+            tg3_asic_rev(tp) == ASIC_REV_57766 ||
             tg3_asic_rev(tp) == ASIC_REV_5762 ||
             (tg3_asic_rev(tp) == ASIC_REV_5717 &&
              tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0) ||
@@ -14524,7 +14951,8 @@ static int tg3_phy_probe(struct tg3 *tp)
 
        tg3_phy_init_link_config(tp);
 
-       if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
+       if (!(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
+           !(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
            !tg3_flag(tp, ENABLE_APE) &&
            !tg3_flag(tp, ENABLE_ASF)) {
                u32 bmsr, dummy;
@@ -15300,7 +15728,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
        } else if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
                   tg3_asic_rev(tp) != ASIC_REV_5701 &&
                   tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
-                       tg3_flag_set(tp, TSO_BUG);
+               tg3_flag_set(tp, FW_TSO);
+               tg3_flag_set(tp, TSO_BUG);
                if (tg3_asic_rev(tp) == ASIC_REV_5705)
                        tp->fw_needed = FIRMWARE_TG3TSO5;
                else
@@ -15311,7 +15740,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
        if (tg3_flag(tp, HW_TSO_1) ||
            tg3_flag(tp, HW_TSO_2) ||
            tg3_flag(tp, HW_TSO_3) ||
-           tp->fw_needed) {
+           tg3_flag(tp, FW_TSO)) {
                /* For firmware TSO, assume ASF is disabled.
                 * We'll disable TSO later if we discover ASF
                 * is enabled in tg3_get_eeprom_hw_cfg().
@@ -15326,6 +15755,9 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
        if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0)
                tp->fw_needed = FIRMWARE_TG3;
 
+       if (tg3_asic_rev(tp) == ASIC_REV_57766)
+               tp->fw_needed = FIRMWARE_TG357766;
+
        tp->irq_max = 1;
 
        if (tg3_flag(tp, 5750_PLUS)) {
@@ -15598,7 +16030,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
         */
        tg3_get_eeprom_hw_cfg(tp);
 
-       if (tp->fw_needed && tg3_flag(tp, ENABLE_ASF)) {
+       if (tg3_flag(tp, FW_TSO) && tg3_flag(tp, ENABLE_ASF)) {
                tg3_flag_clear(tp, TSO_CAPABLE);
                tg3_flag_clear(tp, TSO_BUG);
                tp->fw_needed = NULL;
@@ -15786,6 +16218,11 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
        udelay(50);
        tg3_nvram_init(tp);
 
+       /* If the device has an NVRAM, no need to load patch firmware */
+       if (tg3_asic_rev(tp) == ASIC_REV_57766 &&
+           !tg3_flag(tp, NO_NVRAM))
+               tp->fw_needed = NULL;
+
        grc_misc_cfg = tr32(GRC_MISC_CFG);
        grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
 
@@ -16144,7 +16581,7 @@ out:
 }
 
 static int tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dma,
-                          int size, int to_device)
+                          int size, bool to_device)
 {
        struct tg3_internal_buffer_desc test_desc;
        u32 sram_dma_descs;
@@ -16344,7 +16781,7 @@ static int tg3_test_dma(struct tg3 *tp)
                        p[i] = i;
 
                /* Send the buffer to the chip. */
-               ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 1);
+               ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, true);
                if (ret) {
                        dev_err(&tp->pdev->dev,
                                "%s: Buffer write failed. err = %d\n",
@@ -16367,7 +16804,7 @@ static int tg3_test_dma(struct tg3 *tp)
                }
 #endif
                /* Now read it back. */
-               ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0);
+               ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, false);
                if (ret) {
                        dev_err(&tp->pdev->dev, "%s: Buffer read failed. "
                                "err = %d\n", __func__, ret);
@@ -16763,7 +17200,7 @@ static int tg3_init_one(struct pci_dev *pdev,
 
        tg3_init_bufmgr_config(tp);
 
-       features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+       features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
 
        /* 5700 B0 chips do not support checksumming correctly due
         * to hardware bugs.
@@ -17048,7 +17485,7 @@ static int tg3_suspend(struct device *device)
                tg3_full_lock(tp, 0);
 
                tg3_flag_set(tp, INIT_COMPLETE);
-               err2 = tg3_restart_hw(tp, 1);
+               err2 = tg3_restart_hw(tp, true);
                if (err2)
                        goto out;
 
@@ -17082,7 +17519,8 @@ static int tg3_resume(struct device *device)
        tg3_full_lock(tp, 0);
 
        tg3_flag_set(tp, INIT_COMPLETE);
-       err = tg3_restart_hw(tp, 1);
+       err = tg3_restart_hw(tp,
+                            !(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN));
        if (err)
                goto out;
 
@@ -17098,15 +17536,9 @@ out:
 
        return err;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume);
-#define TG3_PM_OPS (&tg3_pm_ops)
-
-#else
-
-#define TG3_PM_OPS NULL
-
-#endif /* CONFIG_PM_SLEEP */
 
 /**
  * tg3_io_error_detected - called when PCI error is detected
@@ -17221,7 +17653,7 @@ static void tg3_io_resume(struct pci_dev *pdev)
 
        tg3_full_lock(tp, 0);
        tg3_flag_set(tp, INIT_COMPLETE);
-       err = tg3_restart_hw(tp, 1);
+       err = tg3_restart_hw(tp, true);
        if (err) {
                tg3_full_unlock(tp);
                netdev_err(netdev, "Cannot restart hardware after reset.\n");
@@ -17254,7 +17686,7 @@ static struct pci_driver tg3_driver = {
        .probe          = tg3_init_one,
        .remove         = tg3_remove_one,
        .err_handler    = &tg3_err_handler,
-       .driver.pm      = TG3_PM_OPS,
+       .driver.pm      = &tg3_pm_ops,
 };
 
 static int __init tg3_init(void)