Merge branch 'ib/5.17-cros-ec-keyb' into next
[platform/kernel/linux-starfive.git] / drivers / net / ethernet / mscc / ocelot_flower.c
1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3  * Copyright (c) 2019 Microsemi Corporation
4  */
5
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
8 #include <soc/mscc/ocelot_vcap.h>
9 #include "ocelot_vcap.h"
10
11 /* Arbitrarily chosen constants for encoding the VCAP block and lookup number
12  * into the chain number. This is UAPI.
13  */
14 #define VCAP_BLOCK                      10000
15 #define VCAP_LOOKUP                     1000
16 #define VCAP_IS1_NUM_LOOKUPS            3
17 #define VCAP_IS2_NUM_LOOKUPS            2
18 #define VCAP_IS2_NUM_PAG                256
19 #define VCAP_IS1_CHAIN(lookup)          \
20         (1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP)
21 #define VCAP_IS2_CHAIN(lookup, pag)     \
22         (2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag))
23 /* PSFP chain and block ID */
24 #define PSFP_BLOCK_ID                   OCELOT_NUM_VCAP_BLOCKS
25 #define OCELOT_PSFP_CHAIN               (3 * VCAP_BLOCK)
26
27 static int ocelot_chain_to_block(int chain, bool ingress)
28 {
29         int lookup, pag;
30
31         if (!ingress) {
32                 if (chain == 0)
33                         return VCAP_ES0;
34                 return -EOPNOTSUPP;
35         }
36
37         /* Backwards compatibility with older, single-chain tc-flower
38          * offload support in Ocelot
39          */
40         if (chain == 0)
41                 return VCAP_IS2;
42
43         for (lookup = 0; lookup < VCAP_IS1_NUM_LOOKUPS; lookup++)
44                 if (chain == VCAP_IS1_CHAIN(lookup))
45                         return VCAP_IS1;
46
47         for (lookup = 0; lookup < VCAP_IS2_NUM_LOOKUPS; lookup++)
48                 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
49                         if (chain == VCAP_IS2_CHAIN(lookup, pag))
50                                 return VCAP_IS2;
51
52         if (chain == OCELOT_PSFP_CHAIN)
53                 return PSFP_BLOCK_ID;
54
55         return -EOPNOTSUPP;
56 }
57
58 /* Caller must ensure this is a valid IS1 or IS2 chain first,
59  * by calling ocelot_chain_to_block.
60  */
61 static int ocelot_chain_to_lookup(int chain)
62 {
63         /* Backwards compatibility with older, single-chain tc-flower
64          * offload support in Ocelot
65          */
66         if (chain == 0)
67                 return 0;
68
69         return (chain / VCAP_LOOKUP) % 10;
70 }
71
72 /* Caller must ensure this is a valid IS2 chain first,
73  * by calling ocelot_chain_to_block.
74  */
75 static int ocelot_chain_to_pag(int chain)
76 {
77         int lookup;
78
79         /* Backwards compatibility with older, single-chain tc-flower
80          * offload support in Ocelot
81          */
82         if (chain == 0)
83                 return 0;
84
85         lookup = ocelot_chain_to_lookup(chain);
86
87         /* calculate PAG value as chain index relative to the first PAG */
88         return chain - VCAP_IS2_CHAIN(lookup, 0);
89 }
90
91 static bool ocelot_is_goto_target_valid(int goto_target, int chain,
92                                         bool ingress)
93 {
94         int pag;
95
96         /* Can't offload GOTO in VCAP ES0 */
97         if (!ingress)
98                 return (goto_target < 0);
99
100         /* Non-optional GOTOs */
101         if (chain == 0)
102                 /* VCAP IS1 can be skipped, either partially or completely */
103                 return (goto_target == VCAP_IS1_CHAIN(0) ||
104                         goto_target == VCAP_IS1_CHAIN(1) ||
105                         goto_target == VCAP_IS1_CHAIN(2) ||
106                         goto_target == VCAP_IS2_CHAIN(0, 0) ||
107                         goto_target == VCAP_IS2_CHAIN(1, 0) ||
108                         goto_target == OCELOT_PSFP_CHAIN);
109
110         if (chain == VCAP_IS1_CHAIN(0))
111                 return (goto_target == VCAP_IS1_CHAIN(1));
112
113         if (chain == VCAP_IS1_CHAIN(1))
114                 return (goto_target == VCAP_IS1_CHAIN(2));
115
116         /* Lookup 2 of VCAP IS1 can really support non-optional GOTOs,
117          * using a Policy Association Group (PAG) value, which is an 8-bit
118          * value encoding a VCAP IS2 target chain.
119          */
120         if (chain == VCAP_IS1_CHAIN(2)) {
121                 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
122                         if (goto_target == VCAP_IS2_CHAIN(0, pag))
123                                 return true;
124
125                 return false;
126         }
127
128         /* Non-optional GOTO from VCAP IS2 lookup 0 to lookup 1.
129          * We cannot change the PAG at this point.
130          */
131         for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
132                 if (chain == VCAP_IS2_CHAIN(0, pag))
133                         return (goto_target == VCAP_IS2_CHAIN(1, pag));
134
135         /* VCAP IS2 lookup 1 can goto to PSFP block if hardware support */
136         for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
137                 if (chain == VCAP_IS2_CHAIN(1, pag))
138                         return (goto_target == OCELOT_PSFP_CHAIN);
139
140         return false;
141 }
142
143 static struct ocelot_vcap_filter *
144 ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain)
145 {
146         struct ocelot_vcap_filter *filter;
147         struct ocelot_vcap_block *block;
148         int block_id;
149
150         block_id = ocelot_chain_to_block(chain, true);
151         if (block_id < 0)
152                 return NULL;
153
154         if (block_id == VCAP_IS2) {
155                 block = &ocelot->block[VCAP_IS1];
156
157                 list_for_each_entry(filter, &block->rules, list)
158                         if (filter->type == OCELOT_VCAP_FILTER_PAG &&
159                             filter->goto_target == chain)
160                                 return filter;
161         }
162
163         list_for_each_entry(filter, &ocelot->dummy_rules, list)
164                 if (filter->goto_target == chain)
165                         return filter;
166
167         return NULL;
168 }
169
170 static int
171 ocelot_flower_parse_ingress_vlan_modify(struct ocelot *ocelot, int port,
172                                         struct ocelot_vcap_filter *filter,
173                                         const struct flow_action_entry *a,
174                                         struct netlink_ext_ack *extack)
175 {
176         struct ocelot_port *ocelot_port = ocelot->ports[port];
177
178         if (filter->goto_target != -1) {
179                 NL_SET_ERR_MSG_MOD(extack,
180                                    "Last action must be GOTO");
181                 return -EOPNOTSUPP;
182         }
183
184         if (!ocelot_port->vlan_aware) {
185                 NL_SET_ERR_MSG_MOD(extack,
186                                    "Can only modify VLAN under VLAN aware bridge");
187                 return -EOPNOTSUPP;
188         }
189
190         filter->action.vid_replace_ena = true;
191         filter->action.pcp_dei_ena = true;
192         filter->action.vid = a->vlan.vid;
193         filter->action.pcp = a->vlan.prio;
194         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
195
196         return 0;
197 }
198
199 static int
200 ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter,
201                                        const struct flow_action_entry *a,
202                                        struct netlink_ext_ack *extack)
203 {
204         enum ocelot_tag_tpid_sel tpid;
205
206         switch (ntohs(a->vlan.proto)) {
207         case ETH_P_8021Q:
208                 tpid = OCELOT_TAG_TPID_SEL_8021Q;
209                 break;
210         case ETH_P_8021AD:
211                 tpid = OCELOT_TAG_TPID_SEL_8021AD;
212                 break;
213         default:
214                 NL_SET_ERR_MSG_MOD(extack,
215                                    "Cannot modify custom TPID");
216                 return -EOPNOTSUPP;
217         }
218
219         filter->action.tag_a_tpid_sel = tpid;
220         filter->action.push_outer_tag = OCELOT_ES0_TAG;
221         filter->action.tag_a_vid_sel = OCELOT_ES0_VID_PLUS_CLASSIFIED_VID;
222         filter->action.vid_a_val = a->vlan.vid;
223         filter->action.pcp_a_val = a->vlan.prio;
224         filter->action.tag_a_pcp_sel = OCELOT_ES0_PCP;
225         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
226
227         return 0;
228 }
229
230 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
231                                       bool ingress, struct flow_cls_offload *f,
232                                       struct ocelot_vcap_filter *filter)
233 {
234         struct netlink_ext_ack *extack = f->common.extack;
235         bool allow_missing_goto_target = false;
236         const struct flow_action_entry *a;
237         enum ocelot_tag_tpid_sel tpid;
238         int i, chain, egress_port;
239         u32 pol_ix, pol_max;
240         u64 rate;
241         int err;
242
243         if (!flow_action_basic_hw_stats_check(&f->rule->action,
244                                               f->common.extack))
245                 return -EOPNOTSUPP;
246
247         chain = f->common.chain_index;
248         filter->block_id = ocelot_chain_to_block(chain, ingress);
249         if (filter->block_id < 0) {
250                 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
251                 return -EOPNOTSUPP;
252         }
253         if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
254                 filter->lookup = ocelot_chain_to_lookup(chain);
255         if (filter->block_id == VCAP_IS2)
256                 filter->pag = ocelot_chain_to_pag(chain);
257
258         filter->goto_target = -1;
259         filter->type = OCELOT_VCAP_FILTER_DUMMY;
260
261         flow_action_for_each(i, a, &f->rule->action) {
262                 switch (a->id) {
263                 case FLOW_ACTION_DROP:
264                         if (filter->block_id != VCAP_IS2) {
265                                 NL_SET_ERR_MSG_MOD(extack,
266                                                    "Drop action can only be offloaded to VCAP IS2");
267                                 return -EOPNOTSUPP;
268                         }
269                         if (filter->goto_target != -1) {
270                                 NL_SET_ERR_MSG_MOD(extack,
271                                                    "Last action must be GOTO");
272                                 return -EOPNOTSUPP;
273                         }
274                         filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
275                         filter->action.port_mask = 0;
276                         filter->action.police_ena = true;
277                         filter->action.pol_ix = OCELOT_POLICER_DISCARD;
278                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
279                         break;
280                 case FLOW_ACTION_TRAP:
281                         if (filter->block_id != VCAP_IS2) {
282                                 NL_SET_ERR_MSG_MOD(extack,
283                                                    "Trap action can only be offloaded to VCAP IS2");
284                                 return -EOPNOTSUPP;
285                         }
286                         if (filter->goto_target != -1) {
287                                 NL_SET_ERR_MSG_MOD(extack,
288                                                    "Last action must be GOTO");
289                                 return -EOPNOTSUPP;
290                         }
291                         filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
292                         filter->action.port_mask = 0;
293                         filter->action.cpu_copy_ena = true;
294                         filter->action.cpu_qu_num = 0;
295                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
296                         break;
297                 case FLOW_ACTION_POLICE:
298                         if (filter->block_id == PSFP_BLOCK_ID) {
299                                 filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
300                                 break;
301                         }
302                         if (filter->block_id != VCAP_IS2 ||
303                             filter->lookup != 0) {
304                                 NL_SET_ERR_MSG_MOD(extack,
305                                                    "Police action can only be offloaded to VCAP IS2 lookup 0 or PSFP");
306                                 return -EOPNOTSUPP;
307                         }
308                         if (filter->goto_target != -1) {
309                                 NL_SET_ERR_MSG_MOD(extack,
310                                                    "Last action must be GOTO");
311                                 return -EOPNOTSUPP;
312                         }
313                         if (a->police.rate_pkt_ps) {
314                                 NL_SET_ERR_MSG_MOD(extack,
315                                                    "QoS offload not support packets per second");
316                                 return -EOPNOTSUPP;
317                         }
318                         filter->action.police_ena = true;
319
320                         pol_ix = a->hw_index + ocelot->vcap_pol.base;
321                         pol_max = ocelot->vcap_pol.max;
322
323                         if (ocelot->vcap_pol.max2 && pol_ix > pol_max) {
324                                 pol_ix += ocelot->vcap_pol.base2 - pol_max - 1;
325                                 pol_max = ocelot->vcap_pol.max2;
326                         }
327
328                         if (pol_ix >= pol_max)
329                                 return -EINVAL;
330
331                         filter->action.pol_ix = pol_ix;
332
333                         rate = a->police.rate_bytes_ps;
334                         filter->action.pol.rate = div_u64(rate, 1000) * 8;
335                         filter->action.pol.burst = a->police.burst;
336                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
337                         break;
338                 case FLOW_ACTION_REDIRECT:
339                         if (filter->block_id != VCAP_IS2) {
340                                 NL_SET_ERR_MSG_MOD(extack,
341                                                    "Redirect action can only be offloaded to VCAP IS2");
342                                 return -EOPNOTSUPP;
343                         }
344                         if (filter->goto_target != -1) {
345                                 NL_SET_ERR_MSG_MOD(extack,
346                                                    "Last action must be GOTO");
347                                 return -EOPNOTSUPP;
348                         }
349                         egress_port = ocelot->ops->netdev_to_port(a->dev);
350                         if (egress_port < 0) {
351                                 NL_SET_ERR_MSG_MOD(extack,
352                                                    "Destination not an ocelot port");
353                                 return -EOPNOTSUPP;
354                         }
355                         filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
356                         filter->action.port_mask = BIT(egress_port);
357                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
358                         break;
359                 case FLOW_ACTION_VLAN_POP:
360                         if (filter->block_id != VCAP_IS1) {
361                                 NL_SET_ERR_MSG_MOD(extack,
362                                                    "VLAN pop action can only be offloaded to VCAP IS1");
363                                 return -EOPNOTSUPP;
364                         }
365                         if (filter->goto_target != -1) {
366                                 NL_SET_ERR_MSG_MOD(extack,
367                                                    "Last action must be GOTO");
368                                 return -EOPNOTSUPP;
369                         }
370                         filter->action.vlan_pop_cnt_ena = true;
371                         filter->action.vlan_pop_cnt++;
372                         if (filter->action.vlan_pop_cnt > 2) {
373                                 NL_SET_ERR_MSG_MOD(extack,
374                                                    "Cannot pop more than 2 VLAN headers");
375                                 return -EOPNOTSUPP;
376                         }
377                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
378                         break;
379                 case FLOW_ACTION_VLAN_MANGLE:
380                         if (filter->block_id == VCAP_IS1) {
381                                 err = ocelot_flower_parse_ingress_vlan_modify(ocelot, port,
382                                                                               filter, a,
383                                                                               extack);
384                         } else if (filter->block_id == VCAP_ES0) {
385                                 err = ocelot_flower_parse_egress_vlan_modify(filter, a,
386                                                                              extack);
387                         } else {
388                                 NL_SET_ERR_MSG_MOD(extack,
389                                                    "VLAN modify action can only be offloaded to VCAP IS1 or ES0");
390                                 err = -EOPNOTSUPP;
391                         }
392                         if (err)
393                                 return err;
394                         break;
395                 case FLOW_ACTION_PRIORITY:
396                         if (filter->block_id != VCAP_IS1) {
397                                 NL_SET_ERR_MSG_MOD(extack,
398                                                    "Priority action can only be offloaded to VCAP IS1");
399                                 return -EOPNOTSUPP;
400                         }
401                         if (filter->goto_target != -1) {
402                                 NL_SET_ERR_MSG_MOD(extack,
403                                                    "Last action must be GOTO");
404                                 return -EOPNOTSUPP;
405                         }
406                         filter->action.qos_ena = true;
407                         filter->action.qos_val = a->priority;
408                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
409                         break;
410                 case FLOW_ACTION_GOTO:
411                         filter->goto_target = a->chain_index;
412
413                         if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
414                                 int pag = ocelot_chain_to_pag(filter->goto_target);
415
416                                 filter->action.pag_override_mask = 0xff;
417                                 filter->action.pag_val = pag;
418                                 filter->type = OCELOT_VCAP_FILTER_PAG;
419                         }
420                         break;
421                 case FLOW_ACTION_VLAN_PUSH:
422                         if (filter->block_id != VCAP_ES0) {
423                                 NL_SET_ERR_MSG_MOD(extack,
424                                                    "VLAN push action can only be offloaded to VCAP ES0");
425                                 return -EOPNOTSUPP;
426                         }
427                         switch (ntohs(a->vlan.proto)) {
428                         case ETH_P_8021Q:
429                                 tpid = OCELOT_TAG_TPID_SEL_8021Q;
430                                 break;
431                         case ETH_P_8021AD:
432                                 tpid = OCELOT_TAG_TPID_SEL_8021AD;
433                                 break;
434                         default:
435                                 NL_SET_ERR_MSG_MOD(extack,
436                                                    "Cannot push custom TPID");
437                                 return -EOPNOTSUPP;
438                         }
439                         filter->action.tag_a_tpid_sel = tpid;
440                         filter->action.push_outer_tag = OCELOT_ES0_TAG;
441                         filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
442                         filter->action.vid_a_val = a->vlan.vid;
443                         filter->action.pcp_a_val = a->vlan.prio;
444                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
445                         break;
446                 case FLOW_ACTION_GATE:
447                         if (filter->block_id != PSFP_BLOCK_ID) {
448                                 NL_SET_ERR_MSG_MOD(extack,
449                                                    "Gate action can only be offloaded to PSFP chain");
450                                 return -EOPNOTSUPP;
451                         }
452                         filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
453                         break;
454                 default:
455                         NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
456                         return -EOPNOTSUPP;
457                 }
458         }
459
460         if (filter->goto_target == -1) {
461                 if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
462                     chain == 0 || filter->block_id == PSFP_BLOCK_ID) {
463                         allow_missing_goto_target = true;
464                 } else {
465                         NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
466                         return -EOPNOTSUPP;
467                 }
468         }
469
470         if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
471             !allow_missing_goto_target) {
472                 NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
473                 return -EOPNOTSUPP;
474         }
475
476         return 0;
477 }
478
479 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
480                                      struct flow_cls_offload *f,
481                                      struct ocelot_vcap_filter *filter)
482 {
483         struct flow_rule *rule = flow_cls_offload_flow_rule(f);
484         const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
485         int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
486         struct netlink_ext_ack *extack = f->common.extack;
487         struct net_device *dev, *indev;
488         struct flow_match_meta match;
489         int ingress_port;
490
491         flow_rule_match_meta(rule, &match);
492
493         if (!match.mask->ingress_ifindex)
494                 return 0;
495
496         if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
497                 NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
498                 return -EOPNOTSUPP;
499         }
500
501         dev = ocelot->ops->port_to_netdev(ocelot, port);
502         if (!dev)
503                 return -EINVAL;
504
505         indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
506         if (!indev) {
507                 NL_SET_ERR_MSG_MOD(extack,
508                                    "Can't find the ingress port to match on");
509                 return -ENOENT;
510         }
511
512         ingress_port = ocelot->ops->netdev_to_port(indev);
513         if (ingress_port < 0) {
514                 NL_SET_ERR_MSG_MOD(extack,
515                                    "Can only offload an ocelot ingress port");
516                 return -EOPNOTSUPP;
517         }
518         if (ingress_port == port) {
519                 NL_SET_ERR_MSG_MOD(extack,
520                                    "Ingress port is equal to the egress port");
521                 return -EINVAL;
522         }
523
524         filter->ingress_port.value = ingress_port;
525         filter->ingress_port.mask = GENMASK(key_length - 1, 0);
526
527         return 0;
528 }
529
530 static int
531 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
532                         struct flow_cls_offload *f,
533                         struct ocelot_vcap_filter *filter)
534 {
535         struct flow_rule *rule = flow_cls_offload_flow_rule(f);
536         struct flow_dissector *dissector = rule->match.dissector;
537         struct netlink_ext_ack *extack = f->common.extack;
538         u16 proto = ntohs(f->common.protocol);
539         bool match_protocol = true;
540         int ret;
541
542         if (dissector->used_keys &
543             ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
544               BIT(FLOW_DISSECTOR_KEY_BASIC) |
545               BIT(FLOW_DISSECTOR_KEY_META) |
546               BIT(FLOW_DISSECTOR_KEY_PORTS) |
547               BIT(FLOW_DISSECTOR_KEY_VLAN) |
548               BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
549               BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
550               BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
551                 return -EOPNOTSUPP;
552         }
553
554         /* For VCAP ES0 (egress rewriter) we can match on the ingress port */
555         if (!ingress) {
556                 ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
557                 if (ret)
558                         return ret;
559         }
560
561         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
562                 struct flow_match_control match;
563
564                 flow_rule_match_control(rule, &match);
565         }
566
567         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
568                 struct flow_match_eth_addrs match;
569
570                 if (filter->block_id == VCAP_ES0) {
571                         NL_SET_ERR_MSG_MOD(extack,
572                                            "VCAP ES0 cannot match on MAC address");
573                         return -EOPNOTSUPP;
574                 }
575
576                 /* The hw support mac matches only for MAC_ETYPE key,
577                  * therefore if other matches(port, tcp flags, etc) are added
578                  * then just bail out
579                  */
580                 if ((dissector->used_keys &
581                     (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
582                      BIT(FLOW_DISSECTOR_KEY_BASIC) |
583                      BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
584                     (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
585                      BIT(FLOW_DISSECTOR_KEY_BASIC) |
586                      BIT(FLOW_DISSECTOR_KEY_CONTROL)))
587                         return -EOPNOTSUPP;
588
589                 flow_rule_match_eth_addrs(rule, &match);
590
591                 if (filter->block_id == VCAP_IS1 &&
592                     !is_zero_ether_addr(match.mask->dst)) {
593                         NL_SET_ERR_MSG_MOD(extack,
594                                            "Key type S1_NORMAL cannot match on destination MAC");
595                         return -EOPNOTSUPP;
596                 }
597
598                 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
599                 ether_addr_copy(filter->key.etype.dmac.value,
600                                 match.key->dst);
601                 ether_addr_copy(filter->key.etype.smac.value,
602                                 match.key->src);
603                 ether_addr_copy(filter->key.etype.dmac.mask,
604                                 match.mask->dst);
605                 ether_addr_copy(filter->key.etype.smac.mask,
606                                 match.mask->src);
607                 goto finished_key_parsing;
608         }
609
610         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
611                 struct flow_match_basic match;
612
613                 flow_rule_match_basic(rule, &match);
614                 if (ntohs(match.key->n_proto) == ETH_P_IP) {
615                         if (filter->block_id == VCAP_ES0) {
616                                 NL_SET_ERR_MSG_MOD(extack,
617                                                    "VCAP ES0 cannot match on IP protocol");
618                                 return -EOPNOTSUPP;
619                         }
620
621                         filter->key_type = OCELOT_VCAP_KEY_IPV4;
622                         filter->key.ipv4.proto.value[0] =
623                                 match.key->ip_proto;
624                         filter->key.ipv4.proto.mask[0] =
625                                 match.mask->ip_proto;
626                         match_protocol = false;
627                 }
628                 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
629                         if (filter->block_id == VCAP_ES0) {
630                                 NL_SET_ERR_MSG_MOD(extack,
631                                                    "VCAP ES0 cannot match on IP protocol");
632                                 return -EOPNOTSUPP;
633                         }
634
635                         filter->key_type = OCELOT_VCAP_KEY_IPV6;
636                         filter->key.ipv6.proto.value[0] =
637                                 match.key->ip_proto;
638                         filter->key.ipv6.proto.mask[0] =
639                                 match.mask->ip_proto;
640                         match_protocol = false;
641                 }
642         }
643
644         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
645             proto == ETH_P_IP) {
646                 struct flow_match_ipv4_addrs match;
647                 u8 *tmp;
648
649                 if (filter->block_id == VCAP_ES0) {
650                         NL_SET_ERR_MSG_MOD(extack,
651                                            "VCAP ES0 cannot match on IP address");
652                         return -EOPNOTSUPP;
653                 }
654
655                 flow_rule_match_ipv4_addrs(rule, &match);
656
657                 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
658                         NL_SET_ERR_MSG_MOD(extack,
659                                            "Key type S1_NORMAL cannot match on destination IP");
660                         return -EOPNOTSUPP;
661                 }
662
663                 tmp = &filter->key.ipv4.sip.value.addr[0];
664                 memcpy(tmp, &match.key->src, 4);
665
666                 tmp = &filter->key.ipv4.sip.mask.addr[0];
667                 memcpy(tmp, &match.mask->src, 4);
668
669                 tmp = &filter->key.ipv4.dip.value.addr[0];
670                 memcpy(tmp, &match.key->dst, 4);
671
672                 tmp = &filter->key.ipv4.dip.mask.addr[0];
673                 memcpy(tmp, &match.mask->dst, 4);
674                 match_protocol = false;
675         }
676
677         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
678             proto == ETH_P_IPV6) {
679                 return -EOPNOTSUPP;
680         }
681
682         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
683                 struct flow_match_ports match;
684
685                 if (filter->block_id == VCAP_ES0) {
686                         NL_SET_ERR_MSG_MOD(extack,
687                                            "VCAP ES0 cannot match on L4 ports");
688                         return -EOPNOTSUPP;
689                 }
690
691                 flow_rule_match_ports(rule, &match);
692                 filter->key.ipv4.sport.value = ntohs(match.key->src);
693                 filter->key.ipv4.sport.mask = ntohs(match.mask->src);
694                 filter->key.ipv4.dport.value = ntohs(match.key->dst);
695                 filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
696                 match_protocol = false;
697         }
698
699         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
700                 struct flow_match_vlan match;
701
702                 flow_rule_match_vlan(rule, &match);
703                 filter->key_type = OCELOT_VCAP_KEY_ANY;
704                 filter->vlan.vid.value = match.key->vlan_id;
705                 filter->vlan.vid.mask = match.mask->vlan_id;
706                 filter->vlan.pcp.value[0] = match.key->vlan_priority;
707                 filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
708                 match_protocol = false;
709         }
710
711 finished_key_parsing:
712         if (match_protocol && proto != ETH_P_ALL) {
713                 if (filter->block_id == VCAP_ES0) {
714                         NL_SET_ERR_MSG_MOD(extack,
715                                            "VCAP ES0 cannot match on L2 proto");
716                         return -EOPNOTSUPP;
717                 }
718
719                 /* TODO: support SNAP, LLC etc */
720                 if (proto < ETH_P_802_3_MIN)
721                         return -EOPNOTSUPP;
722                 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
723                 *(__be16 *)filter->key.etype.etype.value = htons(proto);
724                 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
725         }
726         /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
727
728         return 0;
729 }
730
731 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
732                                struct flow_cls_offload *f,
733                                struct ocelot_vcap_filter *filter)
734 {
735         int ret;
736
737         filter->prio = f->common.prio;
738         filter->id.cookie = f->cookie;
739         filter->id.tc_offload = true;
740
741         ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
742         if (ret)
743                 return ret;
744
745         /* PSFP filter need to parse key by stream identification function. */
746         if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
747                 return 0;
748
749         return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
750 }
751
752 static struct ocelot_vcap_filter
753 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
754                            struct flow_cls_offload *f)
755 {
756         struct ocelot_vcap_filter *filter;
757
758         filter = kzalloc(sizeof(*filter), GFP_KERNEL);
759         if (!filter)
760                 return NULL;
761
762         if (ingress) {
763                 filter->ingress_port_mask = BIT(port);
764         } else {
765                 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
766                 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
767
768                 filter->egress_port.value = port;
769                 filter->egress_port.mask = GENMASK(key_length - 1, 0);
770         }
771
772         return filter;
773 }
774
775 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
776                                         struct ocelot_vcap_filter *filter)
777 {
778         list_add(&filter->list, &ocelot->dummy_rules);
779
780         return 0;
781 }
782
783 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
784                                         struct ocelot_vcap_filter *filter)
785 {
786         list_del(&filter->list);
787         kfree(filter);
788
789         return 0;
790 }
791
792 /* If we have an egress VLAN modification rule, we need to actually write the
793  * delta between the input VLAN (from the key) and the output VLAN (from the
794  * action), but the action was parsed first. So we need to patch the delta into
795  * the action here.
796  */
797 static int
798 ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
799                                     struct netlink_ext_ack *extack)
800 {
801         if (filter->block_id != VCAP_ES0 ||
802             filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
803                 return 0;
804
805         if (filter->vlan.vid.mask != VLAN_VID_MASK) {
806                 NL_SET_ERR_MSG_MOD(extack,
807                                    "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
808                 return -EOPNOTSUPP;
809         }
810
811         filter->action.vid_a_val -= filter->vlan.vid.value;
812         filter->action.vid_a_val &= VLAN_VID_MASK;
813
814         return 0;
815 }
816
817 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
818                               struct flow_cls_offload *f, bool ingress)
819 {
820         struct netlink_ext_ack *extack = f->common.extack;
821         struct ocelot_vcap_filter *filter;
822         int chain = f->common.chain_index;
823         int block_id, ret;
824
825         if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
826                 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
827                 return -EOPNOTSUPP;
828         }
829
830         block_id = ocelot_chain_to_block(chain, ingress);
831         if (block_id < 0) {
832                 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
833                 return -EOPNOTSUPP;
834         }
835
836         filter = ocelot_vcap_block_find_filter_by_id(&ocelot->block[block_id],
837                                                      f->cookie, true);
838         if (filter) {
839                 /* Filter already exists on other ports */
840                 if (!ingress) {
841                         NL_SET_ERR_MSG_MOD(extack, "VCAP ES0 does not support shared filters");
842                         return -EOPNOTSUPP;
843                 }
844
845                 filter->ingress_port_mask |= BIT(port);
846
847                 return ocelot_vcap_filter_replace(ocelot, filter);
848         }
849
850         /* Filter didn't exist, create it now */
851         filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
852         if (!filter)
853                 return -ENOMEM;
854
855         ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
856         if (ret) {
857                 kfree(filter);
858                 return ret;
859         }
860
861         ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
862         if (ret) {
863                 kfree(filter);
864                 return ret;
865         }
866
867         /* The non-optional GOTOs for the TCAM skeleton don't need
868          * to be actually offloaded.
869          */
870         if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
871                 return ocelot_vcap_dummy_filter_add(ocelot, filter);
872
873         if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
874                 kfree(filter);
875                 if (ocelot->ops->psfp_filter_add)
876                         return ocelot->ops->psfp_filter_add(ocelot, port, f);
877
878                 NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
879                 return -EOPNOTSUPP;
880         }
881
882         return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
883 }
884 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
885
886 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
887                               struct flow_cls_offload *f, bool ingress)
888 {
889         struct ocelot_vcap_filter *filter;
890         struct ocelot_vcap_block *block;
891         int block_id;
892
893         block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
894         if (block_id < 0)
895                 return 0;
896
897         if (block_id == PSFP_BLOCK_ID) {
898                 if (ocelot->ops->psfp_filter_del)
899                         return ocelot->ops->psfp_filter_del(ocelot, f);
900
901                 return -EOPNOTSUPP;
902         }
903
904         block = &ocelot->block[block_id];
905
906         filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
907         if (!filter)
908                 return 0;
909
910         if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
911                 return ocelot_vcap_dummy_filter_del(ocelot, filter);
912
913         if (ingress) {
914                 filter->ingress_port_mask &= ~BIT(port);
915                 if (filter->ingress_port_mask)
916                         return ocelot_vcap_filter_replace(ocelot, filter);
917         }
918
919         return ocelot_vcap_filter_del(ocelot, filter);
920 }
921 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
922
923 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
924                             struct flow_cls_offload *f, bool ingress)
925 {
926         struct ocelot_vcap_filter *filter;
927         struct ocelot_vcap_block *block;
928         struct flow_stats stats = {0};
929         int block_id, ret;
930
931         block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
932         if (block_id < 0)
933                 return 0;
934
935         if (block_id == PSFP_BLOCK_ID) {
936                 if (ocelot->ops->psfp_stats_get) {
937                         ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
938                         if (ret)
939                                 return ret;
940
941                         goto stats_update;
942                 }
943
944                 return -EOPNOTSUPP;
945         }
946
947         block = &ocelot->block[block_id];
948
949         filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
950         if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
951                 return 0;
952
953         ret = ocelot_vcap_filter_stats_update(ocelot, filter);
954         if (ret)
955                 return ret;
956
957         stats.pkts = filter->stats.pkts;
958
959 stats_update:
960         flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
961                           FLOW_ACTION_HW_STATS_IMMEDIATE);
962         return 0;
963 }
964 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);