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 9eeb9d745SJose Abreu #include <linux/bitrev.h> 10091810dbSJose Abreu #include <linux/completion.h> 11eeb9d745SJose Abreu #include <linux/crc32.h> 12091810dbSJose Abreu #include <linux/ethtool.h> 13091810dbSJose Abreu #include <linux/ip.h> 14091810dbSJose Abreu #include <linux/phy.h> 15091810dbSJose Abreu #include <linux/udp.h> 16ccfc639aSJose Abreu #include <net/pkt_cls.h> 1728c1cf73SJose Abreu #include <net/pkt_sched.h> 18091810dbSJose Abreu #include <net/tcp.h> 19091810dbSJose Abreu #include <net/udp.h> 20ccfc639aSJose Abreu #include <net/tc_act/tc_gact.h> 21091810dbSJose Abreu #include "stmmac.h" 22091810dbSJose Abreu 23091810dbSJose Abreu struct stmmachdr { 24091810dbSJose Abreu __be32 version; 25091810dbSJose Abreu __be64 magic; 26091810dbSJose Abreu u8 id; 27091810dbSJose Abreu } __packed; 28091810dbSJose Abreu 29091810dbSJose Abreu #define STMMAC_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \ 30091810dbSJose Abreu sizeof(struct stmmachdr)) 31091810dbSJose Abreu #define STMMAC_TEST_PKT_MAGIC 0xdeadcafecafedeadULL 32091810dbSJose Abreu #define STMMAC_LB_TIMEOUT msecs_to_jiffies(200) 33091810dbSJose Abreu 34091810dbSJose Abreu struct stmmac_packet_attrs { 35091810dbSJose Abreu int vlan; 36091810dbSJose Abreu int vlan_id_in; 37091810dbSJose Abreu int vlan_id_out; 38091810dbSJose Abreu unsigned char *src; 3976660757SJakub Kicinski const unsigned char *dst; 40091810dbSJose Abreu u32 ip_src; 41091810dbSJose Abreu u32 ip_dst; 42091810dbSJose Abreu int tcp; 43091810dbSJose Abreu int sport; 44091810dbSJose Abreu int dport; 45091810dbSJose Abreu u32 exp_hash; 46091810dbSJose Abreu int dont_wait; 47091810dbSJose Abreu int timeout; 48091810dbSJose Abreu int size; 49427849e8SJose Abreu int max_size; 50091810dbSJose Abreu int remove_sa; 51091810dbSJose Abreu u8 id; 528180d579SJose Abreu int sarc; 53427849e8SJose Abreu u16 queue_mapping; 5428c1cf73SJose Abreu u64 timestamp; 55091810dbSJose Abreu }; 56091810dbSJose Abreu 57091810dbSJose Abreu static u8 stmmac_test_next_id; 58091810dbSJose Abreu 59091810dbSJose Abreu static struct sk_buff *stmmac_test_get_udp_skb(struct stmmac_priv *priv, 60091810dbSJose Abreu struct stmmac_packet_attrs *attr) 61091810dbSJose Abreu { 62091810dbSJose Abreu struct sk_buff *skb = NULL; 63091810dbSJose Abreu struct udphdr *uhdr = NULL; 64091810dbSJose Abreu struct tcphdr *thdr = NULL; 65091810dbSJose Abreu struct stmmachdr *shdr; 66091810dbSJose Abreu struct ethhdr *ehdr; 67091810dbSJose Abreu struct iphdr *ihdr; 68091810dbSJose Abreu int iplen, size; 69091810dbSJose Abreu 70091810dbSJose Abreu size = attr->size + STMMAC_TEST_PKT_SIZE; 71091810dbSJose Abreu if (attr->vlan) { 72091810dbSJose Abreu size += 4; 73091810dbSJose Abreu if (attr->vlan > 1) 74091810dbSJose Abreu size += 4; 75091810dbSJose Abreu } 76091810dbSJose Abreu 77091810dbSJose Abreu if (attr->tcp) 78091810dbSJose Abreu size += sizeof(struct tcphdr); 79091810dbSJose Abreu else 80091810dbSJose Abreu size += sizeof(struct udphdr); 81091810dbSJose Abreu 82427849e8SJose Abreu if (attr->max_size && (attr->max_size > size)) 83427849e8SJose Abreu size = attr->max_size; 84427849e8SJose Abreu 850b9f932eSJose Abreu skb = netdev_alloc_skb(priv->dev, size); 86091810dbSJose Abreu if (!skb) 87091810dbSJose Abreu return NULL; 88091810dbSJose Abreu 89091810dbSJose Abreu prefetchw(skb->data); 90091810dbSJose Abreu 91091810dbSJose Abreu if (attr->vlan > 1) 92091810dbSJose Abreu ehdr = skb_push(skb, ETH_HLEN + 8); 93091810dbSJose Abreu else if (attr->vlan) 94091810dbSJose Abreu ehdr = skb_push(skb, ETH_HLEN + 4); 95091810dbSJose Abreu else if (attr->remove_sa) 96091810dbSJose Abreu ehdr = skb_push(skb, ETH_HLEN - 6); 97091810dbSJose Abreu else 98091810dbSJose Abreu ehdr = skb_push(skb, ETH_HLEN); 99091810dbSJose Abreu skb_reset_mac_header(skb); 100091810dbSJose Abreu 101091810dbSJose Abreu skb_set_network_header(skb, skb->len); 102091810dbSJose Abreu ihdr = skb_put(skb, sizeof(*ihdr)); 103091810dbSJose Abreu 104091810dbSJose Abreu skb_set_transport_header(skb, skb->len); 105091810dbSJose Abreu if (attr->tcp) 106091810dbSJose Abreu thdr = skb_put(skb, sizeof(*thdr)); 107091810dbSJose Abreu else 108091810dbSJose Abreu uhdr = skb_put(skb, sizeof(*uhdr)); 109091810dbSJose Abreu 110091810dbSJose Abreu if (!attr->remove_sa) 111091810dbSJose Abreu eth_zero_addr(ehdr->h_source); 112091810dbSJose Abreu eth_zero_addr(ehdr->h_dest); 113091810dbSJose Abreu if (attr->src && !attr->remove_sa) 114091810dbSJose Abreu ether_addr_copy(ehdr->h_source, attr->src); 115091810dbSJose Abreu if (attr->dst) 116091810dbSJose Abreu ether_addr_copy(ehdr->h_dest, attr->dst); 117091810dbSJose Abreu 118091810dbSJose Abreu if (!attr->remove_sa) { 119091810dbSJose Abreu ehdr->h_proto = htons(ETH_P_IP); 120091810dbSJose Abreu } else { 121091810dbSJose Abreu __be16 *ptr = (__be16 *)ehdr; 122091810dbSJose Abreu 123091810dbSJose Abreu /* HACK */ 124091810dbSJose Abreu ptr[3] = htons(ETH_P_IP); 125091810dbSJose Abreu } 126091810dbSJose Abreu 127091810dbSJose Abreu if (attr->vlan) { 1282d135deaSJose Abreu __be16 *tag, *proto; 129091810dbSJose Abreu 130091810dbSJose Abreu if (!attr->remove_sa) { 131091810dbSJose Abreu tag = (void *)ehdr + ETH_HLEN; 132091810dbSJose Abreu proto = (void *)ehdr + (2 * ETH_ALEN); 133091810dbSJose Abreu } else { 134091810dbSJose Abreu tag = (void *)ehdr + ETH_HLEN - 6; 135091810dbSJose Abreu proto = (void *)ehdr + ETH_ALEN; 136091810dbSJose Abreu } 137091810dbSJose Abreu 138091810dbSJose Abreu proto[0] = htons(ETH_P_8021Q); 139091810dbSJose Abreu tag[0] = htons(attr->vlan_id_out); 140091810dbSJose Abreu tag[1] = htons(ETH_P_IP); 141091810dbSJose Abreu if (attr->vlan > 1) { 142091810dbSJose Abreu proto[0] = htons(ETH_P_8021AD); 143091810dbSJose Abreu tag[1] = htons(ETH_P_8021Q); 144091810dbSJose Abreu tag[2] = htons(attr->vlan_id_in); 145091810dbSJose Abreu tag[3] = htons(ETH_P_IP); 146091810dbSJose Abreu } 147091810dbSJose Abreu } 148091810dbSJose Abreu 149091810dbSJose Abreu if (attr->tcp) { 150091810dbSJose Abreu thdr->source = htons(attr->sport); 151091810dbSJose Abreu thdr->dest = htons(attr->dport); 152091810dbSJose Abreu thdr->doff = sizeof(struct tcphdr) / 4; 153091810dbSJose Abreu thdr->check = 0; 154091810dbSJose Abreu } else { 155091810dbSJose Abreu uhdr->source = htons(attr->sport); 156091810dbSJose Abreu uhdr->dest = htons(attr->dport); 157091810dbSJose Abreu uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size); 158427849e8SJose Abreu if (attr->max_size) 159427849e8SJose Abreu uhdr->len = htons(attr->max_size - 160427849e8SJose Abreu (sizeof(*ihdr) + sizeof(*ehdr))); 161091810dbSJose Abreu uhdr->check = 0; 162091810dbSJose Abreu } 163091810dbSJose Abreu 164091810dbSJose Abreu ihdr->ihl = 5; 165091810dbSJose Abreu ihdr->ttl = 32; 166091810dbSJose Abreu ihdr->version = 4; 167091810dbSJose Abreu if (attr->tcp) 168091810dbSJose Abreu ihdr->protocol = IPPROTO_TCP; 169091810dbSJose Abreu else 170091810dbSJose Abreu ihdr->protocol = IPPROTO_UDP; 171091810dbSJose Abreu iplen = sizeof(*ihdr) + sizeof(*shdr) + attr->size; 172091810dbSJose Abreu if (attr->tcp) 173091810dbSJose Abreu iplen += sizeof(*thdr); 174091810dbSJose Abreu else 175091810dbSJose Abreu iplen += sizeof(*uhdr); 176427849e8SJose Abreu 177427849e8SJose Abreu if (attr->max_size) 178427849e8SJose Abreu iplen = attr->max_size - sizeof(*ehdr); 179427849e8SJose Abreu 180091810dbSJose Abreu ihdr->tot_len = htons(iplen); 181091810dbSJose Abreu ihdr->frag_off = 0; 1824647e021SJose Abreu ihdr->saddr = htonl(attr->ip_src); 183091810dbSJose Abreu ihdr->daddr = htonl(attr->ip_dst); 184091810dbSJose Abreu ihdr->tos = 0; 185091810dbSJose Abreu ihdr->id = 0; 186091810dbSJose Abreu ip_send_check(ihdr); 187091810dbSJose Abreu 188091810dbSJose Abreu shdr = skb_put(skb, sizeof(*shdr)); 189091810dbSJose Abreu shdr->version = 0; 190091810dbSJose Abreu shdr->magic = cpu_to_be64(STMMAC_TEST_PKT_MAGIC); 191091810dbSJose Abreu attr->id = stmmac_test_next_id; 192091810dbSJose Abreu shdr->id = stmmac_test_next_id++; 193091810dbSJose Abreu 194091810dbSJose Abreu if (attr->size) 195091810dbSJose Abreu skb_put(skb, attr->size); 196427849e8SJose Abreu if (attr->max_size && (attr->max_size > skb->len)) 197427849e8SJose Abreu skb_put(skb, attr->max_size - skb->len); 198091810dbSJose Abreu 199091810dbSJose Abreu skb->csum = 0; 200091810dbSJose Abreu skb->ip_summed = CHECKSUM_PARTIAL; 201091810dbSJose Abreu if (attr->tcp) { 202091810dbSJose Abreu thdr->check = ~tcp_v4_check(skb->len, ihdr->saddr, ihdr->daddr, 0); 203091810dbSJose Abreu skb->csum_start = skb_transport_header(skb) - skb->head; 204091810dbSJose Abreu skb->csum_offset = offsetof(struct tcphdr, check); 205091810dbSJose Abreu } else { 206091810dbSJose Abreu udp4_hwcsum(skb, ihdr->saddr, ihdr->daddr); 207091810dbSJose Abreu } 208091810dbSJose Abreu 209091810dbSJose Abreu skb->protocol = htons(ETH_P_IP); 210091810dbSJose Abreu skb->pkt_type = PACKET_HOST; 211091810dbSJose Abreu skb->dev = priv->dev; 212091810dbSJose Abreu 21328c1cf73SJose Abreu if (attr->timestamp) 21428c1cf73SJose Abreu skb->tstamp = ns_to_ktime(attr->timestamp); 21528c1cf73SJose Abreu 216091810dbSJose Abreu return skb; 217091810dbSJose Abreu } 218091810dbSJose Abreu 2195e3fb0a6SJose Abreu static struct sk_buff *stmmac_test_get_arp_skb(struct stmmac_priv *priv, 2205e3fb0a6SJose Abreu struct stmmac_packet_attrs *attr) 2215e3fb0a6SJose Abreu { 2225e3fb0a6SJose Abreu __be32 ip_src = htonl(attr->ip_src); 2235e3fb0a6SJose Abreu __be32 ip_dst = htonl(attr->ip_dst); 2245e3fb0a6SJose Abreu struct sk_buff *skb = NULL; 2255e3fb0a6SJose Abreu 2265e3fb0a6SJose Abreu skb = arp_create(ARPOP_REQUEST, ETH_P_ARP, ip_dst, priv->dev, ip_src, 2275e3fb0a6SJose Abreu NULL, attr->src, attr->dst); 2285e3fb0a6SJose Abreu if (!skb) 2295e3fb0a6SJose Abreu return NULL; 2305e3fb0a6SJose Abreu 2315e3fb0a6SJose Abreu skb->pkt_type = PACKET_HOST; 2325e3fb0a6SJose Abreu skb->dev = priv->dev; 2335e3fb0a6SJose Abreu 2345e3fb0a6SJose Abreu return skb; 2355e3fb0a6SJose Abreu } 2365e3fb0a6SJose Abreu 237091810dbSJose Abreu struct stmmac_test_priv { 238091810dbSJose Abreu struct stmmac_packet_attrs *packet; 239091810dbSJose Abreu struct packet_type pt; 240091810dbSJose Abreu struct completion comp; 241091810dbSJose Abreu int double_vlan; 242091810dbSJose Abreu int vlan_id; 243091810dbSJose Abreu int ok; 244091810dbSJose Abreu }; 245091810dbSJose Abreu 246091810dbSJose Abreu static int stmmac_test_loopback_validate(struct sk_buff *skb, 247091810dbSJose Abreu struct net_device *ndev, 248091810dbSJose Abreu struct packet_type *pt, 249091810dbSJose Abreu struct net_device *orig_ndev) 250091810dbSJose Abreu { 251091810dbSJose Abreu struct stmmac_test_priv *tpriv = pt->af_packet_priv; 25276660757SJakub Kicinski const unsigned char *dst = tpriv->packet->dst; 2530b9f932eSJose Abreu unsigned char *src = tpriv->packet->src; 254091810dbSJose Abreu struct stmmachdr *shdr; 255091810dbSJose Abreu struct ethhdr *ehdr; 256091810dbSJose Abreu struct udphdr *uhdr; 257091810dbSJose Abreu struct tcphdr *thdr; 258091810dbSJose Abreu struct iphdr *ihdr; 259091810dbSJose Abreu 260091810dbSJose Abreu skb = skb_unshare(skb, GFP_ATOMIC); 261091810dbSJose Abreu if (!skb) 262091810dbSJose Abreu goto out; 263091810dbSJose Abreu 264091810dbSJose Abreu if (skb_linearize(skb)) 265091810dbSJose Abreu goto out; 266091810dbSJose Abreu if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN)) 267091810dbSJose Abreu goto out; 268091810dbSJose Abreu 269091810dbSJose Abreu ehdr = (struct ethhdr *)skb_mac_header(skb); 2700b9f932eSJose Abreu if (dst) { 2710b9f932eSJose Abreu if (!ether_addr_equal_unaligned(ehdr->h_dest, dst)) 272091810dbSJose Abreu goto out; 273091810dbSJose Abreu } 2748180d579SJose Abreu if (tpriv->packet->sarc) { 2750b9f932eSJose Abreu if (!ether_addr_equal_unaligned(ehdr->h_source, ehdr->h_dest)) 2768180d579SJose Abreu goto out; 2770b9f932eSJose Abreu } else if (src) { 2780b9f932eSJose Abreu if (!ether_addr_equal_unaligned(ehdr->h_source, src)) 279091810dbSJose Abreu goto out; 280091810dbSJose Abreu } 281091810dbSJose Abreu 282091810dbSJose Abreu ihdr = ip_hdr(skb); 283091810dbSJose Abreu if (tpriv->double_vlan) 284091810dbSJose Abreu ihdr = (struct iphdr *)(skb_network_header(skb) + 4); 285091810dbSJose Abreu 286091810dbSJose Abreu if (tpriv->packet->tcp) { 287091810dbSJose Abreu if (ihdr->protocol != IPPROTO_TCP) 288091810dbSJose Abreu goto out; 289091810dbSJose Abreu 290091810dbSJose Abreu thdr = (struct tcphdr *)((u8 *)ihdr + 4 * ihdr->ihl); 291091810dbSJose Abreu if (thdr->dest != htons(tpriv->packet->dport)) 292091810dbSJose Abreu goto out; 293091810dbSJose Abreu 294091810dbSJose Abreu shdr = (struct stmmachdr *)((u8 *)thdr + sizeof(*thdr)); 295091810dbSJose Abreu } else { 296091810dbSJose Abreu if (ihdr->protocol != IPPROTO_UDP) 297091810dbSJose Abreu goto out; 298091810dbSJose Abreu 299091810dbSJose Abreu uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl); 300091810dbSJose Abreu if (uhdr->dest != htons(tpriv->packet->dport)) 301091810dbSJose Abreu goto out; 302091810dbSJose Abreu 303091810dbSJose Abreu shdr = (struct stmmachdr *)((u8 *)uhdr + sizeof(*uhdr)); 304091810dbSJose Abreu } 305091810dbSJose Abreu 306091810dbSJose Abreu if (shdr->magic != cpu_to_be64(STMMAC_TEST_PKT_MAGIC)) 307091810dbSJose Abreu goto out; 308091810dbSJose Abreu if (tpriv->packet->exp_hash && !skb->hash) 309091810dbSJose Abreu goto out; 310091810dbSJose Abreu if (tpriv->packet->id != shdr->id) 311091810dbSJose Abreu goto out; 312091810dbSJose Abreu 313091810dbSJose Abreu tpriv->ok = true; 314091810dbSJose Abreu complete(&tpriv->comp); 315091810dbSJose Abreu out: 316091810dbSJose Abreu kfree_skb(skb); 317091810dbSJose Abreu return 0; 318091810dbSJose Abreu } 319091810dbSJose Abreu 320091810dbSJose Abreu static int __stmmac_test_loopback(struct stmmac_priv *priv, 321091810dbSJose Abreu struct stmmac_packet_attrs *attr) 322091810dbSJose Abreu { 323091810dbSJose Abreu struct stmmac_test_priv *tpriv; 324091810dbSJose Abreu struct sk_buff *skb = NULL; 325091810dbSJose Abreu int ret = 0; 326091810dbSJose Abreu 327091810dbSJose Abreu tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); 328091810dbSJose Abreu if (!tpriv) 329091810dbSJose Abreu return -ENOMEM; 330091810dbSJose Abreu 331091810dbSJose Abreu tpriv->ok = false; 332091810dbSJose Abreu init_completion(&tpriv->comp); 333091810dbSJose Abreu 334091810dbSJose Abreu tpriv->pt.type = htons(ETH_P_IP); 335091810dbSJose Abreu tpriv->pt.func = stmmac_test_loopback_validate; 336091810dbSJose Abreu tpriv->pt.dev = priv->dev; 337091810dbSJose Abreu tpriv->pt.af_packet_priv = tpriv; 338091810dbSJose Abreu tpriv->packet = attr; 33994e18382SJose Abreu 34094e18382SJose Abreu if (!attr->dont_wait) 341091810dbSJose Abreu dev_add_pack(&tpriv->pt); 342091810dbSJose Abreu 343091810dbSJose Abreu skb = stmmac_test_get_udp_skb(priv, attr); 344091810dbSJose Abreu if (!skb) { 345091810dbSJose Abreu ret = -ENOMEM; 346091810dbSJose Abreu goto cleanup; 347091810dbSJose Abreu } 348091810dbSJose Abreu 34905373e31SJose Abreu ret = dev_direct_xmit(skb, attr->queue_mapping); 350091810dbSJose Abreu if (ret) 351091810dbSJose Abreu goto cleanup; 352091810dbSJose Abreu 353091810dbSJose Abreu if (attr->dont_wait) 354091810dbSJose Abreu goto cleanup; 355091810dbSJose Abreu 356091810dbSJose Abreu if (!attr->timeout) 357091810dbSJose Abreu attr->timeout = STMMAC_LB_TIMEOUT; 358091810dbSJose Abreu 359091810dbSJose Abreu wait_for_completion_timeout(&tpriv->comp, attr->timeout); 36095133210SJose Abreu ret = tpriv->ok ? 0 : -ETIMEDOUT; 361091810dbSJose Abreu 362091810dbSJose Abreu cleanup: 36394e18382SJose Abreu if (!attr->dont_wait) 364091810dbSJose Abreu dev_remove_pack(&tpriv->pt); 365091810dbSJose Abreu kfree(tpriv); 366091810dbSJose Abreu return ret; 367091810dbSJose Abreu } 368091810dbSJose Abreu 369091810dbSJose Abreu static int stmmac_test_mac_loopback(struct stmmac_priv *priv) 370091810dbSJose Abreu { 371091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 372091810dbSJose Abreu 373091810dbSJose Abreu attr.dst = priv->dev->dev_addr; 374091810dbSJose Abreu return __stmmac_test_loopback(priv, &attr); 375091810dbSJose Abreu } 376091810dbSJose Abreu 377091810dbSJose Abreu static int stmmac_test_phy_loopback(struct stmmac_priv *priv) 378091810dbSJose Abreu { 379091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 380091810dbSJose Abreu int ret; 381091810dbSJose Abreu 382091810dbSJose Abreu if (!priv->dev->phydev) 383e0fa433dSJose Abreu return -EOPNOTSUPP; 384091810dbSJose Abreu 385091810dbSJose Abreu ret = phy_loopback(priv->dev->phydev, true); 386091810dbSJose Abreu if (ret) 387091810dbSJose Abreu return ret; 388091810dbSJose Abreu 389091810dbSJose Abreu attr.dst = priv->dev->dev_addr; 390091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 391091810dbSJose Abreu 392091810dbSJose Abreu phy_loopback(priv->dev->phydev, false); 393091810dbSJose Abreu return ret; 394091810dbSJose Abreu } 395091810dbSJose Abreu 396091810dbSJose Abreu static int stmmac_test_mmc(struct stmmac_priv *priv) 397091810dbSJose Abreu { 398091810dbSJose Abreu struct stmmac_counters initial, final; 399091810dbSJose Abreu int ret; 400091810dbSJose Abreu 401091810dbSJose Abreu memset(&initial, 0, sizeof(initial)); 402091810dbSJose Abreu memset(&final, 0, sizeof(final)); 403091810dbSJose Abreu 404091810dbSJose Abreu if (!priv->dma_cap.rmon) 405091810dbSJose Abreu return -EOPNOTSUPP; 406091810dbSJose Abreu 407091810dbSJose Abreu /* Save previous results into internal struct */ 408091810dbSJose Abreu stmmac_mmc_read(priv, priv->mmcaddr, &priv->mmc); 409091810dbSJose Abreu 410091810dbSJose Abreu ret = stmmac_test_mac_loopback(priv); 411091810dbSJose Abreu if (ret) 412091810dbSJose Abreu return ret; 413091810dbSJose Abreu 414091810dbSJose Abreu /* These will be loopback results so no need to save them */ 415091810dbSJose Abreu stmmac_mmc_read(priv, priv->mmcaddr, &final); 416091810dbSJose Abreu 417091810dbSJose Abreu /* 418091810dbSJose Abreu * The number of MMC counters available depends on HW configuration 419091810dbSJose Abreu * so we just use this one to validate the feature. I hope there is 420091810dbSJose Abreu * not a version without this counter. 421091810dbSJose Abreu */ 422091810dbSJose Abreu if (final.mmc_tx_framecount_g <= initial.mmc_tx_framecount_g) 423091810dbSJose Abreu return -EINVAL; 424091810dbSJose Abreu 425091810dbSJose Abreu return 0; 426091810dbSJose Abreu } 427091810dbSJose Abreu 428091810dbSJose Abreu static int stmmac_test_eee(struct stmmac_priv *priv) 429091810dbSJose Abreu { 430091810dbSJose Abreu struct stmmac_extra_stats *initial, *final; 431091810dbSJose Abreu int retries = 10; 432091810dbSJose Abreu int ret; 433091810dbSJose Abreu 434091810dbSJose Abreu if (!priv->dma_cap.eee || !priv->eee_active) 435091810dbSJose Abreu return -EOPNOTSUPP; 436091810dbSJose Abreu 437091810dbSJose Abreu initial = kzalloc(sizeof(*initial), GFP_KERNEL); 438091810dbSJose Abreu if (!initial) 439091810dbSJose Abreu return -ENOMEM; 440091810dbSJose Abreu 441091810dbSJose Abreu final = kzalloc(sizeof(*final), GFP_KERNEL); 442091810dbSJose Abreu if (!final) { 443091810dbSJose Abreu ret = -ENOMEM; 444091810dbSJose Abreu goto out_free_initial; 445091810dbSJose Abreu } 446091810dbSJose Abreu 447091810dbSJose Abreu memcpy(initial, &priv->xstats, sizeof(*initial)); 448091810dbSJose Abreu 449091810dbSJose Abreu ret = stmmac_test_mac_loopback(priv); 450091810dbSJose Abreu if (ret) 451091810dbSJose Abreu goto out_free_final; 452091810dbSJose Abreu 453091810dbSJose Abreu /* We have no traffic in the line so, sooner or later it will go LPI */ 454091810dbSJose Abreu while (--retries) { 455091810dbSJose Abreu memcpy(final, &priv->xstats, sizeof(*final)); 456091810dbSJose Abreu 457091810dbSJose Abreu if (final->irq_tx_path_in_lpi_mode_n > 458091810dbSJose Abreu initial->irq_tx_path_in_lpi_mode_n) 459091810dbSJose Abreu break; 460091810dbSJose Abreu msleep(100); 461091810dbSJose Abreu } 462091810dbSJose Abreu 463091810dbSJose Abreu if (!retries) { 464091810dbSJose Abreu ret = -ETIMEDOUT; 465091810dbSJose Abreu goto out_free_final; 466091810dbSJose Abreu } 467091810dbSJose Abreu 468091810dbSJose Abreu if (final->irq_tx_path_in_lpi_mode_n <= 469091810dbSJose Abreu initial->irq_tx_path_in_lpi_mode_n) { 470091810dbSJose Abreu ret = -EINVAL; 471091810dbSJose Abreu goto out_free_final; 472091810dbSJose Abreu } 473091810dbSJose Abreu 474091810dbSJose Abreu if (final->irq_tx_path_exit_lpi_mode_n <= 475091810dbSJose Abreu initial->irq_tx_path_exit_lpi_mode_n) { 476091810dbSJose Abreu ret = -EINVAL; 477091810dbSJose Abreu goto out_free_final; 478091810dbSJose Abreu } 479091810dbSJose Abreu 480091810dbSJose Abreu out_free_final: 481091810dbSJose Abreu kfree(final); 482091810dbSJose Abreu out_free_initial: 483091810dbSJose Abreu kfree(initial); 484091810dbSJose Abreu return ret; 485091810dbSJose Abreu } 486091810dbSJose Abreu 487091810dbSJose Abreu static int stmmac_filter_check(struct stmmac_priv *priv) 488091810dbSJose Abreu { 489091810dbSJose Abreu if (!(priv->dev->flags & IFF_PROMISC)) 490091810dbSJose Abreu return 0; 491091810dbSJose Abreu 492091810dbSJose Abreu netdev_warn(priv->dev, "Test can't be run in promiscuous mode!\n"); 493091810dbSJose Abreu return -EOPNOTSUPP; 494091810dbSJose Abreu } 495091810dbSJose Abreu 496eeb9d745SJose Abreu static bool stmmac_hash_check(struct stmmac_priv *priv, unsigned char *addr) 497eeb9d745SJose Abreu { 498eeb9d745SJose Abreu int mc_offset = 32 - priv->hw->mcast_bits_log2; 499eeb9d745SJose Abreu struct netdev_hw_addr *ha; 500eeb9d745SJose Abreu u32 hash, hash_nr; 501eeb9d745SJose Abreu 502eeb9d745SJose Abreu /* First compute the hash for desired addr */ 503eeb9d745SJose Abreu hash = bitrev32(~crc32_le(~0, addr, 6)) >> mc_offset; 504eeb9d745SJose Abreu hash_nr = hash >> 5; 505eeb9d745SJose Abreu hash = 1 << (hash & 0x1f); 506eeb9d745SJose Abreu 507eeb9d745SJose Abreu /* Now, check if it collides with any existing one */ 508eeb9d745SJose Abreu netdev_for_each_mc_addr(ha, priv->dev) { 509eeb9d745SJose Abreu u32 nr = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)) >> mc_offset; 510eeb9d745SJose Abreu if (((nr >> 5) == hash_nr) && ((1 << (nr & 0x1f)) == hash)) 511eeb9d745SJose Abreu return false; 512eeb9d745SJose Abreu } 513eeb9d745SJose Abreu 514eeb9d745SJose Abreu /* No collisions, address is good to go */ 515eeb9d745SJose Abreu return true; 516eeb9d745SJose Abreu } 517eeb9d745SJose Abreu 518eeb9d745SJose Abreu static bool stmmac_perfect_check(struct stmmac_priv *priv, unsigned char *addr) 519eeb9d745SJose Abreu { 520eeb9d745SJose Abreu struct netdev_hw_addr *ha; 521eeb9d745SJose Abreu 522eeb9d745SJose Abreu /* Check if it collides with any existing one */ 523eeb9d745SJose Abreu netdev_for_each_uc_addr(ha, priv->dev) { 524eeb9d745SJose Abreu if (!memcmp(ha->addr, addr, ETH_ALEN)) 525eeb9d745SJose Abreu return false; 526eeb9d745SJose Abreu } 527eeb9d745SJose Abreu 528eeb9d745SJose Abreu /* No collisions, address is good to go */ 529eeb9d745SJose Abreu return true; 530eeb9d745SJose Abreu } 531eeb9d745SJose Abreu 532091810dbSJose Abreu static int stmmac_test_hfilt(struct stmmac_priv *priv) 533091810dbSJose Abreu { 534eeb9d745SJose Abreu unsigned char gd_addr[ETH_ALEN] = {0xf1, 0xee, 0xdd, 0xcc, 0xbb, 0xaa}; 535eeb9d745SJose Abreu unsigned char bd_addr[ETH_ALEN] = {0xf1, 0xff, 0xff, 0xff, 0xff, 0xff}; 536091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 537eeb9d745SJose Abreu int ret, tries = 256; 538091810dbSJose Abreu 539091810dbSJose Abreu ret = stmmac_filter_check(priv); 540091810dbSJose Abreu if (ret) 541091810dbSJose Abreu return ret; 542091810dbSJose Abreu 543b870b0f8SJose Abreu if (netdev_mc_count(priv->dev) >= priv->hw->multicast_filter_bins) 544b870b0f8SJose Abreu return -EOPNOTSUPP; 545b870b0f8SJose Abreu 546eeb9d745SJose Abreu while (--tries) { 547eeb9d745SJose Abreu /* We only need to check the bd_addr for collisions */ 548eeb9d745SJose Abreu bd_addr[ETH_ALEN - 1] = tries; 549eeb9d745SJose Abreu if (stmmac_hash_check(priv, bd_addr)) 550eeb9d745SJose Abreu break; 551eeb9d745SJose Abreu } 552eeb9d745SJose Abreu 553eeb9d745SJose Abreu if (!tries) 554eeb9d745SJose Abreu return -EOPNOTSUPP; 555eeb9d745SJose Abreu 556091810dbSJose Abreu ret = dev_mc_add(priv->dev, gd_addr); 557091810dbSJose Abreu if (ret) 558091810dbSJose Abreu return ret; 559091810dbSJose Abreu 560091810dbSJose Abreu attr.dst = gd_addr; 561091810dbSJose Abreu 562091810dbSJose Abreu /* Shall receive packet */ 563091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 564091810dbSJose Abreu if (ret) 565091810dbSJose Abreu goto cleanup; 566091810dbSJose Abreu 567091810dbSJose Abreu attr.dst = bd_addr; 568091810dbSJose Abreu 569091810dbSJose Abreu /* Shall NOT receive packet */ 570091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 57195133210SJose Abreu ret = ret ? 0 : -EINVAL; 572091810dbSJose Abreu 573091810dbSJose Abreu cleanup: 574091810dbSJose Abreu dev_mc_del(priv->dev, gd_addr); 575091810dbSJose Abreu return ret; 576091810dbSJose Abreu } 577091810dbSJose Abreu 578091810dbSJose Abreu static int stmmac_test_pfilt(struct stmmac_priv *priv) 579091810dbSJose Abreu { 580eeb9d745SJose Abreu unsigned char gd_addr[ETH_ALEN] = {0xf0, 0x01, 0x44, 0x55, 0x66, 0x77}; 581eeb9d745SJose Abreu unsigned char bd_addr[ETH_ALEN] = {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff}; 582091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 583eeb9d745SJose Abreu int ret, tries = 256; 584091810dbSJose Abreu 585091810dbSJose Abreu if (stmmac_filter_check(priv)) 586091810dbSJose Abreu return -EOPNOTSUPP; 587eeb9d745SJose Abreu if (netdev_uc_count(priv->dev) >= priv->hw->unicast_filter_entries) 588eeb9d745SJose Abreu return -EOPNOTSUPP; 589eeb9d745SJose Abreu 590eeb9d745SJose Abreu while (--tries) { 591eeb9d745SJose Abreu /* We only need to check the bd_addr for collisions */ 592eeb9d745SJose Abreu bd_addr[ETH_ALEN - 1] = tries; 593eeb9d745SJose Abreu if (stmmac_perfect_check(priv, bd_addr)) 594eeb9d745SJose Abreu break; 595eeb9d745SJose Abreu } 596eeb9d745SJose Abreu 597eeb9d745SJose Abreu if (!tries) 598eeb9d745SJose Abreu return -EOPNOTSUPP; 599091810dbSJose Abreu 600091810dbSJose Abreu ret = dev_uc_add(priv->dev, gd_addr); 601091810dbSJose Abreu if (ret) 602091810dbSJose Abreu return ret; 603091810dbSJose Abreu 604091810dbSJose Abreu attr.dst = gd_addr; 605091810dbSJose Abreu 606091810dbSJose Abreu /* Shall receive packet */ 607091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 608091810dbSJose Abreu if (ret) 609091810dbSJose Abreu goto cleanup; 610091810dbSJose Abreu 611091810dbSJose Abreu attr.dst = bd_addr; 612091810dbSJose Abreu 613091810dbSJose Abreu /* Shall NOT receive packet */ 614091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 61595133210SJose Abreu ret = ret ? 0 : -EINVAL; 616091810dbSJose Abreu 617091810dbSJose Abreu cleanup: 618091810dbSJose Abreu dev_uc_del(priv->dev, gd_addr); 619091810dbSJose Abreu return ret; 620091810dbSJose Abreu } 621091810dbSJose Abreu 622091810dbSJose Abreu static int stmmac_test_mcfilt(struct stmmac_priv *priv) 623091810dbSJose Abreu { 624eeb9d745SJose Abreu unsigned char uc_addr[ETH_ALEN] = {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff}; 625eeb9d745SJose Abreu unsigned char mc_addr[ETH_ALEN] = {0xf1, 0xff, 0xff, 0xff, 0xff, 0xff}; 626091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 627eeb9d745SJose Abreu int ret, tries = 256; 628091810dbSJose Abreu 629091810dbSJose Abreu if (stmmac_filter_check(priv)) 630091810dbSJose Abreu return -EOPNOTSUPP; 631eeb9d745SJose Abreu if (netdev_uc_count(priv->dev) >= priv->hw->unicast_filter_entries) 632b870b0f8SJose Abreu return -EOPNOTSUPP; 63308c96543SJose Abreu if (netdev_mc_count(priv->dev) >= priv->hw->multicast_filter_bins) 63408c96543SJose Abreu return -EOPNOTSUPP; 635091810dbSJose Abreu 636eeb9d745SJose Abreu while (--tries) { 637eeb9d745SJose Abreu /* We only need to check the mc_addr for collisions */ 638eeb9d745SJose Abreu mc_addr[ETH_ALEN - 1] = tries; 639eeb9d745SJose Abreu if (stmmac_hash_check(priv, mc_addr)) 640eeb9d745SJose Abreu break; 641eeb9d745SJose Abreu } 642eeb9d745SJose Abreu 643eeb9d745SJose Abreu if (!tries) 644eeb9d745SJose Abreu return -EOPNOTSUPP; 645091810dbSJose Abreu 646091810dbSJose Abreu ret = dev_uc_add(priv->dev, uc_addr); 647091810dbSJose Abreu if (ret) 648eeb9d745SJose Abreu return ret; 649091810dbSJose Abreu 650091810dbSJose Abreu attr.dst = uc_addr; 651091810dbSJose Abreu 652091810dbSJose Abreu /* Shall receive packet */ 653091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 654091810dbSJose Abreu if (ret) 655091810dbSJose Abreu goto cleanup; 656091810dbSJose Abreu 657091810dbSJose Abreu attr.dst = mc_addr; 658091810dbSJose Abreu 659091810dbSJose Abreu /* Shall NOT receive packet */ 660091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 66195133210SJose Abreu ret = ret ? 0 : -EINVAL; 662091810dbSJose Abreu 663091810dbSJose Abreu cleanup: 664091810dbSJose Abreu dev_uc_del(priv->dev, uc_addr); 665091810dbSJose Abreu return ret; 666091810dbSJose Abreu } 667091810dbSJose Abreu 668091810dbSJose Abreu static int stmmac_test_ucfilt(struct stmmac_priv *priv) 669091810dbSJose Abreu { 670eeb9d745SJose Abreu unsigned char uc_addr[ETH_ALEN] = {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff}; 671eeb9d745SJose Abreu unsigned char mc_addr[ETH_ALEN] = {0xf1, 0xff, 0xff, 0xff, 0xff, 0xff}; 672091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 673eeb9d745SJose Abreu int ret, tries = 256; 674091810dbSJose Abreu 675091810dbSJose Abreu if (stmmac_filter_check(priv)) 676091810dbSJose Abreu return -EOPNOTSUPP; 67708c96543SJose Abreu if (netdev_uc_count(priv->dev) >= priv->hw->unicast_filter_entries) 67808c96543SJose Abreu return -EOPNOTSUPP; 679eeb9d745SJose Abreu if (netdev_mc_count(priv->dev) >= priv->hw->multicast_filter_bins) 680b870b0f8SJose Abreu return -EOPNOTSUPP; 681091810dbSJose Abreu 682eeb9d745SJose Abreu while (--tries) { 683eeb9d745SJose Abreu /* We only need to check the uc_addr for collisions */ 684eeb9d745SJose Abreu uc_addr[ETH_ALEN - 1] = tries; 685eeb9d745SJose Abreu if (stmmac_perfect_check(priv, uc_addr)) 686eeb9d745SJose Abreu break; 687eeb9d745SJose Abreu } 688eeb9d745SJose Abreu 689eeb9d745SJose Abreu if (!tries) 690eeb9d745SJose Abreu return -EOPNOTSUPP; 691091810dbSJose Abreu 692091810dbSJose Abreu ret = dev_mc_add(priv->dev, mc_addr); 693091810dbSJose Abreu if (ret) 694eeb9d745SJose Abreu return ret; 695091810dbSJose Abreu 696091810dbSJose Abreu attr.dst = mc_addr; 697091810dbSJose Abreu 698091810dbSJose Abreu /* Shall receive packet */ 699091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 700091810dbSJose Abreu if (ret) 701091810dbSJose Abreu goto cleanup; 702091810dbSJose Abreu 703091810dbSJose Abreu attr.dst = uc_addr; 704091810dbSJose Abreu 705091810dbSJose Abreu /* Shall NOT receive packet */ 706091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 70795133210SJose Abreu ret = ret ? 0 : -EINVAL; 708091810dbSJose Abreu 709091810dbSJose Abreu cleanup: 710091810dbSJose Abreu dev_mc_del(priv->dev, mc_addr); 711091810dbSJose Abreu return ret; 712091810dbSJose Abreu } 713091810dbSJose Abreu 714091810dbSJose Abreu static int stmmac_test_flowctrl_validate(struct sk_buff *skb, 715091810dbSJose Abreu struct net_device *ndev, 716091810dbSJose Abreu struct packet_type *pt, 717091810dbSJose Abreu struct net_device *orig_ndev) 718091810dbSJose Abreu { 719091810dbSJose Abreu struct stmmac_test_priv *tpriv = pt->af_packet_priv; 720091810dbSJose Abreu struct ethhdr *ehdr; 721091810dbSJose Abreu 722091810dbSJose Abreu ehdr = (struct ethhdr *)skb_mac_header(skb); 7230b9f932eSJose Abreu if (!ether_addr_equal_unaligned(ehdr->h_source, orig_ndev->dev_addr)) 724091810dbSJose Abreu goto out; 725091810dbSJose Abreu if (ehdr->h_proto != htons(ETH_P_PAUSE)) 726091810dbSJose Abreu goto out; 727091810dbSJose Abreu 728091810dbSJose Abreu tpriv->ok = true; 729091810dbSJose Abreu complete(&tpriv->comp); 730091810dbSJose Abreu out: 731aeb4a5e8SJose Abreu kfree_skb(skb); 732091810dbSJose Abreu return 0; 733091810dbSJose Abreu } 734091810dbSJose Abreu 735091810dbSJose Abreu static int stmmac_test_flowctrl(struct stmmac_priv *priv) 736091810dbSJose Abreu { 737091810dbSJose Abreu unsigned char paddr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01}; 738091810dbSJose Abreu struct phy_device *phydev = priv->dev->phydev; 739091810dbSJose Abreu u32 rx_cnt = priv->plat->rx_queues_to_use; 740091810dbSJose Abreu struct stmmac_test_priv *tpriv; 741091810dbSJose Abreu unsigned int pkt_count; 742091810dbSJose Abreu int i, ret = 0; 743091810dbSJose Abreu 744b0ce902fSJose Abreu if (!phydev || (!phydev->pause && !phydev->asym_pause)) 745091810dbSJose Abreu return -EOPNOTSUPP; 746091810dbSJose Abreu 747091810dbSJose Abreu tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); 748091810dbSJose Abreu if (!tpriv) 749091810dbSJose Abreu return -ENOMEM; 750091810dbSJose Abreu 751091810dbSJose Abreu tpriv->ok = false; 752091810dbSJose Abreu init_completion(&tpriv->comp); 753091810dbSJose Abreu tpriv->pt.type = htons(ETH_P_PAUSE); 754091810dbSJose Abreu tpriv->pt.func = stmmac_test_flowctrl_validate; 755091810dbSJose Abreu tpriv->pt.dev = priv->dev; 756091810dbSJose Abreu tpriv->pt.af_packet_priv = tpriv; 757091810dbSJose Abreu dev_add_pack(&tpriv->pt); 758091810dbSJose Abreu 759091810dbSJose Abreu /* Compute minimum number of packets to make FIFO full */ 760091810dbSJose Abreu pkt_count = priv->plat->rx_fifo_size; 761091810dbSJose Abreu if (!pkt_count) 762091810dbSJose Abreu pkt_count = priv->dma_cap.rx_fifo_size; 763091810dbSJose Abreu pkt_count /= 1400; 764091810dbSJose Abreu pkt_count *= 2; 765091810dbSJose Abreu 766091810dbSJose Abreu for (i = 0; i < rx_cnt; i++) 767091810dbSJose Abreu stmmac_stop_rx(priv, priv->ioaddr, i); 768091810dbSJose Abreu 769091810dbSJose Abreu ret = dev_set_promiscuity(priv->dev, 1); 770091810dbSJose Abreu if (ret) 771091810dbSJose Abreu goto cleanup; 772091810dbSJose Abreu 773091810dbSJose Abreu ret = dev_mc_add(priv->dev, paddr); 774091810dbSJose Abreu if (ret) 775091810dbSJose Abreu goto cleanup; 776091810dbSJose Abreu 777091810dbSJose Abreu for (i = 0; i < pkt_count; i++) { 778091810dbSJose Abreu struct stmmac_packet_attrs attr = { }; 779091810dbSJose Abreu 780091810dbSJose Abreu attr.dst = priv->dev->dev_addr; 781091810dbSJose Abreu attr.dont_wait = true; 782091810dbSJose Abreu attr.size = 1400; 783091810dbSJose Abreu 784091810dbSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 785091810dbSJose Abreu if (ret) 786091810dbSJose Abreu goto cleanup; 787091810dbSJose Abreu if (tpriv->ok) 788091810dbSJose Abreu break; 789091810dbSJose Abreu } 790091810dbSJose Abreu 791091810dbSJose Abreu /* Wait for some time in case RX Watchdog is enabled */ 792091810dbSJose Abreu msleep(200); 793091810dbSJose Abreu 794091810dbSJose Abreu for (i = 0; i < rx_cnt; i++) { 795091810dbSJose Abreu struct stmmac_channel *ch = &priv->channel[i]; 796b3138c5bSJose Abreu u32 tail; 797091810dbSJose Abreu 798*8531c808SChristian Marangi tail = priv->dma_conf.rx_queue[i].dma_rx_phy + 799*8531c808SChristian Marangi (priv->dma_conf.dma_rx_size * sizeof(struct dma_desc)); 800b3138c5bSJose Abreu 801b3138c5bSJose Abreu stmmac_set_rx_tail_ptr(priv, priv->ioaddr, tail, i); 802091810dbSJose Abreu stmmac_start_rx(priv, priv->ioaddr, i); 803b3138c5bSJose Abreu 804091810dbSJose Abreu local_bh_disable(); 805091810dbSJose Abreu napi_reschedule(&ch->rx_napi); 806091810dbSJose Abreu local_bh_enable(); 807091810dbSJose Abreu } 808091810dbSJose Abreu 809091810dbSJose Abreu wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT); 81095133210SJose Abreu ret = tpriv->ok ? 0 : -ETIMEDOUT; 811091810dbSJose Abreu 812091810dbSJose Abreu cleanup: 813091810dbSJose Abreu dev_mc_del(priv->dev, paddr); 814091810dbSJose Abreu dev_set_promiscuity(priv->dev, -1); 815091810dbSJose Abreu dev_remove_pack(&tpriv->pt); 816091810dbSJose Abreu kfree(tpriv); 817091810dbSJose Abreu return ret; 818091810dbSJose Abreu } 819091810dbSJose Abreu 8201fbdad00SJose Abreu static int stmmac_test_rss(struct stmmac_priv *priv) 8211fbdad00SJose Abreu { 8221fbdad00SJose Abreu struct stmmac_packet_attrs attr = { }; 8231fbdad00SJose Abreu 8241fbdad00SJose Abreu if (!priv->dma_cap.rssen || !priv->rss.enable) 8251fbdad00SJose Abreu return -EOPNOTSUPP; 8261fbdad00SJose Abreu 8271fbdad00SJose Abreu attr.dst = priv->dev->dev_addr; 8281fbdad00SJose Abreu attr.exp_hash = true; 8291fbdad00SJose Abreu attr.sport = 0x321; 8301fbdad00SJose Abreu attr.dport = 0x123; 8311fbdad00SJose Abreu 8321fbdad00SJose Abreu return __stmmac_test_loopback(priv, &attr); 8331fbdad00SJose Abreu } 8341fbdad00SJose Abreu 83574043f6bSJose Abreu static int stmmac_test_vlan_validate(struct sk_buff *skb, 83674043f6bSJose Abreu struct net_device *ndev, 83774043f6bSJose Abreu struct packet_type *pt, 83874043f6bSJose Abreu struct net_device *orig_ndev) 83974043f6bSJose Abreu { 84074043f6bSJose Abreu struct stmmac_test_priv *tpriv = pt->af_packet_priv; 84174043f6bSJose Abreu struct stmmachdr *shdr; 84274043f6bSJose Abreu struct ethhdr *ehdr; 84374043f6bSJose Abreu struct udphdr *uhdr; 84474043f6bSJose Abreu struct iphdr *ihdr; 84594e18382SJose Abreu u16 proto; 84694e18382SJose Abreu 84794e18382SJose Abreu proto = tpriv->double_vlan ? ETH_P_8021AD : ETH_P_8021Q; 84874043f6bSJose Abreu 84974043f6bSJose Abreu skb = skb_unshare(skb, GFP_ATOMIC); 85074043f6bSJose Abreu if (!skb) 85174043f6bSJose Abreu goto out; 85274043f6bSJose Abreu 85374043f6bSJose Abreu if (skb_linearize(skb)) 85474043f6bSJose Abreu goto out; 85574043f6bSJose Abreu if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN)) 85674043f6bSJose Abreu goto out; 85794e18382SJose Abreu if (tpriv->vlan_id) { 85894e18382SJose Abreu if (skb->vlan_proto != htons(proto)) 85994e18382SJose Abreu goto out; 860d39b68e5SJose Abreu if (skb->vlan_tci != tpriv->vlan_id) { 861d39b68e5SJose Abreu /* Means filter did not work. */ 862d39b68e5SJose Abreu tpriv->ok = false; 863d39b68e5SJose Abreu complete(&tpriv->comp); 86494e18382SJose Abreu goto out; 86594e18382SJose Abreu } 866d39b68e5SJose Abreu } 86774043f6bSJose Abreu 86874043f6bSJose Abreu ehdr = (struct ethhdr *)skb_mac_header(skb); 8690b9f932eSJose Abreu if (!ether_addr_equal_unaligned(ehdr->h_dest, tpriv->packet->dst)) 87074043f6bSJose Abreu goto out; 87174043f6bSJose Abreu 87274043f6bSJose Abreu ihdr = ip_hdr(skb); 87374043f6bSJose Abreu if (tpriv->double_vlan) 87474043f6bSJose Abreu ihdr = (struct iphdr *)(skb_network_header(skb) + 4); 87574043f6bSJose Abreu if (ihdr->protocol != IPPROTO_UDP) 87674043f6bSJose Abreu goto out; 87774043f6bSJose Abreu 87874043f6bSJose Abreu uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl); 87974043f6bSJose Abreu if (uhdr->dest != htons(tpriv->packet->dport)) 88074043f6bSJose Abreu goto out; 88174043f6bSJose Abreu 88274043f6bSJose Abreu shdr = (struct stmmachdr *)((u8 *)uhdr + sizeof(*uhdr)); 88374043f6bSJose Abreu if (shdr->magic != cpu_to_be64(STMMAC_TEST_PKT_MAGIC)) 88474043f6bSJose Abreu goto out; 88574043f6bSJose Abreu 88674043f6bSJose Abreu tpriv->ok = true; 88774043f6bSJose Abreu complete(&tpriv->comp); 88874043f6bSJose Abreu 88974043f6bSJose Abreu out: 89074043f6bSJose Abreu kfree_skb(skb); 89174043f6bSJose Abreu return 0; 89274043f6bSJose Abreu } 89374043f6bSJose Abreu 8941b2250a0SJose Abreu static int __stmmac_test_vlanfilt(struct stmmac_priv *priv) 89574043f6bSJose Abreu { 89674043f6bSJose Abreu struct stmmac_packet_attrs attr = { }; 89774043f6bSJose Abreu struct stmmac_test_priv *tpriv; 89874043f6bSJose Abreu struct sk_buff *skb = NULL; 89974043f6bSJose Abreu int ret = 0, i; 90074043f6bSJose Abreu 90174043f6bSJose Abreu tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); 90274043f6bSJose Abreu if (!tpriv) 90374043f6bSJose Abreu return -ENOMEM; 90474043f6bSJose Abreu 90574043f6bSJose Abreu tpriv->ok = false; 90674043f6bSJose Abreu init_completion(&tpriv->comp); 90774043f6bSJose Abreu 90874043f6bSJose Abreu tpriv->pt.type = htons(ETH_P_IP); 90974043f6bSJose Abreu tpriv->pt.func = stmmac_test_vlan_validate; 91074043f6bSJose Abreu tpriv->pt.dev = priv->dev; 91174043f6bSJose Abreu tpriv->pt.af_packet_priv = tpriv; 91274043f6bSJose Abreu tpriv->packet = &attr; 91374043f6bSJose Abreu 91474043f6bSJose Abreu /* 91574043f6bSJose Abreu * As we use HASH filtering, false positives may appear. This is a 91674043f6bSJose Abreu * specially chosen ID so that adjacent IDs (+4) have different 91774043f6bSJose Abreu * HASH values. 91874043f6bSJose Abreu */ 91974043f6bSJose Abreu tpriv->vlan_id = 0x123; 92074043f6bSJose Abreu dev_add_pack(&tpriv->pt); 92174043f6bSJose Abreu 92274043f6bSJose Abreu ret = vlan_vid_add(priv->dev, htons(ETH_P_8021Q), tpriv->vlan_id); 92374043f6bSJose Abreu if (ret) 92474043f6bSJose Abreu goto cleanup; 92574043f6bSJose Abreu 92674043f6bSJose Abreu for (i = 0; i < 4; i++) { 92774043f6bSJose Abreu attr.vlan = 1; 92874043f6bSJose Abreu attr.vlan_id_out = tpriv->vlan_id + i; 92974043f6bSJose Abreu attr.dst = priv->dev->dev_addr; 93074043f6bSJose Abreu attr.sport = 9; 93174043f6bSJose Abreu attr.dport = 9; 93274043f6bSJose Abreu 93374043f6bSJose Abreu skb = stmmac_test_get_udp_skb(priv, &attr); 93474043f6bSJose Abreu if (!skb) { 93574043f6bSJose Abreu ret = -ENOMEM; 93674043f6bSJose Abreu goto vlan_del; 93774043f6bSJose Abreu } 93874043f6bSJose Abreu 93905373e31SJose Abreu ret = dev_direct_xmit(skb, 0); 94074043f6bSJose Abreu if (ret) 94174043f6bSJose Abreu goto vlan_del; 94274043f6bSJose Abreu 94374043f6bSJose Abreu wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT); 94495133210SJose Abreu ret = tpriv->ok ? 0 : -ETIMEDOUT; 94574043f6bSJose Abreu if (ret && !i) { 94674043f6bSJose Abreu goto vlan_del; 94774043f6bSJose Abreu } else if (!ret && i) { 94895133210SJose Abreu ret = -EINVAL; 94974043f6bSJose Abreu goto vlan_del; 95074043f6bSJose Abreu } else { 95174043f6bSJose Abreu ret = 0; 95274043f6bSJose Abreu } 95374043f6bSJose Abreu 95474043f6bSJose Abreu tpriv->ok = false; 95574043f6bSJose Abreu } 95674043f6bSJose Abreu 95774043f6bSJose Abreu vlan_del: 95874043f6bSJose Abreu vlan_vid_del(priv->dev, htons(ETH_P_8021Q), tpriv->vlan_id); 95974043f6bSJose Abreu cleanup: 96074043f6bSJose Abreu dev_remove_pack(&tpriv->pt); 96174043f6bSJose Abreu kfree(tpriv); 96274043f6bSJose Abreu return ret; 96374043f6bSJose Abreu } 96474043f6bSJose Abreu 9651b2250a0SJose Abreu static int stmmac_test_vlanfilt(struct stmmac_priv *priv) 9661b2250a0SJose Abreu { 9671b2250a0SJose Abreu if (!priv->dma_cap.vlhash) 9681b2250a0SJose Abreu return -EOPNOTSUPP; 9691b2250a0SJose Abreu 9701b2250a0SJose Abreu return __stmmac_test_vlanfilt(priv); 9711b2250a0SJose Abreu } 9721b2250a0SJose Abreu 9731b2250a0SJose Abreu static int stmmac_test_vlanfilt_perfect(struct stmmac_priv *priv) 9741b2250a0SJose Abreu { 9751b2250a0SJose Abreu int ret, prev_cap = priv->dma_cap.vlhash; 9761b2250a0SJose Abreu 9774eee13f1SJose Abreu if (!(priv->dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) 9784eee13f1SJose Abreu return -EOPNOTSUPP; 9794eee13f1SJose Abreu 9801b2250a0SJose Abreu priv->dma_cap.vlhash = 0; 9811b2250a0SJose Abreu ret = __stmmac_test_vlanfilt(priv); 9821b2250a0SJose Abreu priv->dma_cap.vlhash = prev_cap; 9831b2250a0SJose Abreu 9841b2250a0SJose Abreu return ret; 9851b2250a0SJose Abreu } 9861b2250a0SJose Abreu 9871b2250a0SJose Abreu static int __stmmac_test_dvlanfilt(struct stmmac_priv *priv) 98874043f6bSJose Abreu { 98974043f6bSJose Abreu struct stmmac_packet_attrs attr = { }; 99074043f6bSJose Abreu struct stmmac_test_priv *tpriv; 99174043f6bSJose Abreu struct sk_buff *skb = NULL; 99274043f6bSJose Abreu int ret = 0, i; 99374043f6bSJose Abreu 99474043f6bSJose Abreu tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); 99574043f6bSJose Abreu if (!tpriv) 99674043f6bSJose Abreu return -ENOMEM; 99774043f6bSJose Abreu 99874043f6bSJose Abreu tpriv->ok = false; 99974043f6bSJose Abreu tpriv->double_vlan = true; 100074043f6bSJose Abreu init_completion(&tpriv->comp); 100174043f6bSJose Abreu 100274043f6bSJose Abreu tpriv->pt.type = htons(ETH_P_8021Q); 100374043f6bSJose Abreu tpriv->pt.func = stmmac_test_vlan_validate; 100474043f6bSJose Abreu tpriv->pt.dev = priv->dev; 100574043f6bSJose Abreu tpriv->pt.af_packet_priv = tpriv; 100674043f6bSJose Abreu tpriv->packet = &attr; 100774043f6bSJose Abreu 100874043f6bSJose Abreu /* 100974043f6bSJose Abreu * As we use HASH filtering, false positives may appear. This is a 101074043f6bSJose Abreu * specially chosen ID so that adjacent IDs (+4) have different 101174043f6bSJose Abreu * HASH values. 101274043f6bSJose Abreu */ 101374043f6bSJose Abreu tpriv->vlan_id = 0x123; 101474043f6bSJose Abreu dev_add_pack(&tpriv->pt); 101574043f6bSJose Abreu 101674043f6bSJose Abreu ret = vlan_vid_add(priv->dev, htons(ETH_P_8021AD), tpriv->vlan_id); 101774043f6bSJose Abreu if (ret) 101874043f6bSJose Abreu goto cleanup; 101974043f6bSJose Abreu 102074043f6bSJose Abreu for (i = 0; i < 4; i++) { 102174043f6bSJose Abreu attr.vlan = 2; 102274043f6bSJose Abreu attr.vlan_id_out = tpriv->vlan_id + i; 102374043f6bSJose Abreu attr.dst = priv->dev->dev_addr; 102474043f6bSJose Abreu attr.sport = 9; 102574043f6bSJose Abreu attr.dport = 9; 102674043f6bSJose Abreu 102774043f6bSJose Abreu skb = stmmac_test_get_udp_skb(priv, &attr); 102874043f6bSJose Abreu if (!skb) { 102974043f6bSJose Abreu ret = -ENOMEM; 103074043f6bSJose Abreu goto vlan_del; 103174043f6bSJose Abreu } 103274043f6bSJose Abreu 103305373e31SJose Abreu ret = dev_direct_xmit(skb, 0); 103474043f6bSJose Abreu if (ret) 103574043f6bSJose Abreu goto vlan_del; 103674043f6bSJose Abreu 103774043f6bSJose Abreu wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT); 103895133210SJose Abreu ret = tpriv->ok ? 0 : -ETIMEDOUT; 103974043f6bSJose Abreu if (ret && !i) { 104074043f6bSJose Abreu goto vlan_del; 104174043f6bSJose Abreu } else if (!ret && i) { 104295133210SJose Abreu ret = -EINVAL; 104374043f6bSJose Abreu goto vlan_del; 104474043f6bSJose Abreu } else { 104574043f6bSJose Abreu ret = 0; 104674043f6bSJose Abreu } 104774043f6bSJose Abreu 104874043f6bSJose Abreu tpriv->ok = false; 104974043f6bSJose Abreu } 105074043f6bSJose Abreu 105174043f6bSJose Abreu vlan_del: 105274043f6bSJose Abreu vlan_vid_del(priv->dev, htons(ETH_P_8021AD), tpriv->vlan_id); 105374043f6bSJose Abreu cleanup: 105474043f6bSJose Abreu dev_remove_pack(&tpriv->pt); 105574043f6bSJose Abreu kfree(tpriv); 105674043f6bSJose Abreu return ret; 105774043f6bSJose Abreu } 105874043f6bSJose Abreu 10591b2250a0SJose Abreu static int stmmac_test_dvlanfilt(struct stmmac_priv *priv) 10601b2250a0SJose Abreu { 10611b2250a0SJose Abreu if (!priv->dma_cap.vlhash) 10621b2250a0SJose Abreu return -EOPNOTSUPP; 10631b2250a0SJose Abreu 10641b2250a0SJose Abreu return __stmmac_test_dvlanfilt(priv); 10651b2250a0SJose Abreu } 10661b2250a0SJose Abreu 10671b2250a0SJose Abreu static int stmmac_test_dvlanfilt_perfect(struct stmmac_priv *priv) 10681b2250a0SJose Abreu { 10691b2250a0SJose Abreu int ret, prev_cap = priv->dma_cap.vlhash; 10701b2250a0SJose Abreu 10714eee13f1SJose Abreu if (!(priv->dev->features & NETIF_F_HW_VLAN_STAG_FILTER)) 10724eee13f1SJose Abreu return -EOPNOTSUPP; 10734eee13f1SJose Abreu 10741b2250a0SJose Abreu priv->dma_cap.vlhash = 0; 10751b2250a0SJose Abreu ret = __stmmac_test_dvlanfilt(priv); 10761b2250a0SJose Abreu priv->dma_cap.vlhash = prev_cap; 10771b2250a0SJose Abreu 10781b2250a0SJose Abreu return ret; 10791b2250a0SJose Abreu } 10801b2250a0SJose Abreu 1081ccfc639aSJose Abreu #ifdef CONFIG_NET_CLS_ACT 1082ccfc639aSJose Abreu static int stmmac_test_rxp(struct stmmac_priv *priv) 1083ccfc639aSJose Abreu { 1084ccfc639aSJose Abreu unsigned char addr[ETH_ALEN] = {0xde, 0xad, 0xbe, 0xef, 0x00, 0x00}; 1085ccfc639aSJose Abreu struct tc_cls_u32_offload cls_u32 = { }; 1086ccfc639aSJose Abreu struct stmmac_packet_attrs attr = { }; 1087fe5c5fc1SJakub Kicinski struct tc_action **actions; 1088ccfc639aSJose Abreu struct tc_u32_sel *sel; 1089fe5c5fc1SJakub Kicinski struct tcf_gact *gact; 1090ccfc639aSJose Abreu struct tcf_exts *exts; 1091ccfc639aSJose Abreu int ret, i, nk = 1; 1092ccfc639aSJose Abreu 1093ccfc639aSJose Abreu if (!tc_can_offload(priv->dev)) 1094ccfc639aSJose Abreu return -EOPNOTSUPP; 1095ccfc639aSJose Abreu if (!priv->dma_cap.frpsel) 1096ccfc639aSJose Abreu return -EOPNOTSUPP; 1097ccfc639aSJose Abreu 10984e638025SGustavo A. R. Silva sel = kzalloc(struct_size(sel, keys, nk), GFP_KERNEL); 1099ccfc639aSJose Abreu if (!sel) 1100ccfc639aSJose Abreu return -ENOMEM; 1101ccfc639aSJose Abreu 1102ccfc639aSJose Abreu exts = kzalloc(sizeof(*exts), GFP_KERNEL); 1103ccfc639aSJose Abreu if (!exts) { 1104ccfc639aSJose Abreu ret = -ENOMEM; 1105ccfc639aSJose Abreu goto cleanup_sel; 1106ccfc639aSJose Abreu } 1107ccfc639aSJose Abreu 110836371876SGustavo A. R. Silva actions = kcalloc(nk, sizeof(*actions), GFP_KERNEL); 1109ccfc639aSJose Abreu if (!actions) { 1110ccfc639aSJose Abreu ret = -ENOMEM; 1111ccfc639aSJose Abreu goto cleanup_exts; 1112ccfc639aSJose Abreu } 1113ccfc639aSJose Abreu 1114fe5c5fc1SJakub Kicinski gact = kcalloc(nk, sizeof(*gact), GFP_KERNEL); 1115fe5c5fc1SJakub Kicinski if (!gact) { 1116ccfc639aSJose Abreu ret = -ENOMEM; 1117ccfc639aSJose Abreu goto cleanup_actions; 1118ccfc639aSJose Abreu } 1119ccfc639aSJose Abreu 1120ccfc639aSJose Abreu cls_u32.command = TC_CLSU32_NEW_KNODE; 1121ccfc639aSJose Abreu cls_u32.common.chain_index = 0; 1122ccfc639aSJose Abreu cls_u32.common.protocol = htons(ETH_P_ALL); 1123ccfc639aSJose Abreu cls_u32.knode.exts = exts; 1124ccfc639aSJose Abreu cls_u32.knode.sel = sel; 1125ccfc639aSJose Abreu cls_u32.knode.handle = 0x123; 1126ccfc639aSJose Abreu 1127ccfc639aSJose Abreu exts->nr_actions = nk; 1128ccfc639aSJose Abreu exts->actions = actions; 1129ccfc639aSJose Abreu for (i = 0; i < nk; i++) { 1130fe5c5fc1SJakub Kicinski actions[i] = (struct tc_action *)&gact[i]; 1131ccfc639aSJose Abreu gact->tcf_action = TC_ACT_SHOT; 1132ccfc639aSJose Abreu } 1133ccfc639aSJose Abreu 1134ccfc639aSJose Abreu sel->nkeys = nk; 1135ccfc639aSJose Abreu sel->offshift = 0; 1136ccfc639aSJose Abreu sel->keys[0].off = 6; 1137ccfc639aSJose Abreu sel->keys[0].val = htonl(0xdeadbeef); 1138ccfc639aSJose Abreu sel->keys[0].mask = ~0x0; 1139ccfc639aSJose Abreu 1140ccfc639aSJose Abreu ret = stmmac_tc_setup_cls_u32(priv, priv, &cls_u32); 1141ccfc639aSJose Abreu if (ret) 1142ccfc639aSJose Abreu goto cleanup_act; 1143ccfc639aSJose Abreu 1144ccfc639aSJose Abreu attr.dst = priv->dev->dev_addr; 1145ccfc639aSJose Abreu attr.src = addr; 1146ccfc639aSJose Abreu 1147ccfc639aSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 114895133210SJose Abreu ret = ret ? 0 : -EINVAL; /* Shall NOT receive packet */ 1149ccfc639aSJose Abreu 1150ccfc639aSJose Abreu cls_u32.command = TC_CLSU32_DELETE_KNODE; 1151ccfc639aSJose Abreu stmmac_tc_setup_cls_u32(priv, priv, &cls_u32); 1152ccfc639aSJose Abreu 1153ccfc639aSJose Abreu cleanup_act: 1154fe5c5fc1SJakub Kicinski kfree(gact); 1155ccfc639aSJose Abreu cleanup_actions: 1156ccfc639aSJose Abreu kfree(actions); 1157ccfc639aSJose Abreu cleanup_exts: 1158ccfc639aSJose Abreu kfree(exts); 1159ccfc639aSJose Abreu cleanup_sel: 1160ccfc639aSJose Abreu kfree(sel); 1161ccfc639aSJose Abreu return ret; 1162ccfc639aSJose Abreu } 1163ccfc639aSJose Abreu #else 1164ccfc639aSJose Abreu static int stmmac_test_rxp(struct stmmac_priv *priv) 1165ccfc639aSJose Abreu { 1166ccfc639aSJose Abreu return -EOPNOTSUPP; 1167ccfc639aSJose Abreu } 1168ccfc639aSJose Abreu #endif 1169ccfc639aSJose Abreu 11708180d579SJose Abreu static int stmmac_test_desc_sai(struct stmmac_priv *priv) 11718180d579SJose Abreu { 11728180d579SJose Abreu unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 11738180d579SJose Abreu struct stmmac_packet_attrs attr = { }; 11748180d579SJose Abreu int ret; 11758180d579SJose Abreu 1176034c8fadSJose Abreu if (!priv->dma_cap.vlins) 1177034c8fadSJose Abreu return -EOPNOTSUPP; 1178034c8fadSJose Abreu 11798180d579SJose Abreu attr.remove_sa = true; 11808180d579SJose Abreu attr.sarc = true; 11818180d579SJose Abreu attr.src = src; 11828180d579SJose Abreu attr.dst = priv->dev->dev_addr; 11838180d579SJose Abreu 11848180d579SJose Abreu priv->sarc_type = 0x1; 11858180d579SJose Abreu 11868180d579SJose Abreu ret = __stmmac_test_loopback(priv, &attr); 11878180d579SJose Abreu 11888180d579SJose Abreu priv->sarc_type = 0x0; 11898180d579SJose Abreu return ret; 11908180d579SJose Abreu } 11918180d579SJose Abreu 11928180d579SJose Abreu static int stmmac_test_desc_sar(struct stmmac_priv *priv) 11938180d579SJose Abreu { 11948180d579SJose Abreu unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 11958180d579SJose Abreu struct stmmac_packet_attrs attr = { }; 11968180d579SJose Abreu int ret; 11978180d579SJose Abreu 1198034c8fadSJose Abreu if (!priv->dma_cap.vlins) 1199034c8fadSJose Abreu return -EOPNOTSUPP; 1200034c8fadSJose Abreu 12018180d579SJose Abreu attr.sarc = true; 12028180d579SJose Abreu attr.src = src; 12038180d579SJose Abreu attr.dst = priv->dev->dev_addr; 12048180d579SJose Abreu 12058180d579SJose Abreu priv->sarc_type = 0x2; 12068180d579SJose Abreu 12078180d579SJose Abreu ret = __stmmac_test_loopback(priv, &attr); 12088180d579SJose Abreu 12098180d579SJose Abreu priv->sarc_type = 0x0; 12108180d579SJose Abreu return ret; 12118180d579SJose Abreu } 12128180d579SJose Abreu 12138180d579SJose Abreu static int stmmac_test_reg_sai(struct stmmac_priv *priv) 12148180d579SJose Abreu { 12158180d579SJose Abreu unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 12168180d579SJose Abreu struct stmmac_packet_attrs attr = { }; 12178180d579SJose Abreu int ret; 12188180d579SJose Abreu 1219034c8fadSJose Abreu if (!priv->dma_cap.vlins) 1220034c8fadSJose Abreu return -EOPNOTSUPP; 1221034c8fadSJose Abreu 12228180d579SJose Abreu attr.remove_sa = true; 12238180d579SJose Abreu attr.sarc = true; 12248180d579SJose Abreu attr.src = src; 12258180d579SJose Abreu attr.dst = priv->dev->dev_addr; 12268180d579SJose Abreu 12278180d579SJose Abreu if (stmmac_sarc_configure(priv, priv->ioaddr, 0x2)) 12288180d579SJose Abreu return -EOPNOTSUPP; 12298180d579SJose Abreu 12308180d579SJose Abreu ret = __stmmac_test_loopback(priv, &attr); 12318180d579SJose Abreu 12328180d579SJose Abreu stmmac_sarc_configure(priv, priv->ioaddr, 0x0); 12338180d579SJose Abreu return ret; 12348180d579SJose Abreu } 12358180d579SJose Abreu 12368180d579SJose Abreu static int stmmac_test_reg_sar(struct stmmac_priv *priv) 12378180d579SJose Abreu { 12388180d579SJose Abreu unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 12398180d579SJose Abreu struct stmmac_packet_attrs attr = { }; 12408180d579SJose Abreu int ret; 12418180d579SJose Abreu 1242034c8fadSJose Abreu if (!priv->dma_cap.vlins) 1243034c8fadSJose Abreu return -EOPNOTSUPP; 1244034c8fadSJose Abreu 12458180d579SJose Abreu attr.sarc = true; 12468180d579SJose Abreu attr.src = src; 12478180d579SJose Abreu attr.dst = priv->dev->dev_addr; 12488180d579SJose Abreu 12498180d579SJose Abreu if (stmmac_sarc_configure(priv, priv->ioaddr, 0x3)) 12508180d579SJose Abreu return -EOPNOTSUPP; 12518180d579SJose Abreu 12528180d579SJose Abreu ret = __stmmac_test_loopback(priv, &attr); 12538180d579SJose Abreu 12548180d579SJose Abreu stmmac_sarc_configure(priv, priv->ioaddr, 0x0); 12558180d579SJose Abreu return ret; 12568180d579SJose Abreu } 12578180d579SJose Abreu 125894e18382SJose Abreu static int stmmac_test_vlanoff_common(struct stmmac_priv *priv, bool svlan) 125994e18382SJose Abreu { 126094e18382SJose Abreu struct stmmac_packet_attrs attr = { }; 126194e18382SJose Abreu struct stmmac_test_priv *tpriv; 126294e18382SJose Abreu struct sk_buff *skb = NULL; 126394e18382SJose Abreu int ret = 0; 126494e18382SJose Abreu u16 proto; 126594e18382SJose Abreu 126694e18382SJose Abreu if (!priv->dma_cap.vlins) 126794e18382SJose Abreu return -EOPNOTSUPP; 126894e18382SJose Abreu 126994e18382SJose Abreu tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); 127094e18382SJose Abreu if (!tpriv) 127194e18382SJose Abreu return -ENOMEM; 127294e18382SJose Abreu 127394e18382SJose Abreu proto = svlan ? ETH_P_8021AD : ETH_P_8021Q; 127494e18382SJose Abreu 127594e18382SJose Abreu tpriv->ok = false; 127694e18382SJose Abreu tpriv->double_vlan = svlan; 127794e18382SJose Abreu init_completion(&tpriv->comp); 127894e18382SJose Abreu 127994e18382SJose Abreu tpriv->pt.type = svlan ? htons(ETH_P_8021Q) : htons(ETH_P_IP); 128094e18382SJose Abreu tpriv->pt.func = stmmac_test_vlan_validate; 128194e18382SJose Abreu tpriv->pt.dev = priv->dev; 128294e18382SJose Abreu tpriv->pt.af_packet_priv = tpriv; 128394e18382SJose Abreu tpriv->packet = &attr; 128494e18382SJose Abreu tpriv->vlan_id = 0x123; 128594e18382SJose Abreu dev_add_pack(&tpriv->pt); 128694e18382SJose Abreu 128794e18382SJose Abreu ret = vlan_vid_add(priv->dev, htons(proto), tpriv->vlan_id); 128894e18382SJose Abreu if (ret) 128994e18382SJose Abreu goto cleanup; 129094e18382SJose Abreu 129194e18382SJose Abreu attr.dst = priv->dev->dev_addr; 129294e18382SJose Abreu 129394e18382SJose Abreu skb = stmmac_test_get_udp_skb(priv, &attr); 129494e18382SJose Abreu if (!skb) { 129594e18382SJose Abreu ret = -ENOMEM; 129694e18382SJose Abreu goto vlan_del; 129794e18382SJose Abreu } 129894e18382SJose Abreu 129994e18382SJose Abreu __vlan_hwaccel_put_tag(skb, htons(proto), tpriv->vlan_id); 130094e18382SJose Abreu skb->protocol = htons(proto); 130194e18382SJose Abreu 130205373e31SJose Abreu ret = dev_direct_xmit(skb, 0); 130394e18382SJose Abreu if (ret) 130494e18382SJose Abreu goto vlan_del; 130594e18382SJose Abreu 130694e18382SJose Abreu wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT); 130794e18382SJose Abreu ret = tpriv->ok ? 0 : -ETIMEDOUT; 130894e18382SJose Abreu 130994e18382SJose Abreu vlan_del: 131094e18382SJose Abreu vlan_vid_del(priv->dev, htons(proto), tpriv->vlan_id); 131194e18382SJose Abreu cleanup: 131294e18382SJose Abreu dev_remove_pack(&tpriv->pt); 131394e18382SJose Abreu kfree(tpriv); 131494e18382SJose Abreu return ret; 131594e18382SJose Abreu } 131694e18382SJose Abreu 131794e18382SJose Abreu static int stmmac_test_vlanoff(struct stmmac_priv *priv) 131894e18382SJose Abreu { 131994e18382SJose Abreu return stmmac_test_vlanoff_common(priv, false); 132094e18382SJose Abreu } 132194e18382SJose Abreu 132294e18382SJose Abreu static int stmmac_test_svlanoff(struct stmmac_priv *priv) 132394e18382SJose Abreu { 132494e18382SJose Abreu if (!priv->dma_cap.dvlan) 132594e18382SJose Abreu return -EOPNOTSUPP; 132694e18382SJose Abreu return stmmac_test_vlanoff_common(priv, true); 132794e18382SJose Abreu } 132894e18382SJose Abreu 13294647e021SJose Abreu #ifdef CONFIG_NET_CLS_ACT 13304647e021SJose Abreu static int __stmmac_test_l3filt(struct stmmac_priv *priv, u32 dst, u32 src, 13314647e021SJose Abreu u32 dst_mask, u32 src_mask) 13324647e021SJose Abreu { 13334647e021SJose Abreu struct flow_dissector_key_ipv4_addrs key, mask; 13344647e021SJose Abreu unsigned long dummy_cookie = 0xdeadbeef; 13354647e021SJose Abreu struct stmmac_packet_attrs attr = { }; 13364647e021SJose Abreu struct flow_dissector *dissector; 13374647e021SJose Abreu struct flow_cls_offload *cls; 1338e715d745SJose Abreu int ret, old_enable = 0; 13394647e021SJose Abreu struct flow_rule *rule; 13404647e021SJose Abreu 13414647e021SJose Abreu if (!tc_can_offload(priv->dev)) 13424647e021SJose Abreu return -EOPNOTSUPP; 13434647e021SJose Abreu if (!priv->dma_cap.l3l4fnum) 13444647e021SJose Abreu return -EOPNOTSUPP; 1345e715d745SJose Abreu if (priv->rss.enable) { 1346e715d745SJose Abreu old_enable = priv->rss.enable; 1347e715d745SJose Abreu priv->rss.enable = false; 1348b6b6cc9aSArnd Bergmann stmmac_rss_configure(priv, priv->hw, NULL, 13494647e021SJose Abreu priv->plat->rx_queues_to_use); 1350e715d745SJose Abreu } 13514647e021SJose Abreu 13524647e021SJose Abreu dissector = kzalloc(sizeof(*dissector), GFP_KERNEL); 13534647e021SJose Abreu if (!dissector) { 13544647e021SJose Abreu ret = -ENOMEM; 13554647e021SJose Abreu goto cleanup_rss; 13564647e021SJose Abreu } 13574647e021SJose Abreu 13584647e021SJose Abreu dissector->used_keys |= (1 << FLOW_DISSECTOR_KEY_IPV4_ADDRS); 13594647e021SJose Abreu dissector->offset[FLOW_DISSECTOR_KEY_IPV4_ADDRS] = 0; 13604647e021SJose Abreu 13614647e021SJose Abreu cls = kzalloc(sizeof(*cls), GFP_KERNEL); 13624647e021SJose Abreu if (!cls) { 13634647e021SJose Abreu ret = -ENOMEM; 13644647e021SJose Abreu goto cleanup_dissector; 13654647e021SJose Abreu } 13664647e021SJose Abreu 13674647e021SJose Abreu cls->common.chain_index = 0; 13684647e021SJose Abreu cls->command = FLOW_CLS_REPLACE; 13694647e021SJose Abreu cls->cookie = dummy_cookie; 13704647e021SJose Abreu 13714647e021SJose Abreu rule = kzalloc(struct_size(rule, action.entries, 1), GFP_KERNEL); 13724647e021SJose Abreu if (!rule) { 13734647e021SJose Abreu ret = -ENOMEM; 13744647e021SJose Abreu goto cleanup_cls; 13754647e021SJose Abreu } 13764647e021SJose Abreu 13774647e021SJose Abreu rule->match.dissector = dissector; 13784647e021SJose Abreu rule->match.key = (void *)&key; 13794647e021SJose Abreu rule->match.mask = (void *)&mask; 13804647e021SJose Abreu 13814647e021SJose Abreu key.src = htonl(src); 13824647e021SJose Abreu key.dst = htonl(dst); 13834647e021SJose Abreu mask.src = src_mask; 13844647e021SJose Abreu mask.dst = dst_mask; 13854647e021SJose Abreu 13864647e021SJose Abreu cls->rule = rule; 13874647e021SJose Abreu 13884647e021SJose Abreu rule->action.entries[0].id = FLOW_ACTION_DROP; 13890dfb2d82SJakub Kicinski rule->action.entries[0].hw_stats = FLOW_ACTION_HW_STATS_ANY; 13904647e021SJose Abreu rule->action.num_entries = 1; 13914647e021SJose Abreu 13924647e021SJose Abreu attr.dst = priv->dev->dev_addr; 13934647e021SJose Abreu attr.ip_dst = dst; 13944647e021SJose Abreu attr.ip_src = src; 13954647e021SJose Abreu 13964647e021SJose Abreu /* Shall receive packet */ 13974647e021SJose Abreu ret = __stmmac_test_loopback(priv, &attr); 13984647e021SJose Abreu if (ret) 13994647e021SJose Abreu goto cleanup_rule; 14004647e021SJose Abreu 14014647e021SJose Abreu ret = stmmac_tc_setup_cls(priv, priv, cls); 14024647e021SJose Abreu if (ret) 14034647e021SJose Abreu goto cleanup_rule; 14044647e021SJose Abreu 14054647e021SJose Abreu /* Shall NOT receive packet */ 14064647e021SJose Abreu ret = __stmmac_test_loopback(priv, &attr); 14074647e021SJose Abreu ret = ret ? 0 : -EINVAL; 14084647e021SJose Abreu 14094647e021SJose Abreu cls->command = FLOW_CLS_DESTROY; 14104647e021SJose Abreu stmmac_tc_setup_cls(priv, priv, cls); 14114647e021SJose Abreu cleanup_rule: 14124647e021SJose Abreu kfree(rule); 14134647e021SJose Abreu cleanup_cls: 14144647e021SJose Abreu kfree(cls); 14154647e021SJose Abreu cleanup_dissector: 14164647e021SJose Abreu kfree(dissector); 14174647e021SJose Abreu cleanup_rss: 1418e715d745SJose Abreu if (old_enable) { 1419e715d745SJose Abreu priv->rss.enable = old_enable; 14204647e021SJose Abreu stmmac_rss_configure(priv, priv->hw, &priv->rss, 14214647e021SJose Abreu priv->plat->rx_queues_to_use); 14224647e021SJose Abreu } 14234647e021SJose Abreu 14244647e021SJose Abreu return ret; 14254647e021SJose Abreu } 14264647e021SJose Abreu #else 14274647e021SJose Abreu static int __stmmac_test_l3filt(struct stmmac_priv *priv, u32 dst, u32 src, 14284647e021SJose Abreu u32 dst_mask, u32 src_mask) 14294647e021SJose Abreu { 14304647e021SJose Abreu return -EOPNOTSUPP; 14314647e021SJose Abreu } 14324647e021SJose Abreu #endif 14334647e021SJose Abreu 14344647e021SJose Abreu static int stmmac_test_l3filt_da(struct stmmac_priv *priv) 14354647e021SJose Abreu { 14364647e021SJose Abreu u32 addr = 0x10203040; 14374647e021SJose Abreu 14384647e021SJose Abreu return __stmmac_test_l3filt(priv, addr, 0, ~0, 0); 14394647e021SJose Abreu } 14404647e021SJose Abreu 14414647e021SJose Abreu static int stmmac_test_l3filt_sa(struct stmmac_priv *priv) 14424647e021SJose Abreu { 14434647e021SJose Abreu u32 addr = 0x10203040; 14444647e021SJose Abreu 14454647e021SJose Abreu return __stmmac_test_l3filt(priv, 0, addr, 0, ~0); 14464647e021SJose Abreu } 14474647e021SJose Abreu 14484647e021SJose Abreu #ifdef CONFIG_NET_CLS_ACT 14494647e021SJose Abreu static int __stmmac_test_l4filt(struct stmmac_priv *priv, u32 dst, u32 src, 14504647e021SJose Abreu u32 dst_mask, u32 src_mask, bool udp) 14514647e021SJose Abreu { 14524647e021SJose Abreu struct { 14534647e021SJose Abreu struct flow_dissector_key_basic bkey; 14544647e021SJose Abreu struct flow_dissector_key_ports key; 14554647e021SJose Abreu } __aligned(BITS_PER_LONG / 8) keys; 14564647e021SJose Abreu struct { 14574647e021SJose Abreu struct flow_dissector_key_basic bmask; 14584647e021SJose Abreu struct flow_dissector_key_ports mask; 14594647e021SJose Abreu } __aligned(BITS_PER_LONG / 8) masks; 14604647e021SJose Abreu unsigned long dummy_cookie = 0xdeadbeef; 14614647e021SJose Abreu struct stmmac_packet_attrs attr = { }; 14624647e021SJose Abreu struct flow_dissector *dissector; 14634647e021SJose Abreu struct flow_cls_offload *cls; 1464e715d745SJose Abreu int ret, old_enable = 0; 14654647e021SJose Abreu struct flow_rule *rule; 14664647e021SJose Abreu 14674647e021SJose Abreu if (!tc_can_offload(priv->dev)) 14684647e021SJose Abreu return -EOPNOTSUPP; 14694647e021SJose Abreu if (!priv->dma_cap.l3l4fnum) 14704647e021SJose Abreu return -EOPNOTSUPP; 1471e715d745SJose Abreu if (priv->rss.enable) { 1472e715d745SJose Abreu old_enable = priv->rss.enable; 1473e715d745SJose Abreu priv->rss.enable = false; 1474b6b6cc9aSArnd Bergmann stmmac_rss_configure(priv, priv->hw, NULL, 14754647e021SJose Abreu priv->plat->rx_queues_to_use); 1476e715d745SJose Abreu } 14774647e021SJose Abreu 14784647e021SJose Abreu dissector = kzalloc(sizeof(*dissector), GFP_KERNEL); 14794647e021SJose Abreu if (!dissector) { 14804647e021SJose Abreu ret = -ENOMEM; 14814647e021SJose Abreu goto cleanup_rss; 14824647e021SJose Abreu } 14834647e021SJose Abreu 14844647e021SJose Abreu dissector->used_keys |= (1 << FLOW_DISSECTOR_KEY_BASIC); 14854647e021SJose Abreu dissector->used_keys |= (1 << FLOW_DISSECTOR_KEY_PORTS); 14864647e021SJose Abreu dissector->offset[FLOW_DISSECTOR_KEY_BASIC] = 0; 14874647e021SJose Abreu dissector->offset[FLOW_DISSECTOR_KEY_PORTS] = offsetof(typeof(keys), key); 14884647e021SJose Abreu 14894647e021SJose Abreu cls = kzalloc(sizeof(*cls), GFP_KERNEL); 14904647e021SJose Abreu if (!cls) { 14914647e021SJose Abreu ret = -ENOMEM; 14924647e021SJose Abreu goto cleanup_dissector; 14934647e021SJose Abreu } 14944647e021SJose Abreu 14954647e021SJose Abreu cls->common.chain_index = 0; 14964647e021SJose Abreu cls->command = FLOW_CLS_REPLACE; 14974647e021SJose Abreu cls->cookie = dummy_cookie; 14984647e021SJose Abreu 14994647e021SJose Abreu rule = kzalloc(struct_size(rule, action.entries, 1), GFP_KERNEL); 15004647e021SJose Abreu if (!rule) { 15014647e021SJose Abreu ret = -ENOMEM; 15024647e021SJose Abreu goto cleanup_cls; 15034647e021SJose Abreu } 15044647e021SJose Abreu 15054647e021SJose Abreu rule->match.dissector = dissector; 15064647e021SJose Abreu rule->match.key = (void *)&keys; 15074647e021SJose Abreu rule->match.mask = (void *)&masks; 15084647e021SJose Abreu 15094647e021SJose Abreu keys.bkey.ip_proto = udp ? IPPROTO_UDP : IPPROTO_TCP; 15104647e021SJose Abreu keys.key.src = htons(src); 15114647e021SJose Abreu keys.key.dst = htons(dst); 15124647e021SJose Abreu masks.mask.src = src_mask; 15134647e021SJose Abreu masks.mask.dst = dst_mask; 15144647e021SJose Abreu 15154647e021SJose Abreu cls->rule = rule; 15164647e021SJose Abreu 15174647e021SJose Abreu rule->action.entries[0].id = FLOW_ACTION_DROP; 15180dfb2d82SJakub Kicinski rule->action.entries[0].hw_stats = FLOW_ACTION_HW_STATS_ANY; 15194647e021SJose Abreu rule->action.num_entries = 1; 15204647e021SJose Abreu 15214647e021SJose Abreu attr.dst = priv->dev->dev_addr; 15224647e021SJose Abreu attr.tcp = !udp; 15234647e021SJose Abreu attr.sport = src; 15244647e021SJose Abreu attr.dport = dst; 15254647e021SJose Abreu attr.ip_dst = 0; 15264647e021SJose Abreu 15274647e021SJose Abreu /* Shall receive packet */ 15284647e021SJose Abreu ret = __stmmac_test_loopback(priv, &attr); 15294647e021SJose Abreu if (ret) 15304647e021SJose Abreu goto cleanup_rule; 15314647e021SJose Abreu 15324647e021SJose Abreu ret = stmmac_tc_setup_cls(priv, priv, cls); 15334647e021SJose Abreu if (ret) 15344647e021SJose Abreu goto cleanup_rule; 15354647e021SJose Abreu 15364647e021SJose Abreu /* Shall NOT receive packet */ 15374647e021SJose Abreu ret = __stmmac_test_loopback(priv, &attr); 15384647e021SJose Abreu ret = ret ? 0 : -EINVAL; 15394647e021SJose Abreu 15404647e021SJose Abreu cls->command = FLOW_CLS_DESTROY; 15414647e021SJose Abreu stmmac_tc_setup_cls(priv, priv, cls); 15424647e021SJose Abreu cleanup_rule: 15434647e021SJose Abreu kfree(rule); 15444647e021SJose Abreu cleanup_cls: 15454647e021SJose Abreu kfree(cls); 15464647e021SJose Abreu cleanup_dissector: 15474647e021SJose Abreu kfree(dissector); 15484647e021SJose Abreu cleanup_rss: 1549e715d745SJose Abreu if (old_enable) { 1550e715d745SJose Abreu priv->rss.enable = old_enable; 15514647e021SJose Abreu stmmac_rss_configure(priv, priv->hw, &priv->rss, 15524647e021SJose Abreu priv->plat->rx_queues_to_use); 15534647e021SJose Abreu } 15544647e021SJose Abreu 15554647e021SJose Abreu return ret; 15564647e021SJose Abreu } 15574647e021SJose Abreu #else 15584647e021SJose Abreu static int __stmmac_test_l4filt(struct stmmac_priv *priv, u32 dst, u32 src, 15594647e021SJose Abreu u32 dst_mask, u32 src_mask, bool udp) 15604647e021SJose Abreu { 15614647e021SJose Abreu return -EOPNOTSUPP; 15624647e021SJose Abreu } 15634647e021SJose Abreu #endif 15644647e021SJose Abreu 15654647e021SJose Abreu static int stmmac_test_l4filt_da_tcp(struct stmmac_priv *priv) 15664647e021SJose Abreu { 15674647e021SJose Abreu u16 dummy_port = 0x123; 15684647e021SJose Abreu 15694647e021SJose Abreu return __stmmac_test_l4filt(priv, dummy_port, 0, ~0, 0, false); 15704647e021SJose Abreu } 15714647e021SJose Abreu 15724647e021SJose Abreu static int stmmac_test_l4filt_sa_tcp(struct stmmac_priv *priv) 15734647e021SJose Abreu { 15744647e021SJose Abreu u16 dummy_port = 0x123; 15754647e021SJose Abreu 15764647e021SJose Abreu return __stmmac_test_l4filt(priv, 0, dummy_port, 0, ~0, false); 15774647e021SJose Abreu } 15784647e021SJose Abreu 15794647e021SJose Abreu static int stmmac_test_l4filt_da_udp(struct stmmac_priv *priv) 15804647e021SJose Abreu { 15814647e021SJose Abreu u16 dummy_port = 0x123; 15824647e021SJose Abreu 15834647e021SJose Abreu return __stmmac_test_l4filt(priv, dummy_port, 0, ~0, 0, true); 15844647e021SJose Abreu } 15854647e021SJose Abreu 15864647e021SJose Abreu static int stmmac_test_l4filt_sa_udp(struct stmmac_priv *priv) 15874647e021SJose Abreu { 15884647e021SJose Abreu u16 dummy_port = 0x123; 15894647e021SJose Abreu 15904647e021SJose Abreu return __stmmac_test_l4filt(priv, 0, dummy_port, 0, ~0, true); 15914647e021SJose Abreu } 15924647e021SJose Abreu 15935e3fb0a6SJose Abreu static int stmmac_test_arp_validate(struct sk_buff *skb, 15945e3fb0a6SJose Abreu struct net_device *ndev, 15955e3fb0a6SJose Abreu struct packet_type *pt, 15965e3fb0a6SJose Abreu struct net_device *orig_ndev) 15975e3fb0a6SJose Abreu { 15985e3fb0a6SJose Abreu struct stmmac_test_priv *tpriv = pt->af_packet_priv; 15995e3fb0a6SJose Abreu struct ethhdr *ehdr; 16005e3fb0a6SJose Abreu struct arphdr *ahdr; 16015e3fb0a6SJose Abreu 16025e3fb0a6SJose Abreu ehdr = (struct ethhdr *)skb_mac_header(skb); 16030b9f932eSJose Abreu if (!ether_addr_equal_unaligned(ehdr->h_dest, tpriv->packet->src)) 16045e3fb0a6SJose Abreu goto out; 16055e3fb0a6SJose Abreu 16065e3fb0a6SJose Abreu ahdr = arp_hdr(skb); 16075e3fb0a6SJose Abreu if (ahdr->ar_op != htons(ARPOP_REPLY)) 16085e3fb0a6SJose Abreu goto out; 16095e3fb0a6SJose Abreu 16105e3fb0a6SJose Abreu tpriv->ok = true; 16115e3fb0a6SJose Abreu complete(&tpriv->comp); 16125e3fb0a6SJose Abreu out: 16135e3fb0a6SJose Abreu kfree_skb(skb); 16145e3fb0a6SJose Abreu return 0; 16155e3fb0a6SJose Abreu } 16165e3fb0a6SJose Abreu 16175e3fb0a6SJose Abreu static int stmmac_test_arpoffload(struct stmmac_priv *priv) 16185e3fb0a6SJose Abreu { 16195e3fb0a6SJose Abreu unsigned char src[ETH_ALEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; 16205e3fb0a6SJose Abreu unsigned char dst[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 16215e3fb0a6SJose Abreu struct stmmac_packet_attrs attr = { }; 16225e3fb0a6SJose Abreu struct stmmac_test_priv *tpriv; 16235e3fb0a6SJose Abreu struct sk_buff *skb = NULL; 16245e3fb0a6SJose Abreu u32 ip_addr = 0xdeadcafe; 16255e3fb0a6SJose Abreu u32 ip_src = 0xdeadbeef; 16265e3fb0a6SJose Abreu int ret; 16275e3fb0a6SJose Abreu 16285e3fb0a6SJose Abreu if (!priv->dma_cap.arpoffsel) 16295e3fb0a6SJose Abreu return -EOPNOTSUPP; 16305e3fb0a6SJose Abreu 16315e3fb0a6SJose Abreu tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); 16325e3fb0a6SJose Abreu if (!tpriv) 16335e3fb0a6SJose Abreu return -ENOMEM; 16345e3fb0a6SJose Abreu 16355e3fb0a6SJose Abreu tpriv->ok = false; 16365e3fb0a6SJose Abreu init_completion(&tpriv->comp); 16375e3fb0a6SJose Abreu 16385e3fb0a6SJose Abreu tpriv->pt.type = htons(ETH_P_ARP); 16395e3fb0a6SJose Abreu tpriv->pt.func = stmmac_test_arp_validate; 16405e3fb0a6SJose Abreu tpriv->pt.dev = priv->dev; 16415e3fb0a6SJose Abreu tpriv->pt.af_packet_priv = tpriv; 16425e3fb0a6SJose Abreu tpriv->packet = &attr; 16435e3fb0a6SJose Abreu dev_add_pack(&tpriv->pt); 16445e3fb0a6SJose Abreu 16455e3fb0a6SJose Abreu attr.src = src; 16465e3fb0a6SJose Abreu attr.ip_src = ip_src; 16475e3fb0a6SJose Abreu attr.dst = dst; 16485e3fb0a6SJose Abreu attr.ip_dst = ip_addr; 16495e3fb0a6SJose Abreu 16505e3fb0a6SJose Abreu skb = stmmac_test_get_arp_skb(priv, &attr); 16515e3fb0a6SJose Abreu if (!skb) { 16525e3fb0a6SJose Abreu ret = -ENOMEM; 16535e3fb0a6SJose Abreu goto cleanup; 16545e3fb0a6SJose Abreu } 16555e3fb0a6SJose Abreu 16565e3fb0a6SJose Abreu ret = stmmac_set_arp_offload(priv, priv->hw, true, ip_addr); 16575e3fb0a6SJose Abreu if (ret) 16585e3fb0a6SJose Abreu goto cleanup; 16595e3fb0a6SJose Abreu 16605e3fb0a6SJose Abreu ret = dev_set_promiscuity(priv->dev, 1); 16615e3fb0a6SJose Abreu if (ret) 16625e3fb0a6SJose Abreu goto cleanup; 16635e3fb0a6SJose Abreu 166405373e31SJose Abreu ret = dev_direct_xmit(skb, 0); 16655e3fb0a6SJose Abreu if (ret) 16665e3fb0a6SJose Abreu goto cleanup_promisc; 16675e3fb0a6SJose Abreu 16685e3fb0a6SJose Abreu wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT); 16695e3fb0a6SJose Abreu ret = tpriv->ok ? 0 : -ETIMEDOUT; 16705e3fb0a6SJose Abreu 16715e3fb0a6SJose Abreu cleanup_promisc: 16725e3fb0a6SJose Abreu dev_set_promiscuity(priv->dev, -1); 16735e3fb0a6SJose Abreu cleanup: 16745e3fb0a6SJose Abreu stmmac_set_arp_offload(priv, priv->hw, false, 0x0); 16755e3fb0a6SJose Abreu dev_remove_pack(&tpriv->pt); 16765e3fb0a6SJose Abreu kfree(tpriv); 16775e3fb0a6SJose Abreu return ret; 16785e3fb0a6SJose Abreu } 16795e3fb0a6SJose Abreu 1680427849e8SJose Abreu static int __stmmac_test_jumbo(struct stmmac_priv *priv, u16 queue) 1681427849e8SJose Abreu { 1682427849e8SJose Abreu struct stmmac_packet_attrs attr = { }; 1683*8531c808SChristian Marangi int size = priv->dma_conf.dma_buf_sz; 1684427849e8SJose Abreu 1685427849e8SJose Abreu attr.dst = priv->dev->dev_addr; 1686427849e8SJose Abreu attr.max_size = size - ETH_FCS_LEN; 1687427849e8SJose Abreu attr.queue_mapping = queue; 1688427849e8SJose Abreu 1689427849e8SJose Abreu return __stmmac_test_loopback(priv, &attr); 1690427849e8SJose Abreu } 1691427849e8SJose Abreu 1692427849e8SJose Abreu static int stmmac_test_jumbo(struct stmmac_priv *priv) 1693427849e8SJose Abreu { 1694427849e8SJose Abreu return __stmmac_test_jumbo(priv, 0); 1695427849e8SJose Abreu } 1696427849e8SJose Abreu 1697427849e8SJose Abreu static int stmmac_test_mjumbo(struct stmmac_priv *priv) 1698427849e8SJose Abreu { 1699427849e8SJose Abreu u32 chan, tx_cnt = priv->plat->tx_queues_to_use; 1700427849e8SJose Abreu int ret; 1701427849e8SJose Abreu 1702427849e8SJose Abreu if (tx_cnt <= 1) 1703427849e8SJose Abreu return -EOPNOTSUPP; 1704427849e8SJose Abreu 1705427849e8SJose Abreu for (chan = 0; chan < tx_cnt; chan++) { 1706427849e8SJose Abreu ret = __stmmac_test_jumbo(priv, chan); 1707427849e8SJose Abreu if (ret) 1708427849e8SJose Abreu return ret; 1709427849e8SJose Abreu } 1710427849e8SJose Abreu 1711427849e8SJose Abreu return 0; 1712427849e8SJose Abreu } 1713427849e8SJose Abreu 17145f8475daSJose Abreu static int stmmac_test_sph(struct stmmac_priv *priv) 17155f8475daSJose Abreu { 17165f8475daSJose Abreu unsigned long cnt_end, cnt_start = priv->xstats.rx_split_hdr_pkt_n; 17175f8475daSJose Abreu struct stmmac_packet_attrs attr = { }; 17185f8475daSJose Abreu int ret; 17195f8475daSJose Abreu 17205f8475daSJose Abreu if (!priv->sph) 17215f8475daSJose Abreu return -EOPNOTSUPP; 17225f8475daSJose Abreu 17235f8475daSJose Abreu /* Check for UDP first */ 17245f8475daSJose Abreu attr.dst = priv->dev->dev_addr; 17255f8475daSJose Abreu attr.tcp = false; 17265f8475daSJose Abreu 17275f8475daSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 17285f8475daSJose Abreu if (ret) 17295f8475daSJose Abreu return ret; 17305f8475daSJose Abreu 17315f8475daSJose Abreu cnt_end = priv->xstats.rx_split_hdr_pkt_n; 17325f8475daSJose Abreu if (cnt_end <= cnt_start) 17335f8475daSJose Abreu return -EINVAL; 17345f8475daSJose Abreu 17355f8475daSJose Abreu /* Check for TCP now */ 17365f8475daSJose Abreu cnt_start = cnt_end; 17375f8475daSJose Abreu 17385f8475daSJose Abreu attr.dst = priv->dev->dev_addr; 17395f8475daSJose Abreu attr.tcp = true; 17405f8475daSJose Abreu 17415f8475daSJose Abreu ret = __stmmac_test_loopback(priv, &attr); 17425f8475daSJose Abreu if (ret) 17435f8475daSJose Abreu return ret; 17445f8475daSJose Abreu 17455f8475daSJose Abreu cnt_end = priv->xstats.rx_split_hdr_pkt_n; 17465f8475daSJose Abreu if (cnt_end <= cnt_start) 17475f8475daSJose Abreu return -EINVAL; 17485f8475daSJose Abreu 17495f8475daSJose Abreu return 0; 17505f8475daSJose Abreu } 17515f8475daSJose Abreu 175228c1cf73SJose Abreu static int stmmac_test_tbs(struct stmmac_priv *priv) 175328c1cf73SJose Abreu { 175428c1cf73SJose Abreu #define STMMAC_TBS_LT_OFFSET (500 * 1000 * 1000) /* 500 ms*/ 175528c1cf73SJose Abreu struct stmmac_packet_attrs attr = { }; 175628c1cf73SJose Abreu struct tc_etf_qopt_offload qopt; 175728c1cf73SJose Abreu u64 start_time, curr_time = 0; 175828c1cf73SJose Abreu unsigned long flags; 175928c1cf73SJose Abreu int ret, i; 176028c1cf73SJose Abreu 176128c1cf73SJose Abreu if (!priv->hwts_tx_en) 176228c1cf73SJose Abreu return -EOPNOTSUPP; 176328c1cf73SJose Abreu 176428c1cf73SJose Abreu /* Find first TBS enabled Queue, if any */ 176528c1cf73SJose Abreu for (i = 0; i < priv->plat->tx_queues_to_use; i++) 1766*8531c808SChristian Marangi if (priv->dma_conf.tx_queue[i].tbs & STMMAC_TBS_AVAIL) 176728c1cf73SJose Abreu break; 176828c1cf73SJose Abreu 176928c1cf73SJose Abreu if (i >= priv->plat->tx_queues_to_use) 177028c1cf73SJose Abreu return -EOPNOTSUPP; 177128c1cf73SJose Abreu 177228c1cf73SJose Abreu qopt.enable = true; 177328c1cf73SJose Abreu qopt.queue = i; 177428c1cf73SJose Abreu 177528c1cf73SJose Abreu ret = stmmac_tc_setup_etf(priv, priv, &qopt); 177628c1cf73SJose Abreu if (ret) 177728c1cf73SJose Abreu return ret; 177828c1cf73SJose Abreu 1779642436a1SYannick Vignon read_lock_irqsave(&priv->ptp_lock, flags); 178028c1cf73SJose Abreu stmmac_get_systime(priv, priv->ptpaddr, &curr_time); 1781642436a1SYannick Vignon read_unlock_irqrestore(&priv->ptp_lock, flags); 178228c1cf73SJose Abreu 178328c1cf73SJose Abreu if (!curr_time) { 178428c1cf73SJose Abreu ret = -EOPNOTSUPP; 178528c1cf73SJose Abreu goto fail_disable; 178628c1cf73SJose Abreu } 178728c1cf73SJose Abreu 178828c1cf73SJose Abreu start_time = curr_time; 178928c1cf73SJose Abreu curr_time += STMMAC_TBS_LT_OFFSET; 179028c1cf73SJose Abreu 179128c1cf73SJose Abreu attr.dst = priv->dev->dev_addr; 179228c1cf73SJose Abreu attr.timestamp = curr_time; 179328c1cf73SJose Abreu attr.timeout = nsecs_to_jiffies(2 * STMMAC_TBS_LT_OFFSET); 179428c1cf73SJose Abreu attr.queue_mapping = i; 179528c1cf73SJose Abreu 179628c1cf73SJose Abreu ret = __stmmac_test_loopback(priv, &attr); 179728c1cf73SJose Abreu if (ret) 179828c1cf73SJose Abreu goto fail_disable; 179928c1cf73SJose Abreu 180028c1cf73SJose Abreu /* Check if expected time has elapsed */ 1801642436a1SYannick Vignon read_lock_irqsave(&priv->ptp_lock, flags); 180228c1cf73SJose Abreu stmmac_get_systime(priv, priv->ptpaddr, &curr_time); 1803642436a1SYannick Vignon read_unlock_irqrestore(&priv->ptp_lock, flags); 180428c1cf73SJose Abreu 180528c1cf73SJose Abreu if ((curr_time - start_time) < STMMAC_TBS_LT_OFFSET) 180628c1cf73SJose Abreu ret = -EINVAL; 180728c1cf73SJose Abreu 180828c1cf73SJose Abreu fail_disable: 180928c1cf73SJose Abreu qopt.enable = false; 181028c1cf73SJose Abreu stmmac_tc_setup_etf(priv, priv, &qopt); 181128c1cf73SJose Abreu return ret; 181228c1cf73SJose Abreu } 181328c1cf73SJose Abreu 1814091810dbSJose Abreu #define STMMAC_LOOPBACK_NONE 0 1815091810dbSJose Abreu #define STMMAC_LOOPBACK_MAC 1 1816091810dbSJose Abreu #define STMMAC_LOOPBACK_PHY 2 1817091810dbSJose Abreu 1818091810dbSJose Abreu static const struct stmmac_test { 1819091810dbSJose Abreu char name[ETH_GSTRING_LEN]; 1820091810dbSJose Abreu int lb; 1821091810dbSJose Abreu int (*fn)(struct stmmac_priv *priv); 1822091810dbSJose Abreu } stmmac_selftests[] = { 1823091810dbSJose Abreu { 1824091810dbSJose Abreu .name = "MAC Loopback ", 1825091810dbSJose Abreu .lb = STMMAC_LOOPBACK_MAC, 1826091810dbSJose Abreu .fn = stmmac_test_mac_loopback, 1827091810dbSJose Abreu }, { 1828091810dbSJose Abreu .name = "PHY Loopback ", 1829091810dbSJose Abreu .lb = STMMAC_LOOPBACK_NONE, /* Test will handle it */ 1830091810dbSJose Abreu .fn = stmmac_test_phy_loopback, 1831091810dbSJose Abreu }, { 1832091810dbSJose Abreu .name = "MMC Counters ", 1833091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1834091810dbSJose Abreu .fn = stmmac_test_mmc, 1835091810dbSJose Abreu }, { 1836091810dbSJose Abreu .name = "EEE ", 1837091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1838091810dbSJose Abreu .fn = stmmac_test_eee, 1839091810dbSJose Abreu }, { 1840091810dbSJose Abreu .name = "Hash Filter MC ", 1841091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1842091810dbSJose Abreu .fn = stmmac_test_hfilt, 1843091810dbSJose Abreu }, { 1844091810dbSJose Abreu .name = "Perfect Filter UC ", 1845091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1846091810dbSJose Abreu .fn = stmmac_test_pfilt, 1847091810dbSJose Abreu }, { 1848091810dbSJose Abreu .name = "MC Filter ", 1849091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1850091810dbSJose Abreu .fn = stmmac_test_mcfilt, 1851091810dbSJose Abreu }, { 1852091810dbSJose Abreu .name = "UC Filter ", 1853091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1854091810dbSJose Abreu .fn = stmmac_test_ucfilt, 1855091810dbSJose Abreu }, { 1856091810dbSJose Abreu .name = "Flow Control ", 1857091810dbSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1858091810dbSJose Abreu .fn = stmmac_test_flowctrl, 18591fbdad00SJose Abreu }, { 18601fbdad00SJose Abreu .name = "RSS ", 18611fbdad00SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 18621fbdad00SJose Abreu .fn = stmmac_test_rss, 186374043f6bSJose Abreu }, { 186474043f6bSJose Abreu .name = "VLAN Filtering ", 186574043f6bSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 186674043f6bSJose Abreu .fn = stmmac_test_vlanfilt, 186774043f6bSJose Abreu }, { 18681b2250a0SJose Abreu .name = "VLAN Filtering (perf) ", 18691b2250a0SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 18701b2250a0SJose Abreu .fn = stmmac_test_vlanfilt_perfect, 18711b2250a0SJose Abreu }, { 18721b2250a0SJose Abreu .name = "Double VLAN Filter ", 187374043f6bSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 187474043f6bSJose Abreu .fn = stmmac_test_dvlanfilt, 1875ccfc639aSJose Abreu }, { 18761b2250a0SJose Abreu .name = "Double VLAN Filter (perf) ", 18771b2250a0SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 18781b2250a0SJose Abreu .fn = stmmac_test_dvlanfilt_perfect, 18791b2250a0SJose Abreu }, { 1880ccfc639aSJose Abreu .name = "Flexible RX Parser ", 1881ccfc639aSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1882ccfc639aSJose Abreu .fn = stmmac_test_rxp, 18838180d579SJose Abreu }, { 18848180d579SJose Abreu .name = "SA Insertion (desc) ", 18858180d579SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 18868180d579SJose Abreu .fn = stmmac_test_desc_sai, 18878180d579SJose Abreu }, { 18888180d579SJose Abreu .name = "SA Replacement (desc) ", 18898180d579SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 18908180d579SJose Abreu .fn = stmmac_test_desc_sar, 18918180d579SJose Abreu }, { 18928180d579SJose Abreu .name = "SA Insertion (reg) ", 18938180d579SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 18948180d579SJose Abreu .fn = stmmac_test_reg_sai, 18958180d579SJose Abreu }, { 18968180d579SJose Abreu .name = "SA Replacement (reg) ", 18978180d579SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 18988180d579SJose Abreu .fn = stmmac_test_reg_sar, 189994e18382SJose Abreu }, { 190094e18382SJose Abreu .name = "VLAN TX Insertion ", 190194e18382SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 190294e18382SJose Abreu .fn = stmmac_test_vlanoff, 190394e18382SJose Abreu }, { 190494e18382SJose Abreu .name = "SVLAN TX Insertion ", 190594e18382SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 190694e18382SJose Abreu .fn = stmmac_test_svlanoff, 19074647e021SJose Abreu }, { 19084647e021SJose Abreu .name = "L3 DA Filtering ", 19094647e021SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 19104647e021SJose Abreu .fn = stmmac_test_l3filt_da, 19114647e021SJose Abreu }, { 19124647e021SJose Abreu .name = "L3 SA Filtering ", 19134647e021SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 19144647e021SJose Abreu .fn = stmmac_test_l3filt_sa, 19154647e021SJose Abreu }, { 19164647e021SJose Abreu .name = "L4 DA TCP Filtering ", 19174647e021SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 19184647e021SJose Abreu .fn = stmmac_test_l4filt_da_tcp, 19194647e021SJose Abreu }, { 19204647e021SJose Abreu .name = "L4 SA TCP Filtering ", 19214647e021SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 19224647e021SJose Abreu .fn = stmmac_test_l4filt_sa_tcp, 19234647e021SJose Abreu }, { 19244647e021SJose Abreu .name = "L4 DA UDP Filtering ", 19254647e021SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 19264647e021SJose Abreu .fn = stmmac_test_l4filt_da_udp, 19274647e021SJose Abreu }, { 19284647e021SJose Abreu .name = "L4 SA UDP Filtering ", 19294647e021SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 19304647e021SJose Abreu .fn = stmmac_test_l4filt_sa_udp, 19315e3fb0a6SJose Abreu }, { 19325e3fb0a6SJose Abreu .name = "ARP Offload ", 19335e3fb0a6SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 19345e3fb0a6SJose Abreu .fn = stmmac_test_arpoffload, 1935427849e8SJose Abreu }, { 1936427849e8SJose Abreu .name = "Jumbo Frame ", 1937427849e8SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1938427849e8SJose Abreu .fn = stmmac_test_jumbo, 1939427849e8SJose Abreu }, { 1940427849e8SJose Abreu .name = "Multichannel Jumbo ", 1941427849e8SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 1942427849e8SJose Abreu .fn = stmmac_test_mjumbo, 19435f8475daSJose Abreu }, { 19445f8475daSJose Abreu .name = "Split Header ", 19455f8475daSJose Abreu .lb = STMMAC_LOOPBACK_PHY, 19465f8475daSJose Abreu .fn = stmmac_test_sph, 194728c1cf73SJose Abreu }, { 194828c1cf73SJose Abreu .name = "TBS (ETF Scheduler) ", 194928c1cf73SJose Abreu .lb = STMMAC_LOOPBACK_PHY, 195028c1cf73SJose Abreu .fn = stmmac_test_tbs, 1951091810dbSJose Abreu }, 1952091810dbSJose Abreu }; 1953091810dbSJose Abreu 1954091810dbSJose Abreu void stmmac_selftest_run(struct net_device *dev, 1955091810dbSJose Abreu struct ethtool_test *etest, u64 *buf) 1956091810dbSJose Abreu { 1957091810dbSJose Abreu struct stmmac_priv *priv = netdev_priv(dev); 1958091810dbSJose Abreu int count = stmmac_selftest_get_count(priv); 1959091810dbSJose Abreu int i, ret; 1960091810dbSJose Abreu 1961091810dbSJose Abreu memset(buf, 0, sizeof(*buf) * count); 1962091810dbSJose Abreu stmmac_test_next_id = 0; 1963091810dbSJose Abreu 1964091810dbSJose Abreu if (etest->flags != ETH_TEST_FL_OFFLINE) { 1965091810dbSJose Abreu netdev_err(priv->dev, "Only offline tests are supported\n"); 1966091810dbSJose Abreu etest->flags |= ETH_TEST_FL_FAILED; 1967091810dbSJose Abreu return; 196805373e31SJose Abreu } else if (!netif_carrier_ok(dev)) { 1969091810dbSJose Abreu netdev_err(priv->dev, "You need valid Link to execute tests\n"); 1970091810dbSJose Abreu etest->flags |= ETH_TEST_FL_FAILED; 1971091810dbSJose Abreu return; 1972091810dbSJose Abreu } 1973091810dbSJose Abreu 1974091810dbSJose Abreu /* Wait for queues drain */ 1975091810dbSJose Abreu msleep(200); 1976091810dbSJose Abreu 1977091810dbSJose Abreu for (i = 0; i < count; i++) { 1978091810dbSJose Abreu ret = 0; 1979091810dbSJose Abreu 1980091810dbSJose Abreu switch (stmmac_selftests[i].lb) { 1981091810dbSJose Abreu case STMMAC_LOOPBACK_PHY: 1982091810dbSJose Abreu ret = -EOPNOTSUPP; 1983091810dbSJose Abreu if (dev->phydev) 1984091810dbSJose Abreu ret = phy_loopback(dev->phydev, true); 1985091810dbSJose Abreu if (!ret) 1986091810dbSJose Abreu break; 1987df561f66SGustavo A. R. Silva fallthrough; 1988091810dbSJose Abreu case STMMAC_LOOPBACK_MAC: 1989091810dbSJose Abreu ret = stmmac_set_mac_loopback(priv, priv->ioaddr, true); 1990091810dbSJose Abreu break; 1991091810dbSJose Abreu case STMMAC_LOOPBACK_NONE: 1992091810dbSJose Abreu break; 1993091810dbSJose Abreu default: 1994091810dbSJose Abreu ret = -EOPNOTSUPP; 1995091810dbSJose Abreu break; 1996091810dbSJose Abreu } 1997091810dbSJose Abreu 1998091810dbSJose Abreu /* 1999091810dbSJose Abreu * First tests will always be MAC / PHY loobpack. If any of 2000091810dbSJose Abreu * them is not supported we abort earlier. 2001091810dbSJose Abreu */ 2002091810dbSJose Abreu if (ret) { 2003091810dbSJose Abreu netdev_err(priv->dev, "Loopback is not supported\n"); 2004091810dbSJose Abreu etest->flags |= ETH_TEST_FL_FAILED; 2005091810dbSJose Abreu break; 2006091810dbSJose Abreu } 2007091810dbSJose Abreu 2008091810dbSJose Abreu ret = stmmac_selftests[i].fn(priv); 2009091810dbSJose Abreu if (ret && (ret != -EOPNOTSUPP)) 2010091810dbSJose Abreu etest->flags |= ETH_TEST_FL_FAILED; 2011091810dbSJose Abreu buf[i] = ret; 2012091810dbSJose Abreu 2013091810dbSJose Abreu switch (stmmac_selftests[i].lb) { 2014091810dbSJose Abreu case STMMAC_LOOPBACK_PHY: 2015091810dbSJose Abreu ret = -EOPNOTSUPP; 2016091810dbSJose Abreu if (dev->phydev) 2017091810dbSJose Abreu ret = phy_loopback(dev->phydev, false); 2018091810dbSJose Abreu if (!ret) 2019091810dbSJose Abreu break; 2020df561f66SGustavo A. R. Silva fallthrough; 2021091810dbSJose Abreu case STMMAC_LOOPBACK_MAC: 2022091810dbSJose Abreu stmmac_set_mac_loopback(priv, priv->ioaddr, false); 2023091810dbSJose Abreu break; 2024091810dbSJose Abreu default: 2025091810dbSJose Abreu break; 2026091810dbSJose Abreu } 2027091810dbSJose Abreu } 2028091810dbSJose Abreu } 2029091810dbSJose Abreu 2030091810dbSJose Abreu void stmmac_selftest_get_strings(struct stmmac_priv *priv, u8 *data) 2031091810dbSJose Abreu { 2032091810dbSJose Abreu u8 *p = data; 2033091810dbSJose Abreu int i; 2034091810dbSJose Abreu 2035091810dbSJose Abreu for (i = 0; i < stmmac_selftest_get_count(priv); i++) { 2036091810dbSJose Abreu snprintf(p, ETH_GSTRING_LEN, "%2d. %s", i + 1, 2037091810dbSJose Abreu stmmac_selftests[i].name); 2038091810dbSJose Abreu p += ETH_GSTRING_LEN; 2039091810dbSJose Abreu } 2040091810dbSJose Abreu } 2041091810dbSJose Abreu 2042091810dbSJose Abreu int stmmac_selftest_get_count(struct stmmac_priv *priv) 2043091810dbSJose Abreu { 2044091810dbSJose Abreu return ARRAY_SIZE(stmmac_selftests); 2045091810dbSJose Abreu } 2046