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

[BNX2]: Add PHY loopback test

Enhance the ethtool loopback test with PHY loopback test.
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 972ec0d4
...@@ -1331,6 +1331,38 @@ bnx2_set_mac_loopback(struct bnx2 *bp) ...@@ -1331,6 +1331,38 @@ bnx2_set_mac_loopback(struct bnx2 *bp)
return 0; return 0;
} }
static int bnx2_test_link(struct bnx2 *);
static int
bnx2_set_phy_loopback(struct bnx2 *bp)
{
u32 mac_mode;
int rc, i;
spin_lock_bh(&bp->phy_lock);
rc = bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
BMCR_SPEED1000);
spin_unlock_bh(&bp->phy_lock);
if (rc)
return rc;
for (i = 0; i < 10; i++) {
if (bnx2_test_link(bp) == 0)
break;
udelay(10);
}
mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
BNX2_EMAC_MODE_25G);
mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
bp->link_up = 1;
return 0;
}
static int static int
bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent) bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
{ {
...@@ -3907,26 +3939,33 @@ bnx2_test_memory(struct bnx2 *bp) ...@@ -3907,26 +3939,33 @@ bnx2_test_memory(struct bnx2 *bp)
return ret; return ret;
} }
#define BNX2_MAC_LOOPBACK 0
#define BNX2_PHY_LOOPBACK 1
static int static int
bnx2_test_loopback(struct bnx2 *bp) bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
{ {
unsigned int pkt_size, num_pkts, i; unsigned int pkt_size, num_pkts, i;
struct sk_buff *skb, *rx_skb; struct sk_buff *skb, *rx_skb;
unsigned char *packet; unsigned char *packet;
u16 rx_start_idx, rx_idx, send_idx; u16 rx_start_idx, rx_idx;
u32 send_bseq, val; u32 val;
dma_addr_t map; dma_addr_t map;
struct tx_bd *txbd; struct tx_bd *txbd;
struct sw_bd *rx_buf; struct sw_bd *rx_buf;
struct l2_fhdr *rx_hdr; struct l2_fhdr *rx_hdr;
int ret = -ENODEV; int ret = -ENODEV;
if (!netif_running(bp->dev)) if (loopback_mode == BNX2_MAC_LOOPBACK) {
return -ENODEV;
bp->loopback = MAC_LOOPBACK; bp->loopback = MAC_LOOPBACK;
bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_DIAG);
bnx2_set_mac_loopback(bp); bnx2_set_mac_loopback(bp);
}
else if (loopback_mode == BNX2_PHY_LOOPBACK) {
bp->loopback = 0;
bnx2_set_phy_loopback(bp);
}
else
return -EINVAL;
pkt_size = 1514; pkt_size = 1514;
skb = dev_alloc_skb(pkt_size); skb = dev_alloc_skb(pkt_size);
...@@ -3948,11 +3987,9 @@ bnx2_test_loopback(struct bnx2 *bp) ...@@ -3948,11 +3987,9 @@ bnx2_test_loopback(struct bnx2 *bp)
udelay(5); udelay(5);
rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0; rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0;
send_idx = 0;
send_bseq = 0;
num_pkts = 0; num_pkts = 0;
txbd = &bp->tx_desc_ring[send_idx]; txbd = &bp->tx_desc_ring[TX_RING_IDX(bp->tx_prod)];
txbd->tx_bd_haddr_hi = (u64) map >> 32; txbd->tx_bd_haddr_hi = (u64) map >> 32;
txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff; txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
...@@ -3960,13 +3997,11 @@ bnx2_test_loopback(struct bnx2 *bp) ...@@ -3960,13 +3997,11 @@ bnx2_test_loopback(struct bnx2 *bp)
txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END; txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
num_pkts++; num_pkts++;
send_idx = NEXT_TX_BD(send_idx); bp->tx_prod = NEXT_TX_BD(bp->tx_prod);
bp->tx_prod_bseq += pkt_size;
send_bseq += pkt_size;
REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, send_idx);
REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, send_bseq);
REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, bp->tx_prod);
REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, bp->tx_prod_bseq);
udelay(100); udelay(100);
...@@ -3979,7 +4014,7 @@ bnx2_test_loopback(struct bnx2 *bp) ...@@ -3979,7 +4014,7 @@ bnx2_test_loopback(struct bnx2 *bp)
pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE); pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
if (bp->status_blk->status_tx_quick_consumer_index0 != send_idx) { if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) {
goto loopback_test_done; goto loopback_test_done;
} }
...@@ -4025,6 +4060,30 @@ bnx2_test_loopback(struct bnx2 *bp) ...@@ -4025,6 +4060,30 @@ bnx2_test_loopback(struct bnx2 *bp)
return ret; return ret;
} }
#define BNX2_MAC_LOOPBACK_FAILED 1
#define BNX2_PHY_LOOPBACK_FAILED 2
#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
BNX2_PHY_LOOPBACK_FAILED)
static int
bnx2_test_loopback(struct bnx2 *bp)
{
int rc = 0;
if (!netif_running(bp->dev))
return BNX2_LOOPBACK_FAILED;
bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
spin_lock_bh(&bp->phy_lock);
bnx2_init_phy(bp);
spin_unlock_bh(&bp->phy_lock);
if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
rc |= BNX2_MAC_LOOPBACK_FAILED;
if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
rc |= BNX2_PHY_LOOPBACK_FAILED;
return rc;
}
#define NVRAM_SIZE 0x200 #define NVRAM_SIZE 0x200
#define CRC32_RESIDUAL 0xdebb20e3 #define CRC32_RESIDUAL 0xdebb20e3
...@@ -5169,10 +5228,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) ...@@ -5169,10 +5228,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
buf[1] = 1; buf[1] = 1;
etest->flags |= ETH_TEST_FL_FAILED; etest->flags |= ETH_TEST_FL_FAILED;
} }
if (bnx2_test_loopback(bp) != 0) { if ((buf[2] = bnx2_test_loopback(bp)) != 0)
buf[2] = 1;
etest->flags |= ETH_TEST_FL_FAILED; etest->flags |= ETH_TEST_FL_FAILED;
}
if (!netif_running(bp->dev)) { if (!netif_running(bp->dev)) {
bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
......
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