Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / ethernet / broadcom / tg3.c
index c777b90..d964f30 100644 (file)
@@ -744,6 +744,9 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
                status = tg3_ape_read32(tp, gnt + off);
                if (status == bit)
                        break;
+               if (pci_channel_offline(tp->pdev))
+                       break;
+
                udelay(10);
        }
 
@@ -965,9 +968,6 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
 
                event = APE_EVENT_STATUS_STATE_UNLOAD;
                break;
-       case RESET_KIND_SUSPEND:
-               event = APE_EVENT_STATUS_STATE_SUSPEND;
-               break;
        default:
                return;
        }
@@ -1314,8 +1314,8 @@ static int tg3_phy_toggle_auxctl_smdsp(struct tg3 *tp, bool enable)
 
        if (err)
                return err;
-       if (enable)
 
+       if (enable)
                val |= MII_TG3_AUXCTL_ACTL_SMDSP_ENA;
        else
                val &= ~MII_TG3_AUXCTL_ACTL_SMDSP_ENA;
@@ -1635,6 +1635,9 @@ static void tg3_wait_for_event_ack(struct tg3 *tp)
        for (i = 0; i < delay_cnt; i++) {
                if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
                        break;
+               if (pci_channel_offline(tp->pdev))
+                       break;
+
                udelay(8);
        }
 }
@@ -1739,10 +1742,6 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
                        break;
                }
        }
-
-       if (kind == RESET_KIND_INIT ||
-           kind == RESET_KIND_SUSPEND)
-               tg3_ape_driver_state_change(tp, kind);
 }
 
 /* tp->lock is held. */
@@ -1764,9 +1763,6 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
                        break;
                }
        }
-
-       if (kind == RESET_KIND_SHUTDOWN)
-               tg3_ape_driver_state_change(tp, kind);
 }
 
 /* tp->lock is held. */
@@ -1813,6 +1809,9 @@ static int tg3_poll_fw(struct tg3 *tp)
                for (i = 0; i < 200; i++) {
                        if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
                                return 0;
+                       if (pci_channel_offline(tp->pdev))
+                               return -ENODEV;
+
                        udelay(100);
                }
                return -ENODEV;
@@ -1823,6 +1822,15 @@ static int tg3_poll_fw(struct tg3 *tp)
                tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
                if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
                        break;
+               if (pci_channel_offline(tp->pdev)) {
+                       if (!tg3_flag(tp, NO_FWARE_REPORTED)) {
+                               tg3_flag_set(tp, NO_FWARE_REPORTED);
+                               netdev_info(tp->dev, "No firmware running\n");
+                       }
+
+                       break;
+               }
+
                udelay(10);
        }
 
@@ -2323,6 +2331,46 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
        tg3_phy_toggle_auxctl_smdsp(tp, false);
 }
 
+static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_eee *eee)
+{
+       u32 val;
+       struct ethtool_eee *dest = &tp->eee;
+
+       if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
+               return;
+
+       if (eee)
+               dest = eee;
+
+       if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, TG3_CL45_D7_EEERES_STAT, &val))
+               return;
+
+       /* Pull eee_active */
+       if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
+           val == TG3_CL45_D7_EEERES_STAT_LP_100TX) {
+               dest->eee_active = 1;
+       } else
+               dest->eee_active = 0;
+
+       /* Pull lp advertised settings */
+       if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, &val))
+               return;
+       dest->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val);
+
+       /* Pull advertised and eee_enabled settings */
+       if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val))
+               return;
+       dest->eee_enabled = !!val;
+       dest->advertised = mmd_eee_adv_to_ethtool_adv_t(val);
+
+       /* Pull tx_lpi_enabled */
+       val = tr32(TG3_CPMU_EEE_MODE);
+       dest->tx_lpi_enabled = !!(val & TG3_CPMU_EEEMD_LPI_IN_TX);
+
+       /* Pull lpi timer value */
+       dest->tx_lpi_timer = tr32(TG3_CPMU_EEE_DBTMR1) & 0xffff;
+}
+
 static void tg3_phy_eee_adjust(struct tg3 *tp, bool current_link_up)
 {
        u32 val;
@@ -2346,11 +2394,8 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, bool current_link_up)
 
                tw32(TG3_CPMU_EEE_CTRL, eeectl);
 
