aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2011-08-19 09:58:21 -0400
committerDavid S. Miller <davem@davemloft.net>2011-08-20 13:34:27 -0400
commit5e5a7f371ffea4b5aeca60253f912e0b36391495 (patch)
treeb14078de84b7bb81e4b1627531ea5a31657ce8a7
parent6e01b20b21d6b2131f27a7c068ff71a7fbe58796 (diff)
tg3: Pull phy int lpbk setup into separate func
This patch pulls out the internal phy loopback setup code into a separate function. This cleans up the loopback test code and makes it available for NETIF_F_LOOPBACK support later. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Reviewed-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c149
1 files changed, 90 insertions, 59 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index abe2ec3c0022..08953b0999d2 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -6370,6 +6370,80 @@ static void tg3_mac_loopback(struct tg3 *tp, bool enable)
6370 udelay(40); 6370 udelay(40);
6371} 6371}
6372 6372
6373static void tg3_phy_lpbk_set(struct tg3 *tp, u32 speed)
6374{
6375 u32 val, bmcr, mac_mode;
6376
6377 tg3_phy_toggle_apd(tp, false);
6378 tg3_phy_toggle_automdix(tp, 0);
6379
6380 bmcr = BMCR_LOOPBACK | BMCR_FULLDPLX;
6381 switch (speed) {
6382 case SPEED_10:
6383 break;
6384 case SPEED_100:
6385 bmcr |= BMCR_SPEED100;
6386 break;
6387 case SPEED_1000:
6388 default:
6389 if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
6390 speed = SPEED_100;
6391 bmcr |= BMCR_SPEED100;
6392 } else {
6393 speed = SPEED_1000;
6394 bmcr |= BMCR_SPEED1000;
6395 }
6396 }
6397
6398 tg3_writephy(tp, MII_BMCR, bmcr);
6399
6400 /* The write needs to be flushed for the FETs */
6401 if (tp->phy_flags & TG3_PHYFLG_IS_FET)
6402 tg3_readphy(tp, MII_BMCR, &bmcr);
6403
6404 udelay(40);
6405
6406 if ((tp->phy_flags & TG3_PHYFLG_IS_FET) &&
6407 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
6408 tg3_writephy(tp, MII_TG3_FET_PTEST,
6409 MII_TG3_FET_PTEST_FRC_TX_LINK |
6410 MII_TG3_FET_PTEST_FRC_TX_LOCK);
6411
6412 /* The write needs to be flushed for the AC131 */
6413 tg3_readphy(tp, MII_TG3_FET_PTEST, &val);
6414 }
6415
6416 /* Reset to prevent losing 1st rx packet intermittently */
6417 if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
6418 tg3_flag(tp, 5780_CLASS)) {
6419 tw32_f(MAC_RX_MODE, RX_MODE_RESET);
6420 udelay(10);
6421 tw32_f(MAC_RX_MODE, tp->rx_mode);
6422 }
6423
6424 mac_mode = tp->mac_mode &
6425 ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
6426 if (speed == SPEED_1000)
6427 mac_mode |= MAC_MODE_PORT_MODE_GMII;
6428 else
6429 mac_mode |= MAC_MODE_PORT_MODE_MII;
6430
6431 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
6432 u32 masked_phy_id = tp->phy_id & TG3_PHY_ID_MASK;
6433
6434 if (masked_phy_id == TG3_PHY_ID_BCM5401)
6435 mac_mode &= ~MAC_MODE_LINK_POLARITY;
6436 else if (masked_phy_id == TG3_PHY_ID_BCM5411)
6437 mac_mode |= MAC_MODE_LINK_POLARITY;
6438
6439 tg3_writephy(tp, MII_TG3_EXT_CTRL,
6440 MII_TG3_EXT_CTRL_LNK3_LED_MODE);
6441 }
6442
6443 tw32(MAC_MODE, mac_mode);
6444 udelay(40);
6445}
6446
6373static void tg3_set_loopback(struct net_device *dev, u32 features) 6447static void tg3_set_loopback(struct net_device *dev, u32 features)
6374{ 6448{
6375 struct tg3 *tp = netdev_priv(dev); 6449 struct tg3 *tp = netdev_priv(dev);
@@ -11265,7 +11339,7 @@ static const u8 tg3_tso_header[] = {
11265 11339
11266static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) 11340static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
11267{ 11341{
11268 u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; 11342 u32 rx_start_idx, rx_idx, tx_idx, opaque_key;
11269 u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val; 11343 u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val;
11270 u32 budget; 11344 u32 budget;
11271 struct sk_buff *skb, *rx_skb; 11345 struct sk_buff *skb, *rx_skb;
@@ -11286,56 +11360,6 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
11286 } 11360 }
11287 coal_now = tnapi->coal_now | rnapi->coal_now; 11361 coal_now = tnapi->coal_now | rnapi->coal_now;
11288 11362
11289 if (loopback_mode != TG3_MAC_LOOPBACK) {
11290 if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
11291 tg3_phy_fet_toggle_apd(tp, false);
11292 val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100;
11293 } else
11294 val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000;
11295
11296 tg3_phy_toggle_automdix(tp, 0);
11297
11298 tg3_writephy(tp, MII_BMCR, val);
11299 udelay(40);
11300
11301 mac_mode = tp->mac_mode &
11302 ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
11303 if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
11304 tg3_writephy(tp, MII_TG3_FET_PTEST,
11305 MII_TG3_FET_PTEST_FRC_TX_LINK |
11306 MII_TG3_FET_PTEST_FRC_TX_LOCK);
11307 /* The write needs to be flushed for the AC131 */
11308 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
11309 tg3_readphy(tp, MII_TG3_FET_PTEST, &val);
11310 mac_mode |= MAC_MODE_PORT_MODE_MII;
11311 } else
11312 mac_mode |= MAC_MODE_PORT_MODE_GMII;
11313
11314 /* reset to prevent losing 1st rx packet intermittently */
11315 if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
11316 tw32_f(MAC_RX_MODE, RX_MODE_RESET);
11317 udelay(10);
11318 tw32_f(MAC_RX_MODE, tp->rx_mode);
11319 }
11320 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
11321 u32 masked_phy_id = tp->phy_id & TG3_PHY_ID_MASK;
11322 if (masked_phy_id == TG3_PHY_ID_BCM5401)
11323 mac_mode &= ~MAC_MODE_LINK_POLARITY;
11324 else if (masked_phy_id == TG3_PHY_ID_BCM5411)
11325 mac_mode |= MAC_MODE_LINK_POLARITY;
11326 tg3_writephy(tp, MII_TG3_EXT_CTRL,
11327 MII_TG3_EXT_CTRL_LNK3_LED_MODE);
11328 }
11329 tw32(MAC_MODE, mac_mode);
11330
11331 /* Wait for link */
11332 for (i = 0; i < 100; i++) {
11333 if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
11334 break;
11335 mdelay(1);
11336 }
11337 }
11338
11339 err = -EIO; 11363 err = -EIO;
11340 11364
11341 tx_len = pktsz; 11365 tx_len = pktsz;
@@ -11547,10 +11571,6 @@ static int tg3_test_loopback(struct tg3 *tp)
11547 tw32(i, 0x0); 11571 tw32(i, 0x0);
11548 } 11572 }
11549 11573
11550 /* Turn off gphy autopowerdown. */
11551 if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
11552 tg3_phy_toggle_apd(tp, false);
11553
11554 /* HW errata - mac loopback fails in some cases on 5780. 11574 /* HW errata - mac loopback fails in some cases on 5780.
11555 * Normal traffic and PHY loopback are not affected by 11575 * Normal traffic and PHY loopback are not affected by
11556 * errata. Also, the MAC loopback test is deprecated for 11576 * errata. Also, the MAC loopback test is deprecated for
@@ -11574,6 +11594,17 @@ static int tg3_test_loopback(struct tg3 *tp)
11574 11594
11575 if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) && 11595 if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
11576 !tg3_flag(tp, USE_PHYLIB)) { 11596 !tg3_flag(tp, USE_PHYLIB)) {
11597 int i;
11598
11599 tg3_phy_lpbk_set(tp, 0);
11600
11601 /* Wait for link */
11602 for (i = 0; i < 100; i++) {
11603 if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
11604 break;
11605 mdelay(1);
11606 }
11607
11577 if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK)) 11608 if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK))
11578 err |= TG3_STD_LOOPBACK_FAILED << 11609 err |= TG3_STD_LOOPBACK_FAILED <<
11579 TG3_PHY_LOOPBACK_SHIFT; 11610 TG3_PHY_LOOPBACK_SHIFT;
@@ -11585,11 +11616,11 @@ static int tg3_test_loopback(struct tg3 *tp)
11585 tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK)) 11616 tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK))
11586 err |= TG3_JMB_LOOPBACK_FAILED << 11617 err |= TG3_JMB_LOOPBACK_FAILED <<
11587 TG3_PHY_LOOPBACK_SHIFT; 11618 TG3_PHY_LOOPBACK_SHIFT;
11588 }
11589 11619
11590 /* Re-enable gphy autopowerdown. */ 11620 /* Re-enable gphy autopowerdown. */
11591 if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD) 11621 if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
11592 tg3_phy_toggle_apd(tp, true); 11622 tg3_phy_toggle_apd(tp, true);
11623 }
11593 11624
11594done: 11625done:
11595 tp->phy_flags |= eee_cap; 11626 tp->phy_flags |= eee_cap;