aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tg3.c
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2007-11-12 21:08:03 -0800
committerDavid S. Miller <davem@davemloft.net>2007-11-12 21:08:03 -0800
commitce057f01956bfcb3cb8588091000ae546be78e00 (patch)
tree6438c33bcdde387ab191912e970b2fb65696b0a0 /drivers/net/tg3.c
parent[TG3]: Fix 5761 PXEboot crash (diff)
downloadlinux-dev-ce057f01956bfcb3cb8588091000ae546be78e00.tar.xz
linux-dev-ce057f01956bfcb3cb8588091000ae546be78e00.zip
[TG3]: 5784 / 5764 GPHY power down fix
5784 and 5764 devices fail to link / pass traffic after one load / unload cycle. This happens because of a hardware bug in the new CPMU. During normal operation, the MAC depends on the PHY clock being available. When the PHY is powered down, the clock the MAC depends on is disabled. The fix is to switch the MAC clock to an alternate source before powering down the PHY, and to restore the MAC clock to the PHY source upon device resume. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r--drivers/net/tg3.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index ddeaa0c78305..82b1cf0e2d18 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1106,6 +1106,19 @@ static int tg3_phy_reset(struct tg3 *tp)
if (err)
return err;
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5761_A0) {
+ u32 val;
+
+ val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
+ if ((val & CPMU_LSPD_1000MB_MACCLK_MASK) ==
+ CPMU_LSPD_1000MB_MACCLK_12_5) {
+ val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
+ udelay(40);
+ tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
+ }
+ }
+
out:
if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
@@ -1297,6 +1310,8 @@ static void tg3_nvram_unlock(struct tg3 *);
static void tg3_power_down_phy(struct tg3 *tp)
{
+ u32 val;
+
if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
@@ -1311,8 +1326,6 @@ static void tg3_power_down_phy(struct tg3 *tp)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
- u32 val;
-
tg3_bmcr_reset(tp);
val = tr32(GRC_MISC_CFG);
tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
@@ -1332,6 +1345,15 @@ static void tg3_power_down_phy(struct tg3 *tp)
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
return;
+
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5761_A0) {
+ val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
+ val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
+ val |= CPMU_LSPD_1000MB_MACCLK_12_5;
+ tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
+ }
+
tg3_writephy(tp, MII_BMCR, BMCR_PDOWN);
}