GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / net / dsa / bcm_sf2_cfp.c
1 /*
2  * Broadcom Starfighter 2 DSA switch CFP support
3  *
4  * Copyright (C) 2016, Broadcom
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <linux/list.h>
13 #include <linux/ethtool.h>
14 #include <linux/if_ether.h>
15 #include <linux/in.h>
16 #include <linux/netdevice.h>
17 #include <net/dsa.h>
18 #include <linux/bitmap.h>
19
20 #include "bcm_sf2.h"
21 #include "bcm_sf2_regs.h"
22
23 struct cfp_udf_layout {
24         u8 slices[UDF_NUM_SLICES];
25         u32 mask_value;
26
27 };
28
29 /* UDF slices layout for a TCPv4/UDPv4 specification */
30 static const struct cfp_udf_layout udf_tcpip4_layout = {
31         .slices = {
32                 /* End of L2, byte offset 12, src IP[0:15] */
33                 CFG_UDF_EOL2 | 6,
34                 /* End of L2, byte offset 14, src IP[16:31] */
35                 CFG_UDF_EOL2 | 7,
36                 /* End of L2, byte offset 16, dst IP[0:15] */
37                 CFG_UDF_EOL2 | 8,
38                 /* End of L2, byte offset 18, dst IP[16:31] */
39                 CFG_UDF_EOL2 | 9,
40                 /* End of L3, byte offset 0, src port */
41                 CFG_UDF_EOL3 | 0,
42                 /* End of L3, byte offset 2, dst port */
43                 CFG_UDF_EOL3 | 1,
44                 0, 0, 0
45         },
46         .mask_value = L3_FRAMING_MASK | IPPROTO_MASK | IP_FRAG,
47 };
48
49 static inline unsigned int bcm_sf2_get_num_udf_slices(const u8 *layout)
50 {
51         unsigned int i, count = 0;
52
53         for (i = 0; i < UDF_NUM_SLICES; i++) {
54                 if (layout[i] != 0)
55                         count++;
56         }
57
58         return count;
59 }
60
61 static void bcm_sf2_cfp_udf_set(struct bcm_sf2_priv *priv,
62                                 unsigned int slice_num,
63                                 const u8 *layout)
64 {
65         u32 offset = CORE_UDF_0_A_0_8_PORT_0 + slice_num * UDF_SLICE_OFFSET;
66         unsigned int i;
67
68         for (i = 0; i < UDF_NUM_SLICES; i++)
69                 core_writel(priv, layout[i], offset + i * 4);
70 }
71
72 static int bcm_sf2_cfp_op(struct bcm_sf2_priv *priv, unsigned int op)
73 {
74         unsigned int timeout = 1000;
75         u32 reg;
76
77         reg = core_readl(priv, CORE_CFP_ACC);
78         reg &= ~(OP_SEL_MASK | RAM_SEL_MASK);
79         reg |= OP_STR_DONE | op;
80         core_writel(priv, reg, CORE_CFP_ACC);
81
82         do {
83                 reg = core_readl(priv, CORE_CFP_ACC);
84                 if (!(reg & OP_STR_DONE))
85                         break;
86
87                 cpu_relax();
88         } while (timeout--);
89
90         if (!timeout)
91                 return -ETIMEDOUT;
92
93         return 0;
94 }
95
96 static inline void bcm_sf2_cfp_rule_addr_set(struct bcm_sf2_priv *priv,
97                                              unsigned int addr)
98 {
99         u32 reg;
100
101         WARN_ON(addr >= priv->num_cfp_rules);
102
103         reg = core_readl(priv, CORE_CFP_ACC);
104         reg &= ~(XCESS_ADDR_MASK << XCESS_ADDR_SHIFT);
105         reg |= addr << XCESS_ADDR_SHIFT;
106         core_writel(priv, reg, CORE_CFP_ACC);
107 }
108
109 static inline unsigned int bcm_sf2_cfp_rule_size(struct bcm_sf2_priv *priv)
110 {
111         /* Entry #0 is reserved */
112         return priv->num_cfp_rules - 1;
113 }
114
115 static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
116                                 struct ethtool_rx_flow_spec *fs)
117 {
118         struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
119         struct ethtool_tcpip4_spec *v4_spec;
120         const struct cfp_udf_layout *layout;
121         unsigned int slice_num, rule_index;
122         unsigned int queue_num, port_num;
123         u8 ip_proto, ip_frag;
124         u8 num_udf;
125         u32 reg;
126         int ret;
127
128         /* Check for unsupported extensions */
129         if ((fs->flow_type & FLOW_EXT) &&
130             (fs->m_ext.vlan_etype || fs->m_ext.data[1]))
131                 return -EINVAL;
132
133         if (fs->location != RX_CLS_LOC_ANY &&
134             fs->location > bcm_sf2_cfp_rule_size(priv))
135                 return -EINVAL;
136
137         if (fs->location != RX_CLS_LOC_ANY &&
138             test_bit(fs->location, priv->cfp.used))
139                 return -EBUSY;
140
141         ip_frag = be32_to_cpu(fs->m_ext.data[0]);
142
143         /* We do not support discarding packets, check that the
144          * destination port is enabled and that we are within the
145          * number of ports supported by the switch
146          */
147         port_num = fs->ring_cookie / 8;
148
149         if (fs->ring_cookie == RX_CLS_FLOW_DISC ||
150             !(BIT(port_num) & ds->enabled_port_mask) ||
151             port_num >= priv->hw_params.num_ports)
152                 return -EINVAL;
153
154         switch (fs->flow_type & ~FLOW_EXT) {
155         case TCP_V4_FLOW:
156                 ip_proto = IPPROTO_TCP;
157                 v4_spec = &fs->h_u.tcp_ip4_spec;
158                 break;
159         case UDP_V4_FLOW:
160                 ip_proto = IPPROTO_UDP;
161                 v4_spec = &fs->h_u.udp_ip4_spec;
162                 break;
163         default:
164                 return -EINVAL;
165         }
166
167         /* We only use one UDF slice for now */
168         slice_num = 1;
169         layout = &udf_tcpip4_layout;
170         num_udf = bcm_sf2_get_num_udf_slices(layout->slices);
171
172         /* Apply the UDF layout for this filter */
173         bcm_sf2_cfp_udf_set(priv, slice_num, layout->slices);
174
175         /* Apply to all packets received through this port */
176         core_writel(priv, BIT(port), CORE_CFP_DATA_PORT(7));
177
178         /* S-Tag status         [31:30]
179          * C-Tag status         [29:28]
180          * L2 framing           [27:26]
181          * L3 framing           [25:24]
182          * IP ToS               [23:16]
183          * IP proto             [15:08]
184          * IP Fragm             [7]
185          * Non 1st frag         [6]
186          * IP Authen            [5]
187          * TTL range            [4:3]
188          * PPPoE session        [2]
189          * Reserved             [1]
190          * UDF_Valid[8]         [0]
191          */
192         core_writel(priv, v4_spec->tos << 16 | ip_proto << 8 | ip_frag << 7,
193                     CORE_CFP_DATA_PORT(6));
194
195         /* UDF_Valid[7:0]       [31:24]
196          * S-Tag                [23:8]
197          * C-Tag                [7:0]
198          */
199         core_writel(priv, GENMASK(num_udf - 1, 0) << 24, CORE_CFP_DATA_PORT(5));
200
201         /* C-Tag                [31:24]
202          * UDF_n_A8             [23:8]
203          * UDF_n_A7             [7:0]
204          */
205         core_writel(priv, 0, CORE_CFP_DATA_PORT(4));
206
207         /* UDF_n_A7             [31:24]
208          * UDF_n_A6             [23:8]
209          * UDF_n_A5             [7:0]
210          */
211         core_writel(priv, be16_to_cpu(v4_spec->pdst) >> 8,
212                     CORE_CFP_DATA_PORT(3));
213
214         /* UDF_n_A5             [31:24]
215          * UDF_n_A4             [23:8]
216          * UDF_n_A3             [7:0]
217          */
218         reg = (be16_to_cpu(v4_spec->pdst) & 0xff) << 24 |
219               (u32)be16_to_cpu(v4_spec->psrc) << 8 |
220               (be32_to_cpu(v4_spec->ip4dst) & 0x0000ff00) >> 8;
221         core_writel(priv, reg, CORE_CFP_DATA_PORT(2));
222
223         /* UDF_n_A3             [31:24]
224          * UDF_n_A2             [23:8]
225          * UDF_n_A1             [7:0]
226          */
227         reg = (u32)(be32_to_cpu(v4_spec->ip4dst) & 0xff) << 24 |
228               (u32)(be32_to_cpu(v4_spec->ip4dst) >> 16) << 8 |
229               (be32_to_cpu(v4_spec->ip4src) & 0x0000ff00) >> 8;
230         core_writel(priv, reg, CORE_CFP_DATA_PORT(1));
231
232         /* UDF_n_A1             [31:24]
233          * UDF_n_A0             [23:8]
234          * Reserved             [7:4]
235          * Slice ID             [3:2]
236          * Slice valid          [1:0]
237          */
238         reg = (u32)(be32_to_cpu(v4_spec->ip4src) & 0xff) << 24 |
239               (u32)(be32_to_cpu(v4_spec->ip4src) >> 16) << 8 |
240               SLICE_NUM(slice_num) | SLICE_VALID;
241         core_writel(priv, reg, CORE_CFP_DATA_PORT(0));
242
243         /* Source port map match */
244         core_writel(priv, 0xff, CORE_CFP_MASK_PORT(7));
245
246         /* Mask with the specific layout for IPv4 packets */
247         core_writel(priv, layout->mask_value, CORE_CFP_MASK_PORT(6));
248
249         /* Mask all but valid UDFs */
250         core_writel(priv, GENMASK(num_udf - 1, 0) << 24, CORE_CFP_MASK_PORT(5));
251
252         /* Mask all */
253         core_writel(priv, 0, CORE_CFP_MASK_PORT(4));
254
255         /* All other UDFs should be matched with the filter */
256         core_writel(priv, 0xff, CORE_CFP_MASK_PORT(3));
257         core_writel(priv, 0xffffffff, CORE_CFP_MASK_PORT(2));
258         core_writel(priv, 0xffffffff, CORE_CFP_MASK_PORT(1));
259         core_writel(priv, 0xffffff0f, CORE_CFP_MASK_PORT(0));
260
261         /* Locate the first rule available */
262         if (fs->location == RX_CLS_LOC_ANY)
263                 rule_index = find_first_zero_bit(priv->cfp.used,
264                                                  bcm_sf2_cfp_rule_size(priv));
265         else
266                 rule_index = fs->location;
267
268         /* Insert into TCAM now */
269         bcm_sf2_cfp_rule_addr_set(priv, rule_index);
270
271         ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | TCAM_SEL);
272         if (ret) {
273                 pr_err("TCAM entry at addr %d failed\n", rule_index);
274                 return ret;
275         }
276
277         /* Replace ARL derived destination with DST_MAP derived, define
278          * which port and queue this should be forwarded to.
279          *
280          * We have a small oddity where Port 6 just does not have a
281          * valid bit here (so we subtract by one).
282          */
283         queue_num = fs->ring_cookie % 8;
284         if (port_num >= 7)
285                 port_num -= 1;
286
287         reg = CHANGE_FWRD_MAP_IB_REP_ARL | BIT(port_num + DST_MAP_IB_SHIFT) |
288                 CHANGE_TC | queue_num << NEW_TC_SHIFT;
289
290         core_writel(priv, reg, CORE_ACT_POL_DATA0);
291
292         /* Set classification ID that needs to be put in Broadcom tag */
293         core_writel(priv, rule_index << CHAIN_ID_SHIFT,
294                     CORE_ACT_POL_DATA1);
295
296         core_writel(priv, 0, CORE_ACT_POL_DATA2);
297
298         /* Configure policer RAM now */
299         ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | ACT_POL_RAM);
300         if (ret) {
301                 pr_err("Policer entry at %d failed\n", rule_index);
302                 return ret;
303         }
304
305         /* Disable the policer */
306         core_writel(priv, POLICER_MODE_DISABLE, CORE_RATE_METER0);
307
308         /* Now the rate meter */
309         ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | RATE_METER_RAM);
310         if (ret) {
311                 pr_err("Meter entry at %d failed\n", rule_index);
312                 return ret;
313         }
314
315         /* Turn on CFP for this rule now */
316         reg = core_readl(priv, CORE_CFP_CTL_REG);
317         reg |= BIT(port);
318         core_writel(priv, reg, CORE_CFP_CTL_REG);
319
320         /* Flag the rule as being used and return it */
321         set_bit(rule_index, priv->cfp.used);
322         fs->location = rule_index;
323
324         return 0;
325 }
326
327 static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port,
328                                 u32 loc)
329 {
330         int ret;
331         u32 reg;
332
333         if (loc > bcm_sf2_cfp_rule_size(priv))
334                 return -EINVAL;
335
336         /* Refuse deletion of unused rules, and the default reserved rule */
337         if (!test_bit(loc, priv->cfp.used) || loc == 0)
338                 return -EINVAL;
339
340         /* Indicate which rule we want to read */
341         bcm_sf2_cfp_rule_addr_set(priv, loc);
342
343         ret =  bcm_sf2_cfp_op(priv, OP_SEL_READ | TCAM_SEL);
344         if (ret)
345                 return ret;
346
347         /* Clear its valid bits */
348         reg = core_readl(priv, CORE_CFP_DATA_PORT(0));
349         reg &= ~SLICE_VALID;
350         core_writel(priv, reg, CORE_CFP_DATA_PORT(0));
351
352         /* Write back this entry into the TCAM now */
353         ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | TCAM_SEL);
354         if (ret)
355                 return ret;
356
357         clear_bit(loc, priv->cfp.used);
358
359         return 0;
360 }
361
362 static void bcm_sf2_invert_masks(struct ethtool_rx_flow_spec *flow)
363 {
364         unsigned int i;
365
366         for (i = 0; i < sizeof(flow->m_u); i++)
367                 flow->m_u.hdata[i] ^= 0xff;
368
369         flow->m_ext.vlan_etype ^= cpu_to_be16(~0);
370         flow->m_ext.vlan_tci ^= cpu_to_be16(~0);
371         flow->m_ext.data[0] ^= cpu_to_be32(~0);
372         flow->m_ext.data[1] ^= cpu_to_be32(~0);
373 }
374
375 static int bcm_sf2_cfp_rule_get(struct bcm_sf2_priv *priv, int port,
376                                 struct ethtool_rxnfc *nfc, bool search)
377 {
378         struct ethtool_tcpip4_spec *v4_spec;
379         unsigned int queue_num;
380         u16 src_dst_port;
381         u32 reg, ipv4;
382         int ret;
383
384         if (!search) {
385                 bcm_sf2_cfp_rule_addr_set(priv, nfc->fs.location);
386
387                 ret = bcm_sf2_cfp_op(priv, OP_SEL_READ | ACT_POL_RAM);
388                 if (ret)
389                         return ret;
390
391                 reg = core_readl(priv, CORE_ACT_POL_DATA0);
392
393                 ret = bcm_sf2_cfp_op(priv, OP_SEL_READ | TCAM_SEL);
394                 if (ret)
395                         return ret;
396         } else {
397                 reg = core_readl(priv, CORE_ACT_POL_DATA0);
398         }
399
400         /* Extract the destination port */
401         nfc->fs.ring_cookie = fls((reg >> DST_MAP_IB_SHIFT) &
402                                   DST_MAP_IB_MASK) - 1;
403
404         /* There is no Port 6, so we compensate for that here */
405         if (nfc->fs.ring_cookie >= 6)
406                 nfc->fs.ring_cookie++;
407         nfc->fs.ring_cookie *= 8;
408
409         /* Extract the destination queue */
410         queue_num = (reg >> NEW_TC_SHIFT) & NEW_TC_MASK;
411         nfc->fs.ring_cookie += queue_num;
412
413         /* Extract the IP protocol */
414         reg = core_readl(priv, CORE_CFP_DATA_PORT(6));
415         switch ((reg & IPPROTO_MASK) >> IPPROTO_SHIFT) {
416         case IPPROTO_TCP:
417                 nfc->fs.flow_type = TCP_V4_FLOW;
418                 v4_spec = &nfc->fs.h_u.tcp_ip4_spec;
419                 break;
420         case IPPROTO_UDP:
421                 nfc->fs.flow_type = UDP_V4_FLOW;
422                 v4_spec = &nfc->fs.h_u.udp_ip4_spec;
423                 break;
424         default:
425                 /* Clear to exit the search process */
426                 if (search)
427                         core_readl(priv, CORE_CFP_DATA_PORT(7));
428                 return -EINVAL;
429         }
430
431         v4_spec->tos = (reg >> 16) & IPPROTO_MASK;
432         nfc->fs.m_ext.data[0] = cpu_to_be32((reg >> 7) & 1);
433
434         reg = core_readl(priv, CORE_CFP_DATA_PORT(3));
435         /* src port [15:8] */
436         src_dst_port = reg << 8;
437
438         reg = core_readl(priv, CORE_CFP_DATA_PORT(2));
439         /* src port [7:0] */
440         src_dst_port |= (reg >> 24);
441
442         v4_spec->pdst = cpu_to_be16(src_dst_port);
443         nfc->fs.m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0);
444         v4_spec->psrc = cpu_to_be16((u16)(reg >> 8));
445         nfc->fs.m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0);
446
447         /* IPv4 dst [15:8] */
448         ipv4 = (reg & 0xff) << 8;
449         reg = core_readl(priv, CORE_CFP_DATA_PORT(1));
450         /* IPv4 dst [31:16] */
451         ipv4 |= ((reg >> 8) & 0xffff) << 16;
452         /* IPv4 dst [7:0] */
453         ipv4 |= (reg >> 24) & 0xff;
454         v4_spec->ip4dst = cpu_to_be32(ipv4);
455         nfc->fs.m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0);
456
457         /* IPv4 src [15:8] */
458         ipv4 = (reg & 0xff) << 8;
459         reg = core_readl(priv, CORE_CFP_DATA_PORT(0));
460
461         if (!(reg & SLICE_VALID))
462                 return -EINVAL;
463
464         /* IPv4 src [7:0] */
465         ipv4 |= (reg >> 24) & 0xff;
466         /* IPv4 src [31:16] */
467         ipv4 |= ((reg >> 8) & 0xffff) << 16;
468         v4_spec->ip4src = cpu_to_be32(ipv4);
469         nfc->fs.m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0);
470
471         /* Read last to avoid next entry clobbering the results during search
472          * operations
473          */
474         reg = core_readl(priv, CORE_CFP_DATA_PORT(7));
475         if (!(reg & 1 << port))
476                 return -EINVAL;
477
478         bcm_sf2_invert_masks(&nfc->fs);
479
480         /* Put the TCAM size here */
481         nfc->data = bcm_sf2_cfp_rule_size(priv);
482
483         return 0;
484 }
485
486 /* We implement the search doing a TCAM search operation */
487 static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv,
488                                     int port, struct ethtool_rxnfc *nfc,
489                                     u32 *rule_locs)
490 {
491         unsigned int index = 1, rules_cnt = 0;
492         int ret;
493         u32 reg;
494
495         /* Do not poll on OP_STR_DONE to be self-clearing for search
496          * operations, we cannot use bcm_sf2_cfp_op here because it completes
497          * on clearing OP_STR_DONE which won't clear until the entire search
498          * operation is over.
499          */
500         reg = core_readl(priv, CORE_CFP_ACC);
501         reg &= ~(XCESS_ADDR_MASK << XCESS_ADDR_SHIFT);
502         reg |= index << XCESS_ADDR_SHIFT;
503         reg &= ~(OP_SEL_MASK | RAM_SEL_MASK);
504         reg |= OP_SEL_SEARCH | TCAM_SEL | OP_STR_DONE;
505         core_writel(priv, reg, CORE_CFP_ACC);
506
507         do {
508                 /* Wait for results to be ready */
509                 reg = core_readl(priv, CORE_CFP_ACC);
510
511                 /* Extract the address we are searching */
512                 index = reg >> XCESS_ADDR_SHIFT;
513                 index &= XCESS_ADDR_MASK;
514
515                 /* We have a valid search result, so flag it accordingly */
516                 if (reg & SEARCH_STS) {
517                         ret = bcm_sf2_cfp_rule_get(priv, port, nfc, true);
518                         if (ret)
519                                 continue;
520
521                         rule_locs[rules_cnt] = index;
522                         rules_cnt++;
523                 }
524
525                 /* Search is over break out */
526                 if (!(reg & OP_STR_DONE))
527                         break;
528
529         } while (index < priv->num_cfp_rules);
530
531         /* Put the TCAM size here */
532         nfc->data = bcm_sf2_cfp_rule_size(priv);
533         nfc->rule_cnt = rules_cnt;
534
535         return 0;
536 }
537
538 int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port,
539                       struct ethtool_rxnfc *nfc, u32 *rule_locs)
540 {
541         struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
542         int ret = 0;
543
544         mutex_lock(&priv->cfp.lock);
545
546         switch (nfc->cmd) {
547         case ETHTOOL_GRXCLSRLCNT:
548                 /* Subtract the default, unusable rule */
549                 nfc->rule_cnt = bitmap_weight(priv->cfp.used,
550                                               priv->num_cfp_rules) - 1;
551                 /* We support specifying rule locations */
552                 nfc->data |= RX_CLS_LOC_SPECIAL;
553                 break;
554         case ETHTOOL_GRXCLSRULE:
555                 ret = bcm_sf2_cfp_rule_get(priv, port, nfc, false);
556                 break;
557         case ETHTOOL_GRXCLSRLALL:
558                 ret = bcm_sf2_cfp_rule_get_all(priv, port, nfc, rule_locs);
559                 break;
560         default:
561                 ret = -EOPNOTSUPP;
562                 break;
563         }
564
565         mutex_unlock(&priv->cfp.lock);
566
567         return ret;
568 }
569
570 int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port,
571                       struct ethtool_rxnfc *nfc)
572 {
573         struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
574         int ret = 0;
575
576         mutex_lock(&priv->cfp.lock);
577
578         switch (nfc->cmd) {
579         case ETHTOOL_SRXCLSRLINS:
580                 ret = bcm_sf2_cfp_rule_set(ds, port, &nfc->fs);
581                 break;
582
583         case ETHTOOL_SRXCLSRLDEL:
584                 ret = bcm_sf2_cfp_rule_del(priv, port, nfc->fs.location);
585                 break;
586         default:
587                 ret = -EOPNOTSUPP;
588                 break;
589         }
590
591         mutex_unlock(&priv->cfp.lock);
592
593         return ret;
594 }
595
596 int bcm_sf2_cfp_rst(struct bcm_sf2_priv *priv)
597 {
598         unsigned int timeout = 1000;
599         u32 reg;
600
601         reg = core_readl(priv, CORE_CFP_ACC);
602         reg |= TCAM_RESET;
603         core_writel(priv, reg, CORE_CFP_ACC);
604
605         do {
606                 reg = core_readl(priv, CORE_CFP_ACC);
607                 if (!(reg & TCAM_RESET))
608                         break;
609
610                 cpu_relax();
611         } while (timeout--);
612
613         if (!timeout)
614                 return -ETIMEDOUT;
615
616         return 0;
617 }