diff options
author | Michael Chan <mchan@broadcom.com> | 2006-01-23 19:13:22 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-01-23 19:13:22 -0500 |
commit | bc5a0690e917206b423c7b565c997b06675fb572 (patch) | |
tree | f741fe9ac8f40971fb14a1bdac95ce146b005d67 /drivers/net | |
parent | 972ec0d4ba67bf0ec7f00cd93fbac47452f80d25 (diff) |
[BNX2]: Add PHY loopback test
Enhance the ethtool loopback test with PHY loopback test.
Signed-off-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/bnx2.c | 101 |
1 files changed, 79 insertions, 22 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 7be011f37d13..9f71cca81e91 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -1331,6 +1331,38 @@ bnx2_set_mac_loopback(struct bnx2 *bp) | |||
1331 | return 0; | 1331 | return 0; |
1332 | } | 1332 | } |
1333 | 1333 | ||
1334 | static int bnx2_test_link(struct bnx2 *); | ||
1335 | |||
1336 | static int | ||
1337 | bnx2_set_phy_loopback(struct bnx2 *bp) | ||
1338 | { | ||
1339 | u32 mac_mode; | ||
1340 | int rc, i; | ||
1341 | |||
1342 | spin_lock_bh(&bp->phy_lock); | ||
1343 | rc = bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX | | ||
1344 | BMCR_SPEED1000); | ||
1345 | spin_unlock_bh(&bp->phy_lock); | ||
1346 | if (rc) | ||
1347 | return rc; | ||
1348 | |||
1349 | for (i = 0; i < 10; i++) { | ||
1350 | if (bnx2_test_link(bp) == 0) | ||
1351 | break; | ||
1352 | udelay(10); | ||
1353 | } | ||
1354 | |||
1355 | mac_mode = REG_RD(bp, BNX2_EMAC_MODE); | ||
1356 | mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX | | ||
1357 | BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK | | ||
1358 | BNX2_EMAC_MODE_25G); | ||
1359 | |||
1360 | mac_mode |= BNX2_EMAC_MODE_PORT_GMII; | ||
1361 | REG_WR(bp, BNX2_EMAC_MODE, mac_mode); | ||
1362 | bp->link_up = 1; | ||
1363 | return 0; | ||
1364 | } | ||
1365 | |||
1334 | static int | 1366 | static int |
1335 | bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent) | 1367 | bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent) |
1336 | { | 1368 | { |
@@ -3907,26 +3939,33 @@ bnx2_test_memory(struct bnx2 *bp) | |||
3907 | return ret; | 3939 | return ret; |
3908 | } | 3940 | } |
3909 | 3941 | ||
3942 | #define BNX2_MAC_LOOPBACK 0 | ||
3943 | #define BNX2_PHY_LOOPBACK 1 | ||
3944 | |||
3910 | static int | 3945 | static int |
3911 | bnx2_test_loopback(struct bnx2 *bp) | 3946 | bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) |
3912 | { | 3947 | { |
3913 | unsigned int pkt_size, num_pkts, i; | 3948 | unsigned int pkt_size, num_pkts, i; |
3914 | struct sk_buff *skb, *rx_skb; | 3949 | struct sk_buff *skb, *rx_skb; |
3915 | unsigned char *packet; | 3950 | unsigned char *packet; |
3916 | u16 rx_start_idx, rx_idx, send_idx; | 3951 | u16 rx_start_idx, rx_idx; |
3917 | u32 send_bseq, val; | 3952 | u32 val; |
3918 | dma_addr_t map; | 3953 | dma_addr_t map; |
3919 | struct tx_bd *txbd; | 3954 | struct tx_bd *txbd; |
3920 | struct sw_bd *rx_buf; | 3955 | struct sw_bd *rx_buf; |
3921 | struct l2_fhdr *rx_hdr; | 3956 | struct l2_fhdr *rx_hdr; |
3922 | int ret = -ENODEV; | 3957 | int ret = -ENODEV; |
3923 | 3958 | ||
3924 | if (!netif_running(bp->dev)) | 3959 | if (loopback_mode == BNX2_MAC_LOOPBACK) { |
3925 | return -ENODEV; | 3960 | bp->loopback = MAC_LOOPBACK; |
3926 | 3961 | bnx2_set_mac_loopback(bp); | |
3927 | bp->loopback = MAC_LOOPBACK; | 3962 | } |
3928 | bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_DIAG); | 3963 | else if (loopback_mode == BNX2_PHY_LOOPBACK) { |
3929 | bnx2_set_mac_loopback(bp); | 3964 | bp->loopback = 0; |
3965 | bnx2_set_phy_loopback(bp); | ||
3966 | } | ||
3967 | else | ||
3968 | return -EINVAL; | ||
3930 | 3969 | ||
3931 | pkt_size = 1514; | 3970 | pkt_size = 1514; |
3932 | skb = dev_alloc_skb(pkt_size); | 3971 | skb = dev_alloc_skb(pkt_size); |
@@ -3948,11 +3987,9 @@ bnx2_test_loopback(struct bnx2 *bp) | |||
3948 | udelay(5); | 3987 | udelay(5); |
3949 | rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0; | 3988 | rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0; |
3950 | 3989 | ||
3951 | send_idx = 0; | ||
3952 | send_bseq = 0; | ||
3953 | num_pkts = 0; | 3990 | num_pkts = 0; |
3954 | 3991 | ||
3955 | txbd = &bp->tx_desc_ring[send_idx]; | 3992 | txbd = &bp->tx_desc_ring[TX_RING_IDX(bp->tx_prod)]; |
3956 | 3993 | ||
3957 | txbd->tx_bd_haddr_hi = (u64) map >> 32; | 3994 | txbd->tx_bd_haddr_hi = (u64) map >> 32; |
3958 | txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff; | 3995 | txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff; |
@@ -3960,13 +3997,11 @@ bnx2_test_loopback(struct bnx2 *bp) | |||
3960 | txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END; | 3997 | txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END; |
3961 | 3998 | ||
3962 | num_pkts++; | 3999 | num_pkts++; |
3963 | send_idx = NEXT_TX_BD(send_idx); | 4000 | bp->tx_prod = NEXT_TX_BD(bp->tx_prod); |
3964 | 4001 | bp->tx_prod_bseq += pkt_size; | |
3965 | send_bseq += pkt_size; | ||
3966 | |||
3967 | REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, send_idx); | ||
3968 | REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, send_bseq); | ||
3969 | 4002 | ||
4003 | REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, bp->tx_prod); | ||
4004 | REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, bp->tx_prod_bseq); | ||
3970 | 4005 | ||
3971 | udelay(100); | 4006 | udelay(100); |
3972 | 4007 | ||
@@ -3979,7 +4014,7 @@ bnx2_test_loopback(struct bnx2 *bp) | |||
3979 | pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE); | 4014 | pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE); |
3980 | dev_kfree_skb_irq(skb); | 4015 | dev_kfree_skb_irq(skb); |
3981 | 4016 | ||
3982 | if (bp->status_blk->status_tx_quick_consumer_index0 != send_idx) { | 4017 | if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) { |
3983 | goto loopback_test_done; | 4018 | goto loopback_test_done; |
3984 | } | 4019 | } |
3985 | 4020 | ||
@@ -4025,6 +4060,30 @@ loopback_test_done: | |||
4025 | return ret; | 4060 | return ret; |
4026 | } | 4061 | } |
4027 | 4062 | ||
4063 | #define BNX2_MAC_LOOPBACK_FAILED 1 | ||
4064 | #define BNX2_PHY_LOOPBACK_FAILED 2 | ||
4065 | #define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \ | ||
4066 | BNX2_PHY_LOOPBACK_FAILED) | ||
4067 | |||
4068 | static int | ||
4069 | bnx2_test_loopback(struct bnx2 *bp) | ||
4070 | { | ||
4071 | int rc = 0; | ||
4072 | |||
4073 | if (!netif_running(bp->dev)) | ||
4074 | return BNX2_LOOPBACK_FAILED; | ||
4075 | |||
4076 | bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET); | ||
4077 | spin_lock_bh(&bp->phy_lock); | ||
4078 | bnx2_init_phy(bp); | ||
4079 | spin_unlock_bh(&bp->phy_lock); | ||
4080 | if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK)) | ||
4081 | rc |= BNX2_MAC_LOOPBACK_FAILED; | ||
4082 | if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK)) | ||
4083 | rc |= BNX2_PHY_LOOPBACK_FAILED; | ||
4084 | return rc; | ||
4085 | } | ||
4086 | |||
4028 | #define NVRAM_SIZE 0x200 | 4087 | #define NVRAM_SIZE 0x200 |
4029 | #define CRC32_RESIDUAL 0xdebb20e3 | 4088 | #define CRC32_RESIDUAL 0xdebb20e3 |
4030 | 4089 | ||
@@ -5169,10 +5228,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) | |||
5169 | buf[1] = 1; | 5228 | buf[1] = 1; |
5170 | etest->flags |= ETH_TEST_FL_FAILED; | 5229 | etest->flags |= ETH_TEST_FL_FAILED; |
5171 | } | 5230 | } |
5172 | if (bnx2_test_loopback(bp) != 0) { | 5231 | if ((buf[2] = bnx2_test_loopback(bp)) != 0) |
5173 | buf[2] = 1; | ||
5174 | etest->flags |= ETH_TEST_FL_FAILED; | 5232 | etest->flags |= ETH_TEST_FL_FAILED; |
5175 | } | ||
5176 | 5233 | ||
5177 | if (!netif_running(bp->dev)) { | 5234 | if (!netif_running(bp->dev)) { |
5178 | bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); | 5235 | bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); |