diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2011-08-19 09:58:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-08-20 13:34:27 -0400 |
commit | 941ec90f35603f35466988efd01395377fd00475 (patch) | |
tree | 4ebf6850d3ce27967cf382d594c54b435c051080 /drivers/net | |
parent | 28a4595786a64fb51d41c0bad819256198525e49 (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.c | 97 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.h | 3 |
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 | ||
1684 | static 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 | |||
1710 | done: | ||
1711 | return err; | ||
1712 | } | ||
1713 | |||
1683 | static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable) | 1714 | static 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 | ||
6374 | static void tg3_phy_lpbk_set(struct tg3 *tp, u32 speed) | 6405 | static 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 | ||
6448 | static void tg3_set_loopback(struct net_device *dev, u32 features) | 6498 | static 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 | ||
11545 | static int tg3_test_loopback(struct tg3 *tp, u64 *data) | 11595 | static 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 | ||
11623 | done: | 11696 | done: |
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 | ||