Skip to content

Commit 7235ffa

Browse files
vishalsdkdavem330
authored andcommitted
cxgb4: add loopback ethtool self-test
In this test, loopback pkt is created and sent on default queue. The packet goes until the Multi Port Switch (MPS) just before the MAC and based on the specified channel number, it either goes outside the wire on one of the physical ports or looped back to Rx path by MPS. In this case, we're specifying loopback channel, instead of physical ports, so the packet gets looped back to Rx path, instead of getting transmitted on the wire. v3: - Modify commit message to include test details. v2: - Add only loopback self-test. Signed-off-by: Vishal Kulkarni <vishal@chelsio.com> Acked-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 15be4ea commit 7235ffa

File tree

3 files changed

+166
-1
lines changed

3 files changed

+166
-1
lines changed

drivers/net/ethernet/chelsio/cxgb4/cxgb4.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,12 @@ static inline struct mbox_cmd *mbox_cmd_log_entry(struct mbox_cmd_log *log,
532532
FW_HDR_FW_VER_BUILD_G(chip##FW_VERSION_BUILD))
533533
#define FW_INTFVER(chip, intf) (FW_HDR_INTFVER_##intf)
534534

535+
struct cxgb4_ethtool_lb_test {
536+
struct completion completion;
537+
int result;
538+
int loopback;
539+
};
540+
535541
struct fw_info {
536542
u8 chip;
537543
char *fs_name;
@@ -685,6 +691,7 @@ struct port_info {
685691
u16 nmirrorqsets;
686692
u32 vi_mirror_count;
687693
struct mutex vi_mirror_mutex; /* Sync access to Mirror VI info */
694+
struct cxgb4_ethtool_lb_test ethtool_lb;
688695
};
689696

690697
struct dentry;
@@ -1595,6 +1602,7 @@ void t4_free_sge_resources(struct adapter *adap);
15951602
void t4_free_ofld_rxqs(struct adapter *adap, int n, struct sge_ofld_rxq *q);
15961603
irq_handler_t t4_intr_handler(struct adapter *adap);
15971604
netdev_tx_t t4_start_xmit(struct sk_buff *skb, struct net_device *dev);
1605+
int cxgb4_selftest_lb_pkt(struct net_device *netdev);
15981606
int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
15991607
const struct pkt_gl *gl);
16001608
int t4_mgmt_tx(struct adapter *adap, struct sk_buff *skb);

drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ static void set_msglevel(struct net_device *dev, u32 val)
2525
netdev2adap(dev)->msg_enable = val;
2626
}
2727

28+
enum cxgb4_ethtool_tests {
29+
CXGB4_ETHTOOL_LB_TEST,
30+
CXGB4_ETHTOOL_MAX_TEST,
31+
};
32+
33+
static const char cxgb4_selftest_strings[CXGB4_ETHTOOL_MAX_TEST][ETH_GSTRING_LEN] = {
34+
"Loop back test",
35+
};
36+
2837
static const char * const flash_region_strings[] = {
2938
"All",
3039
"Firmware",
@@ -166,6 +175,8 @@ static int get_sset_count(struct net_device *dev, int sset)
166175
ARRAY_SIZE(loopback_stats_strings);
167176
case ETH_SS_PRIV_FLAGS:
168177
return ARRAY_SIZE(cxgb4_priv_flags_strings);
178+
case ETH_SS_TEST:
179+
return ARRAY_SIZE(cxgb4_selftest_strings);
169180
default:
170181
return -EOPNOTSUPP;
171182
}
@@ -228,6 +239,9 @@ static void get_strings(struct net_device *dev, u32 stringset, u8 *data)
228239
} else if (stringset == ETH_SS_PRIV_FLAGS) {
229240
memcpy(data, cxgb4_priv_flags_strings,
230241
sizeof(cxgb4_priv_flags_strings));
242+
} else if (stringset == ETH_SS_TEST) {
243+
memcpy(data, cxgb4_selftest_strings,
244+
sizeof(cxgb4_selftest_strings));
231245
}
232246
}
233247

@@ -2056,6 +2070,43 @@ static int cxgb4_set_priv_flags(struct net_device *netdev, u32 flags)
20562070
return 0;
20572071
}
20582072

