1091810dbSJose Abreu // SPDX-License-Identifier: GPL-2.0 2091810dbSJose Abreu /* 3091810dbSJose Abreu * Copyright (c) 2019 Synopsys, Inc. and/or its affiliates. 4091810dbSJose Abreu * stmmac Selftests Support 5091810dbSJose Abreu * 6091810dbSJose Abreu * Author: Jose Abreu <joabreu@synopsys.com> 7091810dbSJose Abreu */ 8091810dbSJose Abreu 9091810dbSJose Abreu #include <linux/completion.h> 10091810dbSJose Abreu #include <linux/ethtool.h> 11091810dbSJose Abreu #include <linux/ip.h> 12091810dbSJose Abreu #include <linux/phy.h> 13091810dbSJose Abreu #include <linux/udp.h> 14091810dbSJose Abreu #include <net/tcp.h> 15091810dbSJose Abreu #include <net/udp.h> 16091810dbSJose Abreu #include "stmmac.h" 17091810dbSJose Abreu 18091810dbSJose Abreu struct stmmachdr { 19091810dbSJose Abreu __be32 version; 20091810dbSJose Abreu __be64 magic; 21091810dbSJose Abreu u8 id; 22091810dbSJose Abreu } __packed; 23091810dbSJose Abreu 24091810dbSJose Abreu #define STMMAC_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \ 25091810dbSJose Abreu sizeof(struct stmmachdr)) 26091810dbSJose Abreu #define STMMAC_TEST_PKT_MAGIC 0xdeadcafecafedeadULL 27091810dbSJose Abreu #define STMMAC_LB_TIMEOUT msecs_to_jiffies(200) 28091810dbSJose Abreu 29091810dbSJose Abreu struct stmmac_packet_attrs { 30091810dbSJose Abreu int vlan; 31091810dbSJose Abreu int vlan_id_in; 32091810dbSJose Abreu int vlan_id_out; 33091810dbSJose Abreu unsigned char *src; 34091810dbSJose Abreu unsigned char *dst; 35091810dbSJose Abreu u32 ip_src; 36091810dbSJose Abreu u32 ip_dst; 37091810dbSJose Abreu int tcp; 38091810dbSJose Abreu int sport; 39091810dbSJose Abreu int dport; 40091810dbSJose Abreu u32 exp_hash; 41091810dbSJose Abreu int dont_wait; 42091810dbSJose Abreu int timeout; 43091810dbSJose Abreu int size; 44091810dbSJose Abreu int remove_sa; 45091810dbSJose Abreu u8 id; 46091810dbSJose Abreu }; 47091810dbSJose Abreu 48091810dbSJose Abreu static u8 stmmac_test_next_id; 49091810dbSJose Abreu 50091810dbSJose Abreu static struct sk_buff *stmmac_test_get_udp_skb(struct stmmac_priv *priv, 51091810dbSJose Abreu struct stmmac_packet_attrs *attr) 52091810dbSJose Abreu { 53091810dbSJose Abreu struct sk_buff *skb = NULL; 54091810dbSJose Abreu struct udphdr *uhdr = NULL; 55091810dbSJose Abreu struct tcphdr *thdr = NULL; 56091810dbSJose Abreu struct stmmachdr *shdr; 57091810dbSJose Abreu struct ethhdr *ehdr; 58091810dbSJose Abreu struct iphdr *ihdr; 59091810dbSJose Abreu int iplen, size; 60091810dbSJose Abreu 61091810dbSJose Abreu size = attr->size + STMMAC_TEST_PKT_SIZE; 62091810dbSJose Abreu if (attr->vlan) { 63091810dbSJose Abreu size += 4; 64091810dbSJose Abreu if (attr->vlan > 1) 65091810dbSJose Abreu size += 4; 66091810dbSJose Abreu } 67091810dbSJose Abreu 68091810dbSJose Abreu if (attr->tcp) 69091810dbSJose Abreu size += sizeof(struct tcphdr); 70091810dbSJose Abreu else 71091810dbSJose Abreu size += sizeof(struct udphdr); 72091810dbSJose Abreu 73091810dbSJose Abreu skb = netdev_alloc_skb(priv->dev, size); 74091810dbSJose Abreu if (!skb) 75091810dbSJose Abreu return NULL; 76091810dbSJose Abreu 77091810dbSJose Abreu prefetchw(skb->data); 78091810dbSJose Abreu skb_reserve(skb, NET_IP_ALIGN); 79091810dbSJose Abreu 80091810dbSJose Abreu if (attr->vlan > 1) 81091810dbSJose Abreu ehdr = skb_push(skb, ETH_HLEN + 8); 82091810dbSJose Abreu else if (attr->vlan) 83091810dbSJose Abreu ehdr = skb_push(skb, ETH_HLEN + 4); 84091810dbSJose Abreu else if (attr->remove_sa) 85091810dbSJose Abreu ehdr = skb_push(skb, ETH_HLEN - 6); 86091810dbSJose Abreu else 87091810dbSJose Abreu ehdr = skb_push(skb, ETH_HLEN); 88091810dbSJose Abreu skb_reset_mac_header(skb); 89091810dbSJose Abreu 90091810dbSJose Abreu skb_set_network_header(skb, skb->len); 91091810dbSJose Abreu ihdr = skb_put(skb, sizeof(*ihdr)); 92091810dbSJose Abreu 93091810dbSJose Abreu skb_set_transport_header(skb, skb->len); 94091810dbSJose Abreu if (attr->tcp) 95091810dbSJose Abreu thdr = skb_put(skb, sizeof(*thdr)); 96091810dbSJose Abreu else 97091810dbSJose Abreu uhdr = skb_put(skb, sizeof(*uhdr)); 98091810dbSJose Abreu 99091810dbSJose Abreu if (!attr->remove_sa) 100091810dbSJose Abreu eth_zero_addr(ehdr->h_source); 101091810dbSJose Abreu eth_zero_addr(ehdr->h_dest); 102091810dbSJose Abreu if (attr->src && !attr->remove_sa) 103091810dbSJose Abreu ether_addr_copy(ehdr->h_source, attr->src); 104091810dbSJose Abreu if (attr->dst) 105091810dbSJose Abreu ether_addr_copy(ehdr->h_dest, attr->dst); 106091810dbSJose Abreu 107091810dbSJose Abreu if (!attr->remove_sa) { 108091810dbSJose Abreu ehdr->h_proto = htons(ETH_P_IP); 109091810dbSJose Abreu } else { 110091810dbSJose Abreu __be16 *ptr = (__be16 *)ehdr; 111091810dbSJose Abreu 112091810dbSJose Abreu /* HACK */ 113091810dbSJose Abreu ptr[3] = htons(ETH_P_IP); 114091810dbSJose Abreu } 115091810dbSJose Abreu 116091810dbSJose Abreu if (attr->vlan) { 117*2d135deaSJose Abreu __be16 *tag, *proto; 118091810dbSJose Abreu 119091810dbSJose Abreu if (!attr->remove_sa) { 120091810dbSJose Abreu tag = (void *)ehdr + ETH_HLEN; 121091810dbSJose Abreu proto = (void *)ehdr + (2 * ETH_ALEN); 122091810dbSJose Abreu } else { 123091810dbSJose Abreu tag = (void *)ehdr + ETH_HLEN - 6; 124091810dbSJose Abreu proto = (void *)ehdr + ETH_ALEN; 125091810dbSJose Abreu } 126091810dbSJose Abreu 127091810dbSJose Abreu proto[0] = htons(ETH_P_8021Q); 128091810dbSJose Abreu tag[0] = htons(attr->vlan_id_out); 129091810dbSJose Abreu tag[1] = htons(ETH_P_IP); 130091810dbSJose Abreu if (attr->vlan > 1) { 131091810dbSJose Abreu proto[0] = htons(ETH_P_8021AD); 132091810dbSJose Abreu tag[1] = htons(ETH_P_8021Q); 133091810dbSJose Abreu tag[2] = htons(attr->vlan_id_in); 134091810dbSJose Abreu tag[3] = htons(ETH_P_IP); 135091810dbSJose Abreu } 136091810dbSJose Abreu } 137091810dbSJose Abreu 138091810dbSJose Abreu if (attr->tcp) { 139091810dbSJose Abreu thdr->source = htons(attr->sport); 140091810dbSJose Abreu thdr->dest = htons(attr->dport); 141091810dbSJose Abreu thdr->doff = sizeof(struct tcphdr) / 4; 142091810dbSJose Abreu thdr->check = 0; 143091810dbSJose Abreu } else { 144091810dbSJose Abreu uhdr->source = htons(attr->sport); 145091810dbSJose Abreu uhdr->dest = htons(attr->dport); 146091810dbSJose Abreu uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size); 147091810dbSJose Abreu uhdr->check = 0; 148091810dbSJose Abreu } 149091810dbSJose Abreu 150091810dbSJose Abreu ihdr->ihl = 5; 151091810dbSJose Abreu ihdr->ttl = 32; 152091810dbSJose Abreu ihdr->version = 4; 153091810dbSJose Abreu if (attr->tcp) 154091810dbSJose Abreu ihdr->protocol = IPPROTO_TCP; 155091810dbSJose Abreu else 156091810dbSJose Abreu ihdr->protocol = IPPROTO_UDP; 157091810dbSJose Abreu iplen = sizeof(*ihdr) + sizeof(*shdr) + attr->size; 158091810dbSJose Abreu if (attr->tcp) 159091810dbSJose Abreu iplen += sizeof(*thdr); 160091810dbSJose Abreu else 161091810dbSJose Abreu iplen += sizeof(*uhdr); 162091810dbSJose Abreu ihdr->tot_len = htons(iplen); 163091810dbSJose Abreu ihdr->frag_off = 0; 164091810dbSJose Abreu ihdr->saddr = 0; 165091810dbSJose Abreu ihdr->daddr = htonl(attr->ip_dst); 166091810dbSJose Abreu ihdr->tos = 0; 167091810dbSJose Abreu ihdr->id = 0; 168091810dbSJose Abreu ip_send_check(ihdr); 169091810dbSJose Abreu 170091810dbSJose Abreu shdr = skb_put(skb, sizeof(*shdr)); 171091810dbSJose Abreu shdr->version = 0; 172091810dbSJose Abreu shdr->magic = cpu_to_be64(STMMAC_TEST_PKT_MAGIC); 173091810dbSJose Abreu attr->id = stmmac_test_next_id; 174091810dbSJose Abreu shdr->id = stmmac_test_next_id++; 175091810dbSJose Abreu 176091810dbSJose Abreu if (attr->size) 177091810dbSJose Abreu skb_put(skb, attr->size); 178091810dbSJose Abreu 179091810dbSJose Abreu skb->csum = 0; 180091810dbSJose Abreu skb->ip_summed = CHECKSUM_PARTIAL; 181091810dbSJose Abreu if (attr->tcp) { 182091810dbSJose Abreu thdr->check = ~tcp_v4_check(skb->len, ihdr->saddr, ihdr->daddr, 0); 183091810dbSJose Abreu skb->csum_start = skb_transport_header(skb) - skb->head; 184091810dbSJose Abreu skb->csum_offset = offsetof(struct tcphdr, check); 185091810dbSJose Abreu } else { 186091810dbSJose Abreu udp4_hwcsum(skb, ihdr->saddr, ihdr->daddr); 187091810dbSJose Abreu } 188091810dbSJose Abreu 189091810dbSJose Abreu skb->protocol = htons(ETH_P_IP); 190091810dbSJose Abreu skb->pkt_type = PACKET_HOST; 191091810dbSJose Abreu skb->dev = priv->dev; 192091810dbSJose Abreu 193091810dbSJose Abreu return skb; 194091810dbSJose Abreu } 195091810dbSJose Abreu 196091810dbSJose Abreu struct stmmac_test_priv { 197091810dbSJose Abreu struct stmmac_packet_attrs *packet; 198091810dbSJose Abreu struct packet_type pt; 199091810dbSJose Abreu struct completion comp; 200091810dbSJose Abreu int double_vlan; 201091810dbSJose Abreu int vlan_id; 202091810dbSJose Abreu int ok; 203091810dbSJose Abreu }; 204091810dbSJose Abreu 205091810dbSJose Abreu static int stmmac_test_loopback_validate(struct sk_buff *skb, 206091810dbSJose Abreu struct net_device *ndev, 207091810dbSJose Abreu struct packet_type *pt, 208091810dbSJose Abreu struct net_device *orig_ndev) 209091810dbSJose Abreu { 210091810dbSJose Abreu struct stmmac_test_priv *tpriv = pt->af_packet_priv; 211091810dbSJose Abreu struct stmmachdr *shdr; 212091810dbSJose Abreu struct ethhdr *ehdr; 213091810dbSJose Abreu struct udphdr *uhdr; 214091810dbSJose Abreu struct tcphdr *thdr; 215091810dbSJose Abreu struct iphdr *ihdr; 216091810dbSJose Abreu 217091810dbSJose Abreu skb = skb_unshare(skb, GFP_ATOMIC); 218091810dbSJose Abreu if (!skb) 219091810dbSJose Abreu goto out; 220091810dbSJose Abreu 221091810dbSJose Abreu if (skb_linearize(skb)) 222091810dbSJose Abreu goto out; 223091810dbSJose Abreu if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN)) 224091810dbSJose Abreu goto out; 225091810dbSJose Abreu 226091810dbSJose Abreu ehdr = (struct ethhdr *)skb_mac_header(skb); 227091810dbSJose Abreu if (tpriv->packet->dst) { 228091810dbSJose Abreu if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst)) 229091810dbSJose Abreu goto out; 230091810dbSJose Abreu } 231091810dbSJose Abreu if (tpriv->packet->src) { 232091810dbSJose Abreu if (!ether_addr_equal(ehdr->h_source, orig_ndev->dev_addr)) 233091810dbSJose Abreu goto out; 234091810dbSJose Abreu } 235091810dbSJose Abreu 236091810dbSJose Abreu ihdr = ip_hdr(skb); 237091810dbSJose Abreu if (tpriv->double_vlan) 238091810dbSJose Abreu ihdr = (struct iphdr *)(skb_network_header(skb) + 4); 239091810dbSJose Abreu 240091810dbSJose Abreu if (tpriv->packet->tcp) { 241091810dbSJose Abreu if (ihdr->protocol != IPPROTO_TCP) 242091810dbSJose Abreu goto out; 243091810dbSJose Abreu 244091810dbSJose Abreu thdr = (struct tcphdr *)((u8 *)ihdr + 4 * ihdr->ihl); 245091810dbSJose Abreu if (thdr->dest != htons(tpriv->packet->dport)) 246091810dbSJose Abreu goto out; 247091810dbSJose Abreu 248091810dbSJose Abreu shdr = (struct stmmachdr *)((u8 *)thdr + sizeof(*thdr)); 249091810dbSJose Abreu } else { 250091810dbSJose Abreu if (ihdr->protocol != IPPROTO_UDP) 251091810dbSJose Abreu goto out; 252091810dbSJose Abreu 253091810dbSJose Abreu uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl); 254091810dbSJose Abreu if (uhdr->dest != htons(tpriv->packet->dport)) 255091810dbSJose Abreu goto out; 256091810dbSJose Abreu 257091810dbSJose Abreu shdr = (struct stmmachdr *)((u8 *)uhdr + sizeof(*uhdr)); 258091810dbSJose Abreu } 259091810dbSJose Abreu 260091810dbSJose Abreu if (shdr->magic != cpu_to_be64(STMMAC_TEST_PKT_MAGIC)) 261091810dbSJose Abreu goto out; 262091810dbSJose Abreu if (tpriv->packet->exp_hash && !skb->hash) 263091810dbSJose Abreu goto out; 264091810dbSJose Abreu if (tpriv->packet->id != shdr->id) 265091810dbSJose Abreu goto out; 266091810dbSJose Abreu 267091810dbSJose Abreu tpriv->ok = true; 268091810dbSJose Abreu complete(&tpriv->comp); 269091810dbSJose Abreu out: 270091810dbSJose Abreu kfree_skb(skb); 271091810dbSJose Abreu return 0; 272091810dbSJose Abreu } 273091810dbSJose Abreu 274091810dbSJose Abreu static int __stmmac_test_loopback(struct stmmac_priv *priv, 275091810dbSJose Abreu struct stmmac_packet_attrs *attr) 276091810dbSJose Abreu { 277091810dbSJose Abreu struct stmmac_test_priv *tpriv; 278091810dbSJose Abreu struct sk_buff *skb = NULL; 279091810dbSJose Abreu int ret = 0; 280091810dbSJose Abreu 281091810dbSJose Abreu tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); 282091810dbSJose Abreu if (!tpriv) 283091810dbSJose Abreu return -ENOMEM; 284091810dbSJose Abreu 285091810dbSJose Abreu tpriv->ok = false; 286091810dbSJose Abreu init_completion(&tpriv->comp); 287091810dbSJose Abreu 288091810dbSJose Abreu tpriv->pt.type = htons(ETH_P_IP); 289091810dbSJose Abreu tpriv->pt.func = stmmac_test_loopback_validate; 290091810dbSJose Abreu tpriv->pt.dev = priv->dev; 291091810dbSJose Abreu tpriv->pt.af_packet_priv = tpriv; 292091810dbSJose Abreu tpriv->packet = attr; 293091810dbSJose Abreu dev_add_pack(&tpriv->pt); 294091810dbSJose Abreu 295091810dbSJose Abreu skb = stmmac_test_get_udp_skb(priv, attr); 296091810dbSJose Abreu if (!skb) { 297091810dbSJose Abreu ret = -ENOMEM; 298091810dbSJose Abreu goto cleanup; 299091810dbSJose Abreu } 300091810dbSJose Abreu 301091810dbSJose Abreu skb_set_queue_mapping(skb, 0); 302091810dbSJose Abreu ret = dev_queue_xmit(skb); 303091810dbSJose Abreu if (ret) 304091810dbSJose Abreu goto cleanup; 305091810dbSJose Abreu 306091810dbSJose Abreu if (attr->dont_wait) 307091810dbSJose Abreu goto cleanup; 308091810dbSJose Abreu 309091810dbSJose Abreu if (!attr->timeout) 310091810dbSJose Abreu attr->timeout = STMMAC_LB_TIMEOUT; 311091810dbSJose Abreu 312091810dbSJose Abreu wait_for_completion_timeout(&tpriv->comp, attr->timeout); 313091810dbSJose Abreu ret = !tpriv->ok; 314091810dbSJose Abreu 315091810dbSJose Abreu cleanup: 316091810dbSJose Abreu dev_remove_pack(&tpriv->pt); 317091810dbSJose Abreu kfree(tpriv); 318091810dbSJose Abreu return ret; 319091810dbSJose Abreu } 320091810dbSJose Abreu 321091810dbSJose Abreu static int stmmac_test_mac_loopback(struct stmmac_priv *priv) 322091810dbSJose Abreu { 323091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 324091810dbSJose Abreu 325091810dbSJose Abreu attr.dst = priv->dev->dev_addr; 326091810dbSJose Abreu return __stmmac_test_loopback(priv, &attr); 327091810dbSJose Abreu } 328091810dbSJose Abreu 329091810dbSJose Abreu static int stmmac_test_phy_loopback(struct stmmac_priv *priv) 330091810dbSJose Abreu { 331091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 332091810dbSJose Abreu int ret; 333091810dbSJose Abreu 334091810dbSJose Abreu if (!priv->dev->phydev) 335091810dbSJose Abreu return -EBUSY; 336091810dbSJose Abreu 337091810dbSJose Abreu ret = phy_loopback(priv->dev->phydev, true); 338091810dbSJose Abreu if (ret) 339091810dbSJose Abreu return ret; 340091810dbSJose Abreu 341091810dbSJose Abreu attr.dst = priv->dev->dev_addr; 342091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 343091810dbSJose Abreu 344091810dbSJose Abreu phy_loopback(priv->dev->phydev, false); 345091810dbSJose Abreu return ret; 346091810dbSJose Abreu } 347091810dbSJose Abreu 348091810dbSJose Abreu static int stmmac_test_mmc(struct stmmac_priv *priv) 349091810dbSJose Abreu { 350091810dbSJose Abreu struct stmmac_counters initial, final; 351091810dbSJose Abreu int ret; 352091810dbSJose Abreu 353091810dbSJose Abreu memset(&initial, 0, sizeof(initial)); 354091810dbSJose Abreu memset(&final, 0, sizeof(final)); 355091810dbSJose Abreu 356091810dbSJose Abreu if (!priv->dma_cap.rmon) 357091810dbSJose Abreu return -EOPNOTSUPP; 358091810dbSJose Abreu 359091810dbSJose Abreu /* Save previous results into internal struct */ 360091810dbSJose Abreu stmmac_mmc_read(priv, priv->mmcaddr, &priv->mmc); 361091810dbSJose Abreu 362091810dbSJose Abreu ret = stmmac_test_mac_loopback(priv); 363091810dbSJose Abreu if (ret) 364091810dbSJose Abreu return ret; 365091810dbSJose Abreu 366091810dbSJose Abreu /* These will be loopback results so no need to save them */ 367091810dbSJose Abreu stmmac_mmc_read(priv, priv->mmcaddr, &final); 368091810dbSJose Abreu 369091810dbSJose Abreu /* 370091810dbSJose Abreu * The number of MMC counters available depends on HW configuration 371091810dbSJose Abreu * so we just use this one to validate the feature. I hope there is 372091810dbSJose Abreu * not a version without this counter. 373091810dbSJose Abreu */ 374091810dbSJose Abreu if (final.mmc_tx_framecount_g <= initial.mmc_tx_framecount_g) 375091810dbSJose Abreu return -EINVAL; 376091810dbSJose Abreu 377091810dbSJose Abreu return 0; 378091810dbSJose Abreu } 379091810dbSJose Abreu 380091810dbSJose Abreu static int stmmac_test_eee(struct stmmac_priv *priv) 381091810dbSJose Abreu { 382091810dbSJose Abreu struct stmmac_extra_stats *initial, *final; 383091810dbSJose Abreu int retries = 10; 384091810dbSJose Abreu int ret; 385091810dbSJose Abreu 386091810dbSJose Abreu if (!priv->dma_cap.eee || !priv->eee_active) 387091810dbSJose Abreu return -EOPNOTSUPP; 388091810dbSJose Abreu 389091810dbSJose Abreu initial = kzalloc(sizeof(*initial), GFP_KERNEL); 390091810dbSJose Abreu if (!initial) 391091810dbSJose Abreu return -ENOMEM; 392091810dbSJose Abreu 393091810dbSJose Abreu final = kzalloc(sizeof(*final), GFP_KERNEL); 394091810dbSJose Abreu if (!final) { 395091810dbSJose Abreu ret = -ENOMEM; 396091810dbSJose Abreu goto out_free_initial; 397091810dbSJose Abreu } 398091810dbSJose Abreu 399091810dbSJose Abreu memcpy(initial, &priv->xstats, sizeof(*initial)); 400091810dbSJose Abreu 401091810dbSJose Abreu ret = stmmac_test_mac_loopback(priv); 402091810dbSJose Abreu if (ret) 403091810dbSJose Abreu goto out_free_final; 404091810dbSJose Abreu 405091810dbSJose Abreu /* We have no traffic in the line so, sooner or later it will go LPI */ 406091810dbSJose Abreu while (--retries) { 407091810dbSJose Abreu memcpy(final, &priv->xstats, sizeof(*final)); 408091810dbSJose Abreu 409091810dbSJose Abreu if (final->irq_tx_path_in_lpi_mode_n > 410091810dbSJose Abreu initial->irq_tx_path_in_lpi_mode_n) 411091810dbSJose Abreu break; 412091810dbSJose Abreu msleep(100); 413091810dbSJose Abreu } 414091810dbSJose Abreu 415091810dbSJose Abreu if (!retries) { 416091810dbSJose Abreu ret = -ETIMEDOUT; 417091810dbSJose Abreu goto out_free_final; 418091810dbSJose Abreu } 419091810dbSJose Abreu 420091810dbSJose Abreu if (final->irq_tx_path_in_lpi_mode_n <= 421091810dbSJose Abreu initial->irq_tx_path_in_lpi_mode_n) { 422091810dbSJose Abreu ret = -EINVAL; 423091810dbSJose Abreu goto out_free_final; 424091810dbSJose Abreu } 425091810dbSJose Abreu 426091810dbSJose Abreu if (final->irq_tx_path_exit_lpi_mode_n <= 427091810dbSJose Abreu initial->irq_tx_path_exit_lpi_mode_n) { 428091810dbSJose Abreu ret = -EINVAL; 429091810dbSJose Abreu goto out_free_final; 430091810dbSJose Abreu } 431091810dbSJose Abreu 432091810dbSJose Abreu out_free_final: 433091810dbSJose Abreu kfree(final); 434091810dbSJose Abreu out_free_initial: 435091810dbSJose Abreu kfree(initial); 436091810dbSJose Abreu return ret; 437091810dbSJose Abreu } 438091810dbSJose Abreu 439091810dbSJose Abreu static int stmmac_filter_check(struct stmmac_priv *priv) 440091810dbSJose Abreu { 441091810dbSJose Abreu if (!(priv->dev->flags & IFF_PROMISC)) 442091810dbSJose Abreu return 0; 443091810dbSJose Abreu 444091810dbSJose Abreu netdev_warn(priv->dev, "Test can't be run in promiscuous mode!\n"); 445091810dbSJose Abreu return -EOPNOTSUPP; 446091810dbSJose Abreu } 447091810dbSJose Abreu 448091810dbSJose Abreu static int stmmac_test_hfilt(struct stmmac_priv *priv) 449091810dbSJose Abreu { 450091810dbSJose Abreu unsigned char gd_addr[ETH_ALEN] = {0x01, 0x00, 0xcc, 0xcc, 0xdd, 0xdd}; 451091810dbSJose Abreu unsigned char bd_addr[ETH_ALEN] = {0x09, 0x00, 0xaa, 0xaa, 0xbb, 0xbb}; 452091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 453091810dbSJose Abreu int ret; 454091810dbSJose Abreu 455091810dbSJose Abreu ret = stmmac_filter_check(priv); 456091810dbSJose Abreu if (ret) 457091810dbSJose Abreu return ret; 458091810dbSJose Abreu 459091810dbSJose Abreu ret = dev_mc_add(priv->dev, gd_addr); 460091810dbSJose Abreu if (ret) 461091810dbSJose Abreu return ret; 462091810dbSJose Abreu 463091810dbSJose Abreu attr.dst = gd_addr; 464091810dbSJose Abreu 465091810dbSJose Abreu /* Shall receive packet */ 466091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 467091810dbSJose Abreu if (ret) 468091810dbSJose Abreu goto cleanup; 469091810dbSJose Abreu 470091810dbSJose Abreu attr.dst = bd_addr; 471091810dbSJose Abreu 472091810dbSJose Abreu /* Shall NOT receive packet */ 473091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 474091810dbSJose Abreu ret = !ret; 475091810dbSJose Abreu 476091810dbSJose Abreu cleanup: 477091810dbSJose Abreu dev_mc_del(priv->dev, gd_addr); 478091810dbSJose Abreu return ret; 479091810dbSJose Abreu } 480091810dbSJose Abreu 481091810dbSJose Abreu static int stmmac_test_pfilt(struct stmmac_priv *priv) 482091810dbSJose Abreu { 483091810dbSJose Abreu unsigned char gd_addr[ETH_ALEN] = {0x00, 0x01, 0x44, 0x55, 0x66, 0x77}; 484091810dbSJose Abreu unsigned char bd_addr[ETH_ALEN] = {0x08, 0x00, 0x22, 0x33, 0x44, 0x55}; 485091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 486091810dbSJose Abreu int ret; 487091810dbSJose Abreu 488091810dbSJose Abreu if (stmmac_filter_check(priv)) 489091810dbSJose Abreu return -EOPNOTSUPP; 490091810dbSJose Abreu 491091810dbSJose Abreu ret = dev_uc_add(priv->dev, gd_addr); 492091810dbSJose Abreu if (ret) 493091810dbSJose Abreu return ret; 494091810dbSJose Abreu 495091810dbSJose Abreu attr.dst = gd_addr; 496091810dbSJose Abreu 497091810dbSJose Abreu /* Shall receive packet */ 498091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 499091810dbSJose Abreu if (ret) 500091810dbSJose Abreu goto cleanup; 501091810dbSJose Abreu 502091810dbSJose Abreu attr.dst = bd_addr; 503091810dbSJose Abreu 504091810dbSJose Abreu /* Shall NOT receive packet */ 505091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 506091810dbSJose Abreu ret = !ret; 507091810dbSJose Abreu 508091810dbSJose Abreu cleanup: 509091810dbSJose Abreu dev_uc_del(priv->dev, gd_addr); 510091810dbSJose Abreu return ret; 511091810dbSJose Abreu } 512091810dbSJose Abreu 513091810dbSJose Abreu static int stmmac_dummy_sync(struct net_device *netdev, const u8 *addr) 514091810dbSJose Abreu { 515091810dbSJose Abreu return 0; 516091810dbSJose Abreu } 517091810dbSJose Abreu 518091810dbSJose Abreu static void stmmac_test_set_rx_mode(struct net_device *netdev) 519091810dbSJose Abreu { 520091810dbSJose Abreu /* As we are in test mode of ethtool we already own the rtnl lock 521091810dbSJose Abreu * so no address will change from user. We can just call the 522091810dbSJose Abreu * ndo_set_rx_mode() callback directly */ 523091810dbSJose Abreu if (netdev->netdev_ops->ndo_set_rx_mode) 524091810dbSJose Abreu netdev->netdev_ops->ndo_set_rx_mode(netdev); 525091810dbSJose Abreu } 526091810dbSJose Abreu 527091810dbSJose Abreu static int stmmac_test_mcfilt(struct stmmac_priv *priv) 528091810dbSJose Abreu { 529091810dbSJose Abreu unsigned char uc_addr[ETH_ALEN] = {0x00, 0x01, 0x44, 0x55, 0x66, 0x77}; 530091810dbSJose Abreu unsigned char mc_addr[ETH_ALEN] = {0x01, 0x01, 0x44, 0x55, 0x66, 0x77}; 531091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 532091810dbSJose Abreu int ret; 533091810dbSJose Abreu 534091810dbSJose Abreu if (stmmac_filter_check(priv)) 535091810dbSJose Abreu return -EOPNOTSUPP; 536091810dbSJose Abreu 537091810dbSJose Abreu /* Remove all MC addresses */ 538091810dbSJose Abreu __dev_mc_unsync(priv->dev, NULL); 539091810dbSJose Abreu stmmac_test_set_rx_mode(priv->dev); 540091810dbSJose Abreu 541091810dbSJose Abreu ret = dev_uc_add(priv->dev, uc_addr); 542091810dbSJose Abreu if (ret) 543091810dbSJose Abreu goto cleanup; 544091810dbSJose Abreu 545091810dbSJose Abreu attr.dst = uc_addr; 546091810dbSJose Abreu 547091810dbSJose Abreu /* Shall receive packet */ 548091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 549091810dbSJose Abreu if (ret) 550091810dbSJose Abreu goto cleanup; 551091810dbSJose Abreu 552091810dbSJose Abreu attr.dst = mc_addr; 553091810dbSJose Abreu 554091810dbSJose Abreu /* Shall NOT receive packet */ 555091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 556091810dbSJose Abreu ret = !ret; 557091810dbSJose Abreu 558091810dbSJose Abreu cleanup: 559091810dbSJose Abreu dev_uc_del(priv->dev, uc_addr); 560091810dbSJose Abreu __dev_mc_sync(priv->dev, stmmac_dummy_sync, NULL); 561091810dbSJose Abreu stmmac_test_set_rx_mode(priv->dev); 562091810dbSJose Abreu return ret; 563091810dbSJose Abreu } 564091810dbSJose Abreu 565091810dbSJose Abreu static int stmmac_test_ucfilt(struct stmmac_priv *priv) 566091810dbSJose Abreu { 567091810dbSJose Abreu unsigned char uc_addr[ETH_ALEN] = {0x00, 0x01, 0x44, 0x55, 0x66, 0x77}; 568091810dbSJose Abreu unsigned char mc_addr[ETH_ALEN] = {0x01, 0x01, 0x44, 0x55, 0x66, 0x77}; 569091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 570091810dbSJose Abreu int ret; 571091810dbSJose Abreu 572091810dbSJose Abreu if (stmmac_filter_check(priv)) 573091810dbSJose Abreu return -EOPNOTSUPP; 574091810dbSJose Abreu 575091810dbSJose Abreu /* Remove all UC addresses */ 576091810dbSJose Abreu __dev_uc_unsync(priv->dev, NULL); 577091810dbSJose Abreu stmmac_test_set_rx_mode(priv->dev); 578091810dbSJose Abreu 579091810dbSJose Abreu ret = dev_mc_add(priv->dev, mc_addr); 580091810dbSJose Abreu if (ret) 581091810dbSJose Abreu goto cleanup; 582091810dbSJose Abreu 583091810dbSJose Abreu attr.dst = mc_addr; 584091810dbSJose Abreu 585091810dbSJose Abreu /* Shall receive packet */ 586091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 587091810dbSJose Abreu if (ret) 588091810dbSJose Abreu goto cleanup; 589091810dbSJose Abreu 590091810dbSJose Abreu attr.dst = uc_addr; 591091810dbSJose Abreu 592091810dbSJose Abreu /* Shall NOT receive packet */ 593091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 594091810dbSJose Abreu ret = !ret; 595091810dbSJose Abreu 596091810dbSJose Abreu cleanup: 597091810dbSJose Abreu dev_mc_del(priv->dev, mc_addr); 598091810dbSJose Abreu __dev_uc_sync(priv->dev, stmmac_dummy_sync, NULL); 599091810dbSJose Abreu stmmac_test_set_rx_mode(priv->dev); 600091810dbSJose Abreu return ret; 601091810dbSJose Abreu } 602091810dbSJose Abreu 603091810dbSJose Abreu static int stmmac_test_flowctrl_validate(struct sk_buff *skb, 604091810dbSJose Abreu struct net_device *ndev, 605091810dbSJose Abreu struct packet_type *pt, 606091810dbSJose Abreu struct net_device *orig_ndev) 607091810dbSJose Abreu { 608091810dbSJose Abreu struct stmmac_test_priv *tpriv = pt->af_packet_priv; 609091810dbSJose Abreu struct ethhdr *ehdr; 610091810dbSJose Abreu 611091810dbSJose Abreu ehdr = (struct ethhdr *)skb_mac_header(skb); 612091810dbSJose Abreu if (!ether_addr_equal(ehdr->h_source, orig_ndev->dev_addr)) 613091810dbSJose Abreu goto out; 614091810dbSJose Abreu if (ehdr->h_proto != htons(ETH_P_PAUSE)) 615091810dbSJose Abreu goto out; 616091810dbSJose Abreu 617091810dbSJose Abreu tpriv->ok = true; 618091810dbSJose Abreu complete(&tpriv->comp); 619091810dbSJose Abreu out: 620091810dbSJose Abreu kfree(skb); 621091810dbSJose Abreu return 0; 622091810dbSJose Abreu } 623091810dbSJose Abreu 624091810dbSJose Abreu static int stmmac_test_flowctrl(struct stmmac_priv *priv) 625091810dbSJose Abreu { 626091810dbSJose Abreu unsigned char paddr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01}; 627091810dbSJose Abreu struct phy_device *phydev = priv->dev->phydev; 628091810dbSJose Abreu u32 rx_cnt = priv->plat->rx_queues_to_use; 629091810dbSJose Abreu struct stmmac_test_priv *tpriv; 630091810dbSJose Abreu unsigned int pkt_count; 631091810dbSJose Abreu int i, ret = 0; 632091810dbSJose Abreu 633091810dbSJose Abreu if (!phydev || !phydev->pause) 634091810dbSJose Abreu return -EOPNOTSUPP; 635091810dbSJose Abreu 636091810dbSJose Abreu tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); 637091810dbSJose Abreu if (!tpriv) 638091810dbSJose Abreu return -ENOMEM; 639091810dbSJose Abreu 640091810dbSJose Abreu tpriv->ok = false; 641091810dbSJose Abreu init_completion(&tpriv->comp); 642091810dbSJose Abreu tpriv->pt.type = htons(ETH_P_PAUSE); 643091810dbSJose Abreu tpriv->pt.func = stmmac_test_flowctrl_validate; 644091810dbSJose Abreu tpriv->pt.dev = priv->dev; 645091810dbSJose Abreu tpriv->pt.af_packet_priv = tpriv; 646091810dbSJose Abreu dev_add_pack(&tpriv->pt); 647091810dbSJose Abreu 648091810dbSJose Abreu /* Compute minimum number of packets to make FIFO full */ 649091810dbSJose Abreu pkt_count = priv->plat->rx_fifo_size; 650091810dbSJose Abreu if (!pkt_count) 651091810dbSJose Abreu pkt_count = priv->dma_cap.rx_fifo_size; 652091810dbSJose Abreu pkt_count /= 1400; 653091810dbSJose Abreu pkt_count *= 2; 654091810dbSJose Abreu 655091810dbSJose Abreu for (i = 0; i < rx_cnt; i++) 656091810dbSJose Abreu stmmac_stop_rx(priv, priv->ioaddr, i); 657091810dbSJose Abreu 658091810dbSJose Abreu ret = dev_set_promiscuity(priv->dev, 1); 659091810dbSJose Abreu if (ret) 660091810dbSJose Abreu goto cleanup; 661091810dbSJose Abreu 662091810dbSJose Abreu ret = dev_mc_add(priv->dev, paddr); 663091810dbSJose Abreu if (ret) 664091810dbSJose Abreu goto cleanup; 665091810dbSJose Abreu 666091810dbSJose Abreu for (i = 0; i < pkt_count; i++) { 667091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 668091810dbSJose Abreu 669091810dbSJose Abreu attr.dst = priv->dev->dev_addr; 670091810dbSJose Abreu attr.dont_wait = true; 671091810dbSJose Abreu attr.size = 1400; 672091810dbSJose Abreu 673091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 674091810dbSJose Abreu if (ret) 675091810dbSJose Abreu goto cleanup; 676091810dbSJose Abreu if (tpriv->ok) 677091810dbSJose Abreu break; 678091810dbSJose Abreu } 679091810dbSJose Abreu 680091810dbSJose Abreu /* Wait for some time in case RX Watchdog is enabled */ 681091810dbSJose Abreu msleep(200); 682091810dbSJose Abreu 683091810dbSJose Abreu for (i = 0; i < rx_cnt; i++) { 684091810dbSJose Abreu struct stmmac_channel *ch = &priv->channel[i]; 685091810dbSJose Abreu 686091810dbSJose Abreu stmmac_start_rx(priv, priv->ioaddr, i); 687091810dbSJose Abreu local_bh_disable(); 688091810dbSJose Abreu napi_reschedule(&ch->rx_napi); 689091810dbSJose Abreu local_bh_enable(); 690091810dbSJose Abreu } 691091810dbSJose Abreu 692091810dbSJose Abreu wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT); 693091810dbSJose Abreu ret = !tpriv->ok; 694091810dbSJose Abreu 695091810dbSJose Abreu cleanup: 696091810dbSJose Abreu dev_mc_del(priv->dev, paddr); 697091810dbSJose Abreu dev_set_promiscuity(priv->dev, -1); 698091810dbSJose Abreu dev_remove_pack(&tpriv->pt); 699091810dbSJose Abreu kfree(tpriv); 700091810dbSJose Abreu return ret; 701091810dbSJose Abreu } 702091810dbSJose Abreu 703091810dbSJose Abreu #define STMMAC_LOOPBACK_NONE 0 704091810dbSJose Abreu #define STMMAC_LOOPBACK_MAC 1 705091810dbSJose Abreu #define STMMAC_LOOPBACK_PHY 2 706091810dbSJose Abreu 707091810dbSJose Abreu static const struct stmmac_test { 708091810dbSJose Abreu char name[ETH_GSTRING_LEN]; 709091810dbSJose Abreu int lb; 710091810dbSJose Abreu int (*fn)(struct stmmac_priv *priv); 711091810dbSJose Abreu } stmmac_selftests[] = { 712091810dbSJose Abreu { 713091810dbSJose Abreu .name = "MAC Loopback ", 714091810dbSJose Abreu .lb = STMMAC_LOOPBACK_MAC, 715091810dbSJose Abreu .fn = stmmac_test_mac_loopback, 716091810dbSJose Abreu }, { 717091810dbSJose Abreu .name = "PHY Loopback ", 718091810dbSJose Abreu .lb = STMMAC_LOOPBACK_NONE, /* Test will handle it */ 719091810dbSJose Abreu .fn = stmmac_test_phy_loopback, 720091810dbSJose Abreu }, { 721091810dbSJose Abreu .name = "MMC Counters ", 722091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 723091810dbSJose Abreu .fn = stmmac_test_mmc, 724091810dbSJose Abreu }, { 725091810dbSJose Abreu .name = "EEE ", 726091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 727091810dbSJose Abreu .fn = stmmac_test_eee, 728091810dbSJose Abreu }, { 729091810dbSJose Abreu .name = "Hash Filter MC ", 730091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 731091810dbSJose Abreu .fn = stmmac_test_hfilt, 732091810dbSJose Abreu }, { 733091810dbSJose Abreu .name = "Perfect Filter UC ", 734091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 735091810dbSJose Abreu .fn = stmmac_test_pfilt, 736091810dbSJose Abreu }, { 737091810dbSJose Abreu .name = "MC Filter ", 738091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 739091810dbSJose Abreu .fn = stmmac_test_mcfilt, 740091810dbSJose Abreu }, { 741091810dbSJose Abreu .name = "UC Filter ", 742091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 743091810dbSJose Abreu .fn = stmmac_test_ucfilt, 744091810dbSJose Abreu }, { 745091810dbSJose Abreu .name = "Flow Control ", 746091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 747091810dbSJose Abreu .fn = stmmac_test_flowctrl, 748091810dbSJose Abreu }, 749091810dbSJose Abreu }; 750091810dbSJose Abreu 751091810dbSJose Abreu void stmmac_selftest_run(struct net_device *dev, 752091810dbSJose Abreu struct ethtool_test *etest, u64 *buf) 753091810dbSJose Abreu { 754091810dbSJose Abreu struct stmmac_priv *priv = netdev_priv(dev); 755091810dbSJose Abreu int count = stmmac_selftest_get_count(priv); 756091810dbSJose Abreu int carrier = netif_carrier_ok(dev); 757091810dbSJose Abreu int i, ret; 758091810dbSJose Abreu 759091810dbSJose Abreu memset(buf, 0, sizeof(*buf) * count); 760091810dbSJose Abreu stmmac_test_next_id = 0; 761091810dbSJose Abreu 762091810dbSJose Abreu if (etest->flags != ETH_TEST_FL_OFFLINE) { 763091810dbSJose Abreu netdev_err(priv->dev, "Only offline tests are supported\n"); 764091810dbSJose Abreu etest->flags |= ETH_TEST_FL_FAILED; 765091810dbSJose Abreu return; 766091810dbSJose Abreu } else if (!carrier) { 767091810dbSJose Abreu netdev_err(priv->dev, "You need valid Link to execute tests\n"); 768091810dbSJose Abreu etest->flags |= ETH_TEST_FL_FAILED; 769091810dbSJose Abreu return; 770091810dbSJose Abreu } 771091810dbSJose Abreu 772091810dbSJose Abreu /* We don't want extra traffic */ 773091810dbSJose Abreu netif_carrier_off(dev); 774091810dbSJose Abreu 775091810dbSJose Abreu /* Wait for queues drain */ 776091810dbSJose Abreu msleep(200); 777091810dbSJose Abreu 778091810dbSJose Abreu for (i = 0; i < count; i++) { 779091810dbSJose Abreu ret = 0; 780091810dbSJose Abreu 781091810dbSJose Abreu switch (stmmac_selftests[i].lb) { 782091810dbSJose Abreu case STMMAC_LOOPBACK_PHY: 783091810dbSJose Abreu ret = -EOPNOTSUPP; 784091810dbSJose Abreu if (dev->phydev) 785091810dbSJose Abreu ret = phy_loopback(dev->phydev, true); 786091810dbSJose Abreu if (!ret) 787091810dbSJose Abreu break; 788091810dbSJose Abreu /* Fallthrough */ 789091810dbSJose Abreu case STMMAC_LOOPBACK_MAC: 790091810dbSJose Abreu ret = stmmac_set_mac_loopback(priv, priv->ioaddr, true); 791091810dbSJose Abreu break; 792091810dbSJose Abreu case STMMAC_LOOPBACK_NONE: 793091810dbSJose Abreu break; 794091810dbSJose Abreu default: 795091810dbSJose Abreu ret = -EOPNOTSUPP; 796091810dbSJose Abreu break; 797091810dbSJose Abreu } 798091810dbSJose Abreu 799091810dbSJose Abreu /* 800091810dbSJose Abreu * First tests will always be MAC / PHY loobpack. If any of 801091810dbSJose Abreu * them is not supported we abort earlier. 802091810dbSJose Abreu */ 803091810dbSJose Abreu if (ret) { 804091810dbSJose Abreu netdev_err(priv->dev, "Loopback is not supported\n"); 805091810dbSJose Abreu etest->flags |= ETH_TEST_FL_FAILED; 806091810dbSJose Abreu break; 807091810dbSJose Abreu } 808091810dbSJose Abreu 809091810dbSJose Abreu ret = stmmac_selftests[i].fn(priv); 810091810dbSJose Abreu if (ret && (ret != -EOPNOTSUPP)) 811091810dbSJose Abreu etest->flags |= ETH_TEST_FL_FAILED; 812091810dbSJose Abreu buf[i] = ret; 813091810dbSJose Abreu 814091810dbSJose Abreu switch (stmmac_selftests[i].lb) { 815091810dbSJose Abreu case STMMAC_LOOPBACK_PHY: 816091810dbSJose Abreu ret = -EOPNOTSUPP; 817091810dbSJose Abreu if (dev->phydev) 818091810dbSJose Abreu ret = phy_loopback(dev->phydev, false); 819091810dbSJose Abreu if (!ret) 820091810dbSJose Abreu break; 821091810dbSJose Abreu /* Fallthrough */ 822091810dbSJose Abreu case STMMAC_LOOPBACK_MAC: 823091810dbSJose Abreu stmmac_set_mac_loopback(priv, priv->ioaddr, false); 824091810dbSJose Abreu break; 825091810dbSJose Abreu default: 826091810dbSJose Abreu break; 827091810dbSJose Abreu } 828091810dbSJose Abreu } 829091810dbSJose Abreu 830091810dbSJose Abreu /* Restart everything */ 831091810dbSJose Abreu if (carrier) 832091810dbSJose Abreu netif_carrier_on(dev); 833091810dbSJose Abreu } 834091810dbSJose Abreu 835091810dbSJose Abreu void stmmac_selftest_get_strings(struct stmmac_priv *priv, u8 *data) 836091810dbSJose Abreu { 837091810dbSJose Abreu u8 *p = data; 838091810dbSJose Abreu int i; 839091810dbSJose Abreu 840091810dbSJose Abreu for (i = 0; i < stmmac_selftest_get_count(priv); i++) { 841091810dbSJose Abreu snprintf(p, ETH_GSTRING_LEN, "%2d. %s", i + 1, 842091810dbSJose Abreu stmmac_selftests[i].name); 843091810dbSJose Abreu p += ETH_GSTRING_LEN; 844091810dbSJose Abreu } 845091810dbSJose Abreu } 846091810dbSJose Abreu 847091810dbSJose Abreu int stmmac_selftest_get_count(struct stmmac_priv *priv) 848091810dbSJose Abreu { 849091810dbSJose Abreu return ARRAY_SIZE(stmmac_selftests); 850091810dbSJose Abreu } 851