tg3: Prevent tx BD corruption
authorMatt Carlson <mcarlson@broadcom.com>
Tue, 25 Aug 2009 10:07:27 +0000 (10:07 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 26 Aug 2009 22:47:47 +0000 (15:47 -0700)
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>
drivers/net/tg3.c
drivers/net/tg3.h

index e8def28877ce8dcc7f814d45bd3accc38b6220fa..595ddf2eb7d2a7b272962c3510f4060de4601271 100644 (file)
@@ -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;
index c613cbb40c2dde49478e49ab260ccae9ecec3acc..bb8591ea330011e7629247ba865a9de7544e1d50 100644 (file)
 #define  RCVLPC_STATSCTRL_ENABLE        0x00000001
 #define  RCVLPC_STATSCTRL_FASTUPD       0x00000002
 #define RCVLPC_STATS_ENABLE            0x00002018
+#define  RCVLPC_STATSENAB_ASF_FIX       0x00000002
 #define  RCVLPC_STATSENAB_DACK_FIX      0x00040000
 #define  RCVLPC_STATSENAB_LNGBRST_RFIX  0x00400000
 #define RCVLPC_STATS_INCMASK           0x0000201c
 #define PCIE_PWR_MGMT_L1_THRESH_MSK     0x0000ff00
 #define PCIE_PWR_MGMT_L1_THRESH_4MS     0x0000ff00
 #define PCIE_PWR_MGMT_EXT_ASPM_TMR_EN   0x01000000
-/* 0x7d2c --> 0x7e70 unused */
+/* 0x7d2c --> 0x7d54 unused */
+
+#define TG3_PCIE_LNKCTL                        0x00007d54
+#define  TG3_PCIE_LNKCTL_L1_PLL_PD_EN   0x00000008
+#define  TG3_PCIE_LNKCTL_L1_PLL_PD_DIS  0x00000080
+/* 0x7d58 --> 0x7e70 unused */
 
 #define TG3_PCIE_EIDLE_DELAY           0x00007e70
 #define  TG3_PCIE_EIDLE_DELAY_MASK      0x0000001f
@@ -2650,6 +2656,7 @@ struct tg3 {
 #define TG3_FLG3_PHY_ENABLE_APD                0x00001000
 #define TG3_FLG3_5755_PLUS             0x00002000
 #define TG3_FLG3_NO_NVRAM              0x00004000
+#define TG3_FLG3_TOGGLE_10_100_L1PLLPD 0x00008000
 
        struct timer_list               timer;
        u16                             timer_counter;