2073+
static void cxgb4_lb_test(struct net_device *netdev, u64 *lb_status)
2074+
{
2075+
int dev_state = netif_running(netdev);
2076+
2077+
if (dev_state) {
2078+
netif_tx_stop_all_queues(netdev);
2079+
netif_carrier_off(netdev);
2080+
}
2081+
2082+
*lb_status = cxgb4_selftest_lb_pkt(netdev);
2083+
2084+
if (dev_state) {
2085+
netif_tx_start_all_queues(netdev);
2086+
netif_carrier_on(netdev);
2087+
}
2088+
}
2089+
2090+
static void cxgb4_self_test(struct net_device *netdev,
2091+
struct ethtool_test *eth_test, u64 *data)
2092+
{
2093+
struct port_info *pi = netdev_priv(netdev);
2094+
struct adapter *adap = pi->adapter;
2095+
2096+
memset(data, 0, sizeof(u64) * CXGB4_ETHTOOL_MAX_TEST);
2097+
2098+
if (!(adap->flags & CXGB4_FW_OK)) {
2099+
eth_test->flags |= ETH_TEST_FL_FAILED;
2100+
return;
2101+
}
2102+
2103+
if (eth_test->flags == ETH_TEST_FL_OFFLINE)
2104+
cxgb4_lb_test(netdev, &data[CXGB4_ETHTOOL_LB_TEST]);
2105+
2106+
if (data[CXGB4_ETHTOOL_LB_TEST])
2107+
eth_test->flags |= ETH_TEST_FL_FAILED;
2108+
}
2109+
20592110
static const struct ethtool_ops cxgb_ethtool_ops = {
20602111
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
20612112
ETHTOOL_COALESCE_RX_MAX_FRAMES |
@@ -2090,6 +2141,7 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
20902141
.get_rxfh_indir_size = get_rss_table_size,
20912142
.get_rxfh = get_rss_table,
20922143
.set_rxfh = set_rss_table,
2144+
.self_test = cxgb4_self_test,
20932145
.flash_device = set_flash,
20942146
.get_ts_info = get_ts_info,
20952147
.set_dump = set_dump,

drivers/net/ethernet/chelsio/cxgb4/sge.c

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2537,6 +2537,80 @@ static void ctrlq_check_stop(struct sge_ctrl_txq *q, struct fw_wr_hdr *wr)
25372537
}
25382538
}
25392539

