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