Commit c94e3941 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller

[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: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 667347f1
...@@ -5806,6 +5806,13 @@ static int tg3_reset_hw(struct tg3 *tp) ...@@ -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) ...@@ -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) ...@@ -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)) { ((bmcr & BMCR_ANENABLE) ||
tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART); (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) ...@@ -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;
......
...@@ -2246,6 +2246,7 @@ struct tg3 { ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment