Merge tags 'ib-mfd-clk-gpio-regulator-rtc-v5.13', 'ib-mfd-extcon-v5.13', 'ib-mfd...
[sfrench/cifs-2.6.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
24 static int ocelot_chain_to_block(int chain, bool ingress)
25 {
26         int lookup, pag;
27
28         if (!ingress) {
29                 if (chain == 0)
30                         return VCAP_ES0;
31                 return -EOPNOTSUPP;
32         }
33
34         /* Backwards compatibility with older, single-chain tc-flower
35          * offload support in Ocelot
36          */
37         if (chain == 0)
38                 return VCAP_IS2;
39
40         for (lookup = 0; lookup < VCAP_IS1_NUM_LOOKUPS; lookup++)
41                 if (chain == VCAP_IS1_CHAIN(lookup))
42                         return VCAP_IS1;
43
44         for (lookup = 0; lookup < VCAP_IS2_NUM_LOOKUPS; lookup++)
45                 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
46                         if (chain == VCAP_IS2_CHAIN(lookup, pag))
47                                 return VCAP_IS2;
48
49         return -EOPNOTSUPP;
50 }
51
52 /* Caller must ensure this is a valid IS1 or IS2 chain first,
53  * by calling ocelot_chain_to_block.
54  */
55 static int ocelot_chain_to_lookup(int chain)
56 {
57         return (chain / VCAP_LOOKUP) % 10;
58 }
59
60 /* Caller must ensure this is a valid IS2 chain first,
61  * by calling ocelot_chain_to_block.
62  */
63 static int ocelot_chain_to_pag(int chain)
64 {
65         int lookup = ocelot_chain_to_lookup(chain);
66
67         /* calculate PAG value as chain index relative to the first PAG */
68         return chain - VCAP_IS2_CHAIN(lookup, 0);
69 }
70
71 static bool ocelot_is_goto_target_valid(int goto_target, int chain,
72                                         bool ingress)
73 {
74         int pag;
75
76         /* Can't offload GOTO in VCAP ES0 */
77         if (!ingress)
78                 return (goto_target < 0);
79
80         /* Non-optional GOTOs */
81         if (chain == 0)
82                 /* VCAP IS1 can be skipped, either partially or completely */
83                 return (goto_target == VCAP_IS1_CHAIN(0) ||
84                         goto_target == VCAP_IS1_CHAIN(1) ||
85                         goto_target == VCAP_IS1_CHAIN(2) ||
86                         goto_target == VCAP_IS2_CHAIN(0, 0) ||
87                         goto_target == VCAP_IS2_CHAIN(1, 0));
88
89         if (chain == VCAP_IS1_CHAIN(0))
90                 return (goto_target == VCAP_IS1_CHAIN(1));
91
92         if (chain == VCAP_IS1_CHAIN(1))
93                 return (goto_target == VCAP_IS1_CHAIN(2));
94
95         /* Lookup 2 of VCAP IS1 can really support non-optional GOTOs,
96          * using a Policy Association Group (PAG) value, which is an 8-bit
97          * value encoding a VCAP IS2 target chain.
98          */
99         if (chain == VCAP_IS1_CHAIN(2)) {
100                 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
101                         if (goto_target == VCAP_IS2_CHAIN(0, pag))
102                                 return true;
103
104                 return false;
105         }
106
107         /* Non-optional GOTO from VCAP IS2 lookup 0 to lookup 1.
108          * We cannot change the PAG at this point.
109          */
110         for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
111                 if (chain == VCAP_IS2_CHAIN(0, pag))
112                         return (goto_target == VCAP_IS2_CHAIN(1, pag));
113
114         /* VCAP IS2 lookup 1 cannot jump anywhere */
115         return false;
116 }
117
118 static struct ocelot_vcap_filter *
119 ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain)
120 {
121         struct ocelot_vcap_filter *filter;
122         struct ocelot_vcap_block *block;
123         int block_id;
124
125         block_id = ocelot_chain_to_block(chain, true);
126         if (block_id < 0)
127                 return NULL;
128
129         if (block_id == VCAP_IS2) {
130                 block = &ocelot->block[VCAP_IS1];
131
132                 list_for_each_entry(filter, &block->rules, list)
133                         if (filter->type == OCELOT_VCAP_FILTER_PAG &&
134                             filter->goto_target == chain)
135                                 return filter;
136         }
137
138         list_for_each_entry(filter, &ocelot->dummy_rules, list)
139                 if (filter->goto_target == chain)
140                         return filter;
141
142         return NULL;
143 }
144
145 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
146                                       bool ingress, struct flow_cls_offload *f,
147                                       struct ocelot_vcap_filter *filter)
148 {
149         struct ocelot_port *ocelot_port = ocelot->ports[port];
150         struct netlink_ext_ack *extack = f->common.extack;
151         bool allow_missing_goto_target = false;
152         const struct flow_action_entry *a;
153         enum ocelot_tag_tpid_sel tpid;
154         int i, chain, egress_port;
155         u64 rate;
156
157         if (!flow_action_basic_hw_stats_check(&f->rule->action,
158                                               f->common.extack))
159                 return -EOPNOTSUPP;
160
161         chain = f->common.chain_index;
162         filter->block_id = ocelot_chain_to_block(chain, ingress);
163         if (filter->block_id < 0) {
164                 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
165                 return -EOPNOTSUPP;
166         }
167         if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
168                 filter->lookup = ocelot_chain_to_lookup(chain);
169         if (filter->block_id == VCAP_IS2)
170                 filter->pag = ocelot_chain_to_pag(chain);
171
172         filter->goto_target = -1;
173         filter->type = OCELOT_VCAP_FILTER_DUMMY;
174
175         flow_action_for_each(i, a, &f->rule->action) {
176                 switch (a->id) {
177                 case FLOW_ACTION_DROP:
178                         if (filter->block_id != VCAP_IS2) {
179                                 NL_SET_ERR_MSG_MOD(extack,
180                                                    "Drop action can only be offloaded to VCAP IS2");
181                                 return -EOPNOTSUPP;
182                         }
183                         if (filter->goto_target != -1) {
184                                 NL_SET_ERR_MSG_MOD(extack,
185                                                    "Last action must be GOTO");
186                                 return -EOPNOTSUPP;
187                         }
188                         filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
189                         filter->action.port_mask = 0;
190                         filter->action.police_ena = true;
191                         filter->action.pol_ix = OCELOT_POLICER_DISCARD;
192                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
193                         break;
194                 case FLOW_ACTION_TRAP:
195                         if (filter->block_id != VCAP_IS2) {
196                                 NL_SET_ERR_MSG_MOD(extack,
197                                                    "Trap action can only be offloaded to VCAP IS2");
198                                 return -EOPNOTSUPP;
199                         }
200                         if (filter->goto_target != -1) {
201                                 NL_SET_ERR_MSG_MOD(extack,
202                                                    "Last action must be GOTO");
203                                 return -EOPNOTSUPP;
204                         }
205                         filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
206                         filter->action.port_mask = 0;
207                         filter->action.cpu_copy_ena = true;
208                         filter->action.cpu_qu_num = 0;
209                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
210                         break;
211                 case FLOW_ACTION_POLICE:
212                         if (filter->block_id != VCAP_IS2 ||
213                             filter->lookup != 0) {
214                                 NL_SET_ERR_MSG_MOD(extack,
215                                                    "Police action can only be offloaded to VCAP IS2 lookup 0");
216                                 return -EOPNOTSUPP;
217                         }
218                         if (filter->goto_target != -1) {
219                                 NL_SET_ERR_MSG_MOD(extack,
220                                                    "Last action must be GOTO");
221                                 return -EOPNOTSUPP;
222                         }
223                         filter->action.police_ena = true;
224                         rate = a->police.rate_bytes_ps;
225                         filter->action.pol.rate = div_u64(rate, 1000) * 8;
226                         filter->action.pol.burst = a->police.burst;
227                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
228                         break;
229                 case FLOW_ACTION_REDIRECT:
230                         if (filter->block_id != VCAP_IS2) {
231                                 NL_SET_ERR_MSG_MOD(extack,
232                                                    "Redirect action can only be offloaded to VCAP IS2");
233                                 return -EOPNOTSUPP;
234                         }
235                         if (filter->goto_target != -1) {
236                                 NL_SET_ERR_MSG_MOD(extack,
237                                                    "Last action must be GOTO");
238                                 return -EOPNOTSUPP;
239                         }
240                         egress_port = ocelot->ops->netdev_to_port(a->dev);
241                         if (egress_port < 0) {
242                                 NL_SET_ERR_MSG_MOD(extack,
243                                                    "Destination not an ocelot port");
244                                 return -EOPNOTSUPP;
245                         }
246                         filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
247                         filter->action.port_mask = BIT(egress_port);
248                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
249                         break;
250                 case FLOW_ACTION_VLAN_POP:
251                         if (filter->block_id != VCAP_IS1) {
252                                 NL_SET_ERR_MSG_MOD(extack,
253                                                    "VLAN pop action can only be offloaded to VCAP IS1");
254                                 return -EOPNOTSUPP;
255                         }
256                         if (filter->goto_target != -1) {
257                                 NL_SET_ERR_MSG_MOD(extack,
258                                                    "Last action must be GOTO");
259                                 return -EOPNOTSUPP;
260                         }
261                         filter->action.vlan_pop_cnt_ena = true;
262                         filter->action.vlan_pop_cnt++;
263                         if (filter->action.vlan_pop_cnt > 2) {
264                                 NL_SET_ERR_MSG_MOD(extack,
265                                                    "Cannot pop more than 2 VLAN headers");
266                                 return -EOPNOTSUPP;
267                         }
268                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
269                         break;
270                 case FLOW_ACTION_VLAN_MANGLE:
271                         if (filter->block_id != VCAP_IS1) {
272                                 NL_SET_ERR_MSG_MOD(extack,
273                                                    "VLAN modify action can only be offloaded to VCAP IS1");
274                                 return -EOPNOTSUPP;
275                         }
276                         if (filter->goto_target != -1) {
277                                 NL_SET_ERR_MSG_MOD(extack,
278                                                    "Last action must be GOTO");
279                                 return -EOPNOTSUPP;
280                         }
281                         if (!ocelot_port->vlan_aware) {
282                                 NL_SET_ERR_MSG_MOD(extack,
283                                                    "Can only modify VLAN under VLAN aware bridge");
284                                 return -EOPNOTSUPP;
285                         }
286                         filter->action.vid_replace_ena = true;
287                         filter->action.pcp_dei_ena = true;
288                         filter->action.vid = a->vlan.vid;
289                         filter->action.pcp = a->vlan.prio;
290                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
291                         break;
292                 case FLOW_ACTION_PRIORITY:
293                         if (filter->block_id != VCAP_IS1) {
294                                 NL_SET_ERR_MSG_MOD(extack,
295                                                    "Priority action can only be offloaded to VCAP IS1");
296                                 return -EOPNOTSUPP;
297                         }
298                         if (filter->goto_target != -1) {
299                                 NL_SET_ERR_MSG_MOD(extack,
300                                                    "Last action must be GOTO");
301                                 return -EOPNOTSUPP;
302                         }
303                         filter->action.qos_ena = true;
304                         filter->action.qos_val = a->priority;
305                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
306                         break;
307                 case FLOW_ACTION_GOTO:
308                         filter->goto_target = a->chain_index;
309
310                         if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
311                                 int pag = ocelot_chain_to_pag(filter->goto_target);
312
313                                 filter->action.pag_override_mask = 0xff;
314                                 filter->action.pag_val = pag;
315                                 filter->type = OCELOT_VCAP_FILTER_PAG;
316                         }
317                         break;
318                 case FLOW_ACTION_VLAN_PUSH:
319                         if (filter->block_id != VCAP_ES0) {
320                                 NL_SET_ERR_MSG_MOD(extack,
321                                                    "VLAN push action can only be offloaded to VCAP ES0");
322                                 return -EOPNOTSUPP;
323                         }
324                         switch (ntohs(a->vlan.proto)) {
325                         case ETH_P_8021Q:
326                                 tpid = OCELOT_TAG_TPID_SEL_8021Q;
327                                 break;
328                         case ETH_P_8021AD:
329                                 tpid = OCELOT_TAG_TPID_SEL_8021AD;
330                                 break;
331                         default:
332                                 NL_SET_ERR_MSG_MOD(extack,
333                                                    "Cannot push custom TPID");
334                                 return -EOPNOTSUPP;
335                         }
336                         filter->action.tag_a_tpid_sel = tpid;
337                         filter->action.push_outer_tag = OCELOT_ES0_TAG;
338                         filter->action.tag_a_vid_sel = 1;
339                         filter->action.vid_a_val = a->vlan.vid;
340                         filter->action.pcp_a_val = a->vlan.prio;
341                         filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
342                         break;
343                 default:
344                         NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
345                         return -EOPNOTSUPP;
346                 }
347         }
348
349         if (filter->goto_target == -1) {
350                 if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
351                     chain == 0) {
352                         allow_missing_goto_target = true;
353                 } else {
354                         NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
355                         return -EOPNOTSUPP;
356                 }
357         }
358
359         if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
360             !allow_missing_goto_target) {
361                 NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
362                 return -EOPNOTSUPP;
363         }
364
365         return 0;
366 }
367
368 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
369                                      struct flow_cls_offload *f,
370                                      struct ocelot_vcap_filter *filter)
371 {
372         struct flow_rule *rule = flow_cls_offload_flow_rule(f);
373         const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
374         int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
375         struct netlink_ext_ack *extack = f->common.extack;
376         struct net_device *dev, *indev;
377         struct flow_match_meta match;
378         int ingress_port;
379
380         flow_rule_match_meta(rule, &match);
381
382         if (!match.mask->ingress_ifindex)
383                 return 0;
384
385         if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
386                 NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
387                 return -EOPNOTSUPP;
388         }
389
390         dev = ocelot->ops->port_to_netdev(ocelot, port);
391         if (!dev)
392                 return -EINVAL;
393
394         indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
395         if (!indev) {
396                 NL_SET_ERR_MSG_MOD(extack,
397                                    "Can't find the ingress port to match on");
398                 return -ENOENT;
399         }
400
401         ingress_port = ocelot->ops->netdev_to_port(indev);
402         if (ingress_port < 0) {
403                 NL_SET_ERR_MSG_MOD(extack,
404                                    "Can only offload an ocelot ingress port");
405                 return -EOPNOTSUPP;
406         }
407         if (ingress_port == port) {
408                 NL_SET_ERR_MSG_MOD(extack,
409                                    "Ingress port is equal to the egress port");
410                 return -EINVAL;
411         }
412
413         filter->ingress_port.value = ingress_port;
414         filter->ingress_port.mask = GENMASK(key_length - 1, 0);
415
416         return 0;
417 }
418
419 static int
420 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
421                         struct flow_cls_offload *f,
422                         struct ocelot_vcap_filter *filter)
423 {
424         struct flow_rule *rule = flow_cls_offload_flow_rule(f);
425         struct flow_dissector *dissector = rule->match.dissector;
426         struct netlink_ext_ack *extack = f->common.extack;
427         u16 proto = ntohs(f->common.protocol);
428         bool match_protocol = true;
429         int ret;
430
431         if (dissector->used_keys &
432             ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
433               BIT(FLOW_DISSECTOR_KEY_BASIC) |
434               BIT(FLOW_DISSECTOR_KEY_META) |
435               BIT(FLOW_DISSECTOR_KEY_PORTS) |
436               BIT(FLOW_DISSECTOR_KEY_VLAN) |
437               BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
438               BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
439               BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
440                 return -EOPNOTSUPP;
441         }
442
443         /* For VCAP ES0 (egress rewriter) we can match on the ingress port */
444         if (!ingress) {
445                 ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
446                 if (ret)
447                         return ret;
448         }
449
450         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
451                 struct flow_match_control match;
452
453                 flow_rule_match_control(rule, &match);
454         }
455
456         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
457                 struct flow_match_eth_addrs match;
458
459                 if (filter->block_id == VCAP_ES0) {
460                         NL_SET_ERR_MSG_MOD(extack,
461                                            "VCAP ES0 cannot match on MAC address");
462                         return -EOPNOTSUPP;
463                 }
464
465                 if (filter->block_id == VCAP_IS1 &&
466                     !is_zero_ether_addr(match.mask->dst)) {
467                         NL_SET_ERR_MSG_MOD(extack,
468                                            "Key type S1_NORMAL cannot match on destination MAC");
469                         return -EOPNOTSUPP;
470                 }
471
472                 /* The hw support mac matches only for MAC_ETYPE key,
473                  * therefore if other matches(port, tcp flags, etc) are added
474                  * then just bail out
475                  */
476                 if ((dissector->used_keys &
477                     (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
478                      BIT(FLOW_DISSECTOR_KEY_BASIC) |
479                      BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
480                     (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
481                      BIT(FLOW_DISSECTOR_KEY_BASIC) |
482                      BIT(FLOW_DISSECTOR_KEY_CONTROL)))
483                         return -EOPNOTSUPP;
484
485                 flow_rule_match_eth_addrs(rule, &match);
486                 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
487                 ether_addr_copy(filter->key.etype.dmac.value,
488                                 match.key->dst);
489                 ether_addr_copy(filter->key.etype.smac.value,
490                                 match.key->src);
491                 ether_addr_copy(filter->key.etype.dmac.mask,
492                                 match.mask->dst);
493                 ether_addr_copy(filter->key.etype.smac.mask,
494                                 match.mask->src);
495                 goto finished_key_parsing;
496         }
497
498         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
499                 struct flow_match_basic match;
500
501                 flow_rule_match_basic(rule, &match);
502                 if (ntohs(match.key->n_proto) == ETH_P_IP) {
503                         if (filter->block_id == VCAP_ES0) {
504                                 NL_SET_ERR_MSG_MOD(extack,
505                                                    "VCAP ES0 cannot match on IP protocol");
506                                 return -EOPNOTSUPP;
507                         }
508
509                         filter->key_type = OCELOT_VCAP_KEY_IPV4;
510                         filter->key.ipv4.proto.value[0] =
511                                 match.key->ip_proto;
512                         filter->key.ipv4.proto.mask[0] =
513                                 match.mask->ip_proto;
514                         match_protocol = false;
515                 }
516                 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
517                         if (filter->block_id == VCAP_ES0) {
518                                 NL_SET_ERR_MSG_MOD(extack,
519                                                    "VCAP ES0 cannot match on IP protocol");
520                                 return -EOPNOTSUPP;
521                         }
522
523                         filter->key_type = OCELOT_VCAP_KEY_IPV6;
524                         filter->key.ipv6.proto.value[0] =
525                                 match.key->ip_proto;
526                         filter->key.ipv6.proto.mask[0] =
527                                 match.mask->ip_proto;
528                         match_protocol = false;
529                 }
530         }
531
532         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
533             proto == ETH_P_IP) {
534                 struct flow_match_ipv4_addrs match;
535                 u8 *tmp;
536
537                 if (filter->block_id == VCAP_ES0) {
538                         NL_SET_ERR_MSG_MOD(extack,
539                                            "VCAP ES0 cannot match on IP address");
540                         return -EOPNOTSUPP;
541                 }
542
543                 flow_rule_match_ipv4_addrs(rule, &match);
544
545                 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
546                         NL_SET_ERR_MSG_MOD(extack,
547                                            "Key type S1_NORMAL cannot match on destination IP");
548                         return -EOPNOTSUPP;
549                 }
550
551                 tmp = &filter->key.ipv4.sip.value.addr[0];
552                 memcpy(tmp, &match.key->src, 4);
553
554                 tmp = &filter->key.ipv4.sip.mask.addr[0];
555                 memcpy(tmp, &match.mask->src, 4);
556
557                 tmp = &filter->key.ipv4.dip.value.addr[0];
558                 memcpy(tmp, &match.key->dst, 4);
559
560                 tmp = &filter->key.ipv4.dip.mask.addr[0];
561                 memcpy(tmp, &match.mask->dst, 4);
562                 match_protocol = false;
563         }
564
565         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
566             proto == ETH_P_IPV6) {
567                 return -EOPNOTSUPP;
568         }
569
570         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
571                 struct flow_match_ports match;
572
573                 if (filter->block_id == VCAP_ES0) {
574                         NL_SET_ERR_MSG_MOD(extack,
575                                            "VCAP ES0 cannot match on L4 ports");
576                         return -EOPNOTSUPP;
577                 }
578
579                 flow_rule_match_ports(rule, &match);
580                 filter->key.ipv4.sport.value = ntohs(match.key->src);
581                 filter->key.ipv4.sport.mask = ntohs(match.mask->src);
582                 filter->key.ipv4.dport.value = ntohs(match.key->dst);
583                 filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
584                 match_protocol = false;
585         }
586
587         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
588                 struct flow_match_vlan match;
589
590                 flow_rule_match_vlan(rule, &match);
591                 filter->key_type = OCELOT_VCAP_KEY_ANY;
592                 filter->vlan.vid.value = match.key->vlan_id;
593                 filter->vlan.vid.mask = match.mask->vlan_id;
594                 filter->vlan.pcp.value[0] = match.key->vlan_priority;
595                 filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
596                 match_protocol = false;
597         }
598
599 finished_key_parsing:
600         if (match_protocol && proto != ETH_P_ALL) {
601                 if (filter->block_id == VCAP_ES0) {
602                         NL_SET_ERR_MSG_MOD(extack,
603                                            "VCAP ES0 cannot match on L2 proto");
604                         return -EOPNOTSUPP;
605                 }
606
607                 /* TODO: support SNAP, LLC etc */
608                 if (proto < ETH_P_802_3_MIN)
609                         return -EOPNOTSUPP;
610                 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
611                 *(__be16 *)filter->key.etype.etype.value = htons(proto);
612                 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
613         }
614         /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
615
616         return 0;
617 }
618
619 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
620                                struct flow_cls_offload *f,
621                                struct ocelot_vcap_filter *filter)
622 {
623         int ret;
624
625         filter->prio = f->common.prio;
626         filter->id.cookie = f->cookie;
627         filter->id.tc_offload = true;
628
629         ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
630         if (ret)
631                 return ret;
632
633         return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
634 }
635
636 static struct ocelot_vcap_filter
637 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
638                            struct flow_cls_offload *f)
639 {
640         struct ocelot_vcap_filter *filter;
641
642         filter = kzalloc(sizeof(*filter), GFP_KERNEL);
643         if (!filter)
644                 return NULL;
645
646         if (ingress) {
647                 filter->ingress_port_mask = BIT(port);
648         } else {
649                 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
650                 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
651
652                 filter->egress_port.value = port;
653                 filter->egress_port.mask = GENMASK(key_length - 1, 0);
654         }
655
656         return filter;
657 }
658
659 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
660                                         struct ocelot_vcap_filter *filter)
661 {
662         list_add(&filter->list, &ocelot->dummy_rules);
663
664         return 0;
665 }
666
667 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
668                                         struct ocelot_vcap_filter *filter)
669 {
670         list_del(&filter->list);
671         kfree(filter);
672
673         return 0;
674 }
675
676 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
677                               struct flow_cls_offload *f, bool ingress)
678 {
679         struct netlink_ext_ack *extack = f->common.extack;
680         struct ocelot_vcap_filter *filter;
681         int chain = f->common.chain_index;
682         int ret;
683
684         if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
685                 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
686                 return -EOPNOTSUPP;
687         }
688
689         filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
690         if (!filter)
691                 return -ENOMEM;
692
693         ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
694         if (ret) {
695                 kfree(filter);
696                 return ret;
697         }
698
699         /* The non-optional GOTOs for the TCAM skeleton don't need
700          * to be actually offloaded.
701          */
702         if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
703                 return ocelot_vcap_dummy_filter_add(ocelot, filter);
704
705         return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
706 }
707 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
708
709 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
710                               struct flow_cls_offload *f, bool ingress)
711 {
712         struct ocelot_vcap_filter *filter;
713         struct ocelot_vcap_block *block;
714         int block_id;
715
716         block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
717         if (block_id < 0)
718                 return 0;
719
720         block = &ocelot->block[block_id];
721
722         filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
723         if (!filter)
724                 return 0;
725
726         if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
727                 return ocelot_vcap_dummy_filter_del(ocelot, filter);
728
729         return ocelot_vcap_filter_del(ocelot, filter);
730 }
731 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
732
733 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
734                             struct flow_cls_offload *f, bool ingress)
735 {
736         struct ocelot_vcap_filter *filter;
737         struct ocelot_vcap_block *block;
738         int block_id, ret;
739
740         block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
741         if (block_id < 0)
742                 return 0;
743
744         block = &ocelot->block[block_id];
745
746         filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
747         if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
748                 return 0;
749
750         ret = ocelot_vcap_filter_stats_update(ocelot, filter);
751         if (ret)
752                 return ret;
753
754         flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
755                           FLOW_ACTION_HW_STATS_IMMEDIATE);
756         return 0;
757 }
758 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);