tg3: Fix link down notify failure when EEE disabled
[linux-2.6-microblaze.git] / drivers / net / tg3.c
index 4137e4e..e0413bc 100644 (file)
@@ -1858,6 +1858,12 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
        }
 
        if (!tp->setlpicnt) {
+               if (current_link_up == 1 &&
+                  !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+                       tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000);
+                       TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+               }
+
                val = tr32(TG3_CPMU_EEE_MODE);
                tw32(TG3_CPMU_EEE_MODE, val & ~TG3_CPMU_EEEMD_LPI_ENABLE);
        }
@@ -1872,7 +1878,9 @@ static void tg3_phy_eee_enable(struct tg3 *tp)
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) &&
            !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
-               tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0003);
+               val = MII_TG3_DSP_TAP26_ALNOKO |
+                     MII_TG3_DSP_TAP26_RMRXSTO;
+               tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val);
                TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
        }
 
@@ -2192,18 +2200,66 @@ out:
        return 0;
 }
 
+#define TG3_GPIO_MSG_DRVR_PRES          0x00000001
+#define TG3_GPIO_MSG_NEED_VAUX          0x00000002
+#define TG3_GPIO_MSG_MASK               (TG3_GPIO_MSG_DRVR_PRES | \
+                                         TG3_GPIO_MSG_NEED_VAUX)
+#define TG3_GPIO_MSG_ALL_DRVR_PRES_MASK \
+       ((TG3_GPIO_MSG_DRVR_PRES << 0) | \
+        (TG3_GPIO_MSG_DRVR_PRES << 4) | \
+        (TG3_GPIO_MSG_DRVR_PRES << 8) | \
+        (TG3_GPIO_MSG_DRVR_PRES << 12))
+
+#define TG3_GPIO_MSG_ALL_NEED_VAUX_MASK \
+       ((TG3_GPIO_MSG_NEED_VAUX << 0) | \
+        (TG3_GPIO_MSG_NEED_VAUX << 4) | \
+        (TG3_GPIO_MSG_NEED_VAUX << 8) | \
+        (TG3_GPIO_MSG_NEED_VAUX << 12))
+
+static inline u32 tg3_set_function_status(struct tg3 *tp, u32 newstat)
+{
+       u32 status, shift;
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+               status = tg3_ape_read32(tp, TG3_APE_GPIO_MSG);
+       else
+               status = tr32(TG3_CPMU_DRV_STATUS);
+
+       shift = TG3_APE_GPIO_MSG_SHIFT + 4 * tp->pci_fn;
+       status &= ~(TG3_GPIO_MSG_MASK << shift);
+       status |= (newstat << shift);
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+               tg3_ape_write32(tp, TG3_APE_GPIO_MSG, status);
+       else
+               tw32(TG3_CPMU_DRV_STATUS, status);
+
+       return status >> TG3_APE_GPIO_MSG_SHIFT;
+}
+
 static inline int tg3_pwrsrc_switch_to_vmain(struct tg3 *tp)
 {
        if (!tg3_flag(tp, IS_NIC))
-               return;
-
-       if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
                return 0;
 
-       tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl,
-                   TG3_GRC_LCLCTL_PWRSW_DELAY);
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+               if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
+                       return -EIO;
 
-       tg3_ape_unlock(tp, TG3_APE_LOCK_GPIO);
+               tg3_set_function_status(tp, TG3_GPIO_MSG_DRVR_PRES);
+
+               tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl,
+                           TG3_GRC_LCLCTL_PWRSW_DELAY);
+
+               tg3_ape_unlock(tp, TG3_APE_LOCK_GPIO);
+       } else {
+               tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl,
+                           TG3_GRC_LCLCTL_PWRSW_DELAY);
+       }
 
        return 0;
 }
@@ -2217,10 +2273,6 @@ static void tg3_pwrsrc_die_with_vmain(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
                return;
 
-
-       if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
-               return;
-
        grc_local_ctrl = tp->grc_local_ctrl | GRC_LCLCTRL_GPIO_OE1;
 
        tw32_wait_f(GRC_LOCAL_CTRL,
@@ -2234,8 +2286,6 @@ static void tg3_pwrsrc_die_with_vmain(struct tg3 *tp)
        tw32_wait_f(GRC_LOCAL_CTRL,
                    grc_local_ctrl | GRC_LCLCTRL_GPIO_OUTPUT1,
                    TG3_GRC_LCLCTL_PWRSW_DELAY);
-
-       tg3_ape_unlock(tp, TG3_APE_LOCK_GPIO);
 }
 
 static void tg3_pwrsrc_switch_to_vaux(struct tg3 *tp)
@@ -2243,9 +2293,6 @@ static void tg3_pwrsrc_switch_to_vaux(struct tg3 *tp)
        if (!tg3_flag(tp, IS_NIC))
                return;
 
-       if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
-               return;
-
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
                tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
@@ -2316,25 +2363,51 @@ static void tg3_pwrsrc_switch_to_vaux(struct tg3 *tp)
                                    TG3_GRC_LCLCTL_PWRSW_DELAY);
                }
        }
+}
+
+static void tg3_frob_aux_power_5717(struct tg3 *tp, bool wol_enable)
+{
+       u32 msg = 0;
 
+       /* Serialize power state transitions */
+       if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
+               return;
+
+       if (tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE) || wol_enable)
+               msg = TG3_GPIO_MSG_NEED_VAUX;
+
+       msg = tg3_set_function_status(tp, msg);
+
+       if (msg & TG3_GPIO_MSG_ALL_DRVR_PRES_MASK)
+               goto done;
+
+       if (msg & TG3_GPIO_MSG_ALL_NEED_VAUX_MASK)
+               tg3_pwrsrc_switch_to_vaux(tp);
+       else
+               tg3_pwrsrc_die_with_vmain(tp);
+
+done:
        tg3_ape_unlock(tp, TG3_APE_LOCK_GPIO);
 }
 
