Merge tag 'bootconfig-fixes-v6.9-rc4' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / drivers / net / ethernet / microchip / sparx5 / sparx5_tc_flower.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip VCAP API
3  *
4  * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5  */
6
7 #include <net/tc_act/tc_gate.h>
8 #include <net/tcp.h>
9
10 #include "sparx5_tc.h"
11 #include "vcap_api.h"
12 #include "vcap_api_client.h"
13 #include "vcap_tc.h"
14 #include "sparx5_main.h"
15 #include "sparx5_vcap_impl.h"
16
17 #define SPX5_MAX_RULE_SIZE 13 /* allows X1, X2, X4, X6 and X12 rules */
18
19 /* Collect keysets and type ids for multiple rules per size */
20 struct sparx5_wildcard_rule {
21         bool selected;
22         u8 value;
23         u8 mask;
24         enum vcap_keyfield_set keyset;
25 };
26
27 struct sparx5_multiple_rules {
28         struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE];
29 };
30
31 struct sparx5_tc_flower_template {
32         struct list_head list; /* for insertion in the list of templates */
33         int cid; /* chain id */
34         enum vcap_keyfield_set orig; /* keyset used before the template */
35         enum vcap_keyfield_set keyset; /* new keyset used by template */
36         u16 l3_proto; /* protocol specified in the template */
37 };
38
39 /* SparX-5 VCAP fragment types:
40  * 0 = no fragment, 1 = initial fragment,
41  * 2 = suspicious fragment, 3 = valid follow-up fragment
42  */
43 enum {                   /* key / mask */
44         FRAG_NOT   = 0x03, /* 0 / 3 */
45         FRAG_SOME  = 0x11, /* 1 / 1 */
46         FRAG_FIRST = 0x13, /* 1 / 3 */
47         FRAG_LATER = 0x33, /* 3 / 3 */
48         FRAG_INVAL = 0xff, /* invalid */
49 };
50
51 /* Flower fragment flag to VCAP fragment type mapping */
52 static const u8 sparx5_vcap_frag_map[4][4] = {            /* is_frag */
53         { FRAG_INVAL, FRAG_INVAL, FRAG_INVAL, FRAG_FIRST }, /* 0/0 */
54         { FRAG_NOT,   FRAG_NOT,   FRAG_INVAL, FRAG_INVAL }, /* 0/1 */
55         { FRAG_INVAL, FRAG_INVAL, FRAG_INVAL, FRAG_INVAL }, /* 1/0 */
56         { FRAG_SOME,  FRAG_LATER, FRAG_INVAL, FRAG_FIRST }  /* 1/1 */
57         /* 0/0        0/1         1/0         1/1 <-- first_frag */
58 };
59
60 static int
61 sparx5_tc_flower_es0_tpid(struct vcap_tc_flower_parse_usage *st)
62 {
63         int err = 0;
64
65         switch (st->tpid) {
66         case ETH_P_8021Q:
67                 err = vcap_rule_add_key_u32(st->vrule,
68                                             VCAP_KF_8021Q_TPID,
69                                             SPX5_TPID_SEL_8100, ~0);
70                 break;
71         case ETH_P_8021AD:
72                 err = vcap_rule_add_key_u32(st->vrule,
73                                             VCAP_KF_8021Q_TPID,
74                                             SPX5_TPID_SEL_88A8, ~0);
75                 break;
76         default:
77                 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
78                                    "Invalid vlan proto");
79                 err = -EINVAL;
80                 break;
81         }
82         return err;
83 }
84
85 static int
86 sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
87 {
88         struct flow_match_basic mt;
89         int err = 0;
90
91         flow_rule_match_basic(st->frule, &mt);
92
93         if (mt.mask->n_proto) {
94                 st->l3_proto = be16_to_cpu(mt.key->n_proto);
95                 if (!sparx5_vcap_is_known_etype(st->admin, st->l3_proto)) {
96                         err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
97                                                     st->l3_proto, ~0);
98                         if (err)
99                                 goto out;
100                 } else if (st->l3_proto == ETH_P_IP) {
101                         err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
102                                                     VCAP_BIT_1);
103                         if (err)
104                                 goto out;
105                 } else if (st->l3_proto == ETH_P_IPV6) {
106                         err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
107                                                     VCAP_BIT_0);
108                         if (err)
109                                 goto out;
110                         if (st->admin->vtype == VCAP_TYPE_IS0) {
111                                 err = vcap_rule_add_key_bit(st->vrule,
112                                                             VCAP_KF_IP_SNAP_IS,
113                                                             VCAP_BIT_1);
114                                 if (err)
115                                         goto out;
116                         }
117                 }
118         }
119
120         if (mt.mask->ip_proto) {
121                 st->l4_proto = mt.key->ip_proto;
122                 if (st->l4_proto == IPPROTO_TCP) {
123                         err = vcap_rule_add_key_bit(st->vrule,
124                                                     VCAP_KF_TCP_IS,
125                                                     VCAP_BIT_1);
126                         if (err)
127                                 goto out;
128                 } else if (st->l4_proto == IPPROTO_UDP) {
129                         err = vcap_rule_add_key_bit(st->vrule,
130                                                     VCAP_KF_TCP_IS,
131                                                     VCAP_BIT_0);
132                         if (err)
133                                 goto out;
134                         if (st->admin->vtype == VCAP_TYPE_IS0) {
135                                 err = vcap_rule_add_key_bit(st->vrule,
136                                                             VCAP_KF_TCP_UDP_IS,
137                                                             VCAP_BIT_1);
138                                 if (err)
139                                         goto out;
140                         }
141                 } else {
142                         err = vcap_rule_add_key_u32(st->vrule,
143                                                     VCAP_KF_L3_IP_PROTO,
144                                                     st->l4_proto, ~0);
145                         if (err)
146                                 goto out;
147                 }
148         }
149
150         st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_BASIC);
151
152         return err;
153
154 out:
155         NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
156         return err;
157 }
158
159 static int
160 sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
161 {
162         struct flow_match_control mt;
163         u32 value, mask;
164         int err = 0;
165
166         flow_rule_match_control(st->frule, &mt);
167
168         if (mt.mask->flags) {
169                 u8 is_frag_key = !!(mt.key->flags & FLOW_DIS_IS_FRAGMENT);
170                 u8 is_frag_mask = !!(mt.mask->flags & FLOW_DIS_IS_FRAGMENT);
171                 u8 is_frag_idx = (is_frag_key << 1) | is_frag_mask;
172
173                 u8 first_frag_key = !!(mt.key->flags & FLOW_DIS_FIRST_FRAG);
174                 u8 first_frag_mask = !!(mt.mask->flags & FLOW_DIS_FIRST_FRAG);
175                 u8 first_frag_idx = (first_frag_key << 1) | first_frag_mask;
176
177                 /* Lookup verdict based on the 2 + 2 input bits */
178                 u8 vdt = sparx5_vcap_frag_map[is_frag_idx][first_frag_idx];
179
180                 if (vdt == FRAG_INVAL) {
181                         NL_SET_ERR_MSG_MOD(st->fco->common.extack,
182                                            "Match on invalid fragment flag combination");
183                         return -EINVAL;
184                 }
185
186                 /* Extract VCAP fragment key and mask from verdict */
187                 value = (vdt >> 4) & 0x3;
188                 mask = vdt & 0x3;
189
190                 err = vcap_rule_add_key_u32(st->vrule,
191                                             VCAP_KF_L3_FRAGMENT_TYPE,
192                                             value, mask);
193                 if (err)
194                         goto out;
195         }
196
197         st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL);
198
199         return err;
200
201 out:
202         NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
203         return err;
204 }
205
206 static int
207 sparx5_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
208 {
209         if (st->admin->vtype != VCAP_TYPE_IS0) {
210                 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
211                                    "cvlan not supported in this VCAP");
212                 return -EINVAL;
213         }
214
215         return vcap_tc_flower_handler_cvlan_usage(st);
216 }
217
218 static int
219 sparx5_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
220 {
221         enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
222         enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
223         int err;
224
225         if (st->admin->vtype == VCAP_TYPE_IS0) {
226                 vid_key = VCAP_KF_8021Q_VID0;
227                 pcp_key = VCAP_KF_8021Q_PCP0;
228         }
229
230         err = vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
231         if (err)
232                 return err;
233
234         if (st->admin->vtype == VCAP_TYPE_ES0 && st->tpid)
235                 err = sparx5_tc_flower_es0_tpid(st);
236
237         return err;
238 }
239
240 static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usage *st) = {
241         [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage,
242         [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage,
243         [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage,
244         [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage,
245         [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage,
246         [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
247         [FLOW_DISSECTOR_KEY_CVLAN] = sparx5_tc_flower_handler_cvlan_usage,
248         [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
249         [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage,
250         [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage,
251         [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
252 };
253
254 static int sparx5_tc_use_dissectors(struct vcap_tc_flower_parse_usage *st,
255                                     struct vcap_admin *admin,
256                                     struct vcap_rule *vrule)
257 {
258         int idx, err = 0;
259
260         for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
261                 if (!flow_rule_match_key(st->frule, idx))
262                         continue;
263                 if (!sparx5_tc_flower_usage_handlers[idx])
264                         continue;
265                 err = sparx5_tc_flower_usage_handlers[idx](st);
266                 if (err)
267                         return err;
268         }
269
270         if (st->frule->match.dissector->used_keys ^ st->used_keys) {
271                 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
272                                    "Unsupported match item");
273                 return -ENOENT;
274         }
275
276         return err;
277 }
278
279 static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
280                                          struct net_device *ndev,
281                                          struct flow_cls_offload *fco,
282                                          bool ingress)
283 {
284         struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
285         struct flow_action_entry *actent, *last_actent = NULL;
286         struct flow_action *act = &rule->action;
287         u64 action_mask = 0;
288         int idx;
289
290         if (!flow_action_has_entries(act)) {
291                 NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
292                 return -EINVAL;
293         }
294
295         if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
296                 return -EOPNOTSUPP;
297
298         flow_action_for_each(idx, actent, act) {
299                 if (action_mask & BIT(actent->id)) {
300                         NL_SET_ERR_MSG_MOD(fco->common.extack,
301                                            "More actions of the same type");
302                         return -EINVAL;
303                 }
304                 action_mask |= BIT(actent->id);
305                 last_actent = actent; /* Save last action for later check */
306         }
307
308         /* Check if last action is a goto
309          * The last chain/lookup does not need to have a goto action
310          */
311         if (last_actent->id == FLOW_ACTION_GOTO) {
312                 /* Check if the destination chain is in one of the VCAPs */
313                 if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
314                                          last_actent->chain_index)) {
315                         NL_SET_ERR_MSG_MOD(fco->common.extack,
316                                            "Invalid goto chain");
317                         return -EINVAL;
318                 }
319         } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
320                                        ingress)) {
321                 NL_SET_ERR_MSG_MOD(fco->common.extack,
322                                    "Last action must be 'goto'");
323                 return -EINVAL;
324         }
325
326         /* Catch unsupported combinations of actions */
327         if (action_mask & BIT(FLOW_ACTION_TRAP) &&
328             action_mask & BIT(FLOW_ACTION_ACCEPT)) {
329                 NL_SET_ERR_MSG_MOD(fco->common.extack,
330                                    "Cannot combine pass and trap action");
331                 return -EOPNOTSUPP;
332         }
333
334         if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
335             action_mask & BIT(FLOW_ACTION_VLAN_POP)) {
336                 NL_SET_ERR_MSG_MOD(fco->common.extack,
337                                    "Cannot combine vlan push and pop action");
338                 return -EOPNOTSUPP;
339         }
340
341         if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
342             action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
343                 NL_SET_ERR_MSG_MOD(fco->common.extack,
344                                    "Cannot combine vlan push and modify action");
345                 return -EOPNOTSUPP;
346         }
347
348         if (action_mask & BIT(FLOW_ACTION_VLAN_POP) &&
349             action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
350                 NL_SET_ERR_MSG_MOD(fco->common.extack,
351                                    "Cannot combine vlan pop and modify action");
352                 return -EOPNOTSUPP;
353         }
354
355         return 0;
356 }
357
358 /* Add a rule counter action */
359 static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
360                                       struct vcap_rule *vrule)
361 {
362         int err;
363
364         switch (admin->vtype) {
365         case VCAP_TYPE_IS0:
366                 break;
367         case VCAP_TYPE_ES0:
368                 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
369                                                vrule->id);
370                 if (err)
371                         return err;
372                 vcap_rule_set_counter_id(vrule, vrule->id);
373                 break;
374         case VCAP_TYPE_IS2:
375         case VCAP_TYPE_ES2:
376                 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
377                                                vrule->id);
378                 if (err)
379                         return err;
380                 vcap_rule_set_counter_id(vrule, vrule->id);
381                 break;
382         default:
383                 pr_err("%s:%d: vcap type: %d not supported\n",
384                        __func__, __LINE__, admin->vtype);
385                 break;
386         }
387         return 0;
388 }
389
390 /* Collect all port keysets and apply the first of them, possibly wildcarded */
391 static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
392                                             struct vcap_rule *vrule,
393                                             struct vcap_admin *admin,
394                                             u16 l3_proto,
395                                             struct sparx5_multiple_rules *multi)
396 {
397         struct sparx5_port *port = netdev_priv(ndev);
398         struct vcap_keyset_list portkeysetlist = {};
399         enum vcap_keyfield_set portkeysets[10] = {};
400         struct vcap_keyset_list matches = {};
401         enum vcap_keyfield_set keysets[10];
402         int idx, jdx, err = 0, count = 0;
403         struct sparx5_wildcard_rule *mru;
404         const struct vcap_set *kinfo;
405         struct vcap_control *vctrl;
406
407         vctrl = port->sparx5->vcap_ctrl;
408
409         /* Find the keysets that the rule can use */
410         matches.keysets = keysets;
411         matches.max = ARRAY_SIZE(keysets);
412         if (!vcap_rule_find_keysets(vrule, &matches))
413                 return -EINVAL;
414
415         /* Find the keysets that the port configuration supports */
416         portkeysetlist.max = ARRAY_SIZE(portkeysets);
417         portkeysetlist.keysets = portkeysets;
418         err = sparx5_vcap_get_port_keyset(ndev,
419                                           admin, vrule->vcap_chain_id,
420                                           l3_proto,
421                                           &portkeysetlist);
422         if (err)
423                 return err;
424
425         /* Find the intersection of the two sets of keyset */
426         for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
427                 kinfo = vcap_keyfieldset(vctrl, admin->vtype,
428                                          portkeysetlist.keysets[idx]);
429                 if (!kinfo)
430                         continue;
431
432                 /* Find a port keyset that matches the required keys
433                  * If there are multiple keysets then compose a type id mask
434                  */
435                 for (jdx = 0; jdx < matches.cnt; ++jdx) {
436                         if (portkeysetlist.keysets[idx] != matches.keysets[jdx])
437                                 continue;
438
439                         mru = &multi->rule[kinfo->sw_per_item];
440                         if (!mru->selected) {
441                                 mru->selected = true;
442                                 mru->keyset = portkeysetlist.keysets[idx];
443                                 mru->value = kinfo->type_id;
444                         }
445                         mru->value &= kinfo->type_id;
446                         mru->mask |= kinfo->type_id;
447                         ++count;
448                 }
449         }
450         if (count == 0)
451                 return -EPROTO;
452
453         if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt)
454                 return -ENOENT;
455
456         for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
457                 mru = &multi->rule[idx];
458                 if (!mru->selected)
459                         continue;
460
461                 /* Align the mask to the combined value */
462                 mru->mask ^= mru->value;
463         }
464
465         /* Set the chosen keyset on the rule and set a wildcarded type if there
466          * are more than one keyset
467          */
468         for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
469                 mru = &multi->rule[idx];
470                 if (!mru->selected)
471                         continue;
472
473                 vcap_set_rule_set_keyset(vrule, mru->keyset);
474                 if (count > 1)
475                         /* Some keysets do not have a type field */
476                         vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
477                                               mru->value,
478                                               ~mru->mask);
479                 mru->selected = false; /* mark as done */
480                 break; /* Stop here and add more rules later */
481         }
482         return err;
483 }
484
485 static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl,
486                                    struct flow_cls_offload *fco,
487                                    struct vcap_rule *erule,
488                                    struct vcap_admin *admin,
489                                    struct sparx5_wildcard_rule *rule)
490 {
491         enum vcap_key_field keylist[] = {
492                 VCAP_KF_IF_IGR_PORT_MASK,
493                 VCAP_KF_IF_IGR_PORT_MASK_SEL,
494                 VCAP_KF_IF_IGR_PORT_MASK_RNG,
495                 VCAP_KF_LOOKUP_FIRST_IS,
496                 VCAP_KF_TYPE,
497         };
498         struct vcap_rule *vrule;
499         int err;
500
501         /* Add an extra rule with a special user and the new keyset */
502         erule->user = VCAP_USER_TC_EXTRA;
503         vrule = vcap_copy_rule(erule);
504         if (IS_ERR(vrule))
505                 return PTR_ERR(vrule);
506
507         /* Link the new rule to the existing rule with the cookie */
508         vrule->cookie = erule->cookie;
509         vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
510         err = vcap_set_rule_set_keyset(vrule, rule->keyset);
511         if (err) {
512                 pr_err("%s:%d: could not set keyset %s in rule: %u\n",
513                        __func__, __LINE__,
514                        vcap_keyset_name(vctrl, rule->keyset),
515                        vrule->id);
516                 goto out;
517         }
518
519         /* Some keysets do not have a type field, so ignore return value */
520         vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
521
522         err = vcap_set_rule_set_actionset(vrule, erule->actionset);
523         if (err)
524                 goto out;
525
526         err = sparx5_tc_add_rule_counter(admin, vrule);
527         if (err)
528                 goto out;
529
530         err = vcap_val_rule(vrule, ETH_P_ALL);
531         if (err) {
532                 pr_err("%s:%d: could not validate rule: %u\n",
533                        __func__, __LINE__, vrule->id);
534                 vcap_set_tc_exterr(fco, vrule);
535                 goto out;
536         }
537         err = vcap_add_rule(vrule);
538         if (err) {
539                 pr_err("%s:%d: could not add rule: %u\n",
540                        __func__, __LINE__, vrule->id);
541                 goto out;
542         }
543 out:
544         vcap_free_rule(vrule);
545         return err;
546 }
547
548 static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl,
549                                          struct flow_cls_offload *fco,
550                                          struct vcap_rule *erule,
551                                          struct vcap_admin *admin,
552                                          struct sparx5_multiple_rules *multi)
553 {
554         int idx, err = 0;
555
556         for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
557                 if (!multi->rule[idx].selected)
558                         continue;
559
560                 err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin,
561                                               &multi->rule[idx]);
562                 if (err)
563                         break;
564         }
565         return err;
566 }
567
568 /* Add the actionset that is the default for the VCAP type */
569 static int sparx5_tc_set_actionset(struct vcap_admin *admin,
570                                    struct vcap_rule *vrule)
571 {
572         enum vcap_actionfield_set aset;
573         int err = 0;
574
575         switch (admin->vtype) {
576         case VCAP_TYPE_IS0:
577                 aset = VCAP_AFS_CLASSIFICATION;
578                 break;
579         case VCAP_TYPE_IS2:
580                 aset = VCAP_AFS_BASE_TYPE;
581                 break;
582         case VCAP_TYPE_ES0:
583                 aset = VCAP_AFS_ES0;
584                 break;
585         case VCAP_TYPE_ES2:
586                 aset = VCAP_AFS_BASE_TYPE;
587                 break;
588         default:
589                 pr_err("%s:%d: %s\n", __func__, __LINE__, "Invalid VCAP type");
590                 return -EINVAL;
591         }
592         /* Do not overwrite any current actionset */
593         if (vrule->actionset == VCAP_AFS_NO_VALUE)
594                 err = vcap_set_rule_set_actionset(vrule, aset);
595         return err;
596 }
597
598 /* Add the VCAP key to match on for a rule target value */
599 static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin,
600                                           struct vcap_rule *vrule,
601                                           int target_cid)
602 {
603         int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
604         int err;
605
606         if (!link_val)
607                 return 0;
608
609         switch (admin->vtype) {
610         case VCAP_TYPE_IS0:
611                 /* Add NXT_IDX key for chaining rules between IS0 instances */
612                 err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
613                                             1, /* enable */
614                                             ~0);
615                 if (err)
616                         return err;
617                 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
618                                              link_val, /* target */
619                                              ~0);
620         case VCAP_TYPE_IS2:
621                 /* Add PAG key for chaining rules from IS0 */
622                 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
623                                              link_val, /* target */
624                                              ~0);
625         case VCAP_TYPE_ES0:
626         case VCAP_TYPE_ES2:
627                 /* Add ISDX key for chaining rules from IS0 */
628                 return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
629                                              ~0);
630         default:
631                 break;
632         }
633         return 0;
634 }
635
636 /* Add the VCAP action that adds a target value to a rule */
637 static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
638                                    struct vcap_admin *admin,
639                                    struct vcap_rule *vrule,
640                                    int from_cid, int to_cid)
641 {
642         struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
643         int diff, err = 0;
644
645         if (!to_admin) {
646                 pr_err("%s:%d: unsupported chain direction: %d\n",
647                        __func__, __LINE__, to_cid);
648                 return -EINVAL;
649         }
650
651         diff = vcap_chain_offset(vctrl, from_cid, to_cid);
652         if (!diff)
653                 return 0;
654
655         if (admin->vtype == VCAP_TYPE_IS0 &&
656             to_admin->vtype == VCAP_TYPE_IS0) {
657                 /* Between IS0 instances the G_IDX value is used */
658                 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX, diff);
659                 if (err)
660                         goto out;
661                 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX_CTRL,
662                                                1); /* Replace */
663                 if (err)
664                         goto out;
665         } else if (admin->vtype == VCAP_TYPE_IS0 &&
666                    to_admin->vtype == VCAP_TYPE_IS2) {
667                 /* Between IS0 and IS2 the PAG value is used */
668                 err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
669                 if (err)
670                         goto out;
671                 err = vcap_rule_add_action_u32(vrule,
672                                                VCAP_AF_PAG_OVERRIDE_MASK,
673                                                0xff);
674                 if (err)
675                         goto out;
676         } else if (admin->vtype == VCAP_TYPE_IS0 &&
677                    (to_admin->vtype == VCAP_TYPE_ES0 ||
678                     to_admin->vtype == VCAP_TYPE_ES2)) {
679                 /* Between IS0 and ES0/ES2 the ISDX value is used */
680                 err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL,
681                                                diff);
682                 if (err)
683                         goto out;
684                 err = vcap_rule_add_action_bit(vrule,
685                                                VCAP_AF_ISDX_ADD_REPLACE_SEL,
686                                                VCAP_BIT_1);
687                 if (err)
688                         goto out;
689         } else {
690                 pr_err("%s:%d: unsupported chain destination: %d\n",
691                        __func__, __LINE__, to_cid);
692                 err = -EOPNOTSUPP;
693         }
694 out:
695         return err;
696 }
697
698 static int sparx5_tc_flower_parse_act_gate(struct sparx5_psfp_sg *sg,
699                                            struct flow_action_entry *act,
700                                            struct netlink_ext_ack *extack)
701 {
702         int i;
703
704         if (act->gate.prio < -1 || act->gate.prio > SPX5_PSFP_SG_MAX_IPV) {
705                 NL_SET_ERR_MSG_MOD(extack, "Invalid gate priority");
706                 return -EINVAL;
707         }
708
709         if (act->gate.cycletime < SPX5_PSFP_SG_MIN_CYCLE_TIME_NS ||
710             act->gate.cycletime > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
711                 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletime");
712                 return -EINVAL;
713         }
714
715         if (act->gate.cycletimeext > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
716                 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletimeext");
717                 return -EINVAL;
718         }
719
720         if (act->gate.num_entries >= SPX5_PSFP_GCE_CNT) {
721                 NL_SET_ERR_MSG_MOD(extack, "Invalid number of gate entries");
722                 return -EINVAL;
723         }
724
725         sg->gate_state = true;
726         sg->ipv = act->gate.prio;
727         sg->num_entries = act->gate.num_entries;
728         sg->cycletime = act->gate.cycletime;
729         sg->cycletimeext = act->gate.cycletimeext;
730
731         for (i = 0; i < sg->num_entries; i++) {
732                 sg->gce[i].gate_state = !!act->gate.entries[i].gate_state;
733                 sg->gce[i].interval = act->gate.entries[i].interval;
734                 sg->gce[i].ipv = act->gate.entries[i].ipv;
735                 sg->gce[i].maxoctets = act->gate.entries[i].maxoctets;
736         }
737
738         return 0;
739 }
740
741 static int sparx5_tc_flower_parse_act_police(struct sparx5_policer *pol,
742                                              struct flow_action_entry *act,
743                                              struct netlink_ext_ack *extack)
744 {
745         pol->type = SPX5_POL_SERVICE;
746         pol->rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
747         pol->burst = act->police.burst;
748         pol->idx = act->hw_index;
749
750         /* rate is now in kbit */
751         if (pol->rate > DIV_ROUND_UP(SPX5_SDLB_GROUP_RATE_MAX, 1000)) {
752                 NL_SET_ERR_MSG_MOD(extack, "Maximum rate exceeded");
753                 return -EINVAL;
754         }
755
756         if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
757                 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when exceed action is not drop");
758                 return -EOPNOTSUPP;
759         }
760
761         if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
762             act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
763                 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform action is not pipe or ok");
764                 return -EOPNOTSUPP;
765         }
766
767         return 0;
768 }
769
770 static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5,
771                                        struct vcap_rule *vrule, int sg_idx,
772                                        int pol_idx, struct sparx5_psfp_sg *sg,
773                                        struct sparx5_psfp_fm *fm,
774                                        struct sparx5_psfp_sf *sf)
775 {
776         u32 psfp_sfid = 0, psfp_fmid = 0, psfp_sgid = 0;
777         int ret;
778
779         /* Must always have a stream gate - max sdu (filter option) is evaluated
780          * after frames have passed the gate, so in case of only a policer, we
781          * allocate a stream gate that is always open.
782          */
783         if (sg_idx < 0) {
784                 sg_idx = sparx5_pool_idx_to_id(SPX5_PSFP_SG_OPEN);
785                 sg->ipv = 0; /* Disabled */
786                 sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
787                 sg->num_entries = 1;
788                 sg->gate_state = 1; /* Open */
789                 sg->gate_enabled = 1;
790                 sg->gce[0].gate_state = 1;
791                 sg->gce[0].interval = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
792                 sg->gce[0].ipv = 0;
793                 sg->gce[0].maxoctets = 0; /* Disabled */
794         }
795
796         ret = sparx5_psfp_sg_add(sparx5, sg_idx, sg, &psfp_sgid);
797         if (ret < 0)
798                 return ret;
799
800         if (pol_idx >= 0) {
801                 /* Add new flow-meter */
802                 ret = sparx5_psfp_fm_add(sparx5, pol_idx, fm, &psfp_fmid);
803                 if (ret < 0)
804                         return ret;
805         }
806
807         /* Map stream filter to stream gate */
808         sf->sgid = psfp_sgid;
809
810         /* Add new stream-filter and map it to a steam gate */
811         ret = sparx5_psfp_sf_add(sparx5, sf, &psfp_sfid);
812         if (ret < 0)
813                 return ret;
814
815         /* Streams are classified by ISDX - map ISDX 1:1 to sfid for now. */
816         sparx5_isdx_conf_set(sparx5, psfp_sfid, psfp_sfid, psfp_fmid);
817
818         ret = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_ADD_REPLACE_SEL,
819                                        VCAP_BIT_1);
820         if (ret)
821                 return ret;
822
823         ret = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL, psfp_sfid);
824         if (ret)
825                 return ret;
826
827         return 0;
828 }
829
830 /* Handle the action trap for a VCAP rule */
831 static int sparx5_tc_action_trap(struct vcap_admin *admin,
832                                  struct vcap_rule *vrule,
833                                  struct flow_cls_offload *fco)
834 {
835         int err = 0;
836
837         switch (admin->vtype) {
838         case VCAP_TYPE_IS2:
839                 err = vcap_rule_add_action_bit(vrule,
840                                                VCAP_AF_CPU_COPY_ENA,
841                                                VCAP_BIT_1);
842                 if (err)
843                         break;
844                 err = vcap_rule_add_action_u32(vrule,
845                                                VCAP_AF_CPU_QUEUE_NUM, 0);
846                 if (err)
847                         break;
848                 err = vcap_rule_add_action_u32(vrule,
849                                                VCAP_AF_MASK_MODE,
850                                                SPX5_PMM_REPLACE_ALL);
851                 break;
852         case VCAP_TYPE_ES0:
853                 err = vcap_rule_add_action_u32(vrule,
854                                                VCAP_AF_FWD_SEL,
855                                                SPX5_FWSEL_REDIRECT_TO_LOOPBACK);
856                 break;
857         case VCAP_TYPE_ES2:
858                 err = vcap_rule_add_action_bit(vrule,
859                                                VCAP_AF_CPU_COPY_ENA,
860                                                VCAP_BIT_1);
861                 if (err)
862                         break;
863                 err = vcap_rule_add_action_u32(vrule,
864                                                VCAP_AF_CPU_QUEUE_NUM, 0);
865                 break;
866         default:
867                 NL_SET_ERR_MSG_MOD(fco->common.extack,
868                                    "Trap action not supported in this VCAP");
869                 err = -EOPNOTSUPP;
870                 break;
871         }
872         return err;
873 }
874
875 static int sparx5_tc_action_vlan_pop(struct vcap_admin *admin,
876                                      struct vcap_rule *vrule,
877                                      struct flow_cls_offload *fco,
878                                      u16 tpid)
879 {
880         int err = 0;
881
882         switch (admin->vtype) {
883         case VCAP_TYPE_ES0:
884                 break;
885         default:
886                 NL_SET_ERR_MSG_MOD(fco->common.extack,
887                                    "VLAN pop action not supported in this VCAP");
888                 return -EOPNOTSUPP;
889         }
890
891         switch (tpid) {
892         case ETH_P_8021Q:
893         case ETH_P_8021AD:
894                 err = vcap_rule_add_action_u32(vrule,
895                                                VCAP_AF_PUSH_OUTER_TAG,
896                                                SPX5_OTAG_UNTAG);
897                 break;
898         default:
899                 NL_SET_ERR_MSG_MOD(fco->common.extack,
900                                    "Invalid vlan proto");
901                 err = -EINVAL;
902         }
903         return err;
904 }
905
906 static int sparx5_tc_action_vlan_modify(struct vcap_admin *admin,
907                                         struct vcap_rule *vrule,
908                                         struct flow_cls_offload *fco,
909                                         struct flow_action_entry *act,
910                                         u16 tpid)
911 {
912         int err = 0;
913
914         switch (admin->vtype) {
915         case VCAP_TYPE_ES0:
916                 err = vcap_rule_add_action_u32(vrule,
917                                                VCAP_AF_PUSH_OUTER_TAG,
918                                                SPX5_OTAG_TAG_A);
919                 if (err)
920                         return err;
921                 break;
922         default:
923                 NL_SET_ERR_MSG_MOD(fco->common.extack,
924                                    "VLAN modify action not supported in this VCAP");
925                 return -EOPNOTSUPP;
926         }
927
928         switch (tpid) {
929         case ETH_P_8021Q:
930                 err = vcap_rule_add_action_u32(vrule,
931                                                VCAP_AF_TAG_A_TPID_SEL,
932                                                SPX5_TPID_A_8100);
933                 break;
934         case ETH_P_8021AD:
935                 err = vcap_rule_add_action_u32(vrule,
936                                                VCAP_AF_TAG_A_TPID_SEL,
937                                                SPX5_TPID_A_88A8);
938                 break;
939         default:
940                 NL_SET_ERR_MSG_MOD(fco->common.extack,
941                                    "Invalid vlan proto");
942                 err = -EINVAL;
943         }
944         if (err)
945                 return err;
946
947         err = vcap_rule_add_action_u32(vrule,
948                                        VCAP_AF_TAG_A_VID_SEL,
949                                        SPX5_VID_A_VAL);
950         if (err)
951                 return err;
952
953         err = vcap_rule_add_action_u32(vrule,
954                                        VCAP_AF_VID_A_VAL,
955                                        act->vlan.vid);
956         if (err)
957                 return err;
958
959         err = vcap_rule_add_action_u32(vrule,
960                                        VCAP_AF_TAG_A_PCP_SEL,
961                                        SPX5_PCP_A_VAL);
962         if (err)
963                 return err;
964
965         err = vcap_rule_add_action_u32(vrule,
966                                        VCAP_AF_PCP_A_VAL,
967                                        act->vlan.prio);
968         if (err)
969                 return err;
970
971         return vcap_rule_add_action_u32(vrule,
972                                         VCAP_AF_TAG_A_DEI_SEL,
973                                         SPX5_DEI_A_CLASSIFIED);
974 }
975
976 static int sparx5_tc_action_vlan_push(struct vcap_admin *admin,
977                                       struct vcap_rule *vrule,
978                                       struct flow_cls_offload *fco,
979                                       struct flow_action_entry *act,
980                                       u16 tpid)
981 {
982         u16 act_tpid = be16_to_cpu(act->vlan.proto);
983         int err = 0;
984
985         switch (admin->vtype) {
986         case VCAP_TYPE_ES0:
987                 break;
988         default:
989                 NL_SET_ERR_MSG_MOD(fco->common.extack,
990                                    "VLAN push action not supported in this VCAP");
991                 return -EOPNOTSUPP;
992         }
993
994         if (tpid == ETH_P_8021AD) {
995                 NL_SET_ERR_MSG_MOD(fco->common.extack,
996                                    "Cannot push on double tagged frames");
997                 return -EOPNOTSUPP;
998         }
999
1000         err = sparx5_tc_action_vlan_modify(admin, vrule, fco, act, act_tpid);
1001         if (err)
1002                 return err;
1003
1004         switch (act_tpid) {
1005         case ETH_P_8021Q:
1006                 break;
1007         case ETH_P_8021AD:
1008                 /* Push classified tag as inner tag */
1009                 err = vcap_rule_add_action_u32(vrule,
1010                                                VCAP_AF_PUSH_INNER_TAG,
1011                                                SPX5_ITAG_PUSH_B_TAG);
1012                 if (err)
1013                         break;
1014                 err = vcap_rule_add_action_u32(vrule,
1015                                                VCAP_AF_TAG_B_TPID_SEL,
1016                                                SPX5_TPID_B_CLASSIFIED);
1017                 break;
1018         default:
1019                 NL_SET_ERR_MSG_MOD(fco->common.extack,
1020                                    "Invalid vlan proto");
1021                 err = -EINVAL;
1022         }
1023         return err;
1024 }
1025
1026 /* Remove rule keys that may prevent templates from matching a keyset */
1027 static void sparx5_tc_flower_simplify_rule(struct vcap_admin *admin,
1028                                            struct vcap_rule *vrule,
1029                                            u16 l3_proto)
1030 {
1031         switch (admin->vtype) {
1032         case VCAP_TYPE_IS0:
1033                 vcap_rule_rem_key(vrule, VCAP_KF_ETYPE);
1034                 switch (l3_proto) {
1035                 case ETH_P_IP:
1036                         break;
1037                 case ETH_P_IPV6:
1038                         vcap_rule_rem_key(vrule, VCAP_KF_IP_SNAP_IS);
1039                         break;
1040                 default:
1041                         break;
1042                 }
1043                 break;
1044         case VCAP_TYPE_ES2:
1045                 switch (l3_proto) {
1046                 case ETH_P_IP:
1047                         if (vrule->keyset == VCAP_KFS_IP4_OTHER)
1048                                 vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1049                         break;
1050                 case ETH_P_IPV6:
1051                         if (vrule->keyset == VCAP_KFS_IP6_STD)
1052                                 vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1053                         vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1054                         break;
1055                 default:
1056                         break;
1057                 }
1058                 break;
1059         case VCAP_TYPE_IS2:
1060                 switch (l3_proto) {
1061                 case ETH_P_IP:
1062                 case ETH_P_IPV6:
1063                         vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1064                         break;
1065                 default:
1066                         break;
1067                 }
1068                 break;
1069         default:
1070                 break;
1071         }
1072 }
1073
1074 static bool sparx5_tc_flower_use_template(struct net_device *ndev,
1075                                           struct flow_cls_offload *fco,
1076                                           struct vcap_admin *admin,
1077                                           struct vcap_rule *vrule)
1078 {
1079         struct sparx5_port *port = netdev_priv(ndev);
1080         struct sparx5_tc_flower_template *ftp;
1081
1082         list_for_each_entry(ftp, &port->tc_templates, list) {
1083                 if (ftp->cid != fco->common.chain_index)
1084                         continue;
1085
1086                 vcap_set_rule_set_keyset(vrule, ftp->keyset);
1087                 sparx5_tc_flower_simplify_rule(admin, vrule, ftp->l3_proto);
1088                 return true;
1089         }
1090         return false;
1091 }
1092
1093 static int sparx5_tc_flower_replace(struct net_device *ndev,
1094                                     struct flow_cls_offload *fco,
1095                                     struct vcap_admin *admin,
1096                                     bool ingress)
1097 {
1098         struct sparx5_psfp_sf sf = { .max_sdu = SPX5_PSFP_SF_MAX_SDU };
1099         struct netlink_ext_ack *extack = fco->common.extack;
1100         int err, idx, tc_sg_idx = -1, tc_pol_idx = -1;
1101         struct vcap_tc_flower_parse_usage state = {
1102                 .fco = fco,
1103                 .l3_proto = ETH_P_ALL,
1104                 .admin = admin,
1105         };
1106         struct sparx5_port *port = netdev_priv(ndev);
1107         struct sparx5_multiple_rules multi = {};
1108         struct sparx5 *sparx5 = port->sparx5;
1109         struct sparx5_psfp_sg sg = { 0 };
1110         struct sparx5_psfp_fm fm = { 0 };
1111         struct flow_action_entry *act;
1112         struct vcap_control *vctrl;
1113         struct flow_rule *frule;
1114         struct vcap_rule *vrule;
1115
1116         vctrl = port->sparx5->vcap_ctrl;
1117
1118         err = sparx5_tc_flower_action_check(vctrl, ndev, fco, ingress);
1119         if (err)
1120                 return err;
1121
1122         vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
1123                                 fco->common.prio, 0);
1124         if (IS_ERR(vrule))
1125                 return PTR_ERR(vrule);
1126
1127         vrule->cookie = fco->cookie;
1128
1129         state.vrule = vrule;
1130         state.frule = flow_cls_offload_flow_rule(fco);
1131         err = sparx5_tc_use_dissectors(&state, admin, vrule);
1132         if (err)
1133                 goto out;
1134
1135         err = sparx5_tc_add_rule_counter(admin, vrule);
1136         if (err)
1137                 goto out;
1138
1139         err = sparx5_tc_add_rule_link_target(admin, vrule,
1140                                              fco->common.chain_index);
1141         if (err)
1142                 goto out;
1143
1144         frule = flow_cls_offload_flow_rule(fco);
1145         flow_action_for_each(idx, act, &frule->action) {
1146                 switch (act->id) {
1147                 case FLOW_ACTION_GATE: {
1148                         err = sparx5_tc_flower_parse_act_gate(&sg, act, extack);
1149                         if (err < 0)
1150                                 goto out;
1151
1152                         tc_sg_idx = act->hw_index;
1153
1154                         break;
1155                 }
1156                 case FLOW_ACTION_POLICE: {
1157                         err = sparx5_tc_flower_parse_act_police(&fm.pol, act,
1158                                                                 extack);
1159                         if (err < 0)
1160                                 goto out;
1161
1162                         tc_pol_idx = fm.pol.idx;
1163                         sf.max_sdu = act->police.mtu;
1164
1165                         break;
1166                 }
1167                 case FLOW_ACTION_TRAP:
1168                         err = sparx5_tc_action_trap(admin, vrule, fco);
1169                         if (err)
1170                                 goto out;
1171                         break;
1172                 case FLOW_ACTION_ACCEPT:
1173                         err = sparx5_tc_set_actionset(admin, vrule);
1174                         if (err)
1175                                 goto out;
1176                         break;
1177                 case FLOW_ACTION_GOTO:
1178                         err = sparx5_tc_set_actionset(admin, vrule);
1179                         if (err)
1180                                 goto out;
1181                         sparx5_tc_add_rule_link(vctrl, admin, vrule,
1182                                                 fco->common.chain_index,
1183                                                 act->chain_index);
1184                         break;
1185                 case FLOW_ACTION_VLAN_POP:
1186                         err = sparx5_tc_action_vlan_pop(admin, vrule, fco,
1187                                                         state.tpid);
1188                         if (err)
1189                                 goto out;
1190                         break;
1191                 case FLOW_ACTION_VLAN_PUSH:
1192                         err = sparx5_tc_action_vlan_push(admin, vrule, fco,
1193                                                          act, state.tpid);
1194                         if (err)
1195                                 goto out;
1196                         break;
1197                 case FLOW_ACTION_VLAN_MANGLE:
1198                         err = sparx5_tc_action_vlan_modify(admin, vrule, fco,
1199                                                            act, state.tpid);
1200                         if (err)
1201                                 goto out;
1202                         break;
1203                 default:
1204                         NL_SET_ERR_MSG_MOD(fco->common.extack,
1205                                            "Unsupported TC action");
1206                         err = -EOPNOTSUPP;
1207                         goto out;
1208                 }
1209         }
1210
1211         /* Setup PSFP */
1212         if (tc_sg_idx >= 0 || tc_pol_idx >= 0) {
1213                 err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx,
1214                                                   tc_pol_idx, &sg, &fm, &sf);
1215                 if (err)
1216                         goto out;
1217         }
1218
1219         if (!sparx5_tc_flower_use_template(ndev, fco, admin, vrule)) {
1220                 err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin,
1221                                                        state.l3_proto, &multi);
1222                 if (err) {
1223                         NL_SET_ERR_MSG_MOD(fco->common.extack,
1224                                            "No matching port keyset for filter protocol and keys");
1225                         goto out;
1226                 }
1227         }
1228
1229         /* provide the l3 protocol to guide the keyset selection */
1230         err = vcap_val_rule(vrule, state.l3_proto);
1231         if (err) {
1232                 vcap_set_tc_exterr(fco, vrule);
1233                 goto out;
1234         }
1235         err = vcap_add_rule(vrule);
1236         if (err)
1237                 NL_SET_ERR_MSG_MOD(fco->common.extack,
1238                                    "Could not add the filter");
1239
1240         if (state.l3_proto == ETH_P_ALL)
1241                 err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
1242                                                     &multi);
1243
1244 out:
1245         vcap_free_rule(vrule);
1246         return err;
1247 }
1248
1249 static void sparx5_tc_free_psfp_resources(struct sparx5 *sparx5,
1250                                           struct vcap_rule *vrule)
1251 {
1252         struct vcap_client_actionfield *afield;
1253         u32 isdx, sfid, sgid, fmid;
1254
1255         /* Check if VCAP_AF_ISDX_VAL action is set for this rule - and if
1256          * it is used for stream and/or flow-meter classification.
1257          */
1258         afield = vcap_find_actionfield(vrule, VCAP_AF_ISDX_VAL);
1259         if (!afield)
1260                 return;
1261
1262         isdx = afield->data.u32.value;
1263         sfid = sparx5_psfp_isdx_get_sf(sparx5, isdx);
1264
1265         if (!sfid)
1266                 return;
1267
1268         fmid = sparx5_psfp_isdx_get_fm(sparx5, isdx);
1269         sgid = sparx5_psfp_sf_get_sg(sparx5, sfid);
1270
1271         if (fmid && sparx5_psfp_fm_del(sparx5, fmid) < 0)
1272                 pr_err("%s:%d Could not delete invalid fmid: %d", __func__,
1273                        __LINE__, fmid);
1274
1275         if (sgid && sparx5_psfp_sg_del(sparx5, sgid) < 0)
1276                 pr_err("%s:%d Could not delete invalid sgid: %d", __func__,
1277                        __LINE__, sgid);
1278
1279         if (sparx5_psfp_sf_del(sparx5, sfid) < 0)
1280                 pr_err("%s:%d Could not delete invalid sfid: %d", __func__,
1281                        __LINE__, sfid);
1282
1283         sparx5_isdx_conf_set(sparx5, isdx, 0, 0);
1284 }
1285
1286 static int sparx5_tc_free_rule_resources(struct net_device *ndev,
1287                                          struct vcap_control *vctrl,
1288                                          int rule_id)
1289 {
1290         struct sparx5_port *port = netdev_priv(ndev);
1291         struct sparx5 *sparx5 = port->sparx5;
1292         struct vcap_rule *vrule;
1293         int ret = 0;
1294
1295         vrule = vcap_get_rule(vctrl, rule_id);
1296         if (IS_ERR(vrule))
1297                 return -EINVAL;
1298
1299         sparx5_tc_free_psfp_resources(sparx5, vrule);
1300
1301         vcap_free_rule(vrule);
1302         return ret;
1303 }
1304
1305 static int sparx5_tc_flower_destroy(struct net_device *ndev,
1306                                     struct flow_cls_offload *fco,
1307                                     struct vcap_admin *admin)
1308 {
1309         struct sparx5_port *port = netdev_priv(ndev);
1310         int err = -ENOENT, count = 0, rule_id;
1311         struct vcap_control *vctrl;
1312
1313         vctrl = port->sparx5->vcap_ctrl;
1314         while (true) {
1315                 rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
1316                 if (rule_id <= 0)
1317                         break;
1318                 if (count == 0) {
1319                         /* Resources are attached to the first rule of
1320                          * a set of rules. Only works if the rules are
1321                          * in the correct order.
1322                          */
1323                         err = sparx5_tc_free_rule_resources(ndev, vctrl,
1324                                                             rule_id);
1325                         if (err)
1326                                 pr_err("%s:%d: could not free resources %d\n",
1327                                        __func__, __LINE__, rule_id);
1328                 }
1329                 err = vcap_del_rule(vctrl, ndev, rule_id);
1330                 if (err) {
1331                         pr_err("%s:%d: could not delete rule %d\n",
1332                                __func__, __LINE__, rule_id);
1333                         break;
1334                 }
1335         }
1336         return err;
1337 }
1338
1339 static int sparx5_tc_flower_stats(struct net_device *ndev,
1340                                   struct flow_cls_offload *fco,
1341                                   struct vcap_admin *admin)
1342 {
1343         struct sparx5_port *port = netdev_priv(ndev);
1344         struct vcap_counter ctr = {};
1345         struct vcap_control *vctrl;
1346         ulong lastused = 0;
1347         int err;
1348
1349         vctrl = port->sparx5->vcap_ctrl;
1350         err = vcap_get_rule_count_by_cookie(vctrl, &ctr, fco->cookie);
1351         if (err)
1352                 return err;
1353         flow_stats_update(&fco->stats, 0x0, ctr.value, 0, lastused,
1354                           FLOW_ACTION_HW_STATS_IMMEDIATE);
1355         return err;
1356 }
1357
1358 static int sparx5_tc_flower_template_create(struct net_device *ndev,
1359                                             struct flow_cls_offload *fco,
1360                                             struct vcap_admin *admin)
1361 {
1362         struct sparx5_port *port = netdev_priv(ndev);
1363         struct vcap_tc_flower_parse_usage state = {
1364                 .fco = fco,
1365                 .l3_proto = ETH_P_ALL,
1366                 .admin = admin,
1367         };
1368         struct sparx5_tc_flower_template *ftp;
1369         struct vcap_keyset_list kslist = {};
1370         enum vcap_keyfield_set keysets[10];
1371         struct vcap_control *vctrl;
1372         struct vcap_rule *vrule;
1373         int count, err;
1374
1375         if (admin->vtype == VCAP_TYPE_ES0) {
1376                 pr_err("%s:%d: %s\n", __func__, __LINE__,
1377                        "VCAP does not support templates");
1378                 return -EINVAL;
1379         }
1380
1381         count = vcap_admin_rule_count(admin, fco->common.chain_index);
1382         if (count > 0) {
1383                 pr_err("%s:%d: %s\n", __func__, __LINE__,
1384                        "Filters are already present");
1385                 return -EBUSY;
1386         }
1387
1388         ftp = kzalloc(sizeof(*ftp), GFP_KERNEL);
1389         if (!ftp)
1390                 return -ENOMEM;
1391
1392         ftp->cid = fco->common.chain_index;
1393         ftp->orig = VCAP_KFS_NO_VALUE;
1394         ftp->keyset = VCAP_KFS_NO_VALUE;
1395
1396         vctrl = port->sparx5->vcap_ctrl;
1397         vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index,
1398                                 VCAP_USER_TC, fco->common.prio, 0);
1399         if (IS_ERR(vrule)) {
1400                 err = PTR_ERR(vrule);
1401                 goto err_rule;
1402         }
1403
1404         state.vrule = vrule;
1405         state.frule = flow_cls_offload_flow_rule(fco);
1406         err = sparx5_tc_use_dissectors(&state, admin, vrule);
1407         if (err) {
1408                 pr_err("%s:%d: key error: %d\n", __func__, __LINE__, err);
1409                 goto out;
1410         }
1411
1412         ftp->l3_proto = state.l3_proto;
1413
1414         sparx5_tc_flower_simplify_rule(admin, vrule, state.l3_proto);
1415
1416         /* Find the keysets that the rule can use */
1417         kslist.keysets = keysets;
1418         kslist.max = ARRAY_SIZE(keysets);
1419         if (!vcap_rule_find_keysets(vrule, &kslist)) {
1420                 pr_err("%s:%d: %s\n", __func__, __LINE__,
1421                        "Could not find a suitable keyset");
1422                 err = -ENOENT;
1423                 goto out;
1424         }
1425
1426         ftp->keyset = vcap_select_min_rule_keyset(vctrl, admin->vtype, &kslist);
1427         kslist.cnt = 0;
1428         sparx5_vcap_set_port_keyset(ndev, admin, fco->common.chain_index,
1429                                     state.l3_proto,
1430                                     ftp->keyset,
1431                                     &kslist);
1432
1433         if (kslist.cnt > 0)
1434                 ftp->orig = kslist.keysets[0];
1435
1436         /* Store new template */
1437         list_add_tail(&ftp->list, &port->tc_templates);
1438         vcap_free_rule(vrule);
1439         return 0;
1440
1441 out:
1442         vcap_free_rule(vrule);
1443 err_rule:
1444         kfree(ftp);
1445         return err;
1446 }
1447
1448 static int sparx5_tc_flower_template_destroy(struct net_device *ndev,
1449                                              struct flow_cls_offload *fco,
1450                                              struct vcap_admin *admin)
1451 {
1452         struct sparx5_port *port = netdev_priv(ndev);
1453         struct sparx5_tc_flower_template *ftp, *tmp;
1454         int err = -ENOENT;
1455
1456         /* Rules using the template are removed by the tc framework */
1457         list_for_each_entry_safe(ftp, tmp, &port->tc_templates, list) {
1458                 if (ftp->cid != fco->common.chain_index)
1459                         continue;
1460
1461                 sparx5_vcap_set_port_keyset(ndev, admin,
1462                                             fco->common.chain_index,
1463                                             ftp->l3_proto, ftp->orig,
1464                                             NULL);
1465                 list_del(&ftp->list);
1466                 kfree(ftp);
1467                 break;
1468         }
1469         return err;
1470 }
1471
1472 int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
1473                      bool ingress)
1474 {
1475         struct sparx5_port *port = netdev_priv(ndev);
1476         struct vcap_control *vctrl;
1477         struct vcap_admin *admin;
1478         int err = -EINVAL;
1479
1480         /* Get vcap instance from the chain id */
1481         vctrl = port->sparx5->vcap_ctrl;
1482         admin = vcap_find_admin(vctrl, fco->common.chain_index);
1483         if (!admin) {
1484                 NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
1485                 return err;
1486         }
1487
1488         switch (fco->command) {
1489         case FLOW_CLS_REPLACE:
1490                 return sparx5_tc_flower_replace(ndev, fco, admin, ingress);
1491         case FLOW_CLS_DESTROY:
1492                 return sparx5_tc_flower_destroy(ndev, fco, admin);
1493         case FLOW_CLS_STATS:
1494                 return sparx5_tc_flower_stats(ndev, fco, admin);
1495         case FLOW_CLS_TMPLT_CREATE:
1496                 return sparx5_tc_flower_template_create(ndev, fco, admin);
1497         case FLOW_CLS_TMPLT_DESTROY:
1498                 return sparx5_tc_flower_template_destroy(ndev, fco, admin);
1499         default:
1500                 return -EOPNOTSUPP;
1501         }
1502 }