2540+
#define CXGB4_SELFTEST_LB_STR "CHELSIO_SELFTEST"
2541+
2542+
int cxgb4_selftest_lb_pkt(struct net_device *netdev)
2543+
{
2544+
struct port_info *pi = netdev_priv(netdev);
2545+
struct adapter *adap = pi->adapter;
2546+
struct cxgb4_ethtool_lb_test *lb;
2547+
int ret, i = 0, pkt_len, credits;
2548+
struct fw_eth_tx_pkt_wr *wr;
2549+
struct cpl_tx_pkt_core *cpl;
2550+
u32 ctrl0, ndesc, flits;
2551+
struct sge_eth_txq *q;
2552+
u8 *sgl;
2553+
2554+
pkt_len = ETH_HLEN + sizeof(CXGB4_SELFTEST_LB_STR);
2555+
2556+
flits = DIV_ROUND_UP(pkt_len + sizeof(struct cpl_tx_pkt) +
2557+
sizeof(*wr), sizeof(__be64));
2558+
ndesc = flits_to_desc(flits);
2559+
2560+
lb = &pi->ethtool_lb;
2561+
lb->loopback = 1;
2562+
2563+
q = &adap->sge.ethtxq[pi->first_qset];
2564+
2565+
reclaim_completed_tx(adap, &q->q, -1, true);
2566+
credits = txq_avail(&q->q) - ndesc;
2567+
if (unlikely(credits < 0))
2568+
return -ENOMEM;
2569+
2570+
wr = (void *)&q->q.desc[q->q.pidx];
2571+
memset(wr, 0, sizeof(struct tx_desc));
2572+
2573+
wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) |
2574+
FW_WR_IMMDLEN_V(pkt_len +
2575+
sizeof(*cpl)));
2576+
wr->equiq_to_len16 = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(flits, 2)));
2577+
wr->r3 = cpu_to_be64(0);
2578+
2579+
cpl = (void *)(wr + 1);
2580+
sgl = (u8 *)(cpl + 1);
2581+
2582+
ctrl0 = TXPKT_OPCODE_V(CPL_TX_PKT_XT) | TXPKT_PF_V(adap->pf) |
2583+
TXPKT_INTF_V(pi->tx_chan + 4);
2584+
2585+
cpl->ctrl0 = htonl(ctrl0);
2586+
cpl->pack = htons(0);
2587+
cpl->len = htons(pkt_len);
2588+
cpl->ctrl1 = cpu_to_be64(TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F);
2589+
2590+
eth_broadcast_addr(sgl);
2591+
i += ETH_ALEN;
2592+
ether_addr_copy(&sgl[i], netdev->dev_addr);
2593+
i += ETH_ALEN;
2594+
2595+
snprintf(&sgl[i], sizeof(CXGB4_SELFTEST_LB_STR), "%s",
2596+
CXGB4_SELFTEST_LB_STR);
2597+
2598+
init_completion(&lb->completion);
2599+
txq_advance(&q->q, ndesc);
2600+
cxgb4_ring_tx_db(adap, &q->q, ndesc);
2601+
2602+
/* wait for the pkt to return */
2603+
ret = wait_for_completion_timeout(&lb->completion, 10 * HZ);
2604+
if (!ret)
2605+
ret = -ETIMEDOUT;
2606+
else
2607+
ret = lb->result;
2608+
2609+
lb->loopback = 0;
2610+
2611+
return ret;
2612+
}
2613+
25402614
/**
25412615
* ctrl_xmit - send a packet through an SGE control Tx queue
25422616
* @q: the control queue
@@ -3413,6 +3487,31 @@ static void t4_tx_completion_handler(struct sge_rspq *rspq,
34133487
t4_sge_eth_txq_egress_update(adapter, txq, -1);
34143488
}
34153489

3490+
static int cxgb4_validate_lb_pkt(struct port_info *pi, const struct pkt_gl *si)
3491+
{
3492+
struct adapter *adap = pi->adapter;
3493+
struct cxgb4_ethtool_lb_test *lb;
3494+
struct sge *s = &adap->sge;
3495+
struct net_device *netdev;
3496+
u8 *data;
3497+
int i;
3498+
3499+
netdev = adap->port[pi->port_id];
3500+
lb = &pi->ethtool_lb;
3501+
data = si->va + s->pktshift;
3502+
3503+
i = ETH_ALEN;
3504+
if (!ether_addr_equal(data + i, netdev->dev_addr))
3505+
return -1;
3506+
3507+
i += ETH_ALEN;
3508+
if (strcmp(&data[i], CXGB4_SELFTEST_LB_STR))
3509+
lb->result = -EIO;
3510+
3511+
complete(&lb->completion);
3512+
return 0;
3513+
}
3514+
34163515
/**
34173516
* t4_ethrx_handler - process an ingress ethernet packet
34183517
* @q: the response queue that received the packet
@@ -3436,6 +3535,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
34363535
struct port_info *pi;
34373536
int ret = 0;
34383537

3538+
pi = netdev_priv(q->netdev);
34393539
/* If we're looking at TX Queue CIDX Update, handle that separately
34403540
* and return.
34413541
*/
@@ -3463,6 +3563,12 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
34633563
if (err_vec)
34643564
rxq->stats.bad_rx_pkts++;
34653565

3566+
if (unlikely(pi->ethtool_lb.loopback && pkt->iff >= NCHAN)) {
3567+
ret = cxgb4_validate_lb_pkt(pi, si);
3568+
if (!ret)
3569+
return 0;
3570+
}
3571+
34663572
if (((pkt->l2info & htonl(RXF_TCP_F)) ||
34673573
tnl_hdr_len) &&
34683574
(q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) {
@@ -3476,7 +3582,6 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
34763582
rxq->stats.rx_drops++;
34773583
return 0;
34783584
}
3479-
pi = netdev_priv(q->netdev);
34803585

34813586
/* Handle PTP Event Rx packet */
34823587
if (unlikely(pi->ptp_enable)) {

0 commit comments

Comments
 (0)