-static void tg3_frob_aux_power(struct tg3 *tp)
+static void tg3_frob_aux_power(struct tg3 *tp, bool include_wol)
 {
        bool need_vaux = false;
 
        /* The GPIOs do something completely different on 57765. */
        if (!tg3_flag(tp, IS_NIC) ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
                return;
 
-       if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
-            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 ||
-            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) &&
-           tp->pdev_peer != tp->pdev) {
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+               tg3_frob_aux_power_5717(tp, include_wol ?
+                                       tg3_flag(tp, WOL_ENABLE) != 0 : 0);
+               return;
+       }
+
+       if (tp->pdev_peer && tp->pdev_peer != tp->pdev) {
                struct net_device *dev_peer;
 
                dev_peer = pci_get_drvdata(tp->pdev_peer);
@@ -2346,13 +2419,14 @@ static void tg3_frob_aux_power(struct tg3 *tp)
                        if (tg3_flag(tp_peer, INIT_COMPLETE))
                                return;
 
-                       if (tg3_flag(tp_peer, WOL_ENABLE) ||
+                       if ((include_wol && tg3_flag(tp_peer, WOL_ENABLE)) ||
                            tg3_flag(tp_peer, ENABLE_ASF))
                                need_vaux = true;
                }
        }
 
-       if (tg3_flag(tp, WOL_ENABLE) || tg3_flag(tp, ENABLE_ASF))
+       if ((include_wol && tg3_flag(tp, WOL_ENABLE)) ||
+           tg3_flag(tp, ENABLE_ASF))
                need_vaux = true;
 
        if (need_vaux)
@@ -2935,7 +3009,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
        if (!(device_should_wake) && !tg3_flag(tp, ENABLE_ASF))
                tg3_power_down_phy(tp, do_low_power);
 
-       tg3_frob_aux_power(tp);
+       tg3_frob_aux_power(tp, true);
 
        /* Workaround for unstable PLL clock */
        if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
@@ -3062,20 +3136,6 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
        if (!err) {
                u32 err2;
 
-               switch (GET_ASIC_REV(tp->pci_chip_rev_id)) {
-               case ASIC_REV_5717:
-               case ASIC_REV_57765:
-                       if (!tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val))
-                               tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2, val |
-                                                MII_TG3_DSP_CH34TP2_HIBW01);
-                       /* Fall through */
-               case ASIC_REV_5719:
-                       val = MII_TG3_DSP_TAP26_ALNOKO |
-                             MII_TG3_DSP_TAP26_RMRXSTO |
-                             MII_TG3_DSP_TAP26_OPCSINPT;
-                       tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val);
-               }
-
                val = 0;
                /* Advertise 100-BaseTX EEE ability */
                if (advertise & ADVERTISED_100baseT_Full)
@@ -3084,6 +3144,25 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
                if (advertise & ADVERTISED_1000baseT_Full)
                        val |= MDIO_AN_EEE_ADV_1000T;
                err = tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
+               if (err)
+                       val = 0;
+
+               switch (GET_ASIC_REV(tp->pci_chip_rev_id)) {
+               case ASIC_REV_5717:
+               case ASIC_REV_57765:
+               case ASIC_REV_5719:
+                       /* If we advertised any eee advertisements above... */
+                       if (val)
+                               val = MII_TG3_DSP_TAP26_ALNOKO |
+                                     MII_TG3_DSP_TAP26_RMRXSTO |
+                                     MII_TG3_DSP_TAP26_OPCSINPT;
+                       tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val);
+                       /* Fall through */
+               case ASIC_REV_5720:
+                       if (!tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val))
+                               tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2, val |
+                                                MII_TG3_DSP_CH34TP2_HIBW01);
+               }
 
                err2 = TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
                if (!err)
@@ -7346,16 +7425,11 @@ static int tg3_chip_reset(struct tg3 *tp)
                tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
        }
 
-       if (tg3_flag(tp, ENABLE_APE))
-               tp->mac_mode = MAC_MODE_APE_TX_EN |
-                              MAC_MODE_APE_RX_EN |
-                              MAC_MODE_TDE_ENABLE;
-
        if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
-               tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
+               tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
                val = tp->mac_mode;
        } else if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
-               tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+               tp->mac_mode = MAC_MODE_PORT_MODE_GMII;
                val = tp->mac_mode;
        } else
                val = 0;
@@ -8493,12 +8567,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                udelay(10);
        }
 
-       if (tg3_flag(tp, ENABLE_APE))
-               tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
-       else
-               tp->mac_mode = 0;
        tp->mac_mode |= MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
-               MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
+                       MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE |
+                       MAC_MODE_FHDE_ENABLE;
+       if (tg3_flag(tp, ENABLE_APE))
+               tp->mac_mode |= MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
        if (!tg3_flag(tp, 5705_PLUS) &&
            !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
@@ -9491,6 +9564,8 @@ err_out2:
 
 err_out1:
        tg3_ints_fini(tp);
+       tg3_frob_aux_power(tp, false);
+       pci_set_power_state(tp->pdev, PCI_D3hot);
        return err;
 }
 
@@ -13692,9 +13767,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
                tp->pdev_peer = tg3_find_peer(tp);
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
@@ -15337,6 +15410,11 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        pci_set_drvdata(pdev, dev);
 
+       if (tg3_flag(tp, 5717_PLUS)) {
+               /* Resume a low-power mode */
+               tg3_frob_aux_power(tp, false);
+       }
+
        err = register_netdev(dev);
        if (err) {
                dev_err(&pdev->dev, "Cannot register net device, aborting\n");