-               tg3_phy_cl45_read(tp, MDIO_MMD_AN,
-                                 TG3_CL45_D7_EEERES_STAT, &val);
-
-               if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
-                   val == TG3_CL45_D7_EEERES_STAT_LP_100TX)
+               tg3_eee_pull_config(tp, NULL);
+               if (tp->eee.eee_active)
                        tp->setlpicnt = 2;
        }
 
@@ -3520,6 +3565,8 @@ static int tg3_pause_cpu(struct tg3 *tp, u32 cpu_base)
                tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
                if (tr32(cpu_base + CPU_MODE) & CPU_MODE_HALT)
                        break;
+               if (pci_channel_offline(tp->pdev))
+                       return -EBUSY;
        }
 
        return (i == iters) ? -EBUSY : 0;
@@ -4172,6 +4219,8 @@ static int tg3_power_down_prepare(struct tg3 *tp)
 
        tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
 
+       tg3_ape_driver_state_change(tp, RESET_KIND_SHUTDOWN);
+
        return 0;
 }
 
@@ -4272,6 +4321,16 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
                /* Advertise 1000-BaseT EEE ability */
                if (advertise & ADVERTISED_1000baseT_Full)
                        val |= MDIO_AN_EEE_ADV_1000T;
+
+               if (!tp->eee.eee_enabled) {
+                       val = 0;
+                       tp->eee.advertised = 0;
+               } else {
+                       tp->eee.advertised = advertise &
+                                            (ADVERTISED_100baseT_Full |
+                                             ADVERTISED_1000baseT_Full);
+               }
+
                err = tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
                if (err)
                        val = 0;
@@ -4516,26 +4575,23 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp)
 
 static bool tg3_phy_eee_config_ok(struct tg3 *tp)
 {
-       u32 val;
-       u32 tgtadv = 0;
-       u32 advertising = tp->link_config.advertising;
+       struct ethtool_eee eee;
 
        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);
+       tg3_eee_pull_config(tp, &eee);
 
-
-       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;
+       if (tp->eee.eee_enabled) {
+               if (tp->eee.advertised != eee.advertised ||
+                   tp->eee.tx_lpi_timer != eee.tx_lpi_timer ||
+                   tp->eee.tx_lpi_enabled != eee.tx_lpi_enabled)
+                       return false;
+       } else {
+               /* EEE is disabled but we're advertising */
+               if (eee.advertised)
+                       return false;
+       }
 
        return true;
 }
@@ -4636,6 +4692,42 @@ static void tg3_clear_mac_status(struct tg3 *tp)
        udelay(40);
 }
 
