net: microchip: sparx5: Add ES0 VCAP keyset configuration for Sparx5
[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 static int
32 sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
33 {
34         struct flow_match_basic mt;
35         int err = 0;
36
37         flow_rule_match_basic(st->frule, &mt);
38
39         if (mt.mask->n_proto) {
40                 st->l3_proto = be16_to_cpu(mt.key->n_proto);
41                 if (!sparx5_vcap_is_known_etype(st->admin, st->l3_proto)) {
42                         err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
43                                                     st->l3_proto, ~0);
44                         if (err)
45                                 goto out;
46                 } else if (st->l3_proto == ETH_P_IP) {
47                         err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
48                                                     VCAP_BIT_1);
49                         if (err)
50                                 goto out;
51                 } else if (st->l3_proto == ETH_P_IPV6) {
52                         err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
53                                                     VCAP_BIT_0);
54                         if (err)
55                                 goto out;
56                         if (st->admin->vtype == VCAP_TYPE_IS0) {
57                                 err = vcap_rule_add_key_bit(st->vrule,
58                                                             VCAP_KF_IP_SNAP_IS,
59                                                             VCAP_BIT_1);
60                                 if (err)
61                                         goto out;
62                         }
63                 }
64         }
65
66         if (mt.mask->ip_proto) {
67                 st->l4_proto = mt.key->ip_proto;
68                 if (st->l4_proto == IPPROTO_TCP) {
69                         err = vcap_rule_add_key_bit(st->vrule,
70                                                     VCAP_KF_TCP_IS,
71                                                     VCAP_BIT_1);
72                         if (err)
73                                 goto out;
74                 } else if (st->l4_proto == IPPROTO_UDP) {
75                         err = vcap_rule_add_key_bit(st->vrule,
76                                                     VCAP_KF_TCP_IS,
77                                                     VCAP_BIT_0);
78                         if (err)
79                                 goto out;
80                         if (st->admin->vtype == VCAP_TYPE_IS0) {
81                                 err = vcap_rule_add_key_bit(st->vrule,
82                                                             VCAP_KF_TCP_UDP_IS,
83                                                             VCAP_BIT_1);
84                                 if (err)
85                                         goto out;
86                         }
87                 } else {
88                         err = vcap_rule_add_key_u32(st->vrule,
89                                                     VCAP_KF_L3_IP_PROTO,
90                                                     st->l4_proto, ~0);
91                         if (err)
92                                 goto out;
93                 }
94         }
95
96         st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
97
98         return err;
99
100 out:
101         NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
102         return err;
103 }
104
105 static int
106 sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
107 {
108         struct flow_match_control mt;
109         u32 value, mask;
110         int err = 0;
111
112         flow_rule_match_control(st->frule, &mt);
113
114         if (mt.mask->flags) {
115                 if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) {
116                         if (mt.key->flags & FLOW_DIS_FIRST_FRAG) {
117                                 value = 1; /* initial fragment */
118                                 mask = 0x3;
119                         } else {
120                                 if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
121                                         value = 3; /* follow up fragment */
122                                         mask = 0x3;
123                                 } else {
124                                         value = 0; /* no fragment */
125                                         mask = 0x3;
126                                 }
127                         }
128                 } else {
129                         if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
130                                 value = 3; /* follow up fragment */
131                                 mask = 0x3;
132                         } else {
133                                 value = 0; /* no fragment */
134                                 mask = 0x3;
135                         }
136                 }
137
138                 err = vcap_rule_add_key_u32(st->vrule,
139                                             VCAP_KF_L3_FRAGMENT_TYPE,
140                                             value, mask);
141                 if (err)
142                         goto out;
143         }
144
145         st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
146
147         return err;
148
149 out:
150         NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
151         return err;
152 }
153
154 static int
155 sparx5_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
156 {
157         if (st->admin->vtype != VCAP_TYPE_IS0) {
158                 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
159                                    "cvlan not supported in this VCAP");
160                 return -EINVAL;
161         }
162
163         return vcap_tc_flower_handler_cvlan_usage(st);
164 }
165
166 static int
167 sparx5_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
168 {
169         enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
170         enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
171
172         if (st->admin->vtype == VCAP_TYPE_IS0) {
173                 vid_key = VCAP_KF_8021Q_VID0;
174                 pcp_key = VCAP_KF_8021Q_PCP0;
175         }
176
177         return vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
178 }
179
180 static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usage *st) = {
181         [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage,
182         [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage,
183         [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage,
184         [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage,
185         [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage,
186         [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
187         [FLOW_DISSECTOR_KEY_CVLAN] = sparx5_tc_flower_handler_cvlan_usage,
188         [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
189         [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage,
190         [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage,
191         [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
192 };
193
194 static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
195                                     struct vcap_admin *admin,
196                                     struct vcap_rule *vrule,
197                                     u16 *l3_proto)
198 {
199         struct vcap_tc_flower_parse_usage state = {
200                 .fco = fco,
201                 .vrule = vrule,
202                 .l3_proto = ETH_P_ALL,
203                 .admin = admin,
204         };
205         int idx, err = 0;
206
207         state.frule = flow_cls_offload_flow_rule(fco);
208         for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
209                 if (!flow_rule_match_key(state.frule, idx))
210                         continue;
211                 if (!sparx5_tc_flower_usage_handlers[idx])
212                         continue;
213                 err = sparx5_tc_flower_usage_handlers[idx](&state);
214                 if (err)
215                         return err;
216         }
217
218         if (state.frule->match.dissector->used_keys ^ state.used_keys) {
219                 NL_SET_ERR_MSG_MOD(fco->common.extack,
220                                    "Unsupported match item");
221                 return -ENOENT;
222         }
223
224         if (l3_proto)
225                 *l3_proto = state.l3_proto;
226         return err;
227 }
228
229 static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
230                                          struct net_device *ndev,
231                                          struct flow_cls_offload *fco,
232                                          bool ingress)
233 {
234         struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
235         struct flow_action_entry *actent, *last_actent = NULL;
236         struct flow_action *act = &rule->action;
237         u64 action_mask = 0;
238         int idx;
239
240         if (!flow_action_has_entries(act)) {
241                 NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
242                 return -EINVAL;
243         }
244
245         if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
246                 return -EOPNOTSUPP;
247
248         flow_action_for_each(idx, actent, act) {
249                 if (action_mask & BIT(actent->id)) {
250                         NL_SET_ERR_MSG_MOD(fco->common.extack,
251                                            "More actions of the same type");
252                         return -EINVAL;
253                 }
254                 action_mask |= BIT(actent->id);
255                 last_actent = actent; /* Save last action for later check */
256         }
257
258         /* Check if last action is a goto
259          * The last chain/lookup does not need to have a goto action
260          */
261         if (last_actent->id == FLOW_ACTION_GOTO) {
262                 /* Check if the destination chain is in one of the VCAPs */
263                 if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
264                                          last_actent->chain_index)) {
265                         NL_SET_ERR_MSG_MOD(fco->common.extack,
266                                            "Invalid goto chain");
267                         return -EINVAL;
268                 }
269         } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
270                                        ingress)) {
271                 NL_SET_ERR_MSG_MOD(fco->common.extack,
272                                    "Last action must be 'goto'");
273                 return -EINVAL;
274         }
275
276         /* Catch unsupported combinations of actions */
277         if (action_mask & BIT(FLOW_ACTION_TRAP) &&
278             action_mask & BIT(FLOW_ACTION_ACCEPT)) {
279                 NL_SET_ERR_MSG_MOD(fco->common.extack,
280                                    "Cannot combine pass and trap action");
281                 return -EOPNOTSUPP;
282         }
283
284         return 0;
285 }
286
287 /* Add a rule counter action */
288 static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
289                                       struct vcap_rule *vrule)
290 {
291         int err;
292
293         switch (admin->vtype) {
294         case VCAP_TYPE_IS0:
295                 break;
296         case VCAP_TYPE_ES0:
297                 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
298                                                vrule->id);
299                 if (err)
300                         return err;
301                 vcap_rule_set_counter_id(vrule, vrule->id);
302                 break;
303         case VCAP_TYPE_IS2:
304         case VCAP_TYPE_ES2:
305                 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
306                                                vrule->id);
307                 if (err)
308                         return err;
309                 vcap_rule_set_counter_id(vrule, vrule->id);
310                 break;
311         default:
312                 pr_err("%s:%d: vcap type: %d not supported\n",
313                        __func__, __LINE__, admin->vtype);
314                 break;
315         }
316         return 0;
317 }
318
319 /* Collect all port keysets and apply the first of them, possibly wildcarded */
320 static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
321                                             struct vcap_rule *vrule,
322                                             struct vcap_admin *admin,
323                                             u16 l3_proto,
324                                             struct sparx5_multiple_rules *multi)
325 {
326         struct sparx5_port *port = netdev_priv(ndev);
327         struct vcap_keyset_list portkeysetlist = {};
328         enum vcap_keyfield_set portkeysets[10] = {};
329         struct vcap_keyset_list matches = {};
330         enum vcap_keyfield_set keysets[10];
331         int idx, jdx, err = 0, count = 0;
332         struct sparx5_wildcard_rule *mru;
333         const struct vcap_set *kinfo;
334         struct vcap_control *vctrl;
335
336         vctrl = port->sparx5->vcap_ctrl;
337
338         /* Find the keysets that the rule can use */
339         matches.keysets = keysets;
340         matches.max = ARRAY_SIZE(keysets);
341         if (vcap_rule_find_keysets(vrule, &matches) == 0)
342                 return -EINVAL;
343
344         /* Find the keysets that the port configuration supports */
345         portkeysetlist.max = ARRAY_SIZE(portkeysets);
346         portkeysetlist.keysets = portkeysets;
347         err = sparx5_vcap_get_port_keyset(ndev,
348                                           admin, vrule->vcap_chain_id,
349                                           l3_proto,
350                                           &portkeysetlist);
351         if (err)
352                 return err;
353
354         /* Find the intersection of the two sets of keyset */
355         for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
356                 kinfo = vcap_keyfieldset(vctrl, admin->vtype,
357                                          portkeysetlist.keysets[idx]);
358                 if (!kinfo)
359                         continue;
360
361                 /* Find a port keyset that matches the required keys
362                  * If there are multiple keysets then compose a type id mask
363                  */
364                 for (jdx = 0; jdx < matches.cnt; ++jdx) {
365                         if (portkeysetlist.keysets[idx] != matches.keysets[jdx])
366                                 continue;
367
368                         mru = &multi->rule[kinfo->sw_per_item];
369                         if (!mru->selected) {
370                                 mru->selected = true;
371                                 mru->keyset = portkeysetlist.keysets[idx];
372                                 mru->value = kinfo->type_id;
373                         }
374                         mru->value &= kinfo->type_id;
375                         mru->mask |= kinfo->type_id;
376                         ++count;
377                 }
378         }
379         if (count == 0)
380                 return -EPROTO;
381
382         if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt)
383                 return -ENOENT;
384
385         for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
386                 mru = &multi->rule[idx];
387                 if (!mru->selected)
388                         continue;
389
390                 /* Align the mask to the combined value */
391                 mru->mask ^= mru->value;
392         }
393
394         /* Set the chosen keyset on the rule and set a wildcarded type if there
395          * are more than one keyset
396          */
397         for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
398                 mru = &multi->rule[idx];
399                 if (!mru->selected)
400                         continue;
401
402                 vcap_set_rule_set_keyset(vrule, mru->keyset);
403                 if (count > 1)
404                         /* Some keysets do not have a type field */
405                         vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
406                                               mru->value,
407                                               ~mru->mask);
408                 mru->selected = false; /* mark as done */
409                 break; /* Stop here and add more rules later */
410         }
411         return err;
412 }
413
414 static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl,
415                                    struct flow_cls_offload *fco,
416                                    struct vcap_rule *erule,
417                                    struct vcap_admin *admin,
418                                    struct sparx5_wildcard_rule *rule)
419 {
420         enum vcap_key_field keylist[] = {
421                 VCAP_KF_IF_IGR_PORT_MASK,
422                 VCAP_KF_IF_IGR_PORT_MASK_SEL,
423                 VCAP_KF_IF_IGR_PORT_MASK_RNG,
424                 VCAP_KF_LOOKUP_FIRST_IS,
425                 VCAP_KF_TYPE,
426         };
427         struct vcap_rule *vrule;
428         int err;
429
430         /* Add an extra rule with a special user and the new keyset */
431         erule->user = VCAP_USER_TC_EXTRA;
432         vrule = vcap_copy_rule(erule);
433         if (IS_ERR(vrule))
434                 return PTR_ERR(vrule);
435
436         /* Link the new rule to the existing rule with the cookie */
437         vrule->cookie = erule->cookie;
438         vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
439         err = vcap_set_rule_set_keyset(vrule, rule->keyset);
440         if (err) {
441                 pr_err("%s:%d: could not set keyset %s in rule: %u\n",
442                        __func__, __LINE__,
443                        vcap_keyset_name(vctrl, rule->keyset),
444                        vrule->id);
445                 goto out;
446         }
447
448         /* Some keysets do not have a type field, so ignore return value */
449         vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
450
451         err = vcap_set_rule_set_actionset(vrule, erule->actionset);
452         if (err)
453                 goto out;
454
455         err = sparx5_tc_add_rule_counter(admin, vrule);
456         if (err)
457                 goto out;
458
459         err = vcap_val_rule(vrule, ETH_P_ALL);
460         if (err) {
461                 pr_err("%s:%d: could not validate rule: %u\n",
462                        __func__, __LINE__, vrule->id);
463                 vcap_set_tc_exterr(fco, vrule);
464                 goto out;
465         }
466         err = vcap_add_rule(vrule);
467         if (err) {
468                 pr_err("%s:%d: could not add rule: %u\n",
469                        __func__, __LINE__, vrule->id);
470                 goto out;
471         }
472 out:
473         vcap_free_rule(vrule);
474         return err;
475 }
476
477 static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl,
478                                          struct flow_cls_offload *fco,
479                                          struct vcap_rule *erule,
480                                          struct vcap_admin *admin,
481                                          struct sparx5_multiple_rules *multi)
482 {
483         int idx, err = 0;
484
485         for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
486                 if (!multi->rule[idx].selected)
487                         continue;
488
489                 err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin,
490                                               &multi->rule[idx]);
491                 if (err)
492                         break;
493         }
494         return err;
495 }
496
497 /* Add the actionset that is the default for the VCAP type */
498 static int sparx5_tc_set_actionset(struct vcap_admin *admin,
499                                    struct vcap_rule *vrule)
500 {
501         enum vcap_actionfield_set aset;
502         int err = 0;
503
504         switch (admin->vtype) {
505         case VCAP_TYPE_IS0:
506                 aset = VCAP_AFS_CLASSIFICATION;
507                 break;
508         case VCAP_TYPE_IS2:
509                 aset = VCAP_AFS_BASE_TYPE;
510                 break;
511         case VCAP_TYPE_ES2:
512                 aset = VCAP_AFS_BASE_TYPE;
513                 break;
514         default:
515                 return -EINVAL;
516         }
517         /* Do not overwrite any current actionset */
518         if (vrule->actionset == VCAP_AFS_NO_VALUE)
519                 err = vcap_set_rule_set_actionset(vrule, aset);
520         return err;
521 }
522
523 /* Add the VCAP key to match on for a rule target value */
524 static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin,
525                                           struct vcap_rule *vrule,
526                                           int target_cid)
527 {
528         int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
529         int err;
530
531         if (!link_val)
532                 return 0;
533
534         switch (admin->vtype) {
535         case VCAP_TYPE_IS0:
536                 /* Add NXT_IDX key for chaining rules between IS0 instances */
537                 err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
538                                             1, /* enable */
539                                             ~0);
540                 if (err)
541                         return err;
542                 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
543                                              link_val, /* target */
544                                              ~0);
545         case VCAP_TYPE_IS2:
546                 /* Add PAG key for chaining rules from IS0 */
547                 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
548                                              link_val, /* target */
549                                              ~0);
550         case VCAP_TYPE_ES2:
551                 /* Add ISDX key for chaining rules from IS0 */
552                 return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
553                                              ~0);
554         default:
555                 break;
556         }
557         return 0;
558 }
559
560 /* Add the VCAP action that adds a target value to a rule */
561 static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
562                                    struct vcap_admin *admin,
563                                    struct vcap_rule *vrule,
564                                    int from_cid, int to_cid)
565 {
566         struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
567         int diff, err = 0;
568
569         if (!to_admin) {
570                 pr_err("%s:%d: unsupported chain direction: %d\n",
571                        __func__, __LINE__, to_cid);
572                 return -EINVAL;
573         }
574
575         diff = vcap_chain_offset(vctrl, from_cid, to_cid);
576         if (!diff)
577                 return 0;
578
579         if (admin->vtype == VCAP_TYPE_IS0 &&
580             to_admin->vtype == VCAP_TYPE_IS0) {
581                 /* Between IS0 instances the G_IDX value is used */
582                 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX, diff);
583                 if (err)
584                         goto out;
585                 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX_CTRL,
586                                                1); /* Replace */
587                 if (err)
588                         goto out;
589         } else if (admin->vtype == VCAP_TYPE_IS0 &&
590                    to_admin->vtype == VCAP_TYPE_IS2) {
591                 /* Between IS0 and IS2 the PAG value is used */
592                 err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
593                 if (err)
594                         goto out;
595                 err = vcap_rule_add_action_u32(vrule,
596                                                VCAP_AF_PAG_OVERRIDE_MASK,
597                                                0xff);
598                 if (err)
599                         goto out;
600         } else if (admin->vtype == VCAP_TYPE_IS0 &&
601                    to_admin->vtype == VCAP_TYPE_ES2) {
602                 /* Between IS0 and ES2 the ISDX value is used */
603                 err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL,
604                                                diff);
605                 if (err)
606                         goto out;
607                 err = vcap_rule_add_action_bit(vrule,
608                                                VCAP_AF_ISDX_ADD_REPLACE_SEL,
609                                                VCAP_BIT_1);
610                 if (err)
611                         goto out;
612         } else {
613                 pr_err("%s:%d: unsupported chain destination: %d\n",
614                        __func__, __LINE__, to_cid);
615                 err = -EOPNOTSUPP;
616         }
617 out:
618         return err;
619 }
620
621 static int sparx5_tc_flower_parse_act_gate(struct sparx5_psfp_sg *sg,
622                                            struct flow_action_entry *act,
623                                            struct netlink_ext_ack *extack)
624 {
625         int i;
626
627         if (act->gate.prio < -1 || act->gate.prio > SPX5_PSFP_SG_MAX_IPV) {
628                 NL_SET_ERR_MSG_MOD(extack, "Invalid gate priority");
629                 return -EINVAL;
630         }
631
632         if (act->gate.cycletime < SPX5_PSFP_SG_MIN_CYCLE_TIME_NS ||
633             act->gate.cycletime > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
634                 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletime");
635                 return -EINVAL;
636         }
637
638         if (act->gate.cycletimeext > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
639                 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletimeext");
640                 return -EINVAL;
641         }
642
643         if (act->gate.num_entries >= SPX5_PSFP_GCE_CNT) {
644                 NL_SET_ERR_MSG_MOD(extack, "Invalid number of gate entries");
645                 return -EINVAL;
646         }
647
648         sg->gate_state = true;
649         sg->ipv = act->gate.prio;
650         sg->num_entries = act->gate.num_entries;
651         sg->cycletime = act->gate.cycletime;
652         sg->cycletimeext = act->gate.cycletimeext;
653
654         for (i = 0; i < sg->num_entries; i++) {
655                 sg->gce[i].gate_state = !!act->gate.entries[i].gate_state;
656                 sg->gce[i].interval = act->gate.entries[i].interval;
657                 sg->gce[i].ipv = act->gate.entries[i].ipv;
658                 sg->gce[i].maxoctets = act->gate.entries[i].maxoctets;
659         }
660
661         return 0;
662 }
663
664 static int sparx5_tc_flower_parse_act_police(struct sparx5_policer *pol,
665                                              struct flow_action_entry *act,
666                                              struct netlink_ext_ack *extack)
667 {
668         pol->type = SPX5_POL_SERVICE;
669         pol->rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
670         pol->burst = act->police.burst;
671         pol->idx = act->hw_index;
672
673         /* rate is now in kbit */
674         if (pol->rate > DIV_ROUND_UP(SPX5_SDLB_GROUP_RATE_MAX, 1000)) {
675                 NL_SET_ERR_MSG_MOD(extack, "Maximum rate exceeded");
676                 return -EINVAL;
677         }
678
679         if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
680                 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when exceed action is not drop");
681                 return -EOPNOTSUPP;
682         }
683
684         if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
685             act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
686                 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform action is not pipe or ok");
687                 return -EOPNOTSUPP;
688         }
689
690         return 0;
691 }
692
693 static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5,
694                                        struct vcap_rule *vrule, int sg_idx,
695                                        int pol_idx, struct sparx5_psfp_sg *sg,
696                                        struct sparx5_psfp_fm *fm,
697                                        struct sparx5_psfp_sf *sf)
698 {
699         u32 psfp_sfid = 0, psfp_fmid = 0, psfp_sgid = 0;
700         int ret;
701
702         /* Must always have a stream gate - max sdu (filter option) is evaluated
703          * after frames have passed the gate, so in case of only a policer, we
704          * allocate a stream gate that is always open.
705          */
706         if (sg_idx < 0) {
707                 sg_idx = sparx5_pool_idx_to_id(SPX5_PSFP_SG_OPEN);
708                 sg->ipv = 0; /* Disabled */
709                 sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
710                 sg->num_entries = 1;
711                 sg->gate_state = 1; /* Open */
712                 sg->gate_enabled = 1;
713                 sg->gce[0].gate_state = 1;
714                 sg->gce[0].interval = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
715                 sg->gce[0].ipv = 0;
716                 sg->gce[0].maxoctets = 0; /* Disabled */
717         }
718
719         ret = sparx5_psfp_sg_add(sparx5, sg_idx, sg, &psfp_sgid);
720         if (ret < 0)
721                 return ret;
722
723         if (pol_idx >= 0) {
724                 /* Add new flow-meter */
725                 ret = sparx5_psfp_fm_add(sparx5, pol_idx, fm, &psfp_fmid);
726                 if (ret < 0)
727                         return ret;
728         }
729
730         /* Map stream filter to stream gate */
731         sf->sgid = psfp_sgid;
732
733         /* Add new stream-filter and map it to a steam gate */
734         ret = sparx5_psfp_sf_add(sparx5, sf, &psfp_sfid);
735         if (ret < 0)
736                 return ret;
737
738         /* Streams are classified by ISDX - map ISDX 1:1 to sfid for now. */
739         sparx5_isdx_conf_set(sparx5, psfp_sfid, psfp_sfid, psfp_fmid);
740
741         ret = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_ADD_REPLACE_SEL,
742                                        VCAP_BIT_1);
743         if (ret)
744                 return ret;
745
746         ret = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL, psfp_sfid);
747         if (ret)
748                 return ret;
749
750         return 0;
751 }
752
753 static int sparx5_tc_flower_replace(struct net_device *ndev,
754                                     struct flow_cls_offload *fco,
755                                     struct vcap_admin *admin,
756                                     bool ingress)
757 {
758         struct sparx5_psfp_sf sf = { .max_sdu = SPX5_PSFP_SF_MAX_SDU };
759         struct netlink_ext_ack *extack = fco->common.extack;
760         int err, idx, tc_sg_idx = -1, tc_pol_idx = -1;
761         struct sparx5_port *port = netdev_priv(ndev);
762         struct sparx5_multiple_rules multi = {};
763         struct sparx5 *sparx5 = port->sparx5;
764         struct sparx5_psfp_sg sg = { 0 };
765         struct sparx5_psfp_fm fm = { 0 };
766         struct flow_action_entry *act;
767         struct vcap_control *vctrl;
768         struct flow_rule *frule;
769         struct vcap_rule *vrule;
770         u16 l3_proto;
771
772         vctrl = port->sparx5->vcap_ctrl;
773
774         err = sparx5_tc_flower_action_check(vctrl, ndev, fco, ingress);
775         if (err)
776                 return err;
777
778         vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
779                                 fco->common.prio, 0);
780         if (IS_ERR(vrule))
781                 return PTR_ERR(vrule);
782
783         vrule->cookie = fco->cookie;
784
785         l3_proto = ETH_P_ALL;
786         err = sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);
787         if (err)
788                 goto out;
789
790         err = sparx5_tc_add_rule_counter(admin, vrule);
791         if (err)
792                 goto out;
793
794         err = sparx5_tc_add_rule_link_target(admin, vrule,
795                                              fco->common.chain_index);
796         if (err)
797                 goto out;
798
799         frule = flow_cls_offload_flow_rule(fco);
800         flow_action_for_each(idx, act, &frule->action) {
801                 switch (act->id) {
802                 case FLOW_ACTION_GATE: {
803                         err = sparx5_tc_flower_parse_act_gate(&sg, act, extack);
804                         if (err < 0)
805                                 goto out;
806
807                         tc_sg_idx = act->hw_index;
808
809                         break;
810                 }
811                 case FLOW_ACTION_POLICE: {
812                         err = sparx5_tc_flower_parse_act_police(&fm.pol, act,
813                                                                 extack);
814                         if (err < 0)
815                                 goto out;
816
817                         tc_pol_idx = fm.pol.idx;
818                         sf.max_sdu = act->police.mtu;
819
820                         break;
821                 }
822                 case FLOW_ACTION_TRAP:
823                         if (admin->vtype != VCAP_TYPE_IS2 &&
824                             admin->vtype != VCAP_TYPE_ES2) {
825                                 NL_SET_ERR_MSG_MOD(fco->common.extack,
826                                                    "Trap action not supported in this VCAP");
827                                 err = -EOPNOTSUPP;
828                                 goto out;
829                         }
830                         err = vcap_rule_add_action_bit(vrule,
831                                                        VCAP_AF_CPU_COPY_ENA,
832                                                        VCAP_BIT_1);
833                         if (err)
834                                 goto out;
835                         err = vcap_rule_add_action_u32(vrule,
836                                                        VCAP_AF_CPU_QUEUE_NUM, 0);
837                         if (err)
838                                 goto out;
839                         if (admin->vtype != VCAP_TYPE_IS2)
840                                 break;
841                         err = vcap_rule_add_action_u32(vrule,
842                                                        VCAP_AF_MASK_MODE,
843                                 SPX5_PMM_REPLACE_ALL);
844                         if (err)
845                                 goto out;
846                         break;
847                 case FLOW_ACTION_ACCEPT:
848                         err = sparx5_tc_set_actionset(admin, vrule);
849                         if (err)
850                                 goto out;
851                         break;
852                 case FLOW_ACTION_GOTO:
853                         err = sparx5_tc_set_actionset(admin, vrule);
854                         if (err)
855                                 goto out;
856                         sparx5_tc_add_rule_link(vctrl, admin, vrule,
857                                                 fco->common.chain_index,
858                                                 act->chain_index);
859                         break;
860                 default:
861                         NL_SET_ERR_MSG_MOD(fco->common.extack,
862                                            "Unsupported TC action");
863                         err = -EOPNOTSUPP;
864                         goto out;
865                 }
866         }
867
868         /* Setup PSFP */
869         if (tc_sg_idx >= 0 || tc_pol_idx >= 0) {
870                 err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx,
871                                                   tc_pol_idx, &sg, &fm, &sf);
872                 if (err)
873                         goto out;
874         }
875
876         err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, l3_proto,
877                                                &multi);
878         if (err) {
879                 NL_SET_ERR_MSG_MOD(fco->common.extack,
880                                    "No matching port keyset for filter protocol and keys");
881                 goto out;
882         }
883
884         /* provide the l3 protocol to guide the keyset selection */
885         err = vcap_val_rule(vrule, l3_proto);
886         if (err) {
887                 vcap_set_tc_exterr(fco, vrule);
888                 goto out;
889         }
890         err = vcap_add_rule(vrule);
891         if (err)
892                 NL_SET_ERR_MSG_MOD(fco->common.extack,
893                                    "Could not add the filter");
894
895         if (l3_proto == ETH_P_ALL)
896                 err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
897                                                     &multi);
898
899 out:
900         vcap_free_rule(vrule);
901         return err;
902 }
903
904 static void sparx5_tc_free_psfp_resources(struct sparx5 *sparx5,
905                                           struct vcap_rule *vrule)
906 {
907         struct vcap_client_actionfield *afield;
908         u32 isdx, sfid, sgid, fmid;
909
910         /* Check if VCAP_AF_ISDX_VAL action is set for this rule - and if
911          * it is used for stream and/or flow-meter classification.
912          */
913         afield = vcap_find_actionfield(vrule, VCAP_AF_ISDX_VAL);
914         if (!afield)
915                 return;
916
917         isdx = afield->data.u32.value;
918         sfid = sparx5_psfp_isdx_get_sf(sparx5, isdx);
919
920         if (!sfid)
921                 return;
922
923         fmid = sparx5_psfp_isdx_get_fm(sparx5, isdx);
924         sgid = sparx5_psfp_sf_get_sg(sparx5, sfid);
925
926         if (fmid && sparx5_psfp_fm_del(sparx5, fmid) < 0)
927                 pr_err("%s:%d Could not delete invalid fmid: %d", __func__,
928                        __LINE__, fmid);
929
930         if (sgid && sparx5_psfp_sg_del(sparx5, sgid) < 0)
931                 pr_err("%s:%d Could not delete invalid sgid: %d", __func__,
932                        __LINE__, sgid);
933
934         if (sparx5_psfp_sf_del(sparx5, sfid) < 0)
935                 pr_err("%s:%d Could not delete invalid sfid: %d", __func__,
936                        __LINE__, sfid);
937
938         sparx5_isdx_conf_set(sparx5, isdx, 0, 0);
939 }
940
941 static int sparx5_tc_free_rule_resources(struct net_device *ndev,
942                                          struct vcap_control *vctrl,
943                                          int rule_id)
944 {
945         struct sparx5_port *port = netdev_priv(ndev);
946         struct sparx5 *sparx5 = port->sparx5;
947         struct vcap_rule *vrule;
948         int ret = 0;
949
950         vrule = vcap_get_rule(vctrl, rule_id);
951         if (!vrule || IS_ERR(vrule))
952                 return -EINVAL;
953
954         sparx5_tc_free_psfp_resources(sparx5, vrule);
955
956         vcap_free_rule(vrule);
957         return ret;
958 }
959
960 static int sparx5_tc_flower_destroy(struct net_device *ndev,
961                                     struct flow_cls_offload *fco,
962                                     struct vcap_admin *admin)
963 {
964         struct sparx5_port *port = netdev_priv(ndev);
965         int err = -ENOENT, count = 0, rule_id;
966         struct vcap_control *vctrl;
967
968         vctrl = port->sparx5->vcap_ctrl;
969         while (true) {
970                 rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
971                 if (rule_id <= 0)
972                         break;
973                 if (count == 0) {
974                         /* Resources are attached to the first rule of
975                          * a set of rules. Only works if the rules are
976                          * in the correct order.
977                          */
978                         err = sparx5_tc_free_rule_resources(ndev, vctrl,
979                                                             rule_id);
980                         if (err)
981                                 pr_err("%s:%d: could not free resources %d\n",
982                                        __func__, __LINE__, rule_id);
983                 }
984                 err = vcap_del_rule(vctrl, ndev, rule_id);
985                 if (err) {
986                         pr_err("%s:%d: could not delete rule %d\n",
987                                __func__, __LINE__, rule_id);
988                         break;
989                 }
990         }
991         return err;
992 }
993
994 static int sparx5_tc_flower_stats(struct net_device *ndev,
995                                   struct flow_cls_offload *fco,
996                                   struct vcap_admin *admin)
997 {
998         struct sparx5_port *port = netdev_priv(ndev);
999         struct vcap_counter ctr = {};
1000         struct vcap_control *vctrl;
1001         ulong lastused = 0;
1002         int err;
1003
1004         vctrl = port->sparx5->vcap_ctrl;
1005         err = vcap_get_rule_count_by_cookie(vctrl, &ctr, fco->cookie);
1006         if (err)
1007                 return err;
1008         flow_stats_update(&fco->stats, 0x0, ctr.value, 0, lastused,
1009                           FLOW_ACTION_HW_STATS_IMMEDIATE);
1010         return err;
1011 }
1012
1013 int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
1014                      bool ingress)
1015 {
1016         struct sparx5_port *port = netdev_priv(ndev);
1017         struct vcap_control *vctrl;
1018         struct vcap_admin *admin;
1019         int err = -EINVAL;
1020
1021         /* Get vcap instance from the chain id */
1022         vctrl = port->sparx5->vcap_ctrl;
1023         admin = vcap_find_admin(vctrl, fco->common.chain_index);
1024         if (!admin) {
1025                 NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
1026                 return err;
1027         }
1028
1029         switch (fco->command) {
1030         case FLOW_CLS_REPLACE:
1031                 return sparx5_tc_flower_replace(ndev, fco, admin, ingress);
1032         case FLOW_CLS_DESTROY:
1033                 return sparx5_tc_flower_destroy(ndev, fco, admin);
1034         case FLOW_CLS_STATS:
1035                 return sparx5_tc_flower_stats(ndev, fco, admin);
1036         default:
1037                 return -EOPNOTSUPP;
1038         }
1039 }