1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause) 2 /* 3 * Copyright (c) 2014-2025, Advanced Micro Devices, Inc. 4 * Copyright (c) 2014, Synopsys, Inc. 5 * All rights reserved 6 * 7 * Author: Raju Rangoju <Raju.Rangoju@amd.com> 8 */ 9 #include <linux/crc32.h> 10 #include <linux/ip.h> 11 #include <linux/udp.h> 12 #include <net/tcp.h> 13 #include <net/udp.h> 14 #include <net/checksum.h> 15 #include <net/selftests.h> 16 17 #include "xgbe.h" 18 #include "xgbe-common.h" 19 20 #define XGBE_LOOPBACK_NONE 0 21 #define XGBE_LOOPBACK_MAC 1 22 #define XGBE_LOOPBACK_PHY 2 23 24 struct xgbe_test { 25 char name[ETH_GSTRING_LEN]; 26 int lb; 27 int (*fn)(struct xgbe_prv_data *pdata); 28 }; 29 30 static u8 xgbe_test_id; 31 32 static int xgbe_test_loopback_validate(struct sk_buff *skb, 33 struct net_device *ndev, 34 struct packet_type *pt, 35 struct net_device *orig_ndev) 36 { 37 struct net_test_priv *tdata = pt->af_packet_priv; 38 const unsigned char *dst = tdata->packet->dst; 39 const unsigned char *src = tdata->packet->src; 40 struct netsfhdr *hdr; 41 struct ethhdr *eh; 42 struct tcphdr *th; 43 struct udphdr *uh; 44 struct iphdr *ih; 45 int eat; 46 47 skb = skb_unshare(skb, GFP_ATOMIC); 48 if (!skb) 49 goto out; 50 51 eat = (skb->tail + skb->data_len) - skb->end; 52 if (eat > 0 && skb_shared(skb)) { 53 skb = skb_share_check(skb, GFP_ATOMIC); 54 if (!skb) 55 goto out; 56 } 57 58 if (skb_linearize(skb)) 59 goto out; 60 61 if (skb_headlen(skb) < (NET_TEST_PKT_SIZE - ETH_HLEN)) 62 goto out; 63 64 eh = (struct ethhdr *)skb_mac_header(skb); 65 if (dst) { 66 if (!ether_addr_equal_unaligned(eh->h_dest, dst)) 67 goto out; 68 } 69 if (src) { 70 if (!ether_addr_equal_unaligned(eh->h_source, src)) 71 goto out; 72 } 73 74 ih = ip_hdr(skb); 75 76 if (tdata->packet->tcp) { 77 if (ih->protocol != IPPROTO_TCP) 78 goto out; 79 80 th = (struct tcphdr *)((u8 *)ih + 4 * ih->ihl); 81 if (th->dest != htons(tdata->packet->dport)) 82 goto out; 83 84 hdr = (struct netsfhdr *)((u8 *)th + sizeof(*th)); 85 } else { 86 if (ih->protocol != IPPROTO_UDP) 87 goto out; 88 89 uh = (struct udphdr *)((u8 *)ih + 4 * ih->ihl); 90 if (uh->dest != htons(tdata->packet->dport)) 91 goto out; 92 93 hdr = (struct netsfhdr *)((u8 *)uh + sizeof(*uh)); 94 } 95 96 if (hdr->magic != cpu_to_be64(NET_TEST_PKT_MAGIC)) 97 goto out; 98 if (tdata->packet->id != hdr->id) 99 goto out; 100 101 tdata->ok = true; 102 complete(&tdata->comp); 103 out: 104 kfree_skb(skb); 105 return 0; 106 } 107 108 static int __xgbe_test_loopback(struct xgbe_prv_data *pdata, 109 struct net_packet_attrs *attr) 110 { 111 struct net_test_priv *tdata; 112 struct sk_buff *skb = NULL; 113 int ret = 0; 114 115 tdata = kzalloc(sizeof(*tdata), GFP_KERNEL); 116 if (!tdata) 117 return -ENOMEM; 118 119 tdata->ok = false; 120 init_completion(&tdata->comp); 121 122 tdata->pt.type = htons(ETH_P_IP); 123 tdata->pt.func = xgbe_test_loopback_validate; 124 tdata->pt.dev = pdata->netdev; 125 tdata->pt.af_packet_priv = tdata; 126 tdata->packet = attr; 127 128 dev_add_pack(&tdata->pt); 129 130 skb = net_test_get_skb(pdata->netdev, xgbe_test_id, attr); 131 if (!skb) { 132 ret = -ENOMEM; 133 goto cleanup; 134 } 135 136 xgbe_test_id++; 137 ret = dev_direct_xmit(skb, attr->queue_mapping); 138 if (ret) 139 goto cleanup; 140 141 if (!attr->timeout) 142 attr->timeout = NET_LB_TIMEOUT; 143 144 wait_for_completion_timeout(&tdata->comp, attr->timeout); 145 ret = tdata->ok ? 0 : -ETIMEDOUT; 146 147 if (ret) 148 netdev_err(pdata->netdev, "Response timedout: ret %d\n", ret); 149 cleanup: 150 dev_remove_pack(&tdata->pt); 151 kfree(tdata); 152 return ret; 153 } 154 155 static int xgbe_test_mac_loopback(struct xgbe_prv_data *pdata) 156 { 157 struct net_packet_attrs attr = {}; 158 159 attr.dst = pdata->netdev->dev_addr; 160 return __xgbe_test_loopback(pdata, &attr); 161 } 162 163 static int xgbe_test_phy_loopback(struct xgbe_prv_data *pdata) 164 { 165 struct net_packet_attrs attr = {}; 166 int ret; 167 168 if (!pdata->netdev->phydev) { 169 netdev_err(pdata->netdev, "phydev not found: cannot start PHY loopback test\n"); 170 return -EOPNOTSUPP; 171 } 172 173 ret = phy_loopback(pdata->netdev->phydev, true, 0); 174 if (ret) 175 return ret; 176 177 attr.dst = pdata->netdev->dev_addr; 178 ret = __xgbe_test_loopback(pdata, &attr); 179 180 phy_loopback(pdata->netdev->phydev, false, 0); 181 return ret; 182 } 183 184 static int xgbe_test_sph(struct xgbe_prv_data *pdata) 185 { 186 struct net_packet_attrs attr = {}; 187 unsigned long cnt_end, cnt_start; 188 int ret; 189 190 cnt_start = pdata->ext_stats.rx_split_header_packets; 191 192 if (!pdata->sph) { 193 netdev_err(pdata->netdev, "Split Header not enabled\n"); 194 return -EOPNOTSUPP; 195 } 196 197 /* UDP test */ 198 attr.dst = pdata->netdev->dev_addr; 199 attr.tcp = false; 200 201 ret = __xgbe_test_loopback(pdata, &attr); 202 if (ret) 203 return ret; 204 205 cnt_end = pdata->ext_stats.rx_split_header_packets; 206 if (cnt_end <= cnt_start) 207 return -EINVAL; 208 209 /* TCP test */ 210 cnt_start = cnt_end; 211 212 attr.dst = pdata->netdev->dev_addr; 213 attr.tcp = true; 214 215 ret = __xgbe_test_loopback(pdata, &attr); 216 if (ret) 217 return ret; 218 219 cnt_end = pdata->ext_stats.rx_split_header_packets; 220 if (cnt_end <= cnt_start) 221 return -EINVAL; 222 223 return 0; 224 } 225 226 static int xgbe_test_jumbo(struct xgbe_prv_data *pdata) 227 { 228 struct net_packet_attrs attr = {}; 229 int size = pdata->rx_buf_size; 230 231 attr.dst = pdata->netdev->dev_addr; 232 attr.max_size = size - ETH_FCS_LEN; 233 234 return __xgbe_test_loopback(pdata, &attr); 235 } 236 237 static const struct xgbe_test xgbe_selftests[] = { 238 { 239 .name = "MAC Loopback ", 240 .lb = XGBE_LOOPBACK_MAC, 241 .fn = xgbe_test_mac_loopback, 242 }, { 243 .name = "PHY Loopback ", 244 .lb = XGBE_LOOPBACK_NONE, 245 .fn = xgbe_test_phy_loopback, 246 }, { 247 .name = "Split Header ", 248 .lb = XGBE_LOOPBACK_PHY, 249 .fn = xgbe_test_sph, 250 }, { 251 .name = "Jumbo Frame ", 252 .lb = XGBE_LOOPBACK_PHY, 253 .fn = xgbe_test_jumbo, 254 }, 255 }; 256 257 void xgbe_selftest_run(struct net_device *dev, 258 struct ethtool_test *etest, u64 *buf) 259 { 260 struct xgbe_prv_data *pdata = netdev_priv(dev); 261 int count = xgbe_selftest_get_count(pdata); 262 int i, ret; 263 264 memset(buf, 0, sizeof(*buf) * count); 265 xgbe_test_id = 0; 266 267 if (etest->flags != ETH_TEST_FL_OFFLINE) { 268 netdev_err(pdata->netdev, "Only offline tests are supported\n"); 269 etest->flags |= ETH_TEST_FL_FAILED; 270 return; 271 } else if (!netif_carrier_ok(dev)) { 272 netdev_err(pdata->netdev, 273 "Invalid link, cannot execute tests\n"); 274 etest->flags |= ETH_TEST_FL_FAILED; 275 return; 276 } 277 278 /* Wait for queues drain */ 279 msleep(200); 280 281 for (i = 0; i < count; i++) { 282 ret = 0; 283 284 switch (xgbe_selftests[i].lb) { 285 case XGBE_LOOPBACK_PHY: 286 ret = -EOPNOTSUPP; 287 if (dev->phydev) 288 ret = phy_loopback(dev->phydev, true, 0); 289 if (!ret) 290 break; 291 fallthrough; 292 case XGBE_LOOPBACK_MAC: 293 ret = xgbe_enable_mac_loopback(pdata); 294 break; 295 case XGBE_LOOPBACK_NONE: 296 break; 297 default: 298 ret = -EOPNOTSUPP; 299 break; 300 } 301 302 /* 303 * First tests will always be MAC / PHY loopback. 304 * If any of them is not supported we abort earlier. 305 */ 306 if (ret) { 307 netdev_err(pdata->netdev, "Loopback not supported\n"); 308 etest->flags |= ETH_TEST_FL_FAILED; 309 break; 310 } 311 312 ret = xgbe_selftests[i].fn(pdata); 313 if (ret && (ret != -EOPNOTSUPP)) 314 etest->flags |= ETH_TEST_FL_FAILED; 315 buf[i] = ret; 316 317 switch (xgbe_selftests[i].lb) { 318 case XGBE_LOOPBACK_PHY: 319 ret = -EOPNOTSUPP; 320 if (dev->phydev) 321 ret = phy_loopback(dev->phydev, false, 0); 322 if (!ret) 323 break; 324 fallthrough; 325 case XGBE_LOOPBACK_MAC: 326 xgbe_disable_mac_loopback(pdata); 327 break; 328 default: 329 break; 330 } 331 } 332 } 333 334 void xgbe_selftest_get_strings(struct xgbe_prv_data *pdata, u8 *data) 335 { 336 u8 *p = data; 337 int i; 338 339 for (i = 0; i < xgbe_selftest_get_count(pdata); i++) 340 ethtool_puts(&p, xgbe_selftests[i].name); 341 } 342 343 int xgbe_selftest_get_count(struct xgbe_prv_data *pdata) 344 { 345 return ARRAY_SIZE(xgbe_selftests); 346 } 347