瀏覽代碼

[TG3]: 5780 PHY fixes

Fix 5780 PHY related problems:

1. MAC_RX_MODE reset must be done before setting up the MAC_MODE
   register on 5705_PLUS chips or the chip will stop receiving after
   a while. The MAC_RX_MODE reset is needed to prevent intermittently
   losing the first receive packet on serdes chips.

2. Skip MAC loopback test on 5780 because of hardware errata. Normal
   traffic including PHY loopback is not affected by the errata.

3. PHY loopback fails intermittently on 5708S and this is fixed by
   putting the PHY in loopback mode first before programming the MAC
   mode register. A MAC_RX_MODE reset is also added.

4. Return -EINVAL in tg3_nway_reset() if device is in TBI mode. Allow
   nway_reset if 5780S is in parallel detect mode.

5. Add missing PHY IDs in KNOWN_PHY_ID() macro.

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Michael Chan 19 年之前
父節點
當前提交
c94e39418a
共有 2 個文件被更改,包括 32 次插入6 次删除
  1. 31 6
      drivers/net/tg3.c
  2. 1 0
      drivers/net/tg3.h

+ 31 - 6
drivers/net/tg3.c

@@ -5806,6 +5806,13 @@ static int tg3_reset_hw(struct tg3 *tp)
 	}
 	}
 	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
 	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
 
 
+	if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+		tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+		/* reset to prevent losing 1st rx packet intermittently */
+		tw32_f(MAC_RX_MODE, RX_MODE_RESET);
+		udelay(10);
+	}
+
 	tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
 	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;
 	tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
 	tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
@@ -5937,7 +5944,7 @@ static int tg3_reset_hw(struct tg3 *tp)
 	tw32(MAC_LED_CTRL, tp->led_ctrl);
 	tw32(MAC_LED_CTRL, tp->led_ctrl);
 
 
 	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
 	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
-	if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
+	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
 		tw32_f(MAC_RX_MODE, RX_MODE_RESET);
 		tw32_f(MAC_RX_MODE, RX_MODE_RESET);
 		udelay(10);
 		udelay(10);
 	}
 	}
@@ -7360,12 +7367,17 @@ static int tg3_nway_reset(struct net_device *dev)
 	if (!netif_running(dev))
 	if (!netif_running(dev))
 		return -EAGAIN;
 		return -EAGAIN;
 
 
+	if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+		return -EINVAL;
+
 	spin_lock_bh(&tp->lock);
 	spin_lock_bh(&tp->lock);
 	r = -EINVAL;
 	r = -EINVAL;
 	tg3_readphy(tp, MII_BMCR, &bmcr);
 	tg3_readphy(tp, MII_BMCR, &bmcr);
 	if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
 	if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
-	    (bmcr & BMCR_ANENABLE)) {
-		tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART);
+	    ((bmcr & BMCR_ANENABLE) ||
+	     (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
+		tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
+					   BMCR_ANENABLE);
 		r = 0;
 		r = 0;
 	}
 	}
 	spin_unlock_bh(&tp->lock);
 	spin_unlock_bh(&tp->lock);
@@ -7927,19 +7939,32 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
 	struct tg3_rx_buffer_desc *desc;
 	struct tg3_rx_buffer_desc *desc;
 
 
 	if (loopback_mode == TG3_MAC_LOOPBACK) {
 	if (loopback_mode == TG3_MAC_LOOPBACK) {
+		/* HW errata - mac loopback fails in some cases on 5780.
+		 * Normal traffic and PHY loopback are not affected by
+		 * errata.
+		 */
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
+			return 0;
+
 		mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
 		mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
 			   MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
 			   MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
 			   MAC_MODE_PORT_MODE_GMII;
 			   MAC_MODE_PORT_MODE_GMII;
 		tw32(MAC_MODE, mac_mode);
 		tw32(MAC_MODE, mac_mode);
 	} else if (loopback_mode == TG3_PHY_LOOPBACK) {
 	} else if (loopback_mode == TG3_PHY_LOOPBACK) {
+		tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
+					   BMCR_SPEED1000);
+		udelay(40);
+		/* reset to prevent losing 1st rx packet intermittently */
+		if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+			tw32_f(MAC_RX_MODE, RX_MODE_RESET);
+			udelay(10);
+			tw32_f(MAC_RX_MODE, tp->rx_mode);
+		}
 		mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
 		mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
 			   MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII;
 			   MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII;
 		if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)
 		if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)
 			mac_mode &= ~MAC_MODE_LINK_POLARITY;
 			mac_mode &= ~MAC_MODE_LINK_POLARITY;
 		tw32(MAC_MODE, mac_mode);
 		tw32(MAC_MODE, mac_mode);
-
-		tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
-					   BMCR_SPEED1000);
 	}
 	}
 	else
 	else
 		return -EINVAL;
 		return -EINVAL;

+ 1 - 0
drivers/net/tg3.h

@@ -2246,6 +2246,7 @@ struct tg3 {
 	 (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
 	 (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
 	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
 	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
 	 (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
 	 (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
+	 (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5780 || \
 	 (X) == PHY_ID_BCM8002)
 	 (X) == PHY_ID_BCM8002)
 
 
 	struct tg3_hw_stats		*hw_stats;
 	struct tg3_hw_stats		*hw_stats;