+static void tg3_setup_eee(struct tg3 *tp)
+{
+       u32 val;
+
+       val = TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
+             TG3_CPMU_EEE_LNKIDL_UART_IDL;
+       if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
+               val |= TG3_CPMU_EEE_LNKIDL_APE_TX_MT;
+
+       tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL, val);
+
+       tw32_f(TG3_CPMU_EEE_CTRL,
+              TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
+
+       val = TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
+             (tp->eee.tx_lpi_enabled ? TG3_CPMU_EEEMD_LPI_IN_TX : 0) |
+             TG3_CPMU_EEEMD_LPI_IN_RX |
+             TG3_CPMU_EEEMD_EEE_ENABLE;
+
+       if (tg3_asic_rev(tp) != ASIC_REV_5717)
+               val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;
+
+       if (tg3_flag(tp, ENABLE_APE))
+               val |= TG3_CPMU_EEEMD_APE_TX_DET_EN;
+
+       tw32_f(TG3_CPMU_EEE_MODE, tp->eee.eee_enabled ? val : 0);
+
+       tw32_f(TG3_CPMU_EEE_DBTMR1,
+              TG3_CPMU_DBTMR1_PCIEXIT_2047US |
+              (tp->eee.tx_lpi_timer & 0xffff));
+
+       tw32_f(TG3_CPMU_EEE_DBTMR2,
+              TG3_CPMU_DBTMR2_APE_TX_2047US |
+              TG3_CPMU_DBTMR2_TXIDXEQ_2047US);
+}
+
 static int tg3_setup_copper_phy(struct tg3 *tp, bool force_reset)
 {
        bool current_link_up;
@@ -4802,8 +4894,10 @@ static int tg3_setup_copper_phy(struct tg3 *tp, bool force_reset)
                         */
                        if (!eee_config_ok &&
                            (tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
-                           !force_reset)
+                           !force_reset) {
+                               tg3_setup_eee(tp);
                                tg3_phy_reset(tp);
+                       }
                } else {
                        if (!(bmcr & BMCR_ANENABLE) &&
                            tp->link_config.speed == current_speed &&
@@ -6315,9 +6409,7 @@ static void tg3_tx_recover(struct tg3 *tp)
                    "Please report the problem to the driver maintainer "
                    "and include system chipset information.\n");
 
-       spin_lock(&tp->lock);
        tg3_flag_set(tp, TX_RECOVERY_PENDING);
-       spin_unlock(&tp->lock);
 }
 
 static inline u32 tg3_tx_avail(struct tg3_napi *tnapi)
@@ -8589,6 +8681,14 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, boo
        tw32_f(ofs, val);
 
        for (i = 0; i < MAX_WAIT_CNT; i++) {
+               if (pci_channel_offline(tp->pdev)) {
+                       dev_err(&tp->pdev->dev,
+                               "tg3_stop_block device offline, "
+                               "ofs=%lx enable_bit=%x\n",
+                               ofs, enable_bit);
+                       return -ENODEV;
+               }
+
                udelay(100);
                val = tr32(ofs);
                if ((val & enable_bit) == 0)
@@ -8612,6 +8712,13 @@ static int tg3_abort_hw(struct tg3 *tp, bool silent)
 
        tg3_disable_ints(tp);
 
+       if (pci_channel_offline(tp->pdev)) {
+               tp->rx_mode &= ~(RX_MODE_ENABLE | TX_MODE_ENABLE);
+               tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
+               err = -ENODEV;
+               goto err_no_dev;
+       }
+
        tp->rx_mode &= ~RX_MODE_ENABLE;
        tw32_f(MAC_RX_MODE, tp->rx_mode);
        udelay(10);
@@ -8660,6 +8767,7 @@ static int tg3_abort_hw(struct tg3 *tp, bool silent)
        err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE, silent);
        err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE, silent);
 
+err_no_dev:
        for (i = 0; i < tp->irq_cnt; i++) {
                struct tg3_napi *tnapi = &tp->napi[i];
                if (tnapi->hw_status)
@@ -9169,11 +9277,9 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
 }
 
 /* tp->lock is held. */
-static void tg3_rings_reset(struct tg3 *tp)
+static void tg3_tx_rcbs_disable(struct tg3 *tp)
 {
-       int i;
-       u32 stblk, txrcb, rxrcb, limit;
-       struct tg3_napi *tnapi = &tp->napi[0];
+       u32 txrcb, limit;
 
        /* Disable all transmit rings but the first. */
        if (!tg3_flag(tp, 5705_PLUS))
@@ -9190,7 +9296,33 @@ static void tg3_rings_reset(struct tg3 *tp)
             txrcb < limit; txrcb += TG3_BDINFO_SIZE)
                tg3_write_mem(tp, txrcb + TG3_BDINFO_MAXLEN_FLAGS,
                              BDINFO_FLAGS_DISABLED);
