summaryrefslogtreecommitdiff
path: root/drivers/net/tg3.c
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2009-08-25 10:07:27 +0000
committerDavid S. Miller <davem@davemloft.net>2009-08-26 15:47:47 -0700
commit255ca311b650caece3ec4f78b88ef298664d561f (patch)
treecf26fdfb0fb9f5fba78bb59a82f37abb132d4b62 /drivers/net/tg3.c
parent521e6b90dd3f0392062845d7ef13e6e41bb99d8a (diff)
tg3: Prevent tx BD corruption
This patch prevents a tx BD corruption bug by preventing the device from powering down the PLL from L1 if the link speed is 10Mbps or 100Mbps. The same bits are also used to prevent a system hang during chip reset resulting from a complicated set of events that ultimately leads to PCIe block register corruption. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Reviewed-by: Michael Chan <mchan@broadcom.com> Reviewed-by: Benjamin Li <benli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r--drivers/net/tg3.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index e8def28877ce..595ddf2eb7d2 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3167,6 +3167,15 @@ relink:
pci_write_config_word(tp->pdev,
tp->pcie_cap + PCI_EXP_LNKCTL,
newlnkctl);
+ } else if (tp->tg3_flags3 & TG3_FLG3_TOGGLE_10_100_L1PLLPD) {
+ u32 newreg, oldreg = tr32(TG3_PCIE_LNKCTL);
+ if (tp->link_config.active_speed == SPEED_100 ||
+ tp->link_config.active_speed == SPEED_10)
+ newreg = oldreg & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
+ else
+ newreg = oldreg | TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
+ if (newreg != oldreg)
+ tw32(TG3_PCIE_LNKCTL, newreg);
}
if (current_link_up != netif_carrier_ok(tp->dev)) {
@@ -6160,6 +6169,11 @@ static int tg3_chip_reset(struct tg3 *tp)
smp_mb();
synchronize_irq(tp->pdev->irq);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+ val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
+ tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS);
+ }
+
/* do the reset */
val = GRC_MISC_CFG_CORECLK_RESET;
@@ -6726,6 +6740,15 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3_CORR_ERR_STAT, TG3_CORR_ERR_STAT_CLEAR);
}
+ if (tp->tg3_flags3 & TG3_FLG3_TOGGLE_10_100_L1PLLPD) {
+ val = tr32(TG3_PCIE_LNKCTL);
+ if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG)
+ val |= TG3_PCIE_LNKCTL_L1_PLL_PD_DIS;
+ else
+ val &= ~TG3_PCIE_LNKCTL_L1_PLL_PD_DIS;
+ tw32(TG3_PCIE_LNKCTL, val);
+ }
+
/* This works around an issue with Athlon chipsets on
* B3 tigon3 silicon. This bit has no effect on any
* other revision. But do not set this on PCI Express
@@ -12274,6 +12297,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB;
+ if ((tp->pci_chip_rev_id == CHIPREV_ID_57780_A1 &&
+ tr32(RCVLPC_STATS_ENABLE) & RCVLPC_STATSENAB_ASF_FIX) ||
+ tp->pci_chip_rev_id == CHIPREV_ID_57780_A0)
+ tp->tg3_flags3 |= TG3_FLG3_TOGGLE_10_100_L1PLLPD;
+
err = tg3_mdio_init(tp);
if (err)
return err;