diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2007-11-13 06:08:03 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-11-13 06:08:03 +0100 |
commit | ce057f01956bfcb3cb8588091000ae546be78e00 (patch) | |
tree | 6438c33bcdde387ab191912e970b2fb65696b0a0 /drivers/net/tg3.c | |
parent | [TG3]: Fix 5761 PXEboot crash (diff) | |
download | linux-ce057f01956bfcb3cb8588091000ae546be78e00.tar.xz linux-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.c | 26 |
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); } |