+}
+
+/* tp->lock is held. */
+static void tg3_tx_rcbs_init(struct tg3 *tp)
+{
+       int i = 0;
+       u32 txrcb = NIC_SRAM_SEND_RCB;
+
+       if (tg3_flag(tp, ENABLE_TSS))
+               i++;
+
+       for (; i < tp->irq_max; i++, txrcb += TG3_BDINFO_SIZE) {
+               struct tg3_napi *tnapi = &tp->napi[i];
 
+               if (!tnapi->tx_ring)
+                       continue;
+
+               tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping,
+                              (TG3_TX_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT),
+                              NIC_SRAM_TX_BUFFER_DESC);
+       }
+}
+
+/* tp->lock is held. */
+static void tg3_rx_ret_rcbs_disable(struct tg3 *tp)
+{
+       u32 rxrcb, limit;
 
        /* Disable all receive return rings but the first. */
        if (tg3_flag(tp, 5717_PLUS))
@@ -9208,6 +9340,39 @@ static void tg3_rings_reset(struct tg3 *tp)
             rxrcb < limit; rxrcb += TG3_BDINFO_SIZE)
                tg3_write_mem(tp, rxrcb + TG3_BDINFO_MAXLEN_FLAGS,
                              BDINFO_FLAGS_DISABLED);
+}
+
+/* tp->lock is held. */
+static void tg3_rx_ret_rcbs_init(struct tg3 *tp)
+{
+       int i = 0;
+       u32 rxrcb = NIC_SRAM_RCV_RET_RCB;
+
+       if (tg3_flag(tp, ENABLE_RSS))
+               i++;
+
+       for (; i < tp->irq_max; i++, rxrcb += TG3_BDINFO_SIZE) {
+               struct tg3_napi *tnapi = &tp->napi[i];
+
+               if (!tnapi->rx_rcb)
+                       continue;
+
+               tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping,
+                              (tp->rx_ret_ring_mask + 1) <<
+                               BDINFO_FLAGS_MAXLEN_SHIFT, 0);
+       }
+}
+
+/* tp->lock is held. */
+static void tg3_rings_reset(struct tg3 *tp)
+{
+       int i;
+       u32 stblk;
+       struct tg3_napi *tnapi = &tp->napi[0];
+
+       tg3_tx_rcbs_disable(tp);
+
+       tg3_rx_ret_rcbs_disable(tp);
 
        /* Disable interrupts */
        tw32_mailbox_f(tp->napi[0].int_mbox, 1);
@@ -9244,9 +9409,6 @@ static void tg3_rings_reset(struct tg3 *tp)
                        tw32_tx_mbox(mbox + i * 8, 0);
        }
 
-       txrcb = NIC_SRAM_SEND_RCB;
-       rxrcb = NIC_SRAM_RCV_RET_RCB;
-
        /* Clear status block in ram. */
        memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE);
 
@@ -9256,46 +9418,20 @@ static void tg3_rings_reset(struct tg3 *tp)
        tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
             ((u64) tnapi->status_mapping & 0xffffffff));
 
-       if (tnapi->tx_ring) {
-               tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping,
-                              (TG3_TX_RING_SIZE <<
-                               BDINFO_FLAGS_MAXLEN_SHIFT),
-                              NIC_SRAM_TX_BUFFER_DESC);
-               txrcb += TG3_BDINFO_SIZE;
-       }
-
-       if (tnapi->rx_rcb) {
-               tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping,
-                              (tp->rx_ret_ring_mask + 1) <<
-                               BDINFO_FLAGS_MAXLEN_SHIFT, 0);
-               rxrcb += TG3_BDINFO_SIZE;
-       }
-
        stblk = HOSTCC_STATBLCK_RING1;
 
        for (i = 1, tnapi++; i < tp->irq_cnt; i++, tnapi++) {
                u64 mapping = (u64)tnapi->status_mapping;
                tw32(stblk + TG3_64BIT_REG_HIGH, mapping >> 32);
                tw32(stblk + TG3_64BIT_REG_LOW, mapping & 0xffffffff);
+               stblk += 8;
 
                /* Clear status block in ram. */
                memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE);
