xref: /linux/drivers/net/ethernet/amd/xgbe/xgbe-selftest.c (revision 862a64c83faf7708e7e79498193ff5270543a68d)
1*862a64c8SRaju Rangoju // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
2*862a64c8SRaju Rangoju /*
3*862a64c8SRaju Rangoju  * Copyright (c) 2014-2025, Advanced Micro Devices, Inc.
4*862a64c8SRaju Rangoju  * Copyright (c) 2014, Synopsys, Inc.
5*862a64c8SRaju Rangoju  * All rights reserved
6*862a64c8SRaju Rangoju  *
7*862a64c8SRaju Rangoju  * Author: Raju Rangoju <Raju.Rangoju@amd.com>
8*862a64c8SRaju Rangoju  */
9*862a64c8SRaju Rangoju #include <linux/crc32.h>
10*862a64c8SRaju Rangoju #include <linux/ip.h>
11*862a64c8SRaju Rangoju #include <linux/udp.h>
12*862a64c8SRaju Rangoju #include <net/tcp.h>
13*862a64c8SRaju Rangoju #include <net/udp.h>
14*862a64c8SRaju Rangoju #include <net/checksum.h>
15*862a64c8SRaju Rangoju #include <net/selftests.h>
16*862a64c8SRaju Rangoju 
17*862a64c8SRaju Rangoju #include "xgbe.h"
18*862a64c8SRaju Rangoju #include "xgbe-common.h"
19*862a64c8SRaju Rangoju 
20*862a64c8SRaju Rangoju #define XGBE_LOOPBACK_NONE	0
21*862a64c8SRaju Rangoju #define XGBE_LOOPBACK_MAC	1
22*862a64c8SRaju Rangoju 
23*862a64c8SRaju Rangoju struct xgbe_test {
24*862a64c8SRaju Rangoju 	char name[ETH_GSTRING_LEN];
25*862a64c8SRaju Rangoju 	int lb;
26*862a64c8SRaju Rangoju 	int (*fn)(struct xgbe_prv_data *pdata);
27*862a64c8SRaju Rangoju };
28*862a64c8SRaju Rangoju 
29*862a64c8SRaju Rangoju static u8 xgbe_test_id;
30*862a64c8SRaju Rangoju 
31*862a64c8SRaju Rangoju static int xgbe_test_loopback_validate(struct sk_buff *skb,
32*862a64c8SRaju Rangoju 				       struct net_device *ndev,
33*862a64c8SRaju Rangoju 				       struct packet_type *pt,
34*862a64c8SRaju Rangoju 				       struct net_device *orig_ndev)
35*862a64c8SRaju Rangoju {
36*862a64c8SRaju Rangoju 	struct net_test_priv *tdata = pt->af_packet_priv;
37*862a64c8SRaju Rangoju 	const unsigned char *dst = tdata->packet->dst;
38*862a64c8SRaju Rangoju 	const unsigned char *src = tdata->packet->src;
39*862a64c8SRaju Rangoju 	struct netsfhdr *hdr;
40*862a64c8SRaju Rangoju 	struct ethhdr *eh;
41*862a64c8SRaju Rangoju 	struct tcphdr *th;
42*862a64c8SRaju Rangoju 	struct udphdr *uh;
43*862a64c8SRaju Rangoju 	struct iphdr *ih;
44*862a64c8SRaju Rangoju 
45*862a64c8SRaju Rangoju 	skb = skb_unshare(skb, GFP_ATOMIC);
46*862a64c8SRaju Rangoju 	if (!skb)
47*862a64c8SRaju Rangoju 		goto out;
48*862a64c8SRaju Rangoju 
49*862a64c8SRaju Rangoju 	if (skb_linearize(skb))
50*862a64c8SRaju Rangoju 		goto out;
51*862a64c8SRaju Rangoju 
52*862a64c8SRaju Rangoju 	if (skb_headlen(skb) < (NET_TEST_PKT_SIZE - ETH_HLEN))
53*862a64c8SRaju Rangoju 		goto out;
54*862a64c8SRaju Rangoju 
55*862a64c8SRaju Rangoju 	eh = (struct ethhdr *)skb_mac_header(skb);
56*862a64c8SRaju Rangoju 	if (dst) {
57*862a64c8SRaju Rangoju 		if (!ether_addr_equal_unaligned(eh->h_dest, dst))
58*862a64c8SRaju Rangoju 			goto out;
59*862a64c8SRaju Rangoju 	}
60*862a64c8SRaju Rangoju 	if (src) {
61*862a64c8SRaju Rangoju 		if (!ether_addr_equal_unaligned(eh->h_source, src))
62*862a64c8SRaju Rangoju 			goto out;
63*862a64c8SRaju Rangoju 	}
64*862a64c8SRaju Rangoju 
65*862a64c8SRaju Rangoju 	ih = ip_hdr(skb);
66*862a64c8SRaju Rangoju 
67*862a64c8SRaju Rangoju 	if (tdata->packet->tcp) {
68*862a64c8SRaju Rangoju 		if (ih->protocol != IPPROTO_TCP)
69*862a64c8SRaju Rangoju 			goto out;
70*862a64c8SRaju Rangoju 
71*862a64c8SRaju Rangoju 		th = (struct tcphdr *)((u8 *)ih + 4 * ih->ihl);
72*862a64c8SRaju Rangoju 		if (th->dest != htons(tdata->packet->dport))
73*862a64c8SRaju Rangoju 			goto out;
74*862a64c8SRaju Rangoju 
75*862a64c8SRaju Rangoju 		hdr = (struct netsfhdr *)((u8 *)th + sizeof(*th));
76*862a64c8SRaju Rangoju 	} else {
77*862a64c8SRaju Rangoju 		if (ih->protocol != IPPROTO_UDP)
78*862a64c8SRaju Rangoju 			goto out;
79*862a64c8SRaju Rangoju 
80*862a64c8SRaju Rangoju 		uh = (struct udphdr *)((u8 *)ih + 4 * ih->ihl);
81*862a64c8SRaju Rangoju 		if (uh->dest != htons(tdata->packet->dport))
82*862a64c8SRaju Rangoju 			goto out;
83*862a64c8SRaju Rangoju 
84*862a64c8SRaju Rangoju 		hdr = (struct netsfhdr *)((u8 *)uh + sizeof(*uh));
85*862a64c8SRaju Rangoju 	}
86*862a64c8SRaju Rangoju 
87*862a64c8SRaju Rangoju 	if (hdr->magic != cpu_to_be64(NET_TEST_PKT_MAGIC))
88*862a64c8SRaju Rangoju 		goto out;
89*862a64c8SRaju Rangoju 	if (tdata->packet->id != hdr->id)
90*862a64c8SRaju Rangoju 		goto out;
91*862a64c8SRaju Rangoju 
92*862a64c8SRaju Rangoju 	tdata->ok = true;
93*862a64c8SRaju Rangoju 	complete(&tdata->comp);
94*862a64c8SRaju Rangoju out:
95*862a64c8SRaju Rangoju 	kfree_skb(skb);
96*862a64c8SRaju Rangoju 	return 0;
97*862a64c8SRaju Rangoju }
98*862a64c8SRaju Rangoju 
99*862a64c8SRaju Rangoju static int __xgbe_test_loopback(struct xgbe_prv_data *pdata,
100*862a64c8SRaju Rangoju 				struct net_packet_attrs *attr)
101*862a64c8SRaju Rangoju {
102*862a64c8SRaju Rangoju 	struct net_test_priv *tdata;
103*862a64c8SRaju Rangoju 	struct sk_buff *skb = NULL;
104*862a64c8SRaju Rangoju 	int ret = 0;
105*862a64c8SRaju Rangoju 
106*862a64c8SRaju Rangoju 	tdata = kzalloc(sizeof(*tdata), GFP_KERNEL);
107*862a64c8SRaju Rangoju 	if (!tdata)
108*862a64c8SRaju Rangoju 		return -ENOMEM;
109*862a64c8SRaju Rangoju 
110*862a64c8SRaju Rangoju 	tdata->ok = false;
111*862a64c8SRaju Rangoju 	init_completion(&tdata->comp);
112*862a64c8SRaju Rangoju 
113*862a64c8SRaju Rangoju 	tdata->pt.type = htons(ETH_P_IP);
114*862a64c8SRaju Rangoju 	tdata->pt.func = xgbe_test_loopback_validate;
115*862a64c8SRaju Rangoju 	tdata->pt.dev = pdata->netdev;
116*862a64c8SRaju Rangoju 	tdata->pt.af_packet_priv = tdata;
117*862a64c8SRaju Rangoju 	tdata->packet = attr;
118*862a64c8SRaju Rangoju 
119*862a64c8SRaju Rangoju 	dev_add_pack(&tdata->pt);
120*862a64c8SRaju Rangoju 
121*862a64c8SRaju Rangoju 	skb = net_test_get_skb(pdata->netdev, xgbe_test_id, attr);
122*862a64c8SRaju Rangoju 	if (!skb) {
123*862a64c8SRaju Rangoju 		ret = -ENOMEM;
124*862a64c8SRaju Rangoju 		goto cleanup;
125*862a64c8SRaju Rangoju 	}
126*862a64c8SRaju Rangoju 
127*862a64c8SRaju Rangoju 	xgbe_test_id++;
128*862a64c8SRaju Rangoju 	ret = dev_direct_xmit(skb, attr->queue_mapping);
129*862a64c8SRaju Rangoju 	if (ret)
130*862a64c8SRaju Rangoju 		goto cleanup;
131*862a64c8SRaju Rangoju 
132*862a64c8SRaju Rangoju 	if (!attr->timeout)
133*862a64c8SRaju Rangoju 		attr->timeout = NET_LB_TIMEOUT;
134*862a64c8SRaju Rangoju 
135*862a64c8SRaju Rangoju 	wait_for_completion_timeout(&tdata->comp, attr->timeout);
136*862a64c8SRaju Rangoju 	ret = tdata->ok ? 0 : -ETIMEDOUT;
137*862a64c8SRaju Rangoju 
138*862a64c8SRaju Rangoju 	if (ret)
139*862a64c8SRaju Rangoju 		netdev_err(pdata->netdev, "Response timedout: ret %d\n", ret);
140*862a64c8SRaju Rangoju cleanup:
141*862a64c8SRaju Rangoju 	dev_remove_pack(&tdata->pt);
142*862a64c8SRaju Rangoju 	kfree(tdata);
143*862a64c8SRaju Rangoju 	return ret;
144*862a64c8SRaju Rangoju }
145*862a64c8SRaju Rangoju 
146*862a64c8SRaju Rangoju static int xgbe_test_mac_loopback(struct xgbe_prv_data *pdata)
147*862a64c8SRaju Rangoju {
148*862a64c8SRaju Rangoju 	struct net_packet_attrs attr = {};
149*862a64c8SRaju Rangoju 
150*862a64c8SRaju Rangoju 	attr.dst = pdata->netdev->dev_addr;
151*862a64c8SRaju Rangoju 	return __xgbe_test_loopback(pdata, &attr);
152*862a64c8SRaju Rangoju }
153*862a64c8SRaju Rangoju 
154*862a64c8SRaju Rangoju static const struct xgbe_test xgbe_selftests[] = {
155*862a64c8SRaju Rangoju 	{
156*862a64c8SRaju Rangoju 		.name = "MAC Loopback   ",
157*862a64c8SRaju Rangoju 		.lb = XGBE_LOOPBACK_MAC,
158*862a64c8SRaju Rangoju 		.fn = xgbe_test_mac_loopback,
159*862a64c8SRaju Rangoju 	},
160*862a64c8SRaju Rangoju };
161*862a64c8SRaju Rangoju 
162*862a64c8SRaju Rangoju void xgbe_selftest_run(struct net_device *dev,
163*862a64c8SRaju Rangoju 		       struct ethtool_test *etest, u64 *buf)
164*862a64c8SRaju Rangoju {
165*862a64c8SRaju Rangoju 	struct xgbe_prv_data *pdata = netdev_priv(dev);
166*862a64c8SRaju Rangoju 	int count = xgbe_selftest_get_count(pdata);
167*862a64c8SRaju Rangoju 	int i, ret;
168*862a64c8SRaju Rangoju 
169*862a64c8SRaju Rangoju 	memset(buf, 0, sizeof(*buf) * count);
170*862a64c8SRaju Rangoju 	xgbe_test_id = 0;
171*862a64c8SRaju Rangoju 
172*862a64c8SRaju Rangoju 	if (etest->flags != ETH_TEST_FL_OFFLINE) {
173*862a64c8SRaju Rangoju 		netdev_err(pdata->netdev, "Only offline tests are supported\n");
174*862a64c8SRaju Rangoju 		etest->flags |= ETH_TEST_FL_FAILED;
175*862a64c8SRaju Rangoju 		return;
176*862a64c8SRaju Rangoju 	} else if (!netif_carrier_ok(dev)) {
177*862a64c8SRaju Rangoju 		netdev_err(pdata->netdev,
178*862a64c8SRaju Rangoju 			   "Invalid link, cannot execute tests\n");
179*862a64c8SRaju Rangoju 		etest->flags |= ETH_TEST_FL_FAILED;
180*862a64c8SRaju Rangoju 		return;
181*862a64c8SRaju Rangoju 	}
182*862a64c8SRaju Rangoju 
183*862a64c8SRaju Rangoju 	/* Wait for queues drain */
184*862a64c8SRaju Rangoju 	msleep(200);
185*862a64c8SRaju Rangoju 
186*862a64c8SRaju Rangoju 	for (i = 0; i < count; i++) {
187*862a64c8SRaju Rangoju 		ret = 0;
188*862a64c8SRaju Rangoju 
189*862a64c8SRaju Rangoju 		switch (xgbe_selftests[i].lb) {
190*862a64c8SRaju Rangoju 		case XGBE_LOOPBACK_MAC:
191*862a64c8SRaju Rangoju 			ret = xgbe_enable_mac_loopback(pdata);
192*862a64c8SRaju Rangoju 			break;
193*862a64c8SRaju Rangoju 		case XGBE_LOOPBACK_NONE:
194*862a64c8SRaju Rangoju 			break;
195*862a64c8SRaju Rangoju 		default:
196*862a64c8SRaju Rangoju 			ret = -EOPNOTSUPP;
197*862a64c8SRaju Rangoju 			break;
198*862a64c8SRaju Rangoju 		}
199*862a64c8SRaju Rangoju 
200*862a64c8SRaju Rangoju 		/*
201*862a64c8SRaju Rangoju 		 * First tests will always be MAC / PHY loopback.
202*862a64c8SRaju Rangoju 		 * If any of them is not supported we abort earlier.
203*862a64c8SRaju Rangoju 		 */
204*862a64c8SRaju Rangoju 		if (ret) {
205*862a64c8SRaju Rangoju 			netdev_err(pdata->netdev, "Loopback not supported\n");
206*862a64c8SRaju Rangoju 			etest->flags |= ETH_TEST_FL_FAILED;
207*862a64c8SRaju Rangoju 			break;
208*862a64c8SRaju Rangoju 		}
209*862a64c8SRaju Rangoju 
210*862a64c8SRaju Rangoju 		ret = xgbe_selftests[i].fn(pdata);
211*862a64c8SRaju Rangoju 		if (ret && (ret != -EOPNOTSUPP))
212*862a64c8SRaju Rangoju 			etest->flags |= ETH_TEST_FL_FAILED;
213*862a64c8SRaju Rangoju 		buf[i] = ret;
214*862a64c8SRaju Rangoju 
215*862a64c8SRaju Rangoju 		switch (xgbe_selftests[i].lb) {
216*862a64c8SRaju Rangoju 		case XGBE_LOOPBACK_MAC:
217*862a64c8SRaju Rangoju 			xgbe_disable_mac_loopback(pdata);
218*862a64c8SRaju Rangoju 			break;
219*862a64c8SRaju Rangoju 		default:
220*862a64c8SRaju Rangoju 			break;
221*862a64c8SRaju Rangoju 		}
222*862a64c8SRaju Rangoju 	}
223*862a64c8SRaju Rangoju }
224*862a64c8SRaju Rangoju 
225*862a64c8SRaju Rangoju void xgbe_selftest_get_strings(struct xgbe_prv_data *pdata, u8 *data)
226*862a64c8SRaju Rangoju {
227*862a64c8SRaju Rangoju 	u8 *p = data;
228*862a64c8SRaju Rangoju 	int i;
229*862a64c8SRaju Rangoju 
230*862a64c8SRaju Rangoju 	for (i = 0; i < xgbe_selftest_get_count(pdata); i++)
231*862a64c8SRaju Rangoju 		ethtool_puts(&p, xgbe_selftests[i].name);
232*862a64c8SRaju Rangoju }
233*862a64c8SRaju Rangoju 
234*862a64c8SRaju Rangoju int xgbe_selftest_get_count(struct xgbe_prv_data *pdata)
235*862a64c8SRaju Rangoju {
236*862a64c8SRaju Rangoju 	return ARRAY_SIZE(xgbe_selftests);
237*862a64c8SRaju Rangoju }
238