aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2011-08-19 09:58:23 -0400
committerDavid S. Miller <davem@davemloft.net>2011-08-20 13:34:27 -0400
commit941ec90f35603f35466988efd01395377fd00475 (patch)
tree4ebf6850d3ce27967cf382d594c54b435c051080 /drivers/net
parent28a4595786a64fb51d41c0bad819256198525e49 (diff)
tg3: Add external loopback support to selftest
This patch adds external loopback support to tg3's ethtool selftest. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Reviewed-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c97
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h3
2 files changed, 90 insertions, 10 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 177fbaf67082..e42c4fe68929 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -396,6 +396,7 @@ static const struct {
396 { "memory test (offline)" }, 396 { "memory test (offline)" },
397 { "mac loopback test (offline)" }, 397 { "mac loopback test (offline)" },
398 { "phy loopback test (offline)" }, 398 { "phy loopback test (offline)" },
399 { "ext loopback test (offline)" },
399 { "interrupt test (offline)" }, 400 { "interrupt test (offline)" },
400}; 401};
401 402
@@ -1680,6 +1681,36 @@ static void tg3_phy_fini(struct tg3 *tp)
1680 } 1681 }
1681} 1682}
1682 1683
1684static int tg3_phy_set_extloopbk(struct tg3 *tp)
1685{
1686 int err;
1687 u32 val;
1688
1689 if (tp->phy_flags & TG3_PHYFLG_IS_FET)
1690 return 0;
1691
1692 if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
1693 /* Cannot do read-modify-write on 5401 */
1694 err = tg3_phy_auxctl_write(tp,
1695 MII_TG3_AUXCTL_SHDWSEL_AUXCTL,
1696 MII_TG3_AUXCTL_ACTL_EXTLOOPBK |
1697 0x4c20);
1698 goto done;
1699 }
1700
1701 err = tg3_phy_auxctl_read(tp,
1702 MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val);
1703 if (err)
1704 return err;
1705
1706 val |= MII_TG3_AUXCTL_ACTL_EXTLOOPBK;
1707 err = tg3_phy_auxctl_write(tp,
1708 MII_TG3_AUXCTL_SHDWSEL_AUXCTL, val);
1709
1710done:
1711 return err;
1712}
1713
1683static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable) 1714static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable)
1684{ 1715{
1685 u32 phytest; 1716 u32 phytest;
@@ -6371,14 +6402,17 @@ static void tg3_mac_loopback(struct tg3 *tp, bool enable)
6371 udelay(40); 6402 udelay(40);
6372} 6403}
6373 6404
6374static void tg3_phy_lpbk_set(struct tg3 *tp, u32 speed) 6405static int tg3_phy_lpbk_set(struct tg3 *tp, u32 speed, bool extlpbk)
6375{ 6406{
6376 u32 val, bmcr, mac_mode; 6407 u32 val, bmcr, mac_mode, ptest = 0;
6377 6408
6378 tg3_phy_toggle_apd(tp, false); 6409 tg3_phy_toggle_apd(tp, false);
6379 tg3_phy_toggle_automdix(tp, 0); 6410 tg3_phy_toggle_automdix(tp, 0);
6380 6411
6381 bmcr = BMCR_LOOPBACK | BMCR_FULLDPLX; 6412 if (extlpbk && tg3_phy_set_extloopbk(tp))
6413 return -EIO;
6414
6415 bmcr = BMCR_FULLDPLX;
6382 switch (speed) { 6416 switch (speed) {
6383 case SPEED_10: 6417 case SPEED_10:
6384 break; 6418 break;
@@ -6396,6 +6430,20 @@ static void tg3_phy_lpbk_set(struct tg3 *tp, u32 speed)
6396 } 6430 }
6397 } 6431 }
6398 6432
6433 if (extlpbk) {
6434 if (!(tp->phy_flags & TG3_PHYFLG_IS_FET)) {
6435 tg3_readphy(tp, MII_CTRL1000, &val);
6436 val |= CTL1000_AS_MASTER |
6437 CTL1000_ENABLE_MASTER;
6438 tg3_writephy(tp, MII_CTRL1000, val);
6439 } else {
6440 ptest = MII_TG3_FET_PTEST_TRIM_SEL |
6441 MII_TG3_FET_PTEST_TRIM_2;
6442 tg3_writephy(tp, MII_TG3_FET_PTEST, ptest);
6443 }
6444 } else
6445 bmcr |= BMCR_LOOPBACK;
6446
6399 tg3_writephy(tp, MII_BMCR, bmcr); 6447 tg3_writephy(tp, MII_BMCR, bmcr);
6400 6448
6401 /* The write needs to be flushed for the FETs */ 6449 /* The write needs to be flushed for the FETs */
@@ -6406,7 +6454,7 @@ static void tg3_phy_lpbk_set(struct tg3 *tp, u32 speed)
6406 6454
6407 if ((tp->phy_flags & TG3_PHYFLG_IS_FET) && 6455 if ((tp->phy_flags & TG3_PHYFLG_IS_FET) &&
6408 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { 6456 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
6409 tg3_writephy(tp, MII_TG3_FET_PTEST, 6457 tg3_writephy(tp, MII_TG3_FET_PTEST, ptest |
6410 MII_TG3_FET_PTEST_FRC_TX_LINK | 6458 MII_TG3_FET_PTEST_FRC_TX_LINK |
6411 MII_TG3_FET_PTEST_FRC_TX_LOCK); 6459 MII_TG3_FET_PTEST_FRC_TX_LOCK);
6412 6460
@@ -6443,6 +6491,8 @@ static void tg3_phy_lpbk_set(struct tg3 *tp, u32 speed)
6443 6491
6444 tw32(MAC_MODE, mac_mode); 6492 tw32(MAC_MODE, mac_mode);
6445 udelay(40); 6493 udelay(40);
6494
6495 return 0;
6446} 6496}
6447 6497
6448static void tg3_set_loopback(struct net_device *dev, u32 features) 6498static void tg3_set_loopback(struct net_device *dev, u32 features)
@@ -11542,7 +11592,7 @@ out:
11542 TG3_JMB_LOOPBACK_FAILED | \ 11592 TG3_JMB_LOOPBACK_FAILED | \
11543 TG3_TSO_LOOPBACK_FAILED) 11593 TG3_TSO_LOOPBACK_FAILED)
11544 11594
11545static int tg3_test_loopback(struct tg3 *tp, u64 *data) 11595static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
11546{ 11596{
11547 int err = -EIO; 11597 int err = -EIO;
11548 u32 eee_cap; 11598 u32 eee_cap;
@@ -11553,6 +11603,8 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data)
11553 if (!netif_running(tp->dev)) { 11603 if (!netif_running(tp->dev)) {
11554 data[0] = TG3_LOOPBACK_FAILED; 11604 data[0] = TG3_LOOPBACK_FAILED;
11555 data[1] = TG3_LOOPBACK_FAILED; 11605 data[1] = TG3_LOOPBACK_FAILED;
11606 if (do_extlpbk)
11607 data[2] = TG3_LOOPBACK_FAILED;
11556 goto done; 11608 goto done;
11557 } 11609 }
11558 11610
@@ -11560,6 +11612,8 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data)
11560 if (err) { 11612 if (err) {
11561 data[0] = TG3_LOOPBACK_FAILED; 11613 data[0] = TG3_LOOPBACK_FAILED;
11562 data[1] = TG3_LOOPBACK_FAILED; 11614 data[1] = TG3_LOOPBACK_FAILED;
11615 if (do_extlpbk)
11616 data[2] = TG3_LOOPBACK_FAILED;
11563 goto done; 11617 goto done;
11564 } 11618 }
11565 11619
@@ -11595,7 +11649,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data)
11595 !tg3_flag(tp, USE_PHYLIB)) { 11649 !tg3_flag(tp, USE_PHYLIB)) {
11596 int i; 11650 int i;
11597 11651
11598 tg3_phy_lpbk_set(tp, 0); 11652 tg3_phy_lpbk_set(tp, 0, false);
11599 11653
11600 /* Wait for link */ 11654 /* Wait for link */
11601 for (i = 0; i < 100; i++) { 11655 for (i = 0; i < 100; i++) {
@@ -11613,12 +11667,31 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data)
11613 tg3_run_loopback(tp, 9000 + ETH_HLEN, false)) 11667 tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
11614 data[1] |= TG3_JMB_LOOPBACK_FAILED; 11668 data[1] |= TG3_JMB_LOOPBACK_FAILED;
11615 11669
11670 if (do_extlpbk) {
11671 tg3_phy_lpbk_set(tp, 0, true);
11672
11673 /* All link indications report up, but the hardware
11674 * isn't really ready for about 20 msec. Double it
11675 * to be sure.
11676 */
11677 mdelay(40);
11678
11679 if (tg3_run_loopback(tp, ETH_FRAME_LEN, false))
11680 data[2] |= TG3_STD_LOOPBACK_FAILED;
11681 if (tg3_flag(tp, TSO_CAPABLE) &&
11682 tg3_run_loopback(tp, ETH_FRAME_LEN, true))
11683 data[2] |= TG3_TSO_LOOPBACK_FAILED;
11684 if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
11685 tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
11686 data[2] |= TG3_JMB_LOOPBACK_FAILED;
11687 }
11688
11616 /* Re-enable gphy autopowerdown. */ 11689 /* Re-enable gphy autopowerdown. */
11617 if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD) 11690 if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
11618 tg3_phy_toggle_apd(tp, true); 11691 tg3_phy_toggle_apd(tp, true);
11619 } 11692 }
11620 11693
11621 err = (data[0] | data[1]) ? -EIO : 0; 11694 err = (data[0] | data[1] | data[2]) ? -EIO : 0;
11622 11695
11623done: 11696done:
11624 tp->phy_flags |= eee_cap; 11697 tp->phy_flags |= eee_cap;
@@ -11630,6 +11703,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
11630 u64 *data) 11703 u64 *data)
11631{ 11704{
11632 struct tg3 *tp = netdev_priv(dev); 11705 struct tg3 *tp = netdev_priv(dev);
11706 bool doextlpbk = etest->flags & ETH_TEST_FL_EXTERNAL_LB;
11633 11707
11634 if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) && 11708 if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) &&
11635 tg3_power_up(tp)) { 11709 tg3_power_up(tp)) {
@@ -11644,7 +11718,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
11644 etest->flags |= ETH_TEST_FL_FAILED; 11718 etest->flags |= ETH_TEST_FL_FAILED;
11645 data[0] = 1; 11719 data[0] = 1;
11646 } 11720 }
11647 if (tg3_test_link(tp) != 0) { 11721 if (!doextlpbk && tg3_test_link(tp)) {
11648 etest->flags |= ETH_TEST_FL_FAILED; 11722 etest->flags |= ETH_TEST_FL_FAILED;
11649 data[1] = 1; 11723 data[1] = 1;
11650 } 11724 }
@@ -11680,14 +11754,17 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
11680 data[3] = 1; 11754 data[3] = 1;
11681 } 11755 }
11682 11756
11683 if (tg3_test_loopback(tp, &data[4])) 11757 if (doextlpbk)
11758 etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
11759
11760 if (tg3_test_loopback(tp, &data[4], doextlpbk))
11684 etest->flags |= ETH_TEST_FL_FAILED; 11761 etest->flags |= ETH_TEST_FL_FAILED;
11685 11762
11686 tg3_full_unlock(tp); 11763 tg3_full_unlock(tp);
11687 11764
11688 if (tg3_test_interrupt(tp) != 0) { 11765 if (tg3_test_interrupt(tp) != 0) {
11689 etest->flags |= ETH_TEST_FL_FAILED; 11766 etest->flags |= ETH_TEST_FL_FAILED;
11690 data[6] = 1; 11767 data[7] = 1;
11691 } 11768 }
11692 11769
11693 tg3_full_lock(tp, 0); 11770 tg3_full_lock(tp, 0);
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 2ea456dd5880..d2976f39b2fc 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2197,6 +2197,7 @@
2197#define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400 2197#define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400
2198#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800 2198#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800
2199#define MII_TG3_AUXCTL_ACTL_EXTPKTLEN 0x4000 2199#define MII_TG3_AUXCTL_ACTL_EXTPKTLEN 0x4000
2200#define MII_TG3_AUXCTL_ACTL_EXTLOOPBK 0x8000
2200 2201
2201#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002 2202#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002
2202#define MII_TG3_AUXCTL_PCTL_WOL_EN 0x0008 2203#define MII_TG3_AUXCTL_PCTL_WOL_EN 0x0008
@@ -2262,6 +2263,8 @@
2262 2263
2263/* Fast Ethernet Tranceiver definitions */ 2264/* Fast Ethernet Tranceiver definitions */
2264#define MII_TG3_FET_PTEST 0x17 2265#define MII_TG3_FET_PTEST 0x17
2266#define MII_TG3_FET_PTEST_TRIM_SEL 0x0010
2267#define MII_TG3_FET_PTEST_TRIM_2 0x0002
2265#define MII_TG3_FET_PTEST_FRC_TX_LINK 0x1000 2268#define MII_TG3_FET_PTEST_FRC_TX_LINK 0x1000
2266#define MII_TG3_FET_PTEST_FRC_TX_LOCK 0x0800 2269#define MII_TG3_FET_PTEST_FRC_TX_LOCK 0x0800
2267 2270