-
-               if (tnapi->tx_ring) {
-                       tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping,
-                                      (TG3_TX_RING_SIZE <<
-                                       BDINFO_FLAGS_MAXLEN_SHIFT),
-                                      NIC_SRAM_TX_BUFFER_DESC);
-                       txrcb += TG3_BDINFO_SIZE;
-               }
-
-               tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping,
-                              ((tp->rx_ret_ring_mask + 1) <<
-                               BDINFO_FLAGS_MAXLEN_SHIFT), 0);
-
-               stblk += 8;
-               rxrcb += TG3_BDINFO_SIZE;
        }
+
+       tg3_tx_rcbs_init(tp);
+       tg3_rx_ret_rcbs_init(tp);
 }
 
 static void tg3_setup_rxbd_thresholds(struct tg3 *tp)
@@ -9495,46 +9631,17 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
        if (tg3_flag(tp, INIT_COMPLETE))
                tg3_abort_hw(tp, 1);
 
-       /* Enable MAC control of LPI */
-       if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
-               val = TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
-                     TG3_CPMU_EEE_LNKIDL_UART_IDL;
-               if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
-                       val |= TG3_CPMU_EEE_LNKIDL_APE_TX_MT;
-
-               tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL, val);
-
-               tw32_f(TG3_CPMU_EEE_CTRL,
-                      TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
-
-               val = TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
-                     TG3_CPMU_EEEMD_LPI_IN_TX |
-                     TG3_CPMU_EEEMD_LPI_IN_RX |
-                     TG3_CPMU_EEEMD_EEE_ENABLE;
-
-               if (tg3_asic_rev(tp) != ASIC_REV_5717)
-                       val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;
-
-               if (tg3_flag(tp, ENABLE_APE))
-                       val |= TG3_CPMU_EEEMD_APE_TX_DET_EN;
-
-               tw32_f(TG3_CPMU_EEE_MODE, val);
-
-               tw32_f(TG3_CPMU_EEE_DBTMR1,
-                      TG3_CPMU_DBTMR1_PCIEXIT_2047US |
-                      TG3_CPMU_DBTMR1_LNKIDLE_2047US);
-
-               tw32_f(TG3_CPMU_EEE_DBTMR2,
-                      TG3_CPMU_DBTMR2_APE_TX_2047US |
-                      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);
+               tg3_eee_pull_config(tp, NULL);
                tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
        }
 
+       /* Enable MAC control of LPI */
+       if (tp->phy_flags & TG3_PHYFLG_EEE_CAP)
+               tg3_setup_eee(tp);
+
        if (reset_phy)
                tg3_phy_reset(tp);
 
@@ -11190,7 +11297,7 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
         */
        err = tg3_alloc_consistent(tp);
        if (err)
-               goto err_out1;
+               goto out_ints_fini;
 
        tg3_napi_init(tp);
 
@@ -11204,12 +11311,15 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
                                tnapi = &tp->napi[i];
                                free_irq(tnapi->irq_vec, tnapi);
                        }
-                       goto err_out2;
+                       goto out_napi_fini;
                }
        }
 
        tg3_full_lock(tp, 0);
 
+       if (init)
+               tg3_ape_driver_state_change(tp, RESET_KIND_INIT);
+
        err = tg3_init_hw(tp, reset_phy);
        if (err) {
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
@@ -11219,7 +11329,7 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
        tg3_full_unlock(tp);
 
        if (err)
-               goto err_out3;
+               goto out_free_irq;
 
        if (test_irq && tg3_flag(tp, USING_MSI)) {
                err = tg3_test_msi(tp);
@@ -11230,7 +11340,7 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
                        tg3_free_rings(tp);
                        tg3_full_unlock(tp);
 
-                       goto err_out2;
+                       goto out_napi_fini;
                }
 
                if (!tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) {
@@ -11270,18 +11380,18 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
 
        return 0;
 
-err_out3:
+out_free_irq:
        for (i = tp->irq_cnt - 1; i >= 0; i--) {
                struct tg3_napi *tnapi = &tp->napi[i];
                free_irq(tnapi->irq_vec, tnapi);
        }
 
-err_out2:
+out_napi_fini:
        tg3_napi_disable(tp);
        tg3_napi_fini(tp);
        tg3_free_consistent(tp);
 
-err_out1:
+out_ints_fini:
        tg3_ints_fini(tp);
 
        return err;
@@ -13326,11 +13436,13 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
        struct tg3 *tp = netdev_priv(dev);
        bool doextlpbk = etest->flags & ETH_TEST_FL_EXTERNAL_LB;
 
-       if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) &&
-           tg3_power_up(tp)) {
-               etest->flags |= ETH_TEST_FL_FAILED;
-               memset(data, 1, sizeof(u64) * TG3_NUM_TEST);
-               return;
+       if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+               if (tg3_power_up(tp)) {
+                       etest->flags |= ETH_TEST_FL_FAILED;
+                       memset(data, 1, sizeof(u64) * TG3_NUM_TEST);
+                       return;
+               }
+               tg3_ape_driver_state_change(tp, RESET_KIND_INIT);
        }
 
        memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
