1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2019 Synopsys, Inc. and/or its affiliates.
4*4882a593Smuzhiyun * stmmac Selftests Support
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Author: Jose Abreu <joabreu@synopsys.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/bitrev.h>
10*4882a593Smuzhiyun #include <linux/completion.h>
11*4882a593Smuzhiyun #include <linux/crc32.h>
12*4882a593Smuzhiyun #include <linux/ethtool.h>
13*4882a593Smuzhiyun #include <linux/ip.h>
14*4882a593Smuzhiyun #include <linux/phy.h>
15*4882a593Smuzhiyun #include <linux/udp.h>
16*4882a593Smuzhiyun #include <net/pkt_cls.h>
17*4882a593Smuzhiyun #include <net/pkt_sched.h>
18*4882a593Smuzhiyun #include <net/tcp.h>
19*4882a593Smuzhiyun #include <net/udp.h>
20*4882a593Smuzhiyun #include <net/tc_act/tc_gact.h>
21*4882a593Smuzhiyun #include "stmmac.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun struct stmmachdr {
24*4882a593Smuzhiyun __be32 version;
25*4882a593Smuzhiyun __be64 magic;
26*4882a593Smuzhiyun u8 id;
27*4882a593Smuzhiyun } __packed;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define STMMAC_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
30*4882a593Smuzhiyun sizeof(struct stmmachdr))
31*4882a593Smuzhiyun #define STMMAC_TEST_PKT_MAGIC 0xdeadcafecafedeadULL
32*4882a593Smuzhiyun #define STMMAC_LB_TIMEOUT msecs_to_jiffies(200)
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun struct stmmac_packet_attrs {
35*4882a593Smuzhiyun int vlan;
36*4882a593Smuzhiyun int vlan_id_in;
37*4882a593Smuzhiyun int vlan_id_out;
38*4882a593Smuzhiyun unsigned char *src;
39*4882a593Smuzhiyun unsigned char *dst;
40*4882a593Smuzhiyun u32 ip_src;
41*4882a593Smuzhiyun u32 ip_dst;
42*4882a593Smuzhiyun int tcp;
43*4882a593Smuzhiyun int sport;
44*4882a593Smuzhiyun int dport;
45*4882a593Smuzhiyun u32 exp_hash;
46*4882a593Smuzhiyun int dont_wait;
47*4882a593Smuzhiyun int timeout;
48*4882a593Smuzhiyun int size;
49*4882a593Smuzhiyun int max_size;
50*4882a593Smuzhiyun int remove_sa;
51*4882a593Smuzhiyun u8 id;
52*4882a593Smuzhiyun int sarc;
53*4882a593Smuzhiyun u16 queue_mapping;
54*4882a593Smuzhiyun u64 timestamp;
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun static u8 stmmac_test_next_id;
58*4882a593Smuzhiyun
stmmac_test_get_udp_skb(struct stmmac_priv * priv,struct stmmac_packet_attrs * attr)59*4882a593Smuzhiyun static struct sk_buff *stmmac_test_get_udp_skb(struct stmmac_priv *priv,
60*4882a593Smuzhiyun struct stmmac_packet_attrs *attr)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun struct sk_buff *skb = NULL;
63*4882a593Smuzhiyun struct udphdr *uhdr = NULL;
64*4882a593Smuzhiyun struct tcphdr *thdr = NULL;
65*4882a593Smuzhiyun struct stmmachdr *shdr;
66*4882a593Smuzhiyun struct ethhdr *ehdr;
67*4882a593Smuzhiyun struct iphdr *ihdr;
68*4882a593Smuzhiyun int iplen, size;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun size = attr->size + STMMAC_TEST_PKT_SIZE;
71*4882a593Smuzhiyun if (attr->vlan) {
72*4882a593Smuzhiyun size += 4;
73*4882a593Smuzhiyun if (attr->vlan > 1)
74*4882a593Smuzhiyun size += 4;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (attr->tcp)
78*4882a593Smuzhiyun size += sizeof(struct tcphdr);
79*4882a593Smuzhiyun else
80*4882a593Smuzhiyun size += sizeof(struct udphdr);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun if (attr->max_size && (attr->max_size > size))
83*4882a593Smuzhiyun size = attr->max_size;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun skb = netdev_alloc_skb(priv->dev, size);
86*4882a593Smuzhiyun if (!skb)
87*4882a593Smuzhiyun return NULL;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun prefetchw(skb->data);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (attr->vlan > 1)
92*4882a593Smuzhiyun ehdr = skb_push(skb, ETH_HLEN + 8);
93*4882a593Smuzhiyun else if (attr->vlan)
94*4882a593Smuzhiyun ehdr = skb_push(skb, ETH_HLEN + 4);
95*4882a593Smuzhiyun else if (attr->remove_sa)
96*4882a593Smuzhiyun ehdr = skb_push(skb, ETH_HLEN - 6);
97*4882a593Smuzhiyun else
98*4882a593Smuzhiyun ehdr = skb_push(skb, ETH_HLEN);
99*4882a593Smuzhiyun skb_reset_mac_header(skb);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun skb_set_network_header(skb, skb->len);
102*4882a593Smuzhiyun ihdr = skb_put(skb, sizeof(*ihdr));
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun skb_set_transport_header(skb, skb->len);
105*4882a593Smuzhiyun if (attr->tcp)
106*4882a593Smuzhiyun thdr = skb_put(skb, sizeof(*thdr));
107*4882a593Smuzhiyun else
108*4882a593Smuzhiyun uhdr = skb_put(skb, sizeof(*uhdr));
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if (!attr->remove_sa)
111*4882a593Smuzhiyun eth_zero_addr(ehdr->h_source);
112*4882a593Smuzhiyun eth_zero_addr(ehdr->h_dest);
113*4882a593Smuzhiyun if (attr->src && !attr->remove_sa)
114*4882a593Smuzhiyun ether_addr_copy(ehdr->h_source, attr->src);
115*4882a593Smuzhiyun if (attr->dst)
116*4882a593Smuzhiyun ether_addr_copy(ehdr->h_dest, attr->dst);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (!attr->remove_sa) {
119*4882a593Smuzhiyun ehdr->h_proto = htons(ETH_P_IP);
120*4882a593Smuzhiyun } else {
121*4882a593Smuzhiyun __be16 *ptr = (__be16 *)ehdr;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /* HACK */
124*4882a593Smuzhiyun ptr[3] = htons(ETH_P_IP);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (attr->vlan) {
128*4882a593Smuzhiyun __be16 *tag, *proto;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun if (!attr->remove_sa) {
131*4882a593Smuzhiyun tag = (void *)ehdr + ETH_HLEN;
132*4882a593Smuzhiyun proto = (void *)ehdr + (2 * ETH_ALEN);
133*4882a593Smuzhiyun } else {
134*4882a593Smuzhiyun tag = (void *)ehdr + ETH_HLEN - 6;
135*4882a593Smuzhiyun proto = (void *)ehdr + ETH_ALEN;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun proto[0] = htons(ETH_P_8021Q);
139*4882a593Smuzhiyun tag[0] = htons(attr->vlan_id_out);
140*4882a593Smuzhiyun tag[1] = htons(ETH_P_IP);
141*4882a593Smuzhiyun if (attr->vlan > 1) {
142*4882a593Smuzhiyun proto[0] = htons(ETH_P_8021AD);
143*4882a593Smuzhiyun tag[1] = htons(ETH_P_8021Q);
144*4882a593Smuzhiyun tag[2] = htons(attr->vlan_id_in);
145*4882a593Smuzhiyun tag[3] = htons(ETH_P_IP);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (attr->tcp) {
150*4882a593Smuzhiyun thdr->source = htons(attr->sport);
151*4882a593Smuzhiyun thdr->dest = htons(attr->dport);
152*4882a593Smuzhiyun thdr->doff = sizeof(struct tcphdr) / 4;
153*4882a593Smuzhiyun thdr->check = 0;
154*4882a593Smuzhiyun } else {
155*4882a593Smuzhiyun uhdr->source = htons(attr->sport);
156*4882a593Smuzhiyun uhdr->dest = htons(attr->dport);
157*4882a593Smuzhiyun uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size);
158*4882a593Smuzhiyun if (attr->max_size)
159*4882a593Smuzhiyun uhdr->len = htons(attr->max_size -
160*4882a593Smuzhiyun (sizeof(*ihdr) + sizeof(*ehdr)));
161*4882a593Smuzhiyun uhdr->check = 0;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun ihdr->ihl = 5;
165*4882a593Smuzhiyun ihdr->ttl = 32;
166*4882a593Smuzhiyun ihdr->version = 4;
167*4882a593Smuzhiyun if (attr->tcp)
168*4882a593Smuzhiyun ihdr->protocol = IPPROTO_TCP;
169*4882a593Smuzhiyun else
170*4882a593Smuzhiyun ihdr->protocol = IPPROTO_UDP;
171*4882a593Smuzhiyun iplen = sizeof(*ihdr) + sizeof(*shdr) + attr->size;
172*4882a593Smuzhiyun if (attr->tcp)
173*4882a593Smuzhiyun iplen += sizeof(*thdr);
174*4882a593Smuzhiyun else
175*4882a593Smuzhiyun iplen += sizeof(*uhdr);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun if (attr->max_size)
178*4882a593Smuzhiyun iplen = attr->max_size - sizeof(*ehdr);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun ihdr->tot_len = htons(iplen);
181*4882a593Smuzhiyun ihdr->frag_off = 0;
182*4882a593Smuzhiyun ihdr->saddr = htonl(attr->ip_src);
183*4882a593Smuzhiyun ihdr->daddr = htonl(attr->ip_dst);
184*4882a593Smuzhiyun ihdr->tos = 0;
185*4882a593Smuzhiyun ihdr->id = 0;
186*4882a593Smuzhiyun ip_send_check(ihdr);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun shdr = skb_put(skb, sizeof(*shdr));
189*4882a593Smuzhiyun shdr->version = 0;
190*4882a593Smuzhiyun shdr->magic = cpu_to_be64(STMMAC_TEST_PKT_MAGIC);
191*4882a593Smuzhiyun attr->id = stmmac_test_next_id;
192*4882a593Smuzhiyun shdr->id = stmmac_test_next_id++;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun if (attr->size)
195*4882a593Smuzhiyun skb_put(skb, attr->size);
196*4882a593Smuzhiyun if (attr->max_size && (attr->max_size > skb->len))
197*4882a593Smuzhiyun skb_put(skb, attr->max_size - skb->len);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun skb->csum = 0;
200*4882a593Smuzhiyun skb->ip_summed = CHECKSUM_PARTIAL;
201*4882a593Smuzhiyun if (attr->tcp) {
202*4882a593Smuzhiyun thdr->check = ~tcp_v4_check(skb->len, ihdr->saddr, ihdr->daddr, 0);
203*4882a593Smuzhiyun skb->csum_start = skb_transport_header(skb) - skb->head;
204*4882a593Smuzhiyun skb->csum_offset = offsetof(struct tcphdr, check);
205*4882a593Smuzhiyun } else {
206*4882a593Smuzhiyun udp4_hwcsum(skb, ihdr->saddr, ihdr->daddr);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun skb->protocol = htons(ETH_P_IP);
210*4882a593Smuzhiyun skb->pkt_type = PACKET_HOST;
211*4882a593Smuzhiyun skb->dev = priv->dev;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (attr->timestamp)
214*4882a593Smuzhiyun skb->tstamp = ns_to_ktime(attr->timestamp);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun return skb;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
stmmac_test_get_arp_skb(struct stmmac_priv * priv,struct stmmac_packet_attrs * attr)219*4882a593Smuzhiyun static struct sk_buff *stmmac_test_get_arp_skb(struct stmmac_priv *priv,
220*4882a593Smuzhiyun struct stmmac_packet_attrs *attr)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun __be32 ip_src = htonl(attr->ip_src);
223*4882a593Smuzhiyun __be32 ip_dst = htonl(attr->ip_dst);
224*4882a593Smuzhiyun struct sk_buff *skb = NULL;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun skb = arp_create(ARPOP_REQUEST, ETH_P_ARP, ip_dst, priv->dev, ip_src,
227*4882a593Smuzhiyun NULL, attr->src, attr->dst);
228*4882a593Smuzhiyun if (!skb)
229*4882a593Smuzhiyun return NULL;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun skb->pkt_type = PACKET_HOST;
232*4882a593Smuzhiyun skb->dev = priv->dev;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun return skb;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun struct stmmac_test_priv {
238*4882a593Smuzhiyun struct stmmac_packet_attrs *packet;
239*4882a593Smuzhiyun struct packet_type pt;
240*4882a593Smuzhiyun struct completion comp;
241*4882a593Smuzhiyun int double_vlan;
242*4882a593Smuzhiyun int vlan_id;
243*4882a593Smuzhiyun int ok;
244*4882a593Smuzhiyun };
245*4882a593Smuzhiyun
stmmac_test_loopback_validate(struct sk_buff * skb,struct net_device * ndev,struct packet_type * pt,struct net_device * orig_ndev)246*4882a593Smuzhiyun static int stmmac_test_loopback_validate(struct sk_buff *skb,
247*4882a593Smuzhiyun struct net_device *ndev,
248*4882a593Smuzhiyun struct packet_type *pt,
249*4882a593Smuzhiyun struct net_device *orig_ndev)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun struct stmmac_test_priv *tpriv = pt->af_packet_priv;
252*4882a593Smuzhiyun unsigned char *src = tpriv->packet->src;
253*4882a593Smuzhiyun unsigned char *dst = tpriv->packet->dst;
254*4882a593Smuzhiyun struct stmmachdr *shdr;
255*4882a593Smuzhiyun struct ethhdr *ehdr;
256*4882a593Smuzhiyun struct udphdr *uhdr;
257*4882a593Smuzhiyun struct tcphdr *thdr;
258*4882a593Smuzhiyun struct iphdr *ihdr;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun skb = skb_unshare(skb, GFP_ATOMIC);
261*4882a593Smuzhiyun if (!skb)
262*4882a593Smuzhiyun goto out;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (skb_linearize(skb))
265*4882a593Smuzhiyun goto out;
266*4882a593Smuzhiyun if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN))
267*4882a593Smuzhiyun goto out;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun ehdr = (struct ethhdr *)skb_mac_header(skb);
270*4882a593Smuzhiyun if (dst) {
271*4882a593Smuzhiyun if (!ether_addr_equal_unaligned(ehdr->h_dest, dst))
272*4882a593Smuzhiyun goto out;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun if (tpriv->packet->sarc) {
275*4882a593Smuzhiyun if (!ether_addr_equal_unaligned(ehdr->h_source, ehdr->h_dest))
276*4882a593Smuzhiyun goto out;
277*4882a593Smuzhiyun } else if (src) {
278*4882a593Smuzhiyun if (!ether_addr_equal_unaligned(ehdr->h_source, src))
279*4882a593Smuzhiyun goto out;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun ihdr = ip_hdr(skb);
283*4882a593Smuzhiyun if (tpriv->double_vlan)
284*4882a593Smuzhiyun ihdr = (struct iphdr *)(skb_network_header(skb) + 4);
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if (tpriv->packet->tcp) {
287*4882a593Smuzhiyun if (ihdr->protocol != IPPROTO_TCP)
288*4882a593Smuzhiyun goto out;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun thdr = (struct tcphdr *)((u8 *)ihdr + 4 * ihdr->ihl);
291*4882a593Smuzhiyun if (thdr->dest != htons(tpriv->packet->dport))
292*4882a593Smuzhiyun goto out;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun shdr = (struct stmmachdr *)((u8 *)thdr + sizeof(*thdr));
295*4882a593Smuzhiyun } else {
296*4882a593Smuzhiyun if (ihdr->protocol != IPPROTO_UDP)
297*4882a593Smuzhiyun goto out;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl);
300*4882a593Smuzhiyun if (uhdr->dest != htons(tpriv->packet->dport))
301*4882a593Smuzhiyun goto out;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun shdr = (struct stmmachdr *)((u8 *)uhdr + sizeof(*uhdr));
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun if (shdr->magic != cpu_to_be64(STMMAC_TEST_PKT_MAGIC))
307*4882a593Smuzhiyun goto out;
308*4882a593Smuzhiyun if (tpriv->packet->exp_hash && !skb->hash)
309*4882a593Smuzhiyun goto out;
310*4882a593Smuzhiyun if (tpriv->packet->id != shdr->id)
311*4882a593Smuzhiyun goto out;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun tpriv->ok = true;
314*4882a593Smuzhiyun complete(&tpriv->comp);
315*4882a593Smuzhiyun out:
316*4882a593Smuzhiyun kfree_skb(skb);
317*4882a593Smuzhiyun return 0;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
__stmmac_test_loopback(struct stmmac_priv * priv,struct stmmac_packet_attrs * attr)320*4882a593Smuzhiyun static int __stmmac_test_loopback(struct stmmac_priv *priv,
321*4882a593Smuzhiyun struct stmmac_packet_attrs *attr)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun struct stmmac_test_priv *tpriv;
324*4882a593Smuzhiyun struct sk_buff *skb = NULL;
325*4882a593Smuzhiyun int ret = 0;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
328*4882a593Smuzhiyun if (!tpriv)
329*4882a593Smuzhiyun return -ENOMEM;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun tpriv->ok = false;
332*4882a593Smuzhiyun init_completion(&tpriv->comp);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun tpriv->pt.type = htons(ETH_P_IP);
335*4882a593Smuzhiyun tpriv->pt.func = stmmac_test_loopback_validate;
336*4882a593Smuzhiyun tpriv->pt.dev = priv->dev;
337*4882a593Smuzhiyun tpriv->pt.af_packet_priv = tpriv;
338*4882a593Smuzhiyun tpriv->packet = attr;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun if (!attr->dont_wait)
341*4882a593Smuzhiyun dev_add_pack(&tpriv->pt);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun skb = stmmac_test_get_udp_skb(priv, attr);
344*4882a593Smuzhiyun if (!skb) {
345*4882a593Smuzhiyun ret = -ENOMEM;
346*4882a593Smuzhiyun goto cleanup;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun ret = dev_direct_xmit(skb, attr->queue_mapping);
350*4882a593Smuzhiyun if (ret)
351*4882a593Smuzhiyun goto cleanup;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun if (attr->dont_wait)
354*4882a593Smuzhiyun goto cleanup;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun if (!attr->timeout)
357*4882a593Smuzhiyun attr->timeout = STMMAC_LB_TIMEOUT;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun wait_for_completion_timeout(&tpriv->comp, attr->timeout);
360*4882a593Smuzhiyun ret = tpriv->ok ? 0 : -ETIMEDOUT;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun cleanup:
363*4882a593Smuzhiyun if (!attr->dont_wait)
364*4882a593Smuzhiyun dev_remove_pack(&tpriv->pt);
365*4882a593Smuzhiyun kfree(tpriv);
366*4882a593Smuzhiyun return ret;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
stmmac_test_mac_loopback(struct stmmac_priv * priv)369*4882a593Smuzhiyun static int stmmac_test_mac_loopback(struct stmmac_priv *priv)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
374*4882a593Smuzhiyun return __stmmac_test_loopback(priv, &attr);
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
stmmac_test_phy_loopback(struct stmmac_priv * priv)377*4882a593Smuzhiyun static int stmmac_test_phy_loopback(struct stmmac_priv *priv)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
380*4882a593Smuzhiyun int ret;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun if (!priv->dev->phydev)
383*4882a593Smuzhiyun return -EOPNOTSUPP;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun ret = phy_loopback(priv->dev->phydev, true);
386*4882a593Smuzhiyun if (ret)
387*4882a593Smuzhiyun return ret;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
390*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun phy_loopback(priv->dev->phydev, false);
393*4882a593Smuzhiyun return ret;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
stmmac_test_mmc(struct stmmac_priv * priv)396*4882a593Smuzhiyun static int stmmac_test_mmc(struct stmmac_priv *priv)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct stmmac_counters initial, final;
399*4882a593Smuzhiyun int ret;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun memset(&initial, 0, sizeof(initial));
402*4882a593Smuzhiyun memset(&final, 0, sizeof(final));
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun if (!priv->dma_cap.rmon)
405*4882a593Smuzhiyun return -EOPNOTSUPP;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /* Save previous results into internal struct */
408*4882a593Smuzhiyun stmmac_mmc_read(priv, priv->mmcaddr, &priv->mmc);
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun ret = stmmac_test_mac_loopback(priv);
411*4882a593Smuzhiyun if (ret)
412*4882a593Smuzhiyun return ret;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun /* These will be loopback results so no need to save them */
415*4882a593Smuzhiyun stmmac_mmc_read(priv, priv->mmcaddr, &final);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /*
418*4882a593Smuzhiyun * The number of MMC counters available depends on HW configuration
419*4882a593Smuzhiyun * so we just use this one to validate the feature. I hope there is
420*4882a593Smuzhiyun * not a version without this counter.
421*4882a593Smuzhiyun */
422*4882a593Smuzhiyun if (final.mmc_tx_framecount_g <= initial.mmc_tx_framecount_g)
423*4882a593Smuzhiyun return -EINVAL;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun return 0;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
stmmac_test_eee(struct stmmac_priv * priv)428*4882a593Smuzhiyun static int stmmac_test_eee(struct stmmac_priv *priv)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun struct stmmac_extra_stats *initial, *final;
431*4882a593Smuzhiyun int retries = 10;
432*4882a593Smuzhiyun int ret;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun if (!priv->dma_cap.eee || !priv->eee_active)
435*4882a593Smuzhiyun return -EOPNOTSUPP;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun initial = kzalloc(sizeof(*initial), GFP_KERNEL);
438*4882a593Smuzhiyun if (!initial)
439*4882a593Smuzhiyun return -ENOMEM;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun final = kzalloc(sizeof(*final), GFP_KERNEL);
442*4882a593Smuzhiyun if (!final) {
443*4882a593Smuzhiyun ret = -ENOMEM;
444*4882a593Smuzhiyun goto out_free_initial;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun memcpy(initial, &priv->xstats, sizeof(*initial));
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun ret = stmmac_test_mac_loopback(priv);
450*4882a593Smuzhiyun if (ret)
451*4882a593Smuzhiyun goto out_free_final;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun /* We have no traffic in the line so, sooner or later it will go LPI */
454*4882a593Smuzhiyun while (--retries) {
455*4882a593Smuzhiyun memcpy(final, &priv->xstats, sizeof(*final));
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun if (final->irq_tx_path_in_lpi_mode_n >
458*4882a593Smuzhiyun initial->irq_tx_path_in_lpi_mode_n)
459*4882a593Smuzhiyun break;
460*4882a593Smuzhiyun msleep(100);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun if (!retries) {
464*4882a593Smuzhiyun ret = -ETIMEDOUT;
465*4882a593Smuzhiyun goto out_free_final;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun if (final->irq_tx_path_in_lpi_mode_n <=
469*4882a593Smuzhiyun initial->irq_tx_path_in_lpi_mode_n) {
470*4882a593Smuzhiyun ret = -EINVAL;
471*4882a593Smuzhiyun goto out_free_final;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun if (final->irq_tx_path_exit_lpi_mode_n <=
475*4882a593Smuzhiyun initial->irq_tx_path_exit_lpi_mode_n) {
476*4882a593Smuzhiyun ret = -EINVAL;
477*4882a593Smuzhiyun goto out_free_final;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun out_free_final:
481*4882a593Smuzhiyun kfree(final);
482*4882a593Smuzhiyun out_free_initial:
483*4882a593Smuzhiyun kfree(initial);
484*4882a593Smuzhiyun return ret;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
stmmac_filter_check(struct stmmac_priv * priv)487*4882a593Smuzhiyun static int stmmac_filter_check(struct stmmac_priv *priv)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun if (!(priv->dev->flags & IFF_PROMISC))
490*4882a593Smuzhiyun return 0;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun netdev_warn(priv->dev, "Test can't be run in promiscuous mode!\n");
493*4882a593Smuzhiyun return -EOPNOTSUPP;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
stmmac_hash_check(struct stmmac_priv * priv,unsigned char * addr)496*4882a593Smuzhiyun static bool stmmac_hash_check(struct stmmac_priv *priv, unsigned char *addr)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun int mc_offset = 32 - priv->hw->mcast_bits_log2;
499*4882a593Smuzhiyun struct netdev_hw_addr *ha;
500*4882a593Smuzhiyun u32 hash, hash_nr;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* First compute the hash for desired addr */
503*4882a593Smuzhiyun hash = bitrev32(~crc32_le(~0, addr, 6)) >> mc_offset;
504*4882a593Smuzhiyun hash_nr = hash >> 5;
505*4882a593Smuzhiyun hash = 1 << (hash & 0x1f);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun /* Now, check if it collides with any existing one */
508*4882a593Smuzhiyun netdev_for_each_mc_addr(ha, priv->dev) {
509*4882a593Smuzhiyun u32 nr = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)) >> mc_offset;
510*4882a593Smuzhiyun if (((nr >> 5) == hash_nr) && ((1 << (nr & 0x1f)) == hash))
511*4882a593Smuzhiyun return false;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun /* No collisions, address is good to go */
515*4882a593Smuzhiyun return true;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
stmmac_perfect_check(struct stmmac_priv * priv,unsigned char * addr)518*4882a593Smuzhiyun static bool stmmac_perfect_check(struct stmmac_priv *priv, unsigned char *addr)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun struct netdev_hw_addr *ha;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun /* Check if it collides with any existing one */
523*4882a593Smuzhiyun netdev_for_each_uc_addr(ha, priv->dev) {
524*4882a593Smuzhiyun if (!memcmp(ha->addr, addr, ETH_ALEN))
525*4882a593Smuzhiyun return false;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun /* No collisions, address is good to go */
529*4882a593Smuzhiyun return true;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
stmmac_test_hfilt(struct stmmac_priv * priv)532*4882a593Smuzhiyun static int stmmac_test_hfilt(struct stmmac_priv *priv)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun unsigned char gd_addr[ETH_ALEN] = {0xf1, 0xee, 0xdd, 0xcc, 0xbb, 0xaa};
535*4882a593Smuzhiyun unsigned char bd_addr[ETH_ALEN] = {0xf1, 0xff, 0xff, 0xff, 0xff, 0xff};
536*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
537*4882a593Smuzhiyun int ret, tries = 256;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun ret = stmmac_filter_check(priv);
540*4882a593Smuzhiyun if (ret)
541*4882a593Smuzhiyun return ret;
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun if (netdev_mc_count(priv->dev) >= priv->hw->multicast_filter_bins)
544*4882a593Smuzhiyun return -EOPNOTSUPP;
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun while (--tries) {
547*4882a593Smuzhiyun /* We only need to check the bd_addr for collisions */
548*4882a593Smuzhiyun bd_addr[ETH_ALEN - 1] = tries;
549*4882a593Smuzhiyun if (stmmac_hash_check(priv, bd_addr))
550*4882a593Smuzhiyun break;
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun if (!tries)
554*4882a593Smuzhiyun return -EOPNOTSUPP;
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun ret = dev_mc_add(priv->dev, gd_addr);
557*4882a593Smuzhiyun if (ret)
558*4882a593Smuzhiyun return ret;
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun attr.dst = gd_addr;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun /* Shall receive packet */
563*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
564*4882a593Smuzhiyun if (ret)
565*4882a593Smuzhiyun goto cleanup;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun attr.dst = bd_addr;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun /* Shall NOT receive packet */
570*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
571*4882a593Smuzhiyun ret = ret ? 0 : -EINVAL;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun cleanup:
574*4882a593Smuzhiyun dev_mc_del(priv->dev, gd_addr);
575*4882a593Smuzhiyun return ret;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
stmmac_test_pfilt(struct stmmac_priv * priv)578*4882a593Smuzhiyun static int stmmac_test_pfilt(struct stmmac_priv *priv)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun unsigned char gd_addr[ETH_ALEN] = {0xf0, 0x01, 0x44, 0x55, 0x66, 0x77};
581*4882a593Smuzhiyun unsigned char bd_addr[ETH_ALEN] = {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff};
582*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
583*4882a593Smuzhiyun int ret, tries = 256;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun if (stmmac_filter_check(priv))
586*4882a593Smuzhiyun return -EOPNOTSUPP;
587*4882a593Smuzhiyun if (netdev_uc_count(priv->dev) >= priv->hw->unicast_filter_entries)
588*4882a593Smuzhiyun return -EOPNOTSUPP;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun while (--tries) {
591*4882a593Smuzhiyun /* We only need to check the bd_addr for collisions */
592*4882a593Smuzhiyun bd_addr[ETH_ALEN - 1] = tries;
593*4882a593Smuzhiyun if (stmmac_perfect_check(priv, bd_addr))
594*4882a593Smuzhiyun break;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (!tries)
598*4882a593Smuzhiyun return -EOPNOTSUPP;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun ret = dev_uc_add(priv->dev, gd_addr);
601*4882a593Smuzhiyun if (ret)
602*4882a593Smuzhiyun return ret;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun attr.dst = gd_addr;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun /* Shall receive packet */
607*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
608*4882a593Smuzhiyun if (ret)
609*4882a593Smuzhiyun goto cleanup;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun attr.dst = bd_addr;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun /* Shall NOT receive packet */
614*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
615*4882a593Smuzhiyun ret = ret ? 0 : -EINVAL;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun cleanup:
618*4882a593Smuzhiyun dev_uc_del(priv->dev, gd_addr);
619*4882a593Smuzhiyun return ret;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
stmmac_test_mcfilt(struct stmmac_priv * priv)622*4882a593Smuzhiyun static int stmmac_test_mcfilt(struct stmmac_priv *priv)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun unsigned char uc_addr[ETH_ALEN] = {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff};
625*4882a593Smuzhiyun unsigned char mc_addr[ETH_ALEN] = {0xf1, 0xff, 0xff, 0xff, 0xff, 0xff};
626*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
627*4882a593Smuzhiyun int ret, tries = 256;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun if (stmmac_filter_check(priv))
630*4882a593Smuzhiyun return -EOPNOTSUPP;
631*4882a593Smuzhiyun if (netdev_uc_count(priv->dev) >= priv->hw->unicast_filter_entries)
632*4882a593Smuzhiyun return -EOPNOTSUPP;
633*4882a593Smuzhiyun if (netdev_mc_count(priv->dev) >= priv->hw->multicast_filter_bins)
634*4882a593Smuzhiyun return -EOPNOTSUPP;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun while (--tries) {
637*4882a593Smuzhiyun /* We only need to check the mc_addr for collisions */
638*4882a593Smuzhiyun mc_addr[ETH_ALEN - 1] = tries;
639*4882a593Smuzhiyun if (stmmac_hash_check(priv, mc_addr))
640*4882a593Smuzhiyun break;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun if (!tries)
644*4882a593Smuzhiyun return -EOPNOTSUPP;
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun ret = dev_uc_add(priv->dev, uc_addr);
647*4882a593Smuzhiyun if (ret)
648*4882a593Smuzhiyun return ret;
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun attr.dst = uc_addr;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun /* Shall receive packet */
653*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
654*4882a593Smuzhiyun if (ret)
655*4882a593Smuzhiyun goto cleanup;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun attr.dst = mc_addr;
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun /* Shall NOT receive packet */
660*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
661*4882a593Smuzhiyun ret = ret ? 0 : -EINVAL;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun cleanup:
664*4882a593Smuzhiyun dev_uc_del(priv->dev, uc_addr);
665*4882a593Smuzhiyun return ret;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
stmmac_test_ucfilt(struct stmmac_priv * priv)668*4882a593Smuzhiyun static int stmmac_test_ucfilt(struct stmmac_priv *priv)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun unsigned char uc_addr[ETH_ALEN] = {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff};
671*4882a593Smuzhiyun unsigned char mc_addr[ETH_ALEN] = {0xf1, 0xff, 0xff, 0xff, 0xff, 0xff};
672*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
673*4882a593Smuzhiyun int ret, tries = 256;
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun if (stmmac_filter_check(priv))
676*4882a593Smuzhiyun return -EOPNOTSUPP;
677*4882a593Smuzhiyun if (netdev_uc_count(priv->dev) >= priv->hw->unicast_filter_entries)
678*4882a593Smuzhiyun return -EOPNOTSUPP;
679*4882a593Smuzhiyun if (netdev_mc_count(priv->dev) >= priv->hw->multicast_filter_bins)
680*4882a593Smuzhiyun return -EOPNOTSUPP;
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun while (--tries) {
683*4882a593Smuzhiyun /* We only need to check the uc_addr for collisions */
684*4882a593Smuzhiyun uc_addr[ETH_ALEN - 1] = tries;
685*4882a593Smuzhiyun if (stmmac_perfect_check(priv, uc_addr))
686*4882a593Smuzhiyun break;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun if (!tries)
690*4882a593Smuzhiyun return -EOPNOTSUPP;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun ret = dev_mc_add(priv->dev, mc_addr);
693*4882a593Smuzhiyun if (ret)
694*4882a593Smuzhiyun return ret;
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun attr.dst = mc_addr;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun /* Shall receive packet */
699*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
700*4882a593Smuzhiyun if (ret)
701*4882a593Smuzhiyun goto cleanup;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun attr.dst = uc_addr;
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun /* Shall NOT receive packet */
706*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
707*4882a593Smuzhiyun ret = ret ? 0 : -EINVAL;
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun cleanup:
710*4882a593Smuzhiyun dev_mc_del(priv->dev, mc_addr);
711*4882a593Smuzhiyun return ret;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
stmmac_test_flowctrl_validate(struct sk_buff * skb,struct net_device * ndev,struct packet_type * pt,struct net_device * orig_ndev)714*4882a593Smuzhiyun static int stmmac_test_flowctrl_validate(struct sk_buff *skb,
715*4882a593Smuzhiyun struct net_device *ndev,
716*4882a593Smuzhiyun struct packet_type *pt,
717*4882a593Smuzhiyun struct net_device *orig_ndev)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun struct stmmac_test_priv *tpriv = pt->af_packet_priv;
720*4882a593Smuzhiyun struct ethhdr *ehdr;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun ehdr = (struct ethhdr *)skb_mac_header(skb);
723*4882a593Smuzhiyun if (!ether_addr_equal_unaligned(ehdr->h_source, orig_ndev->dev_addr))
724*4882a593Smuzhiyun goto out;
725*4882a593Smuzhiyun if (ehdr->h_proto != htons(ETH_P_PAUSE))
726*4882a593Smuzhiyun goto out;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun tpriv->ok = true;
729*4882a593Smuzhiyun complete(&tpriv->comp);
730*4882a593Smuzhiyun out:
731*4882a593Smuzhiyun kfree_skb(skb);
732*4882a593Smuzhiyun return 0;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun
stmmac_test_flowctrl(struct stmmac_priv * priv)735*4882a593Smuzhiyun static int stmmac_test_flowctrl(struct stmmac_priv *priv)
736*4882a593Smuzhiyun {
737*4882a593Smuzhiyun unsigned char paddr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01};
738*4882a593Smuzhiyun struct phy_device *phydev = priv->dev->phydev;
739*4882a593Smuzhiyun u32 rx_cnt = priv->plat->rx_queues_to_use;
740*4882a593Smuzhiyun struct stmmac_test_priv *tpriv;
741*4882a593Smuzhiyun unsigned int pkt_count;
742*4882a593Smuzhiyun int i, ret = 0;
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun if (!phydev || (!phydev->pause && !phydev->asym_pause))
745*4882a593Smuzhiyun return -EOPNOTSUPP;
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
748*4882a593Smuzhiyun if (!tpriv)
749*4882a593Smuzhiyun return -ENOMEM;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun tpriv->ok = false;
752*4882a593Smuzhiyun init_completion(&tpriv->comp);
753*4882a593Smuzhiyun tpriv->pt.type = htons(ETH_P_PAUSE);
754*4882a593Smuzhiyun tpriv->pt.func = stmmac_test_flowctrl_validate;
755*4882a593Smuzhiyun tpriv->pt.dev = priv->dev;
756*4882a593Smuzhiyun tpriv->pt.af_packet_priv = tpriv;
757*4882a593Smuzhiyun dev_add_pack(&tpriv->pt);
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun /* Compute minimum number of packets to make FIFO full */
760*4882a593Smuzhiyun pkt_count = priv->plat->rx_fifo_size;
761*4882a593Smuzhiyun if (!pkt_count)
762*4882a593Smuzhiyun pkt_count = priv->dma_cap.rx_fifo_size;
763*4882a593Smuzhiyun pkt_count /= 1400;
764*4882a593Smuzhiyun pkt_count *= 2;
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun for (i = 0; i < rx_cnt; i++)
767*4882a593Smuzhiyun stmmac_stop_rx(priv, priv->ioaddr, i);
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun ret = dev_set_promiscuity(priv->dev, 1);
770*4882a593Smuzhiyun if (ret)
771*4882a593Smuzhiyun goto cleanup;
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun ret = dev_mc_add(priv->dev, paddr);
774*4882a593Smuzhiyun if (ret)
775*4882a593Smuzhiyun goto cleanup;
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun for (i = 0; i < pkt_count; i++) {
778*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
781*4882a593Smuzhiyun attr.dont_wait = true;
782*4882a593Smuzhiyun attr.size = 1400;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
785*4882a593Smuzhiyun if (ret)
786*4882a593Smuzhiyun goto cleanup;
787*4882a593Smuzhiyun if (tpriv->ok)
788*4882a593Smuzhiyun break;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun /* Wait for some time in case RX Watchdog is enabled */
792*4882a593Smuzhiyun msleep(200);
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun for (i = 0; i < rx_cnt; i++) {
795*4882a593Smuzhiyun struct stmmac_channel *ch = &priv->channel[i];
796*4882a593Smuzhiyun u32 tail;
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun tail = priv->rx_queue[i].dma_rx_phy +
799*4882a593Smuzhiyun (priv->dma_rx_size * sizeof(struct dma_desc));
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun stmmac_set_rx_tail_ptr(priv, priv->ioaddr, tail, i);
802*4882a593Smuzhiyun stmmac_start_rx(priv, priv->ioaddr, i);
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun local_bh_disable();
805*4882a593Smuzhiyun napi_reschedule(&ch->rx_napi);
806*4882a593Smuzhiyun local_bh_enable();
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT);
810*4882a593Smuzhiyun ret = tpriv->ok ? 0 : -ETIMEDOUT;
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun cleanup:
813*4882a593Smuzhiyun dev_mc_del(priv->dev, paddr);
814*4882a593Smuzhiyun dev_set_promiscuity(priv->dev, -1);
815*4882a593Smuzhiyun dev_remove_pack(&tpriv->pt);
816*4882a593Smuzhiyun kfree(tpriv);
817*4882a593Smuzhiyun return ret;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
stmmac_test_rss(struct stmmac_priv * priv)820*4882a593Smuzhiyun static int stmmac_test_rss(struct stmmac_priv *priv)
821*4882a593Smuzhiyun {
822*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun if (!priv->dma_cap.rssen || !priv->rss.enable)
825*4882a593Smuzhiyun return -EOPNOTSUPP;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
828*4882a593Smuzhiyun attr.exp_hash = true;
829*4882a593Smuzhiyun attr.sport = 0x321;
830*4882a593Smuzhiyun attr.dport = 0x123;
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun return __stmmac_test_loopback(priv, &attr);
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun
stmmac_test_vlan_validate(struct sk_buff * skb,struct net_device * ndev,struct packet_type * pt,struct net_device * orig_ndev)835*4882a593Smuzhiyun static int stmmac_test_vlan_validate(struct sk_buff *skb,
836*4882a593Smuzhiyun struct net_device *ndev,
837*4882a593Smuzhiyun struct packet_type *pt,
838*4882a593Smuzhiyun struct net_device *orig_ndev)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun struct stmmac_test_priv *tpriv = pt->af_packet_priv;
841*4882a593Smuzhiyun struct stmmachdr *shdr;
842*4882a593Smuzhiyun struct ethhdr *ehdr;
843*4882a593Smuzhiyun struct udphdr *uhdr;
844*4882a593Smuzhiyun struct iphdr *ihdr;
845*4882a593Smuzhiyun u16 proto;
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun proto = tpriv->double_vlan ? ETH_P_8021AD : ETH_P_8021Q;
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun skb = skb_unshare(skb, GFP_ATOMIC);
850*4882a593Smuzhiyun if (!skb)
851*4882a593Smuzhiyun goto out;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun if (skb_linearize(skb))
854*4882a593Smuzhiyun goto out;
855*4882a593Smuzhiyun if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN))
856*4882a593Smuzhiyun goto out;
857*4882a593Smuzhiyun if (tpriv->vlan_id) {
858*4882a593Smuzhiyun if (skb->vlan_proto != htons(proto))
859*4882a593Smuzhiyun goto out;
860*4882a593Smuzhiyun if (skb->vlan_tci != tpriv->vlan_id) {
861*4882a593Smuzhiyun /* Means filter did not work. */
862*4882a593Smuzhiyun tpriv->ok = false;
863*4882a593Smuzhiyun complete(&tpriv->comp);
864*4882a593Smuzhiyun goto out;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun ehdr = (struct ethhdr *)skb_mac_header(skb);
869*4882a593Smuzhiyun if (!ether_addr_equal_unaligned(ehdr->h_dest, tpriv->packet->dst))
870*4882a593Smuzhiyun goto out;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun ihdr = ip_hdr(skb);
873*4882a593Smuzhiyun if (tpriv->double_vlan)
874*4882a593Smuzhiyun ihdr = (struct iphdr *)(skb_network_header(skb) + 4);
875*4882a593Smuzhiyun if (ihdr->protocol != IPPROTO_UDP)
876*4882a593Smuzhiyun goto out;
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl);
879*4882a593Smuzhiyun if (uhdr->dest != htons(tpriv->packet->dport))
880*4882a593Smuzhiyun goto out;
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun shdr = (struct stmmachdr *)((u8 *)uhdr + sizeof(*uhdr));
883*4882a593Smuzhiyun if (shdr->magic != cpu_to_be64(STMMAC_TEST_PKT_MAGIC))
884*4882a593Smuzhiyun goto out;
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun tpriv->ok = true;
887*4882a593Smuzhiyun complete(&tpriv->comp);
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun out:
890*4882a593Smuzhiyun kfree_skb(skb);
891*4882a593Smuzhiyun return 0;
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun
__stmmac_test_vlanfilt(struct stmmac_priv * priv)894*4882a593Smuzhiyun static int __stmmac_test_vlanfilt(struct stmmac_priv *priv)
895*4882a593Smuzhiyun {
896*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
897*4882a593Smuzhiyun struct stmmac_test_priv *tpriv;
898*4882a593Smuzhiyun struct sk_buff *skb = NULL;
899*4882a593Smuzhiyun int ret = 0, i;
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
902*4882a593Smuzhiyun if (!tpriv)
903*4882a593Smuzhiyun return -ENOMEM;
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun tpriv->ok = false;
906*4882a593Smuzhiyun init_completion(&tpriv->comp);
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun tpriv->pt.type = htons(ETH_P_IP);
909*4882a593Smuzhiyun tpriv->pt.func = stmmac_test_vlan_validate;
910*4882a593Smuzhiyun tpriv->pt.dev = priv->dev;
911*4882a593Smuzhiyun tpriv->pt.af_packet_priv = tpriv;
912*4882a593Smuzhiyun tpriv->packet = &attr;
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun /*
915*4882a593Smuzhiyun * As we use HASH filtering, false positives may appear. This is a
916*4882a593Smuzhiyun * specially chosen ID so that adjacent IDs (+4) have different
917*4882a593Smuzhiyun * HASH values.
918*4882a593Smuzhiyun */
919*4882a593Smuzhiyun tpriv->vlan_id = 0x123;
920*4882a593Smuzhiyun dev_add_pack(&tpriv->pt);
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun ret = vlan_vid_add(priv->dev, htons(ETH_P_8021Q), tpriv->vlan_id);
923*4882a593Smuzhiyun if (ret)
924*4882a593Smuzhiyun goto cleanup;
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
927*4882a593Smuzhiyun attr.vlan = 1;
928*4882a593Smuzhiyun attr.vlan_id_out = tpriv->vlan_id + i;
929*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
930*4882a593Smuzhiyun attr.sport = 9;
931*4882a593Smuzhiyun attr.dport = 9;
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun skb = stmmac_test_get_udp_skb(priv, &attr);
934*4882a593Smuzhiyun if (!skb) {
935*4882a593Smuzhiyun ret = -ENOMEM;
936*4882a593Smuzhiyun goto vlan_del;
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun ret = dev_direct_xmit(skb, 0);
940*4882a593Smuzhiyun if (ret)
941*4882a593Smuzhiyun goto vlan_del;
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT);
944*4882a593Smuzhiyun ret = tpriv->ok ? 0 : -ETIMEDOUT;
945*4882a593Smuzhiyun if (ret && !i) {
946*4882a593Smuzhiyun goto vlan_del;
947*4882a593Smuzhiyun } else if (!ret && i) {
948*4882a593Smuzhiyun ret = -EINVAL;
949*4882a593Smuzhiyun goto vlan_del;
950*4882a593Smuzhiyun } else {
951*4882a593Smuzhiyun ret = 0;
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun tpriv->ok = false;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun vlan_del:
958*4882a593Smuzhiyun vlan_vid_del(priv->dev, htons(ETH_P_8021Q), tpriv->vlan_id);
959*4882a593Smuzhiyun cleanup:
960*4882a593Smuzhiyun dev_remove_pack(&tpriv->pt);
961*4882a593Smuzhiyun kfree(tpriv);
962*4882a593Smuzhiyun return ret;
963*4882a593Smuzhiyun }
964*4882a593Smuzhiyun
stmmac_test_vlanfilt(struct stmmac_priv * priv)965*4882a593Smuzhiyun static int stmmac_test_vlanfilt(struct stmmac_priv *priv)
966*4882a593Smuzhiyun {
967*4882a593Smuzhiyun if (!priv->dma_cap.vlhash)
968*4882a593Smuzhiyun return -EOPNOTSUPP;
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun return __stmmac_test_vlanfilt(priv);
971*4882a593Smuzhiyun }
972*4882a593Smuzhiyun
stmmac_test_vlanfilt_perfect(struct stmmac_priv * priv)973*4882a593Smuzhiyun static int stmmac_test_vlanfilt_perfect(struct stmmac_priv *priv)
974*4882a593Smuzhiyun {
975*4882a593Smuzhiyun int ret, prev_cap = priv->dma_cap.vlhash;
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun if (!(priv->dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
978*4882a593Smuzhiyun return -EOPNOTSUPP;
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun priv->dma_cap.vlhash = 0;
981*4882a593Smuzhiyun ret = __stmmac_test_vlanfilt(priv);
982*4882a593Smuzhiyun priv->dma_cap.vlhash = prev_cap;
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun return ret;
985*4882a593Smuzhiyun }
986*4882a593Smuzhiyun
__stmmac_test_dvlanfilt(struct stmmac_priv * priv)987*4882a593Smuzhiyun static int __stmmac_test_dvlanfilt(struct stmmac_priv *priv)
988*4882a593Smuzhiyun {
989*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
990*4882a593Smuzhiyun struct stmmac_test_priv *tpriv;
991*4882a593Smuzhiyun struct sk_buff *skb = NULL;
992*4882a593Smuzhiyun int ret = 0, i;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
995*4882a593Smuzhiyun if (!tpriv)
996*4882a593Smuzhiyun return -ENOMEM;
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun tpriv->ok = false;
999*4882a593Smuzhiyun tpriv->double_vlan = true;
1000*4882a593Smuzhiyun init_completion(&tpriv->comp);
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun tpriv->pt.type = htons(ETH_P_8021Q);
1003*4882a593Smuzhiyun tpriv->pt.func = stmmac_test_vlan_validate;
1004*4882a593Smuzhiyun tpriv->pt.dev = priv->dev;
1005*4882a593Smuzhiyun tpriv->pt.af_packet_priv = tpriv;
1006*4882a593Smuzhiyun tpriv->packet = &attr;
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun /*
1009*4882a593Smuzhiyun * As we use HASH filtering, false positives may appear. This is a
1010*4882a593Smuzhiyun * specially chosen ID so that adjacent IDs (+4) have different
1011*4882a593Smuzhiyun * HASH values.
1012*4882a593Smuzhiyun */
1013*4882a593Smuzhiyun tpriv->vlan_id = 0x123;
1014*4882a593Smuzhiyun dev_add_pack(&tpriv->pt);
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun ret = vlan_vid_add(priv->dev, htons(ETH_P_8021AD), tpriv->vlan_id);
1017*4882a593Smuzhiyun if (ret)
1018*4882a593Smuzhiyun goto cleanup;
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
1021*4882a593Smuzhiyun attr.vlan = 2;
1022*4882a593Smuzhiyun attr.vlan_id_out = tpriv->vlan_id + i;
1023*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1024*4882a593Smuzhiyun attr.sport = 9;
1025*4882a593Smuzhiyun attr.dport = 9;
1026*4882a593Smuzhiyun
1027*4882a593Smuzhiyun skb = stmmac_test_get_udp_skb(priv, &attr);
1028*4882a593Smuzhiyun if (!skb) {
1029*4882a593Smuzhiyun ret = -ENOMEM;
1030*4882a593Smuzhiyun goto vlan_del;
1031*4882a593Smuzhiyun }
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun ret = dev_direct_xmit(skb, 0);
1034*4882a593Smuzhiyun if (ret)
1035*4882a593Smuzhiyun goto vlan_del;
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT);
1038*4882a593Smuzhiyun ret = tpriv->ok ? 0 : -ETIMEDOUT;
1039*4882a593Smuzhiyun if (ret && !i) {
1040*4882a593Smuzhiyun goto vlan_del;
1041*4882a593Smuzhiyun } else if (!ret && i) {
1042*4882a593Smuzhiyun ret = -EINVAL;
1043*4882a593Smuzhiyun goto vlan_del;
1044*4882a593Smuzhiyun } else {
1045*4882a593Smuzhiyun ret = 0;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun tpriv->ok = false;
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun
1051*4882a593Smuzhiyun vlan_del:
1052*4882a593Smuzhiyun vlan_vid_del(priv->dev, htons(ETH_P_8021AD), tpriv->vlan_id);
1053*4882a593Smuzhiyun cleanup:
1054*4882a593Smuzhiyun dev_remove_pack(&tpriv->pt);
1055*4882a593Smuzhiyun kfree(tpriv);
1056*4882a593Smuzhiyun return ret;
1057*4882a593Smuzhiyun }
1058*4882a593Smuzhiyun
stmmac_test_dvlanfilt(struct stmmac_priv * priv)1059*4882a593Smuzhiyun static int stmmac_test_dvlanfilt(struct stmmac_priv *priv)
1060*4882a593Smuzhiyun {
1061*4882a593Smuzhiyun if (!priv->dma_cap.vlhash)
1062*4882a593Smuzhiyun return -EOPNOTSUPP;
1063*4882a593Smuzhiyun
1064*4882a593Smuzhiyun return __stmmac_test_dvlanfilt(priv);
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
stmmac_test_dvlanfilt_perfect(struct stmmac_priv * priv)1067*4882a593Smuzhiyun static int stmmac_test_dvlanfilt_perfect(struct stmmac_priv *priv)
1068*4882a593Smuzhiyun {
1069*4882a593Smuzhiyun int ret, prev_cap = priv->dma_cap.vlhash;
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun if (!(priv->dev->features & NETIF_F_HW_VLAN_STAG_FILTER))
1072*4882a593Smuzhiyun return -EOPNOTSUPP;
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun priv->dma_cap.vlhash = 0;
1075*4882a593Smuzhiyun ret = __stmmac_test_dvlanfilt(priv);
1076*4882a593Smuzhiyun priv->dma_cap.vlhash = prev_cap;
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun return ret;
1079*4882a593Smuzhiyun }
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun #ifdef CONFIG_NET_CLS_ACT
stmmac_test_rxp(struct stmmac_priv * priv)1082*4882a593Smuzhiyun static int stmmac_test_rxp(struct stmmac_priv *priv)
1083*4882a593Smuzhiyun {
1084*4882a593Smuzhiyun unsigned char addr[ETH_ALEN] = {0xde, 0xad, 0xbe, 0xef, 0x00, 0x00};
1085*4882a593Smuzhiyun struct tc_cls_u32_offload cls_u32 = { };
1086*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1087*4882a593Smuzhiyun struct tc_action **actions;
1088*4882a593Smuzhiyun struct tc_u32_sel *sel;
1089*4882a593Smuzhiyun struct tcf_gact *gact;
1090*4882a593Smuzhiyun struct tcf_exts *exts;
1091*4882a593Smuzhiyun int ret, i, nk = 1;
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun if (!tc_can_offload(priv->dev))
1094*4882a593Smuzhiyun return -EOPNOTSUPP;
1095*4882a593Smuzhiyun if (!priv->dma_cap.frpsel)
1096*4882a593Smuzhiyun return -EOPNOTSUPP;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun sel = kzalloc(struct_size(sel, keys, nk), GFP_KERNEL);
1099*4882a593Smuzhiyun if (!sel)
1100*4882a593Smuzhiyun return -ENOMEM;
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun exts = kzalloc(sizeof(*exts), GFP_KERNEL);
1103*4882a593Smuzhiyun if (!exts) {
1104*4882a593Smuzhiyun ret = -ENOMEM;
1105*4882a593Smuzhiyun goto cleanup_sel;
1106*4882a593Smuzhiyun }
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun actions = kcalloc(nk, sizeof(*actions), GFP_KERNEL);
1109*4882a593Smuzhiyun if (!actions) {
1110*4882a593Smuzhiyun ret = -ENOMEM;
1111*4882a593Smuzhiyun goto cleanup_exts;
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun
1114*4882a593Smuzhiyun gact = kcalloc(nk, sizeof(*gact), GFP_KERNEL);
1115*4882a593Smuzhiyun if (!gact) {
1116*4882a593Smuzhiyun ret = -ENOMEM;
1117*4882a593Smuzhiyun goto cleanup_actions;
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun cls_u32.command = TC_CLSU32_NEW_KNODE;
1121*4882a593Smuzhiyun cls_u32.common.chain_index = 0;
1122*4882a593Smuzhiyun cls_u32.common.protocol = htons(ETH_P_ALL);
1123*4882a593Smuzhiyun cls_u32.knode.exts = exts;
1124*4882a593Smuzhiyun cls_u32.knode.sel = sel;
1125*4882a593Smuzhiyun cls_u32.knode.handle = 0x123;
1126*4882a593Smuzhiyun
1127*4882a593Smuzhiyun exts->nr_actions = nk;
1128*4882a593Smuzhiyun exts->actions = actions;
1129*4882a593Smuzhiyun for (i = 0; i < nk; i++) {
1130*4882a593Smuzhiyun actions[i] = (struct tc_action *)&gact[i];
1131*4882a593Smuzhiyun gact->tcf_action = TC_ACT_SHOT;
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun sel->nkeys = nk;
1135*4882a593Smuzhiyun sel->offshift = 0;
1136*4882a593Smuzhiyun sel->keys[0].off = 6;
1137*4882a593Smuzhiyun sel->keys[0].val = htonl(0xdeadbeef);
1138*4882a593Smuzhiyun sel->keys[0].mask = ~0x0;
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun ret = stmmac_tc_setup_cls_u32(priv, priv, &cls_u32);
1141*4882a593Smuzhiyun if (ret)
1142*4882a593Smuzhiyun goto cleanup_act;
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1145*4882a593Smuzhiyun attr.src = addr;
1146*4882a593Smuzhiyun
1147*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1148*4882a593Smuzhiyun ret = ret ? 0 : -EINVAL; /* Shall NOT receive packet */
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun cls_u32.command = TC_CLSU32_DELETE_KNODE;
1151*4882a593Smuzhiyun stmmac_tc_setup_cls_u32(priv, priv, &cls_u32);
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun cleanup_act:
1154*4882a593Smuzhiyun kfree(gact);
1155*4882a593Smuzhiyun cleanup_actions:
1156*4882a593Smuzhiyun kfree(actions);
1157*4882a593Smuzhiyun cleanup_exts:
1158*4882a593Smuzhiyun kfree(exts);
1159*4882a593Smuzhiyun cleanup_sel:
1160*4882a593Smuzhiyun kfree(sel);
1161*4882a593Smuzhiyun return ret;
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun #else
stmmac_test_rxp(struct stmmac_priv * priv)1164*4882a593Smuzhiyun static int stmmac_test_rxp(struct stmmac_priv *priv)
1165*4882a593Smuzhiyun {
1166*4882a593Smuzhiyun return -EOPNOTSUPP;
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun #endif
1169*4882a593Smuzhiyun
stmmac_test_desc_sai(struct stmmac_priv * priv)1170*4882a593Smuzhiyun static int stmmac_test_desc_sai(struct stmmac_priv *priv)
1171*4882a593Smuzhiyun {
1172*4882a593Smuzhiyun unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1173*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1174*4882a593Smuzhiyun int ret;
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun if (!priv->dma_cap.vlins)
1177*4882a593Smuzhiyun return -EOPNOTSUPP;
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun attr.remove_sa = true;
1180*4882a593Smuzhiyun attr.sarc = true;
1181*4882a593Smuzhiyun attr.src = src;
1182*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1183*4882a593Smuzhiyun
1184*4882a593Smuzhiyun priv->sarc_type = 0x1;
1185*4882a593Smuzhiyun
1186*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun priv->sarc_type = 0x0;
1189*4882a593Smuzhiyun return ret;
1190*4882a593Smuzhiyun }
1191*4882a593Smuzhiyun
stmmac_test_desc_sar(struct stmmac_priv * priv)1192*4882a593Smuzhiyun static int stmmac_test_desc_sar(struct stmmac_priv *priv)
1193*4882a593Smuzhiyun {
1194*4882a593Smuzhiyun unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1195*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1196*4882a593Smuzhiyun int ret;
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun if (!priv->dma_cap.vlins)
1199*4882a593Smuzhiyun return -EOPNOTSUPP;
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun attr.sarc = true;
1202*4882a593Smuzhiyun attr.src = src;
1203*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1204*4882a593Smuzhiyun
1205*4882a593Smuzhiyun priv->sarc_type = 0x2;
1206*4882a593Smuzhiyun
1207*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun priv->sarc_type = 0x0;
1210*4882a593Smuzhiyun return ret;
1211*4882a593Smuzhiyun }
1212*4882a593Smuzhiyun
stmmac_test_reg_sai(struct stmmac_priv * priv)1213*4882a593Smuzhiyun static int stmmac_test_reg_sai(struct stmmac_priv *priv)
1214*4882a593Smuzhiyun {
1215*4882a593Smuzhiyun unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1216*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1217*4882a593Smuzhiyun int ret;
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun if (!priv->dma_cap.vlins)
1220*4882a593Smuzhiyun return -EOPNOTSUPP;
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun attr.remove_sa = true;
1223*4882a593Smuzhiyun attr.sarc = true;
1224*4882a593Smuzhiyun attr.src = src;
1225*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun if (stmmac_sarc_configure(priv, priv->ioaddr, 0x2))
1228*4882a593Smuzhiyun return -EOPNOTSUPP;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun stmmac_sarc_configure(priv, priv->ioaddr, 0x0);
1233*4882a593Smuzhiyun return ret;
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun
stmmac_test_reg_sar(struct stmmac_priv * priv)1236*4882a593Smuzhiyun static int stmmac_test_reg_sar(struct stmmac_priv *priv)
1237*4882a593Smuzhiyun {
1238*4882a593Smuzhiyun unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1239*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1240*4882a593Smuzhiyun int ret;
1241*4882a593Smuzhiyun
1242*4882a593Smuzhiyun if (!priv->dma_cap.vlins)
1243*4882a593Smuzhiyun return -EOPNOTSUPP;
1244*4882a593Smuzhiyun
1245*4882a593Smuzhiyun attr.sarc = true;
1246*4882a593Smuzhiyun attr.src = src;
1247*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun if (stmmac_sarc_configure(priv, priv->ioaddr, 0x3))
1250*4882a593Smuzhiyun return -EOPNOTSUPP;
1251*4882a593Smuzhiyun
1252*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1253*4882a593Smuzhiyun
1254*4882a593Smuzhiyun stmmac_sarc_configure(priv, priv->ioaddr, 0x0);
1255*4882a593Smuzhiyun return ret;
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun
stmmac_test_vlanoff_common(struct stmmac_priv * priv,bool svlan)1258*4882a593Smuzhiyun static int stmmac_test_vlanoff_common(struct stmmac_priv *priv, bool svlan)
1259*4882a593Smuzhiyun {
1260*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1261*4882a593Smuzhiyun struct stmmac_test_priv *tpriv;
1262*4882a593Smuzhiyun struct sk_buff *skb = NULL;
1263*4882a593Smuzhiyun int ret = 0;
1264*4882a593Smuzhiyun u16 proto;
1265*4882a593Smuzhiyun
1266*4882a593Smuzhiyun if (!priv->dma_cap.vlins)
1267*4882a593Smuzhiyun return -EOPNOTSUPP;
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
1270*4882a593Smuzhiyun if (!tpriv)
1271*4882a593Smuzhiyun return -ENOMEM;
1272*4882a593Smuzhiyun
1273*4882a593Smuzhiyun proto = svlan ? ETH_P_8021AD : ETH_P_8021Q;
1274*4882a593Smuzhiyun
1275*4882a593Smuzhiyun tpriv->ok = false;
1276*4882a593Smuzhiyun tpriv->double_vlan = svlan;
1277*4882a593Smuzhiyun init_completion(&tpriv->comp);
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun tpriv->pt.type = svlan ? htons(ETH_P_8021Q) : htons(ETH_P_IP);
1280*4882a593Smuzhiyun tpriv->pt.func = stmmac_test_vlan_validate;
1281*4882a593Smuzhiyun tpriv->pt.dev = priv->dev;
1282*4882a593Smuzhiyun tpriv->pt.af_packet_priv = tpriv;
1283*4882a593Smuzhiyun tpriv->packet = &attr;
1284*4882a593Smuzhiyun tpriv->vlan_id = 0x123;
1285*4882a593Smuzhiyun dev_add_pack(&tpriv->pt);
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun ret = vlan_vid_add(priv->dev, htons(proto), tpriv->vlan_id);
1288*4882a593Smuzhiyun if (ret)
1289*4882a593Smuzhiyun goto cleanup;
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun skb = stmmac_test_get_udp_skb(priv, &attr);
1294*4882a593Smuzhiyun if (!skb) {
1295*4882a593Smuzhiyun ret = -ENOMEM;
1296*4882a593Smuzhiyun goto vlan_del;
1297*4882a593Smuzhiyun }
1298*4882a593Smuzhiyun
1299*4882a593Smuzhiyun __vlan_hwaccel_put_tag(skb, htons(proto), tpriv->vlan_id);
1300*4882a593Smuzhiyun skb->protocol = htons(proto);
1301*4882a593Smuzhiyun
1302*4882a593Smuzhiyun ret = dev_direct_xmit(skb, 0);
1303*4882a593Smuzhiyun if (ret)
1304*4882a593Smuzhiyun goto vlan_del;
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT);
1307*4882a593Smuzhiyun ret = tpriv->ok ? 0 : -ETIMEDOUT;
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun vlan_del:
1310*4882a593Smuzhiyun vlan_vid_del(priv->dev, htons(proto), tpriv->vlan_id);
1311*4882a593Smuzhiyun cleanup:
1312*4882a593Smuzhiyun dev_remove_pack(&tpriv->pt);
1313*4882a593Smuzhiyun kfree(tpriv);
1314*4882a593Smuzhiyun return ret;
1315*4882a593Smuzhiyun }
1316*4882a593Smuzhiyun
stmmac_test_vlanoff(struct stmmac_priv * priv)1317*4882a593Smuzhiyun static int stmmac_test_vlanoff(struct stmmac_priv *priv)
1318*4882a593Smuzhiyun {
1319*4882a593Smuzhiyun return stmmac_test_vlanoff_common(priv, false);
1320*4882a593Smuzhiyun }
1321*4882a593Smuzhiyun
stmmac_test_svlanoff(struct stmmac_priv * priv)1322*4882a593Smuzhiyun static int stmmac_test_svlanoff(struct stmmac_priv *priv)
1323*4882a593Smuzhiyun {
1324*4882a593Smuzhiyun if (!priv->dma_cap.dvlan)
1325*4882a593Smuzhiyun return -EOPNOTSUPP;
1326*4882a593Smuzhiyun return stmmac_test_vlanoff_common(priv, true);
1327*4882a593Smuzhiyun }
1328*4882a593Smuzhiyun
1329*4882a593Smuzhiyun #ifdef CONFIG_NET_CLS_ACT
__stmmac_test_l3filt(struct stmmac_priv * priv,u32 dst,u32 src,u32 dst_mask,u32 src_mask)1330*4882a593Smuzhiyun static int __stmmac_test_l3filt(struct stmmac_priv *priv, u32 dst, u32 src,
1331*4882a593Smuzhiyun u32 dst_mask, u32 src_mask)
1332*4882a593Smuzhiyun {
1333*4882a593Smuzhiyun struct flow_dissector_key_ipv4_addrs key, mask;
1334*4882a593Smuzhiyun unsigned long dummy_cookie = 0xdeadbeef;
1335*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1336*4882a593Smuzhiyun struct flow_dissector *dissector;
1337*4882a593Smuzhiyun struct flow_cls_offload *cls;
1338*4882a593Smuzhiyun int ret, old_enable = 0;
1339*4882a593Smuzhiyun struct flow_rule *rule;
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun if (!tc_can_offload(priv->dev))
1342*4882a593Smuzhiyun return -EOPNOTSUPP;
1343*4882a593Smuzhiyun if (!priv->dma_cap.l3l4fnum)
1344*4882a593Smuzhiyun return -EOPNOTSUPP;
1345*4882a593Smuzhiyun if (priv->rss.enable) {
1346*4882a593Smuzhiyun old_enable = priv->rss.enable;
1347*4882a593Smuzhiyun priv->rss.enable = false;
1348*4882a593Smuzhiyun stmmac_rss_configure(priv, priv->hw, NULL,
1349*4882a593Smuzhiyun priv->plat->rx_queues_to_use);
1350*4882a593Smuzhiyun }
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun dissector = kzalloc(sizeof(*dissector), GFP_KERNEL);
1353*4882a593Smuzhiyun if (!dissector) {
1354*4882a593Smuzhiyun ret = -ENOMEM;
1355*4882a593Smuzhiyun goto cleanup_rss;
1356*4882a593Smuzhiyun }
1357*4882a593Smuzhiyun
1358*4882a593Smuzhiyun dissector->used_keys |= (1 << FLOW_DISSECTOR_KEY_IPV4_ADDRS);
1359*4882a593Smuzhiyun dissector->offset[FLOW_DISSECTOR_KEY_IPV4_ADDRS] = 0;
1360*4882a593Smuzhiyun
1361*4882a593Smuzhiyun cls = kzalloc(sizeof(*cls), GFP_KERNEL);
1362*4882a593Smuzhiyun if (!cls) {
1363*4882a593Smuzhiyun ret = -ENOMEM;
1364*4882a593Smuzhiyun goto cleanup_dissector;
1365*4882a593Smuzhiyun }
1366*4882a593Smuzhiyun
1367*4882a593Smuzhiyun cls->common.chain_index = 0;
1368*4882a593Smuzhiyun cls->command = FLOW_CLS_REPLACE;
1369*4882a593Smuzhiyun cls->cookie = dummy_cookie;
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun rule = kzalloc(struct_size(rule, action.entries, 1), GFP_KERNEL);
1372*4882a593Smuzhiyun if (!rule) {
1373*4882a593Smuzhiyun ret = -ENOMEM;
1374*4882a593Smuzhiyun goto cleanup_cls;
1375*4882a593Smuzhiyun }
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun rule->match.dissector = dissector;
1378*4882a593Smuzhiyun rule->match.key = (void *)&key;
1379*4882a593Smuzhiyun rule->match.mask = (void *)&mask;
1380*4882a593Smuzhiyun
1381*4882a593Smuzhiyun key.src = htonl(src);
1382*4882a593Smuzhiyun key.dst = htonl(dst);
1383*4882a593Smuzhiyun mask.src = src_mask;
1384*4882a593Smuzhiyun mask.dst = dst_mask;
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun cls->rule = rule;
1387*4882a593Smuzhiyun
1388*4882a593Smuzhiyun rule->action.entries[0].id = FLOW_ACTION_DROP;
1389*4882a593Smuzhiyun rule->action.entries[0].hw_stats = FLOW_ACTION_HW_STATS_ANY;
1390*4882a593Smuzhiyun rule->action.num_entries = 1;
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1393*4882a593Smuzhiyun attr.ip_dst = dst;
1394*4882a593Smuzhiyun attr.ip_src = src;
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun /* Shall receive packet */
1397*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1398*4882a593Smuzhiyun if (ret)
1399*4882a593Smuzhiyun goto cleanup_rule;
1400*4882a593Smuzhiyun
1401*4882a593Smuzhiyun ret = stmmac_tc_setup_cls(priv, priv, cls);
1402*4882a593Smuzhiyun if (ret)
1403*4882a593Smuzhiyun goto cleanup_rule;
1404*4882a593Smuzhiyun
1405*4882a593Smuzhiyun /* Shall NOT receive packet */
1406*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1407*4882a593Smuzhiyun ret = ret ? 0 : -EINVAL;
1408*4882a593Smuzhiyun
1409*4882a593Smuzhiyun cls->command = FLOW_CLS_DESTROY;
1410*4882a593Smuzhiyun stmmac_tc_setup_cls(priv, priv, cls);
1411*4882a593Smuzhiyun cleanup_rule:
1412*4882a593Smuzhiyun kfree(rule);
1413*4882a593Smuzhiyun cleanup_cls:
1414*4882a593Smuzhiyun kfree(cls);
1415*4882a593Smuzhiyun cleanup_dissector:
1416*4882a593Smuzhiyun kfree(dissector);
1417*4882a593Smuzhiyun cleanup_rss:
1418*4882a593Smuzhiyun if (old_enable) {
1419*4882a593Smuzhiyun priv->rss.enable = old_enable;
1420*4882a593Smuzhiyun stmmac_rss_configure(priv, priv->hw, &priv->rss,
1421*4882a593Smuzhiyun priv->plat->rx_queues_to_use);
1422*4882a593Smuzhiyun }
1423*4882a593Smuzhiyun
1424*4882a593Smuzhiyun return ret;
1425*4882a593Smuzhiyun }
1426*4882a593Smuzhiyun #else
__stmmac_test_l3filt(struct stmmac_priv * priv,u32 dst,u32 src,u32 dst_mask,u32 src_mask)1427*4882a593Smuzhiyun static int __stmmac_test_l3filt(struct stmmac_priv *priv, u32 dst, u32 src,
1428*4882a593Smuzhiyun u32 dst_mask, u32 src_mask)
1429*4882a593Smuzhiyun {
1430*4882a593Smuzhiyun return -EOPNOTSUPP;
1431*4882a593Smuzhiyun }
1432*4882a593Smuzhiyun #endif
1433*4882a593Smuzhiyun
stmmac_test_l3filt_da(struct stmmac_priv * priv)1434*4882a593Smuzhiyun static int stmmac_test_l3filt_da(struct stmmac_priv *priv)
1435*4882a593Smuzhiyun {
1436*4882a593Smuzhiyun u32 addr = 0x10203040;
1437*4882a593Smuzhiyun
1438*4882a593Smuzhiyun return __stmmac_test_l3filt(priv, addr, 0, ~0, 0);
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun
stmmac_test_l3filt_sa(struct stmmac_priv * priv)1441*4882a593Smuzhiyun static int stmmac_test_l3filt_sa(struct stmmac_priv *priv)
1442*4882a593Smuzhiyun {
1443*4882a593Smuzhiyun u32 addr = 0x10203040;
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun return __stmmac_test_l3filt(priv, 0, addr, 0, ~0);
1446*4882a593Smuzhiyun }
1447*4882a593Smuzhiyun
1448*4882a593Smuzhiyun #ifdef CONFIG_NET_CLS_ACT
__stmmac_test_l4filt(struct stmmac_priv * priv,u32 dst,u32 src,u32 dst_mask,u32 src_mask,bool udp)1449*4882a593Smuzhiyun static int __stmmac_test_l4filt(struct stmmac_priv *priv, u32 dst, u32 src,
1450*4882a593Smuzhiyun u32 dst_mask, u32 src_mask, bool udp)
1451*4882a593Smuzhiyun {
1452*4882a593Smuzhiyun struct {
1453*4882a593Smuzhiyun struct flow_dissector_key_basic bkey;
1454*4882a593Smuzhiyun struct flow_dissector_key_ports key;
1455*4882a593Smuzhiyun } __aligned(BITS_PER_LONG / 8) keys;
1456*4882a593Smuzhiyun struct {
1457*4882a593Smuzhiyun struct flow_dissector_key_basic bmask;
1458*4882a593Smuzhiyun struct flow_dissector_key_ports mask;
1459*4882a593Smuzhiyun } __aligned(BITS_PER_LONG / 8) masks;
1460*4882a593Smuzhiyun unsigned long dummy_cookie = 0xdeadbeef;
1461*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1462*4882a593Smuzhiyun struct flow_dissector *dissector;
1463*4882a593Smuzhiyun struct flow_cls_offload *cls;
1464*4882a593Smuzhiyun int ret, old_enable = 0;
1465*4882a593Smuzhiyun struct flow_rule *rule;
1466*4882a593Smuzhiyun
1467*4882a593Smuzhiyun if (!tc_can_offload(priv->dev))
1468*4882a593Smuzhiyun return -EOPNOTSUPP;
1469*4882a593Smuzhiyun if (!priv->dma_cap.l3l4fnum)
1470*4882a593Smuzhiyun return -EOPNOTSUPP;
1471*4882a593Smuzhiyun if (priv->rss.enable) {
1472*4882a593Smuzhiyun old_enable = priv->rss.enable;
1473*4882a593Smuzhiyun priv->rss.enable = false;
1474*4882a593Smuzhiyun stmmac_rss_configure(priv, priv->hw, NULL,
1475*4882a593Smuzhiyun priv->plat->rx_queues_to_use);
1476*4882a593Smuzhiyun }
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun dissector = kzalloc(sizeof(*dissector), GFP_KERNEL);
1479*4882a593Smuzhiyun if (!dissector) {
1480*4882a593Smuzhiyun ret = -ENOMEM;
1481*4882a593Smuzhiyun goto cleanup_rss;
1482*4882a593Smuzhiyun }
1483*4882a593Smuzhiyun
1484*4882a593Smuzhiyun dissector->used_keys |= (1 << FLOW_DISSECTOR_KEY_BASIC);
1485*4882a593Smuzhiyun dissector->used_keys |= (1 << FLOW_DISSECTOR_KEY_PORTS);
1486*4882a593Smuzhiyun dissector->offset[FLOW_DISSECTOR_KEY_BASIC] = 0;
1487*4882a593Smuzhiyun dissector->offset[FLOW_DISSECTOR_KEY_PORTS] = offsetof(typeof(keys), key);
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun cls = kzalloc(sizeof(*cls), GFP_KERNEL);
1490*4882a593Smuzhiyun if (!cls) {
1491*4882a593Smuzhiyun ret = -ENOMEM;
1492*4882a593Smuzhiyun goto cleanup_dissector;
1493*4882a593Smuzhiyun }
1494*4882a593Smuzhiyun
1495*4882a593Smuzhiyun cls->common.chain_index = 0;
1496*4882a593Smuzhiyun cls->command = FLOW_CLS_REPLACE;
1497*4882a593Smuzhiyun cls->cookie = dummy_cookie;
1498*4882a593Smuzhiyun
1499*4882a593Smuzhiyun rule = kzalloc(struct_size(rule, action.entries, 1), GFP_KERNEL);
1500*4882a593Smuzhiyun if (!rule) {
1501*4882a593Smuzhiyun ret = -ENOMEM;
1502*4882a593Smuzhiyun goto cleanup_cls;
1503*4882a593Smuzhiyun }
1504*4882a593Smuzhiyun
1505*4882a593Smuzhiyun rule->match.dissector = dissector;
1506*4882a593Smuzhiyun rule->match.key = (void *)&keys;
1507*4882a593Smuzhiyun rule->match.mask = (void *)&masks;
1508*4882a593Smuzhiyun
1509*4882a593Smuzhiyun keys.bkey.ip_proto = udp ? IPPROTO_UDP : IPPROTO_TCP;
1510*4882a593Smuzhiyun keys.key.src = htons(src);
1511*4882a593Smuzhiyun keys.key.dst = htons(dst);
1512*4882a593Smuzhiyun masks.mask.src = src_mask;
1513*4882a593Smuzhiyun masks.mask.dst = dst_mask;
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun cls->rule = rule;
1516*4882a593Smuzhiyun
1517*4882a593Smuzhiyun rule->action.entries[0].id = FLOW_ACTION_DROP;
1518*4882a593Smuzhiyun rule->action.entries[0].hw_stats = FLOW_ACTION_HW_STATS_ANY;
1519*4882a593Smuzhiyun rule->action.num_entries = 1;
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1522*4882a593Smuzhiyun attr.tcp = !udp;
1523*4882a593Smuzhiyun attr.sport = src;
1524*4882a593Smuzhiyun attr.dport = dst;
1525*4882a593Smuzhiyun attr.ip_dst = 0;
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun /* Shall receive packet */
1528*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1529*4882a593Smuzhiyun if (ret)
1530*4882a593Smuzhiyun goto cleanup_rule;
1531*4882a593Smuzhiyun
1532*4882a593Smuzhiyun ret = stmmac_tc_setup_cls(priv, priv, cls);
1533*4882a593Smuzhiyun if (ret)
1534*4882a593Smuzhiyun goto cleanup_rule;
1535*4882a593Smuzhiyun
1536*4882a593Smuzhiyun /* Shall NOT receive packet */
1537*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1538*4882a593Smuzhiyun ret = ret ? 0 : -EINVAL;
1539*4882a593Smuzhiyun
1540*4882a593Smuzhiyun cls->command = FLOW_CLS_DESTROY;
1541*4882a593Smuzhiyun stmmac_tc_setup_cls(priv, priv, cls);
1542*4882a593Smuzhiyun cleanup_rule:
1543*4882a593Smuzhiyun kfree(rule);
1544*4882a593Smuzhiyun cleanup_cls:
1545*4882a593Smuzhiyun kfree(cls);
1546*4882a593Smuzhiyun cleanup_dissector:
1547*4882a593Smuzhiyun kfree(dissector);
1548*4882a593Smuzhiyun cleanup_rss:
1549*4882a593Smuzhiyun if (old_enable) {
1550*4882a593Smuzhiyun priv->rss.enable = old_enable;
1551*4882a593Smuzhiyun stmmac_rss_configure(priv, priv->hw, &priv->rss,
1552*4882a593Smuzhiyun priv->plat->rx_queues_to_use);
1553*4882a593Smuzhiyun }
1554*4882a593Smuzhiyun
1555*4882a593Smuzhiyun return ret;
1556*4882a593Smuzhiyun }
1557*4882a593Smuzhiyun #else
__stmmac_test_l4filt(struct stmmac_priv * priv,u32 dst,u32 src,u32 dst_mask,u32 src_mask,bool udp)1558*4882a593Smuzhiyun static int __stmmac_test_l4filt(struct stmmac_priv *priv, u32 dst, u32 src,
1559*4882a593Smuzhiyun u32 dst_mask, u32 src_mask, bool udp)
1560*4882a593Smuzhiyun {
1561*4882a593Smuzhiyun return -EOPNOTSUPP;
1562*4882a593Smuzhiyun }
1563*4882a593Smuzhiyun #endif
1564*4882a593Smuzhiyun
stmmac_test_l4filt_da_tcp(struct stmmac_priv * priv)1565*4882a593Smuzhiyun static int stmmac_test_l4filt_da_tcp(struct stmmac_priv *priv)
1566*4882a593Smuzhiyun {
1567*4882a593Smuzhiyun u16 dummy_port = 0x123;
1568*4882a593Smuzhiyun
1569*4882a593Smuzhiyun return __stmmac_test_l4filt(priv, dummy_port, 0, ~0, 0, false);
1570*4882a593Smuzhiyun }
1571*4882a593Smuzhiyun
stmmac_test_l4filt_sa_tcp(struct stmmac_priv * priv)1572*4882a593Smuzhiyun static int stmmac_test_l4filt_sa_tcp(struct stmmac_priv *priv)
1573*4882a593Smuzhiyun {
1574*4882a593Smuzhiyun u16 dummy_port = 0x123;
1575*4882a593Smuzhiyun
1576*4882a593Smuzhiyun return __stmmac_test_l4filt(priv, 0, dummy_port, 0, ~0, false);
1577*4882a593Smuzhiyun }
1578*4882a593Smuzhiyun
stmmac_test_l4filt_da_udp(struct stmmac_priv * priv)1579*4882a593Smuzhiyun static int stmmac_test_l4filt_da_udp(struct stmmac_priv *priv)
1580*4882a593Smuzhiyun {
1581*4882a593Smuzhiyun u16 dummy_port = 0x123;
1582*4882a593Smuzhiyun
1583*4882a593Smuzhiyun return __stmmac_test_l4filt(priv, dummy_port, 0, ~0, 0, true);
1584*4882a593Smuzhiyun }
1585*4882a593Smuzhiyun
stmmac_test_l4filt_sa_udp(struct stmmac_priv * priv)1586*4882a593Smuzhiyun static int stmmac_test_l4filt_sa_udp(struct stmmac_priv *priv)
1587*4882a593Smuzhiyun {
1588*4882a593Smuzhiyun u16 dummy_port = 0x123;
1589*4882a593Smuzhiyun
1590*4882a593Smuzhiyun return __stmmac_test_l4filt(priv, 0, dummy_port, 0, ~0, true);
1591*4882a593Smuzhiyun }
1592*4882a593Smuzhiyun
stmmac_test_arp_validate(struct sk_buff * skb,struct net_device * ndev,struct packet_type * pt,struct net_device * orig_ndev)1593*4882a593Smuzhiyun static int stmmac_test_arp_validate(struct sk_buff *skb,
1594*4882a593Smuzhiyun struct net_device *ndev,
1595*4882a593Smuzhiyun struct packet_type *pt,
1596*4882a593Smuzhiyun struct net_device *orig_ndev)
1597*4882a593Smuzhiyun {
1598*4882a593Smuzhiyun struct stmmac_test_priv *tpriv = pt->af_packet_priv;
1599*4882a593Smuzhiyun struct ethhdr *ehdr;
1600*4882a593Smuzhiyun struct arphdr *ahdr;
1601*4882a593Smuzhiyun
1602*4882a593Smuzhiyun ehdr = (struct ethhdr *)skb_mac_header(skb);
1603*4882a593Smuzhiyun if (!ether_addr_equal_unaligned(ehdr->h_dest, tpriv->packet->src))
1604*4882a593Smuzhiyun goto out;
1605*4882a593Smuzhiyun
1606*4882a593Smuzhiyun ahdr = arp_hdr(skb);
1607*4882a593Smuzhiyun if (ahdr->ar_op != htons(ARPOP_REPLY))
1608*4882a593Smuzhiyun goto out;
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun tpriv->ok = true;
1611*4882a593Smuzhiyun complete(&tpriv->comp);
1612*4882a593Smuzhiyun out:
1613*4882a593Smuzhiyun kfree_skb(skb);
1614*4882a593Smuzhiyun return 0;
1615*4882a593Smuzhiyun }
1616*4882a593Smuzhiyun
stmmac_test_arpoffload(struct stmmac_priv * priv)1617*4882a593Smuzhiyun static int stmmac_test_arpoffload(struct stmmac_priv *priv)
1618*4882a593Smuzhiyun {
1619*4882a593Smuzhiyun unsigned char src[ETH_ALEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
1620*4882a593Smuzhiyun unsigned char dst[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1621*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1622*4882a593Smuzhiyun struct stmmac_test_priv *tpriv;
1623*4882a593Smuzhiyun struct sk_buff *skb = NULL;
1624*4882a593Smuzhiyun u32 ip_addr = 0xdeadcafe;
1625*4882a593Smuzhiyun u32 ip_src = 0xdeadbeef;
1626*4882a593Smuzhiyun int ret;
1627*4882a593Smuzhiyun
1628*4882a593Smuzhiyun if (!priv->dma_cap.arpoffsel)
1629*4882a593Smuzhiyun return -EOPNOTSUPP;
1630*4882a593Smuzhiyun
1631*4882a593Smuzhiyun tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
1632*4882a593Smuzhiyun if (!tpriv)
1633*4882a593Smuzhiyun return -ENOMEM;
1634*4882a593Smuzhiyun
1635*4882a593Smuzhiyun tpriv->ok = false;
1636*4882a593Smuzhiyun init_completion(&tpriv->comp);
1637*4882a593Smuzhiyun
1638*4882a593Smuzhiyun tpriv->pt.type = htons(ETH_P_ARP);
1639*4882a593Smuzhiyun tpriv->pt.func = stmmac_test_arp_validate;
1640*4882a593Smuzhiyun tpriv->pt.dev = priv->dev;
1641*4882a593Smuzhiyun tpriv->pt.af_packet_priv = tpriv;
1642*4882a593Smuzhiyun tpriv->packet = &attr;
1643*4882a593Smuzhiyun dev_add_pack(&tpriv->pt);
1644*4882a593Smuzhiyun
1645*4882a593Smuzhiyun attr.src = src;
1646*4882a593Smuzhiyun attr.ip_src = ip_src;
1647*4882a593Smuzhiyun attr.dst = dst;
1648*4882a593Smuzhiyun attr.ip_dst = ip_addr;
1649*4882a593Smuzhiyun
1650*4882a593Smuzhiyun skb = stmmac_test_get_arp_skb(priv, &attr);
1651*4882a593Smuzhiyun if (!skb) {
1652*4882a593Smuzhiyun ret = -ENOMEM;
1653*4882a593Smuzhiyun goto cleanup;
1654*4882a593Smuzhiyun }
1655*4882a593Smuzhiyun
1656*4882a593Smuzhiyun ret = stmmac_set_arp_offload(priv, priv->hw, true, ip_addr);
1657*4882a593Smuzhiyun if (ret)
1658*4882a593Smuzhiyun goto cleanup;
1659*4882a593Smuzhiyun
1660*4882a593Smuzhiyun ret = dev_set_promiscuity(priv->dev, 1);
1661*4882a593Smuzhiyun if (ret)
1662*4882a593Smuzhiyun goto cleanup;
1663*4882a593Smuzhiyun
1664*4882a593Smuzhiyun ret = dev_direct_xmit(skb, 0);
1665*4882a593Smuzhiyun if (ret)
1666*4882a593Smuzhiyun goto cleanup_promisc;
1667*4882a593Smuzhiyun
1668*4882a593Smuzhiyun wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT);
1669*4882a593Smuzhiyun ret = tpriv->ok ? 0 : -ETIMEDOUT;
1670*4882a593Smuzhiyun
1671*4882a593Smuzhiyun cleanup_promisc:
1672*4882a593Smuzhiyun dev_set_promiscuity(priv->dev, -1);
1673*4882a593Smuzhiyun cleanup:
1674*4882a593Smuzhiyun stmmac_set_arp_offload(priv, priv->hw, false, 0x0);
1675*4882a593Smuzhiyun dev_remove_pack(&tpriv->pt);
1676*4882a593Smuzhiyun kfree(tpriv);
1677*4882a593Smuzhiyun return ret;
1678*4882a593Smuzhiyun }
1679*4882a593Smuzhiyun
__stmmac_test_jumbo(struct stmmac_priv * priv,u16 queue)1680*4882a593Smuzhiyun static int __stmmac_test_jumbo(struct stmmac_priv *priv, u16 queue)
1681*4882a593Smuzhiyun {
1682*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1683*4882a593Smuzhiyun int size = priv->dma_buf_sz;
1684*4882a593Smuzhiyun
1685*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1686*4882a593Smuzhiyun attr.max_size = size - ETH_FCS_LEN;
1687*4882a593Smuzhiyun attr.queue_mapping = queue;
1688*4882a593Smuzhiyun
1689*4882a593Smuzhiyun return __stmmac_test_loopback(priv, &attr);
1690*4882a593Smuzhiyun }
1691*4882a593Smuzhiyun
stmmac_test_jumbo(struct stmmac_priv * priv)1692*4882a593Smuzhiyun static int stmmac_test_jumbo(struct stmmac_priv *priv)
1693*4882a593Smuzhiyun {
1694*4882a593Smuzhiyun return __stmmac_test_jumbo(priv, 0);
1695*4882a593Smuzhiyun }
1696*4882a593Smuzhiyun
stmmac_test_mjumbo(struct stmmac_priv * priv)1697*4882a593Smuzhiyun static int stmmac_test_mjumbo(struct stmmac_priv *priv)
1698*4882a593Smuzhiyun {
1699*4882a593Smuzhiyun u32 chan, tx_cnt = priv->plat->tx_queues_to_use;
1700*4882a593Smuzhiyun int ret;
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun if (tx_cnt <= 1)
1703*4882a593Smuzhiyun return -EOPNOTSUPP;
1704*4882a593Smuzhiyun
1705*4882a593Smuzhiyun for (chan = 0; chan < tx_cnt; chan++) {
1706*4882a593Smuzhiyun ret = __stmmac_test_jumbo(priv, chan);
1707*4882a593Smuzhiyun if (ret)
1708*4882a593Smuzhiyun return ret;
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun
1711*4882a593Smuzhiyun return 0;
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun
stmmac_test_sph(struct stmmac_priv * priv)1714*4882a593Smuzhiyun static int stmmac_test_sph(struct stmmac_priv *priv)
1715*4882a593Smuzhiyun {
1716*4882a593Smuzhiyun unsigned long cnt_end, cnt_start = priv->xstats.rx_split_hdr_pkt_n;
1717*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1718*4882a593Smuzhiyun int ret;
1719*4882a593Smuzhiyun
1720*4882a593Smuzhiyun if (!priv->sph)
1721*4882a593Smuzhiyun return -EOPNOTSUPP;
1722*4882a593Smuzhiyun
1723*4882a593Smuzhiyun /* Check for UDP first */
1724*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1725*4882a593Smuzhiyun attr.tcp = false;
1726*4882a593Smuzhiyun
1727*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1728*4882a593Smuzhiyun if (ret)
1729*4882a593Smuzhiyun return ret;
1730*4882a593Smuzhiyun
1731*4882a593Smuzhiyun cnt_end = priv->xstats.rx_split_hdr_pkt_n;
1732*4882a593Smuzhiyun if (cnt_end <= cnt_start)
1733*4882a593Smuzhiyun return -EINVAL;
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun /* Check for TCP now */
1736*4882a593Smuzhiyun cnt_start = cnt_end;
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1739*4882a593Smuzhiyun attr.tcp = true;
1740*4882a593Smuzhiyun
1741*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1742*4882a593Smuzhiyun if (ret)
1743*4882a593Smuzhiyun return ret;
1744*4882a593Smuzhiyun
1745*4882a593Smuzhiyun cnt_end = priv->xstats.rx_split_hdr_pkt_n;
1746*4882a593Smuzhiyun if (cnt_end <= cnt_start)
1747*4882a593Smuzhiyun return -EINVAL;
1748*4882a593Smuzhiyun
1749*4882a593Smuzhiyun return 0;
1750*4882a593Smuzhiyun }
1751*4882a593Smuzhiyun
stmmac_test_tbs(struct stmmac_priv * priv)1752*4882a593Smuzhiyun static int stmmac_test_tbs(struct stmmac_priv *priv)
1753*4882a593Smuzhiyun {
1754*4882a593Smuzhiyun #define STMMAC_TBS_LT_OFFSET (500 * 1000 * 1000) /* 500 ms*/
1755*4882a593Smuzhiyun struct stmmac_packet_attrs attr = { };
1756*4882a593Smuzhiyun struct tc_etf_qopt_offload qopt;
1757*4882a593Smuzhiyun u64 start_time, curr_time = 0;
1758*4882a593Smuzhiyun unsigned long flags;
1759*4882a593Smuzhiyun int ret, i;
1760*4882a593Smuzhiyun
1761*4882a593Smuzhiyun if (!priv->hwts_tx_en)
1762*4882a593Smuzhiyun return -EOPNOTSUPP;
1763*4882a593Smuzhiyun
1764*4882a593Smuzhiyun /* Find first TBS enabled Queue, if any */
1765*4882a593Smuzhiyun for (i = 0; i < priv->plat->tx_queues_to_use; i++)
1766*4882a593Smuzhiyun if (priv->tx_queue[i].tbs & STMMAC_TBS_AVAIL)
1767*4882a593Smuzhiyun break;
1768*4882a593Smuzhiyun
1769*4882a593Smuzhiyun if (i >= priv->plat->tx_queues_to_use)
1770*4882a593Smuzhiyun return -EOPNOTSUPP;
1771*4882a593Smuzhiyun
1772*4882a593Smuzhiyun qopt.enable = true;
1773*4882a593Smuzhiyun qopt.queue = i;
1774*4882a593Smuzhiyun
1775*4882a593Smuzhiyun ret = stmmac_tc_setup_etf(priv, priv, &qopt);
1776*4882a593Smuzhiyun if (ret)
1777*4882a593Smuzhiyun return ret;
1778*4882a593Smuzhiyun
1779*4882a593Smuzhiyun spin_lock_irqsave(&priv->ptp_lock, flags);
1780*4882a593Smuzhiyun stmmac_get_systime(priv, priv->ptpaddr, &curr_time);
1781*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->ptp_lock, flags);
1782*4882a593Smuzhiyun
1783*4882a593Smuzhiyun if (!curr_time) {
1784*4882a593Smuzhiyun ret = -EOPNOTSUPP;
1785*4882a593Smuzhiyun goto fail_disable;
1786*4882a593Smuzhiyun }
1787*4882a593Smuzhiyun
1788*4882a593Smuzhiyun start_time = curr_time;
1789*4882a593Smuzhiyun curr_time += STMMAC_TBS_LT_OFFSET;
1790*4882a593Smuzhiyun
1791*4882a593Smuzhiyun attr.dst = priv->dev->dev_addr;
1792*4882a593Smuzhiyun attr.timestamp = curr_time;
1793*4882a593Smuzhiyun attr.timeout = nsecs_to_jiffies(2 * STMMAC_TBS_LT_OFFSET);
1794*4882a593Smuzhiyun attr.queue_mapping = i;
1795*4882a593Smuzhiyun
1796*4882a593Smuzhiyun ret = __stmmac_test_loopback(priv, &attr);
1797*4882a593Smuzhiyun if (ret)
1798*4882a593Smuzhiyun goto fail_disable;
1799*4882a593Smuzhiyun
1800*4882a593Smuzhiyun /* Check if expected time has elapsed */
1801*4882a593Smuzhiyun spin_lock_irqsave(&priv->ptp_lock, flags);
1802*4882a593Smuzhiyun stmmac_get_systime(priv, priv->ptpaddr, &curr_time);
1803*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->ptp_lock, flags);
1804*4882a593Smuzhiyun
1805*4882a593Smuzhiyun if ((curr_time - start_time) < STMMAC_TBS_LT_OFFSET)
1806*4882a593Smuzhiyun ret = -EINVAL;
1807*4882a593Smuzhiyun
1808*4882a593Smuzhiyun fail_disable:
1809*4882a593Smuzhiyun qopt.enable = false;
1810*4882a593Smuzhiyun stmmac_tc_setup_etf(priv, priv, &qopt);
1811*4882a593Smuzhiyun return ret;
1812*4882a593Smuzhiyun }
1813*4882a593Smuzhiyun
1814*4882a593Smuzhiyun #define STMMAC_LOOPBACK_NONE 0
1815*4882a593Smuzhiyun #define STMMAC_LOOPBACK_MAC 1
1816*4882a593Smuzhiyun #define STMMAC_LOOPBACK_PHY 2
1817*4882a593Smuzhiyun
1818*4882a593Smuzhiyun static const struct stmmac_test {
1819*4882a593Smuzhiyun char name[ETH_GSTRING_LEN];
1820*4882a593Smuzhiyun int lb;
1821*4882a593Smuzhiyun int (*fn)(struct stmmac_priv *priv);
1822*4882a593Smuzhiyun } stmmac_selftests[] = {
1823*4882a593Smuzhiyun {
1824*4882a593Smuzhiyun .name = "MAC Loopback ",
1825*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_MAC,
1826*4882a593Smuzhiyun .fn = stmmac_test_mac_loopback,
1827*4882a593Smuzhiyun }, {
1828*4882a593Smuzhiyun .name = "PHY Loopback ",
1829*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_NONE, /* Test will handle it */
1830*4882a593Smuzhiyun .fn = stmmac_test_phy_loopback,
1831*4882a593Smuzhiyun }, {
1832*4882a593Smuzhiyun .name = "MMC Counters ",
1833*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1834*4882a593Smuzhiyun .fn = stmmac_test_mmc,
1835*4882a593Smuzhiyun }, {
1836*4882a593Smuzhiyun .name = "EEE ",
1837*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1838*4882a593Smuzhiyun .fn = stmmac_test_eee,
1839*4882a593Smuzhiyun }, {
1840*4882a593Smuzhiyun .name = "Hash Filter MC ",
1841*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1842*4882a593Smuzhiyun .fn = stmmac_test_hfilt,
1843*4882a593Smuzhiyun }, {
1844*4882a593Smuzhiyun .name = "Perfect Filter UC ",
1845*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1846*4882a593Smuzhiyun .fn = stmmac_test_pfilt,
1847*4882a593Smuzhiyun }, {
1848*4882a593Smuzhiyun .name = "MC Filter ",
1849*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1850*4882a593Smuzhiyun .fn = stmmac_test_mcfilt,
1851*4882a593Smuzhiyun }, {
1852*4882a593Smuzhiyun .name = "UC Filter ",
1853*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1854*4882a593Smuzhiyun .fn = stmmac_test_ucfilt,
1855*4882a593Smuzhiyun }, {
1856*4882a593Smuzhiyun .name = "Flow Control ",
1857*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1858*4882a593Smuzhiyun .fn = stmmac_test_flowctrl,
1859*4882a593Smuzhiyun }, {
1860*4882a593Smuzhiyun .name = "RSS ",
1861*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1862*4882a593Smuzhiyun .fn = stmmac_test_rss,
1863*4882a593Smuzhiyun }, {
1864*4882a593Smuzhiyun .name = "VLAN Filtering ",
1865*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1866*4882a593Smuzhiyun .fn = stmmac_test_vlanfilt,
1867*4882a593Smuzhiyun }, {
1868*4882a593Smuzhiyun .name = "VLAN Filtering (perf) ",
1869*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1870*4882a593Smuzhiyun .fn = stmmac_test_vlanfilt_perfect,
1871*4882a593Smuzhiyun }, {
1872*4882a593Smuzhiyun .name = "Double VLAN Filter ",
1873*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1874*4882a593Smuzhiyun .fn = stmmac_test_dvlanfilt,
1875*4882a593Smuzhiyun }, {
1876*4882a593Smuzhiyun .name = "Double VLAN Filter (perf) ",
1877*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1878*4882a593Smuzhiyun .fn = stmmac_test_dvlanfilt_perfect,
1879*4882a593Smuzhiyun }, {
1880*4882a593Smuzhiyun .name = "Flexible RX Parser ",
1881*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1882*4882a593Smuzhiyun .fn = stmmac_test_rxp,
1883*4882a593Smuzhiyun }, {
1884*4882a593Smuzhiyun .name = "SA Insertion (desc) ",
1885*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1886*4882a593Smuzhiyun .fn = stmmac_test_desc_sai,
1887*4882a593Smuzhiyun }, {
1888*4882a593Smuzhiyun .name = "SA Replacement (desc) ",
1889*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1890*4882a593Smuzhiyun .fn = stmmac_test_desc_sar,
1891*4882a593Smuzhiyun }, {
1892*4882a593Smuzhiyun .name = "SA Insertion (reg) ",
1893*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1894*4882a593Smuzhiyun .fn = stmmac_test_reg_sai,
1895*4882a593Smuzhiyun }, {
1896*4882a593Smuzhiyun .name = "SA Replacement (reg) ",
1897*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1898*4882a593Smuzhiyun .fn = stmmac_test_reg_sar,
1899*4882a593Smuzhiyun }, {
1900*4882a593Smuzhiyun .name = "VLAN TX Insertion ",
1901*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1902*4882a593Smuzhiyun .fn = stmmac_test_vlanoff,
1903*4882a593Smuzhiyun }, {
1904*4882a593Smuzhiyun .name = "SVLAN TX Insertion ",
1905*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1906*4882a593Smuzhiyun .fn = stmmac_test_svlanoff,
1907*4882a593Smuzhiyun }, {
1908*4882a593Smuzhiyun .name = "L3 DA Filtering ",
1909*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1910*4882a593Smuzhiyun .fn = stmmac_test_l3filt_da,
1911*4882a593Smuzhiyun }, {
1912*4882a593Smuzhiyun .name = "L3 SA Filtering ",
1913*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1914*4882a593Smuzhiyun .fn = stmmac_test_l3filt_sa,
1915*4882a593Smuzhiyun }, {
1916*4882a593Smuzhiyun .name = "L4 DA TCP Filtering ",
1917*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1918*4882a593Smuzhiyun .fn = stmmac_test_l4filt_da_tcp,
1919*4882a593Smuzhiyun }, {
1920*4882a593Smuzhiyun .name = "L4 SA TCP Filtering ",
1921*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1922*4882a593Smuzhiyun .fn = stmmac_test_l4filt_sa_tcp,
1923*4882a593Smuzhiyun }, {
1924*4882a593Smuzhiyun .name = "L4 DA UDP Filtering ",
1925*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1926*4882a593Smuzhiyun .fn = stmmac_test_l4filt_da_udp,
1927*4882a593Smuzhiyun }, {
1928*4882a593Smuzhiyun .name = "L4 SA UDP Filtering ",
1929*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1930*4882a593Smuzhiyun .fn = stmmac_test_l4filt_sa_udp,
1931*4882a593Smuzhiyun }, {
1932*4882a593Smuzhiyun .name = "ARP Offload ",
1933*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1934*4882a593Smuzhiyun .fn = stmmac_test_arpoffload,
1935*4882a593Smuzhiyun }, {
1936*4882a593Smuzhiyun .name = "Jumbo Frame ",
1937*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1938*4882a593Smuzhiyun .fn = stmmac_test_jumbo,
1939*4882a593Smuzhiyun }, {
1940*4882a593Smuzhiyun .name = "Multichannel Jumbo ",
1941*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1942*4882a593Smuzhiyun .fn = stmmac_test_mjumbo,
1943*4882a593Smuzhiyun }, {
1944*4882a593Smuzhiyun .name = "Split Header ",
1945*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1946*4882a593Smuzhiyun .fn = stmmac_test_sph,
1947*4882a593Smuzhiyun }, {
1948*4882a593Smuzhiyun .name = "TBS (ETF Scheduler) ",
1949*4882a593Smuzhiyun .lb = STMMAC_LOOPBACK_PHY,
1950*4882a593Smuzhiyun .fn = stmmac_test_tbs,
1951*4882a593Smuzhiyun },
1952*4882a593Smuzhiyun };
1953*4882a593Smuzhiyun
stmmac_selftest_run(struct net_device * dev,struct ethtool_test * etest,u64 * buf)1954*4882a593Smuzhiyun void stmmac_selftest_run(struct net_device *dev,
1955*4882a593Smuzhiyun struct ethtool_test *etest, u64 *buf)
1956*4882a593Smuzhiyun {
1957*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(dev);
1958*4882a593Smuzhiyun int count = stmmac_selftest_get_count(priv);
1959*4882a593Smuzhiyun int i, ret;
1960*4882a593Smuzhiyun
1961*4882a593Smuzhiyun memset(buf, 0, sizeof(*buf) * count);
1962*4882a593Smuzhiyun stmmac_test_next_id = 0;
1963*4882a593Smuzhiyun
1964*4882a593Smuzhiyun if (etest->flags != ETH_TEST_FL_OFFLINE) {
1965*4882a593Smuzhiyun netdev_err(priv->dev, "Only offline tests are supported\n");
1966*4882a593Smuzhiyun etest->flags |= ETH_TEST_FL_FAILED;
1967*4882a593Smuzhiyun return;
1968*4882a593Smuzhiyun } else if (!netif_carrier_ok(dev)) {
1969*4882a593Smuzhiyun netdev_err(priv->dev, "You need valid Link to execute tests\n");
1970*4882a593Smuzhiyun etest->flags |= ETH_TEST_FL_FAILED;
1971*4882a593Smuzhiyun return;
1972*4882a593Smuzhiyun }
1973*4882a593Smuzhiyun
1974*4882a593Smuzhiyun /* Wait for queues drain */
1975*4882a593Smuzhiyun msleep(200);
1976*4882a593Smuzhiyun
1977*4882a593Smuzhiyun for (i = 0; i < count; i++) {
1978*4882a593Smuzhiyun ret = 0;
1979*4882a593Smuzhiyun
1980*4882a593Smuzhiyun switch (stmmac_selftests[i].lb) {
1981*4882a593Smuzhiyun case STMMAC_LOOPBACK_PHY:
1982*4882a593Smuzhiyun ret = -EOPNOTSUPP;
1983*4882a593Smuzhiyun if (dev->phydev)
1984*4882a593Smuzhiyun ret = phy_loopback(dev->phydev, true);
1985*4882a593Smuzhiyun if (!ret)
1986*4882a593Smuzhiyun break;
1987*4882a593Smuzhiyun fallthrough;
1988*4882a593Smuzhiyun case STMMAC_LOOPBACK_MAC:
1989*4882a593Smuzhiyun ret = stmmac_set_mac_loopback(priv, priv->ioaddr, true);
1990*4882a593Smuzhiyun break;
1991*4882a593Smuzhiyun case STMMAC_LOOPBACK_NONE:
1992*4882a593Smuzhiyun break;
1993*4882a593Smuzhiyun default:
1994*4882a593Smuzhiyun ret = -EOPNOTSUPP;
1995*4882a593Smuzhiyun break;
1996*4882a593Smuzhiyun }
1997*4882a593Smuzhiyun
1998*4882a593Smuzhiyun /*
1999*4882a593Smuzhiyun * First tests will always be MAC / PHY loobpack. If any of
2000*4882a593Smuzhiyun * them is not supported we abort earlier.
2001*4882a593Smuzhiyun */
2002*4882a593Smuzhiyun if (ret) {
2003*4882a593Smuzhiyun netdev_err(priv->dev, "Loopback is not supported\n");
2004*4882a593Smuzhiyun etest->flags |= ETH_TEST_FL_FAILED;
2005*4882a593Smuzhiyun break;
2006*4882a593Smuzhiyun }
2007*4882a593Smuzhiyun
2008*4882a593Smuzhiyun ret = stmmac_selftests[i].fn(priv);
2009*4882a593Smuzhiyun if (ret && (ret != -EOPNOTSUPP))
2010*4882a593Smuzhiyun etest->flags |= ETH_TEST_FL_FAILED;
2011*4882a593Smuzhiyun buf[i] = ret;
2012*4882a593Smuzhiyun
2013*4882a593Smuzhiyun switch (stmmac_selftests[i].lb) {
2014*4882a593Smuzhiyun case STMMAC_LOOPBACK_PHY:
2015*4882a593Smuzhiyun ret = -EOPNOTSUPP;
2016*4882a593Smuzhiyun if (dev->phydev)
2017*4882a593Smuzhiyun ret = phy_loopback(dev->phydev, false);
2018*4882a593Smuzhiyun if (!ret)
2019*4882a593Smuzhiyun break;
2020*4882a593Smuzhiyun fallthrough;
2021*4882a593Smuzhiyun case STMMAC_LOOPBACK_MAC:
2022*4882a593Smuzhiyun stmmac_set_mac_loopback(priv, priv->ioaddr, false);
2023*4882a593Smuzhiyun break;
2024*4882a593Smuzhiyun default:
2025*4882a593Smuzhiyun break;
2026*4882a593Smuzhiyun }
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun }
2029*4882a593Smuzhiyun
stmmac_selftest_get_strings(struct stmmac_priv * priv,u8 * data)2030*4882a593Smuzhiyun void stmmac_selftest_get_strings(struct stmmac_priv *priv, u8 *data)
2031*4882a593Smuzhiyun {
2032*4882a593Smuzhiyun u8 *p = data;
2033*4882a593Smuzhiyun int i;
2034*4882a593Smuzhiyun
2035*4882a593Smuzhiyun for (i = 0; i < stmmac_selftest_get_count(priv); i++) {
2036*4882a593Smuzhiyun snprintf(p, ETH_GSTRING_LEN, "%2d. %s", i + 1,
2037*4882a593Smuzhiyun stmmac_selftests[i].name);
2038*4882a593Smuzhiyun p += ETH_GSTRING_LEN;
2039*4882a593Smuzhiyun }
2040*4882a593Smuzhiyun }
2041*4882a593Smuzhiyun
stmmac_selftest_get_count(struct stmmac_priv * priv)2042*4882a593Smuzhiyun int stmmac_selftest_get_count(struct stmmac_priv *priv)
2043*4882a593Smuzhiyun {
2044*4882a593Smuzhiyun return ARRAY_SIZE(stmmac_selftests);
2045*4882a593Smuzhiyun }
2046