@@ -13621,6 +13733,57 @@ static int tg3_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
        return 0;
 }
 
+static int tg3_set_eee(struct net_device *dev, struct ethtool_eee *edata)
+{
+       struct tg3 *tp = netdev_priv(dev);
+
+       if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
+               netdev_warn(tp->dev, "Board does not support EEE!\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (edata->advertised != tp->eee.advertised) {
+               netdev_warn(tp->dev,
+                           "Direct manipulation of EEE advertisement is not supported\n");
+               return -EINVAL;
+       }
+
+       if (edata->tx_lpi_timer > TG3_CPMU_DBTMR1_LNKIDLE_MAX) {
+               netdev_warn(tp->dev,
+                           "Maximal Tx Lpi timer supported is %#x(u)\n",
+                           TG3_CPMU_DBTMR1_LNKIDLE_MAX);
+               return -EINVAL;
+       }
+
+       tp->eee = *edata;
+
+       tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
+       tg3_warn_mgmt_link_flap(tp);
+
+       if (netif_running(tp->dev)) {
+               tg3_full_lock(tp, 0);
+               tg3_setup_eee(tp);
+               tg3_phy_reset(tp);
+               tg3_full_unlock(tp);
+       }
+
+       return 0;
+}
+
+static int tg3_get_eee(struct net_device *dev, struct ethtool_eee *edata)
+{
+       struct tg3 *tp = netdev_priv(dev);
+
+       if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
+               netdev_warn(tp->dev,
+                           "Board does not support EEE!\n");
+               return -EOPNOTSUPP;
+       }
+
+       *edata = tp->eee;
+       return 0;
+}
+
 static const struct ethtool_ops tg3_ethtool_ops = {
        .get_settings           = tg3_get_settings,
        .set_settings           = tg3_set_settings,
@@ -13654,6 +13817,8 @@ static const struct ethtool_ops tg3_ethtool_ops = {
        .get_channels           = tg3_get_channels,
        .set_channels           = tg3_set_channels,
        .get_ts_info            = tg3_get_ts_info,
+       .get_eee                = tg3_get_eee,
+       .set_eee                = tg3_set_eee,
 };
 
 static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
@@ -15002,9 +15167,18 @@ static int tg3_phy_probe(struct tg3 *tp)
             (tg3_asic_rev(tp) == ASIC_REV_5717 &&
              tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0) ||
             (tg3_asic_rev(tp) == ASIC_REV_57765 &&
-             tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0)))
+             tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0))) {
                tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
 
+               tp->eee.supported = SUPPORTED_100baseT_Full |
+                                   SUPPORTED_1000baseT_Full;
+               tp->eee.advertised = ADVERTISED_100baseT_Full |
+                                    ADVERTISED_1000baseT_Full;
+               tp->eee.eee_enabled = 1;
+               tp->eee.tx_lpi_enabled = 1;
+               tp->eee.tx_lpi_timer = TG3_CPMU_DBTMR1_LNKIDLE_2047US;
+       }
+
        tg3_phy_init_link_config(tp);
 
        if (!(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
@@ -17076,7 +17250,7 @@ static int tg3_init_one(struct pci_dev *pdev,
 {
        struct net_device *dev;
        struct tg3 *tp;
-       int i, err, pm_cap;
+       int i, err;
        u32 sndmbx, rcvmbx, intmbx;
        char str[40];
        u64 dma_mask, persist_dma_mask;
@@ -17098,25 +17272,10 @@ static int tg3_init_one(struct pci_dev *pdev,
 
        pci_set_master(pdev);
 
-       /* Find power-management capability. */
-       pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (pm_cap == 0) {
-               dev_err(&pdev->dev,
-                       "Cannot find Power Management capability, aborting\n");
-               err = -EIO;
-               goto err_out_free_res;
-       }
-
-       err = pci_set_power_state(pdev, PCI_D0);
-       if (err) {
-               dev_err(&pdev->dev, "Transition to D0 failed, aborting\n");
-               goto err_out_free_res;
-       }
-
        dev = alloc_etherdev_mq(sizeof(*tp), TG3_IRQ_MAX_VECS);
        if (!dev) {
                err = -ENOMEM;
-               goto err_out_power_down;
+               goto err_out_free_res;
        }
 
        SET_NETDEV_DEV(dev, &pdev->dev);
@@ -17124,7 +17283,7 @@ static int tg3_init_one(struct pci_dev *pdev,
        tp = netdev_priv(dev);
        tp->pdev = pdev;
        tp->dev = dev;
-       tp->pm_cap = pm_cap;
+       tp->pm_cap = pdev->pm_cap;
        tp->rx_mode = TG3_DEF_RX_MODE;
        tp->tx_mode = TG3_DEF_TX_MODE;
        tp->irq_sync = 1;
@@ -17462,9 +17621,6 @@ err_out_iounmap:
 err_out_free_dev:
        free_netdev(dev);
 
-err_out_power_down:
-       pci_set_power_state(pdev, PCI_D3hot);
-
 err_out_free_res:
        pci_release_regions(pdev);
 
@@ -17574,6 +17730,8 @@ static int tg3_resume(struct device *device)
 
        tg3_full_lock(tp, 0);
 
+       tg3_ape_driver_state_change(tp, RESET_KIND_INIT);
+
        tg3_flag_set(tp, INIT_COMPLETE);
        err = tg3_restart_hw(tp,
                             !(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN));
@@ -17635,10 +17793,13 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
        tg3_full_unlock(tp);
 
 done:
-       if (state == pci_channel_io_perm_failure)
+       if (state == pci_channel_io_perm_failure) {
+               tg3_napi_enable(tp);
+               dev_close(netdev);
                err = PCI_ERS_RESULT_DISCONNECT;
-       else
+       } else {
                pci_disable_device(pdev);
+       }
 
        rtnl_unlock();
 
@@ -17684,6 +17845,10 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
        rc = PCI_ERS_RESULT_RECOVERED;
 
 done:
+       if (rc != PCI_ERS_RESULT_RECOVERED && netif_running(netdev)) {
+               tg3_napi_enable(tp);
+               dev_close(netdev);
+       }
        rtnl_unlock();
 
        return rc;
@@ -17708,6 +17873,7 @@ static void tg3_io_resume(struct pci_dev *pdev)
                goto done;
 
        tg3_full_lock(tp, 0);
+       tg3_ape_driver_state_change(tp, RESET_KIND_INIT);
        tg3_flag_set(tp, INIT_COMPLETE);
        err = tg3_restart_hw(tp, true);
        if (err) {
@@ -17745,15 +17911,4 @@ static struct pci_driver tg3_driver = {
        .driver.pm      = &tg3_pm_ops,
 };
 
-static int __init tg3_init(void)
-{
-       return pci_register_driver(&tg3_driver);
-}
-
-static void __exit tg3_cleanup(void)
-{
-       pci_unregister_driver(&tg3_driver);
-}
-
-module_init(tg3_init);
-module_exit(tg3_cleanup);
+module_pci_driver(tg3_driver);