GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / ethernet / mellanox / mlxsw / core_acl_flex_actions.c
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3
4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <linux/slab.h>
7 #include <linux/errno.h>
8 #include <linux/rhashtable.h>
9 #include <linux/list.h>
10 #include <linux/idr.h>
11 #include <linux/refcount.h>
12 #include <net/flow_offload.h>
13
14 #include "item.h"
15 #include "trap.h"
16 #include "core_acl_flex_actions.h"
17
18 enum mlxsw_afa_set_type {
19         MLXSW_AFA_SET_TYPE_NEXT,
20         MLXSW_AFA_SET_TYPE_GOTO,
21 };
22
23 /* afa_set_type
24  * Type of the record at the end of the action set.
25  */
26 MLXSW_ITEM32(afa, set, type, 0xA0, 28, 4);
27
28 /* afa_set_next_action_set_ptr
29  * A pointer to the next action set in the KVD Centralized database.
30  */
31 MLXSW_ITEM32(afa, set, next_action_set_ptr, 0xA4, 0, 24);
32
33 /* afa_set_goto_g
34  * group - When set, the binding is of an ACL group. When cleared,
35  * the binding is of an ACL.
36  * Must be set to 1 for Spectrum.
37  */
38 MLXSW_ITEM32(afa, set, goto_g, 0xA4, 29, 1);
39
40 enum mlxsw_afa_set_goto_binding_cmd {
41         /* continue go the next binding point */
42         MLXSW_AFA_SET_GOTO_BINDING_CMD_NONE,
43         /* jump to the next binding point no return */
44         MLXSW_AFA_SET_GOTO_BINDING_CMD_JUMP,
45         /* terminate the acl binding */
46         MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM = 4,
47 };
48
49 /* afa_set_goto_binding_cmd */
50 MLXSW_ITEM32(afa, set, goto_binding_cmd, 0xA4, 24, 3);
51
52 /* afa_set_goto_next_binding
53  * ACL/ACL group identifier. If the g bit is set, this field should hold
54  * the acl_group_id, else it should hold the acl_id.
55  */
56 MLXSW_ITEM32(afa, set, goto_next_binding, 0xA4, 0, 16);
57
58 /* afa_all_action_type
59  * Action Type.
60  */
61 MLXSW_ITEM32(afa, all, action_type, 0x00, 24, 6);
62
63 struct mlxsw_afa {
64         unsigned int max_acts_per_set;
65         const struct mlxsw_afa_ops *ops;
66         void *ops_priv;
67         struct rhashtable set_ht;
68         struct rhashtable fwd_entry_ht;
69         struct rhashtable cookie_ht;
70         struct rhashtable policer_ht;
71         struct idr cookie_idr;
72         struct list_head policer_list;
73 };
74
75 #define MLXSW_AFA_SET_LEN 0xA8
76
77 struct mlxsw_afa_set_ht_key {
78         char enc_actions[MLXSW_AFA_SET_LEN]; /* Encoded set */
79         bool is_first;
80 };
81
82 /* Set structure holds one action set record. It contains up to three
83  * actions (depends on size of particular actions). The set is either
84  * put directly to a rule, or it is stored in KVD linear area.
85  * To prevent duplicate entries in KVD linear area, a hashtable is
86  * used to track sets that were previously inserted and may be shared.
87  */
88
89 struct mlxsw_afa_set {
90         struct rhash_head ht_node;
91         struct mlxsw_afa_set_ht_key ht_key;
92         u32 kvdl_index;
93         u8 shared:1, /* Inserted in hashtable (doesn't mean that
94                       * kvdl_index is valid).
95                       */
96            has_trap:1,
97            has_police:1;
98         refcount_t ref_count;
99         struct mlxsw_afa_set *next; /* Pointer to the next set. */
100         struct mlxsw_afa_set *prev; /* Pointer to the previous set,
101                                      * note that set may have multiple
102                                      * sets from multiple blocks
103                                      * pointing at it. This is only
104                                      * usable until commit.
105                                      */
106 };
107
108 static const struct rhashtable_params mlxsw_afa_set_ht_params = {
109         .key_len = sizeof(struct mlxsw_afa_set_ht_key),
110         .key_offset = offsetof(struct mlxsw_afa_set, ht_key),
111         .head_offset = offsetof(struct mlxsw_afa_set, ht_node),
112         .automatic_shrinking = true,
113 };
114
115 struct mlxsw_afa_fwd_entry_ht_key {
116         u16 local_port;
117 };
118
119 struct mlxsw_afa_fwd_entry {
120         struct rhash_head ht_node;
121         struct mlxsw_afa_fwd_entry_ht_key ht_key;
122         u32 kvdl_index;
123         refcount_t ref_count;
124 };
125
126 static const struct rhashtable_params mlxsw_afa_fwd_entry_ht_params = {
127         .key_len = sizeof(struct mlxsw_afa_fwd_entry_ht_key),
128         .key_offset = offsetof(struct mlxsw_afa_fwd_entry, ht_key),
129         .head_offset = offsetof(struct mlxsw_afa_fwd_entry, ht_node),
130         .automatic_shrinking = true,
131 };
132
133 struct mlxsw_afa_cookie {
134         struct rhash_head ht_node;
135         refcount_t ref_count;
136         struct rcu_head rcu;
137         u32 cookie_index;
138         struct flow_action_cookie fa_cookie;
139 };
140
141 static u32 mlxsw_afa_cookie_hash(const struct flow_action_cookie *fa_cookie,
142                                  u32 seed)
143 {
144         return jhash2((u32 *) fa_cookie->cookie,
145                       fa_cookie->cookie_len / sizeof(u32), seed);
146 }
147
148 static u32 mlxsw_afa_cookie_key_hashfn(const void *data, u32 len, u32 seed)
149 {
150         const struct flow_action_cookie *fa_cookie = data;
151
152         return mlxsw_afa_cookie_hash(fa_cookie, seed);
153 }
154
155 static u32 mlxsw_afa_cookie_obj_hashfn(const void *data, u32 len, u32 seed)
156 {
157         const struct mlxsw_afa_cookie *cookie = data;
158
159         return mlxsw_afa_cookie_hash(&cookie->fa_cookie, seed);
160 }
161
162 static int mlxsw_afa_cookie_obj_cmpfn(struct rhashtable_compare_arg *arg,
163                                       const void *obj)
164 {
165         const struct flow_action_cookie *fa_cookie = arg->key;
166         const struct mlxsw_afa_cookie *cookie = obj;
167
168         if (cookie->fa_cookie.cookie_len == fa_cookie->cookie_len)
169                 return memcmp(cookie->fa_cookie.cookie, fa_cookie->cookie,
170                               fa_cookie->cookie_len);
171         return 1;
172 }
173
174 static const struct rhashtable_params mlxsw_afa_cookie_ht_params = {
175         .head_offset = offsetof(struct mlxsw_afa_cookie, ht_node),
176         .hashfn = mlxsw_afa_cookie_key_hashfn,
177         .obj_hashfn = mlxsw_afa_cookie_obj_hashfn,
178         .obj_cmpfn = mlxsw_afa_cookie_obj_cmpfn,
179         .automatic_shrinking = true,
180 };
181
182 struct mlxsw_afa_policer {
183         struct rhash_head ht_node;
184         struct list_head list; /* Member of policer_list */
185         refcount_t ref_count;
186         u32 fa_index;
187         u16 policer_index;
188 };
189
190 static const struct rhashtable_params mlxsw_afa_policer_ht_params = {
191         .key_len = sizeof(u32),
192         .key_offset = offsetof(struct mlxsw_afa_policer, fa_index),
193         .head_offset = offsetof(struct mlxsw_afa_policer, ht_node),
194         .automatic_shrinking = true,
195 };
196
197 struct mlxsw_afa *mlxsw_afa_create(unsigned int max_acts_per_set,
198                                    const struct mlxsw_afa_ops *ops,
199                                    void *ops_priv)
200 {
201         struct mlxsw_afa *mlxsw_afa;
202         int err;
203
204         mlxsw_afa = kzalloc(sizeof(*mlxsw_afa), GFP_KERNEL);
205         if (!mlxsw_afa)
206                 return ERR_PTR(-ENOMEM);
207         err = rhashtable_init(&mlxsw_afa->set_ht, &mlxsw_afa_set_ht_params);
208         if (err)
209                 goto err_set_rhashtable_init;
210         err = rhashtable_init(&mlxsw_afa->fwd_entry_ht,
211                               &mlxsw_afa_fwd_entry_ht_params);
212         if (err)
213                 goto err_fwd_entry_rhashtable_init;
214         err = rhashtable_init(&mlxsw_afa->cookie_ht,
215                               &mlxsw_afa_cookie_ht_params);
216         if (err)
217                 goto err_cookie_rhashtable_init;
218         err = rhashtable_init(&mlxsw_afa->policer_ht,
219                               &mlxsw_afa_policer_ht_params);
220         if (err)
221                 goto err_policer_rhashtable_init;
222         idr_init(&mlxsw_afa->cookie_idr);
223         INIT_LIST_HEAD(&mlxsw_afa->policer_list);
224         mlxsw_afa->max_acts_per_set = max_acts_per_set;
225         mlxsw_afa->ops = ops;
226         mlxsw_afa->ops_priv = ops_priv;
227         return mlxsw_afa;
228
229 err_policer_rhashtable_init:
230         rhashtable_destroy(&mlxsw_afa->cookie_ht);
231 err_cookie_rhashtable_init:
232         rhashtable_destroy(&mlxsw_afa->fwd_entry_ht);
233 err_fwd_entry_rhashtable_init:
234         rhashtable_destroy(&mlxsw_afa->set_ht);
235 err_set_rhashtable_init:
236         kfree(mlxsw_afa);
237         return ERR_PTR(err);
238 }
239 EXPORT_SYMBOL(mlxsw_afa_create);
240
241 void mlxsw_afa_destroy(struct mlxsw_afa *mlxsw_afa)
242 {
243         WARN_ON(!list_empty(&mlxsw_afa->policer_list));
244         WARN_ON(!idr_is_empty(&mlxsw_afa->cookie_idr));
245         idr_destroy(&mlxsw_afa->cookie_idr);
246         rhashtable_destroy(&mlxsw_afa->policer_ht);
247         rhashtable_destroy(&mlxsw_afa->cookie_ht);
248         rhashtable_destroy(&mlxsw_afa->fwd_entry_ht);
249         rhashtable_destroy(&mlxsw_afa->set_ht);
250         kfree(mlxsw_afa);
251 }
252 EXPORT_SYMBOL(mlxsw_afa_destroy);
253
254 static void mlxsw_afa_set_goto_set(struct mlxsw_afa_set *set,
255                                    enum mlxsw_afa_set_goto_binding_cmd cmd,
256                                    u16 group_id)
257 {
258         char *actions = set->ht_key.enc_actions;
259
260         mlxsw_afa_set_type_set(actions, MLXSW_AFA_SET_TYPE_GOTO);
261         mlxsw_afa_set_goto_g_set(actions, true);
262         mlxsw_afa_set_goto_binding_cmd_set(actions, cmd);
263         mlxsw_afa_set_goto_next_binding_set(actions, group_id);
264 }
265
266 static void mlxsw_afa_set_next_set(struct mlxsw_afa_set *set,
267                                    u32 next_set_kvdl_index)
268 {
269         char *actions = set->ht_key.enc_actions;
270
271         mlxsw_afa_set_type_set(actions, MLXSW_AFA_SET_TYPE_NEXT);
272         mlxsw_afa_set_next_action_set_ptr_set(actions, next_set_kvdl_index);
273 }
274
275 static struct mlxsw_afa_set *mlxsw_afa_set_create(bool is_first)
276 {
277         struct mlxsw_afa_set *set;
278
279         set = kzalloc(sizeof(*set), GFP_KERNEL);
280         if (!set)
281                 return NULL;
282         /* Need to initialize the set to pass by default */
283         mlxsw_afa_set_goto_set(set, MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0);
284         set->ht_key.is_first = is_first;
285         refcount_set(&set->ref_count, 1);
286         return set;
287 }
288
289 static void mlxsw_afa_set_destroy(struct mlxsw_afa_set *set)
290 {
291         kfree(set);
292 }
293
294 static int mlxsw_afa_set_share(struct mlxsw_afa *mlxsw_afa,
295                                struct mlxsw_afa_set *set)
296 {
297         int err;
298
299         err = rhashtable_insert_fast(&mlxsw_afa->set_ht, &set->ht_node,
300                                      mlxsw_afa_set_ht_params);
301         if (err)
302                 return err;
303         err = mlxsw_afa->ops->kvdl_set_add(mlxsw_afa->ops_priv,
304                                            &set->kvdl_index,
305                                            set->ht_key.enc_actions,
306                                            set->ht_key.is_first);
307         if (err)
308                 goto err_kvdl_set_add;
309         set->shared = true;
310         set->prev = NULL;
311         return 0;
312
313 err_kvdl_set_add:
314         rhashtable_remove_fast(&mlxsw_afa->set_ht, &set->ht_node,
315                                mlxsw_afa_set_ht_params);
316         return err;
317 }
318
319 static void mlxsw_afa_set_unshare(struct mlxsw_afa *mlxsw_afa,
320                                   struct mlxsw_afa_set *set)
321 {
322         mlxsw_afa->ops->kvdl_set_del(mlxsw_afa->ops_priv,
323                                      set->kvdl_index,
324                                      set->ht_key.is_first);
325         rhashtable_remove_fast(&mlxsw_afa->set_ht, &set->ht_node,
326                                mlxsw_afa_set_ht_params);
327         set->shared = false;
328 }
329
330 static void mlxsw_afa_set_put(struct mlxsw_afa *mlxsw_afa,
331                               struct mlxsw_afa_set *set)
332 {
333         if (!refcount_dec_and_test(&set->ref_count))
334                 return;
335         if (set->shared)
336                 mlxsw_afa_set_unshare(mlxsw_afa, set);
337         mlxsw_afa_set_destroy(set);
338 }
339
340 static struct mlxsw_afa_set *mlxsw_afa_set_get(struct mlxsw_afa *mlxsw_afa,
341                                                struct mlxsw_afa_set *orig_set)
342 {
343         struct mlxsw_afa_set *set;
344         int err;
345
346         /* There is a hashtable of sets maintained. If a set with the exact
347          * same encoding exists, we reuse it. Otherwise, the current set
348          * is shared by making it available to others using the hash table.
349          */
350         set = rhashtable_lookup_fast(&mlxsw_afa->set_ht, &orig_set->ht_key,
351                                      mlxsw_afa_set_ht_params);
352         if (set) {
353                 refcount_inc(&set->ref_count);
354                 mlxsw_afa_set_put(mlxsw_afa, orig_set);
355         } else {
356                 set = orig_set;
357                 err = mlxsw_afa_set_share(mlxsw_afa, set);
358                 if (err)
359                         return ERR_PTR(err);
360         }
361         return set;
362 }
363
364 /* Block structure holds a list of action sets. One action block
365  * represents one chain of actions executed upon match of a rule.
366  */
367
368 struct mlxsw_afa_block {
369         struct mlxsw_afa *afa;
370         bool finished;
371         struct mlxsw_afa_set *first_set;
372         struct mlxsw_afa_set *cur_set;
373         unsigned int cur_act_index; /* In current set. */
374         struct list_head resource_list; /* List of resources held by actions
375                                          * in this block.
376                                          */
377 };
378
379 struct mlxsw_afa_resource {
380         struct list_head list;
381         void (*destructor)(struct mlxsw_afa_block *block,
382                            struct mlxsw_afa_resource *resource);
383 };
384
385 static void mlxsw_afa_resource_add(struct mlxsw_afa_block *block,
386                                    struct mlxsw_afa_resource *resource)
387 {
388         list_add(&resource->list, &block->resource_list);
389 }
390
391 static void mlxsw_afa_resource_del(struct mlxsw_afa_resource *resource)
392 {
393         list_del(&resource->list);
394 }
395
396 static void mlxsw_afa_resources_destroy(struct mlxsw_afa_block *block)
397 {
398         struct mlxsw_afa_resource *resource, *tmp;
399
400         list_for_each_entry_safe(resource, tmp, &block->resource_list, list) {
401                 resource->destructor(block, resource);
402         }
403 }
404
405 struct mlxsw_afa_block *mlxsw_afa_block_create(struct mlxsw_afa *mlxsw_afa)
406 {
407         struct mlxsw_afa_block *block;
408
409         block = kzalloc(sizeof(*block), GFP_KERNEL);
410         if (!block)
411                 return ERR_PTR(-ENOMEM);
412         INIT_LIST_HEAD(&block->resource_list);
413         block->afa = mlxsw_afa;
414
415         /* At least one action set is always present, so just create it here */
416         block->first_set = mlxsw_afa_set_create(true);
417         if (!block->first_set)
418                 goto err_first_set_create;
419
420         /* In case user instructs to have dummy first set, we leave it
421          * empty here and create another, real, set right away.
422          */
423         if (mlxsw_afa->ops->dummy_first_set) {
424                 block->cur_set = mlxsw_afa_set_create(false);
425                 if (!block->cur_set)
426                         goto err_second_set_create;
427                 block->cur_set->prev = block->first_set;
428                 block->first_set->next = block->cur_set;
429         } else {
430                 block->cur_set = block->first_set;
431         }
432
433         return block;
434
435 err_second_set_create:
436         mlxsw_afa_set_destroy(block->first_set);
437 err_first_set_create:
438         kfree(block);
439         return ERR_PTR(-ENOMEM);
440 }
441 EXPORT_SYMBOL(mlxsw_afa_block_create);
442
443 void mlxsw_afa_block_destroy(struct mlxsw_afa_block *block)
444 {
445         struct mlxsw_afa_set *set = block->first_set;
446         struct mlxsw_afa_set *next_set;
447
448         do {
449                 next_set = set->next;
450                 mlxsw_afa_set_put(block->afa, set);
451                 set = next_set;
452         } while (set);
453         mlxsw_afa_resources_destroy(block);
454         kfree(block);
455 }
456 EXPORT_SYMBOL(mlxsw_afa_block_destroy);
457
458 int mlxsw_afa_block_commit(struct mlxsw_afa_block *block)
459 {
460         struct mlxsw_afa_set *set = block->cur_set;
461         struct mlxsw_afa_set *prev_set;
462
463         block->cur_set = NULL;
464         block->finished = true;
465
466         /* Go over all linked sets starting from last
467          * and try to find existing set in the hash table.
468          * In case it is not there, assign a KVD linear index
469          * and insert it.
470          */
471         do {
472                 prev_set = set->prev;
473                 set = mlxsw_afa_set_get(block->afa, set);
474                 if (IS_ERR(set))
475                         /* No rollback is needed since the chain is
476                          * in consistent state and mlxsw_afa_block_destroy
477                          * will take care of putting it away.
478                          */
479                         return PTR_ERR(set);
480                 if (prev_set) {
481                         prev_set->next = set;
482                         mlxsw_afa_set_next_set(prev_set, set->kvdl_index);
483                         set = prev_set;
484                 }
485         } while (prev_set);
486
487         block->first_set = set;
488         return 0;
489 }
490 EXPORT_SYMBOL(mlxsw_afa_block_commit);
491
492 char *mlxsw_afa_block_first_set(struct mlxsw_afa_block *block)
493 {
494         return block->first_set->ht_key.enc_actions;
495 }
496 EXPORT_SYMBOL(mlxsw_afa_block_first_set);
497
498 char *mlxsw_afa_block_cur_set(struct mlxsw_afa_block *block)
499 {
500         return block->cur_set->ht_key.enc_actions;
501 }
502 EXPORT_SYMBOL(mlxsw_afa_block_cur_set);
503
504 u32 mlxsw_afa_block_first_kvdl_index(struct mlxsw_afa_block *block)
505 {
506         /* First set is never in KVD linear. So the first set
507          * with valid KVD linear index is always the second one.
508          */
509         if (WARN_ON(!block->first_set->next))
510                 return 0;
511         return block->first_set->next->kvdl_index;
512 }
513 EXPORT_SYMBOL(mlxsw_afa_block_first_kvdl_index);
514
515 int mlxsw_afa_block_activity_get(struct mlxsw_afa_block *block, bool *activity)
516 {
517         u32 kvdl_index = mlxsw_afa_block_first_kvdl_index(block);
518
519         return block->afa->ops->kvdl_set_activity_get(block->afa->ops_priv,
520                                                       kvdl_index, activity);
521 }
522 EXPORT_SYMBOL(mlxsw_afa_block_activity_get);
523
524 int mlxsw_afa_block_continue(struct mlxsw_afa_block *block)
525 {
526         if (block->finished)
527                 return -EINVAL;
528         mlxsw_afa_set_goto_set(block->cur_set,
529                                MLXSW_AFA_SET_GOTO_BINDING_CMD_NONE, 0);
530         block->finished = true;
531         return 0;
532 }
533 EXPORT_SYMBOL(mlxsw_afa_block_continue);
534
535 int mlxsw_afa_block_jump(struct mlxsw_afa_block *block, u16 group_id)
536 {
537         if (block->finished)
538                 return -EINVAL;
539         mlxsw_afa_set_goto_set(block->cur_set,
540                                MLXSW_AFA_SET_GOTO_BINDING_CMD_JUMP, group_id);
541         block->finished = true;
542         return 0;
543 }
544 EXPORT_SYMBOL(mlxsw_afa_block_jump);
545
546 int mlxsw_afa_block_terminate(struct mlxsw_afa_block *block)
547 {
548         if (block->finished)
549                 return -EINVAL;
550         mlxsw_afa_set_goto_set(block->cur_set,
551                                MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0);
552         block->finished = true;
553         return 0;
554 }
555 EXPORT_SYMBOL(mlxsw_afa_block_terminate);
556
557 static struct mlxsw_afa_fwd_entry *
558 mlxsw_afa_fwd_entry_create(struct mlxsw_afa *mlxsw_afa, u16 local_port)
559 {
560         struct mlxsw_afa_fwd_entry *fwd_entry;
561         int err;
562
563         fwd_entry = kzalloc(sizeof(*fwd_entry), GFP_KERNEL);
564         if (!fwd_entry)
565                 return ERR_PTR(-ENOMEM);
566         fwd_entry->ht_key.local_port = local_port;
567         refcount_set(&fwd_entry->ref_count, 1);
568
569         err = rhashtable_insert_fast(&mlxsw_afa->fwd_entry_ht,
570                                      &fwd_entry->ht_node,
571                                      mlxsw_afa_fwd_entry_ht_params);
572         if (err)
573                 goto err_rhashtable_insert;
574
575         err = mlxsw_afa->ops->kvdl_fwd_entry_add(mlxsw_afa->ops_priv,
576                                                  &fwd_entry->kvdl_index,
577                                                  local_port);
578         if (err)
579                 goto err_kvdl_fwd_entry_add;
580         return fwd_entry;
581
582 err_kvdl_fwd_entry_add:
583         rhashtable_remove_fast(&mlxsw_afa->fwd_entry_ht, &fwd_entry->ht_node,
584                                mlxsw_afa_fwd_entry_ht_params);
585 err_rhashtable_insert:
586         kfree(fwd_entry);
587         return ERR_PTR(err);
588 }
589
590 static void mlxsw_afa_fwd_entry_destroy(struct mlxsw_afa *mlxsw_afa,
591                                         struct mlxsw_afa_fwd_entry *fwd_entry)
592 {
593         mlxsw_afa->ops->kvdl_fwd_entry_del(mlxsw_afa->ops_priv,
594                                            fwd_entry->kvdl_index);
595         rhashtable_remove_fast(&mlxsw_afa->fwd_entry_ht, &fwd_entry->ht_node,
596                                mlxsw_afa_fwd_entry_ht_params);
597         kfree(fwd_entry);
598 }
599
600 static struct mlxsw_afa_fwd_entry *
601 mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u16 local_port)
602 {
603         struct mlxsw_afa_fwd_entry_ht_key ht_key = {0};
604         struct mlxsw_afa_fwd_entry *fwd_entry;
605
606         ht_key.local_port = local_port;
607         fwd_entry = rhashtable_lookup_fast(&mlxsw_afa->fwd_entry_ht, &ht_key,
608                                            mlxsw_afa_fwd_entry_ht_params);
609         if (fwd_entry) {
610                 refcount_inc(&fwd_entry->ref_count);
611                 return fwd_entry;
612         }
613         return mlxsw_afa_fwd_entry_create(mlxsw_afa, local_port);
614 }
615
616 static void mlxsw_afa_fwd_entry_put(struct mlxsw_afa *mlxsw_afa,
617                                     struct mlxsw_afa_fwd_entry *fwd_entry)
618 {
619         if (!refcount_dec_and_test(&fwd_entry->ref_count))
620                 return;
621         mlxsw_afa_fwd_entry_destroy(mlxsw_afa, fwd_entry);
622 }
623
624 struct mlxsw_afa_fwd_entry_ref {
625         struct mlxsw_afa_resource resource;
626         struct mlxsw_afa_fwd_entry *fwd_entry;
627 };
628
629 static void
630 mlxsw_afa_fwd_entry_ref_destroy(struct mlxsw_afa_block *block,
631                                 struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref)
632 {
633         mlxsw_afa_resource_del(&fwd_entry_ref->resource);
634         mlxsw_afa_fwd_entry_put(block->afa, fwd_entry_ref->fwd_entry);
635         kfree(fwd_entry_ref);
636 }
637
638 static void
639 mlxsw_afa_fwd_entry_ref_destructor(struct mlxsw_afa_block *block,
640                                    struct mlxsw_afa_resource *resource)
641 {
642         struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref;
643
644         fwd_entry_ref = container_of(resource, struct mlxsw_afa_fwd_entry_ref,
645                                      resource);
646         mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref);
647 }
648
649 static struct mlxsw_afa_fwd_entry_ref *
650 mlxsw_afa_fwd_entry_ref_create(struct mlxsw_afa_block *block, u16 local_port)
651 {
652         struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref;
653         struct mlxsw_afa_fwd_entry *fwd_entry;
654         int err;
655
656         fwd_entry_ref = kzalloc(sizeof(*fwd_entry_ref), GFP_KERNEL);
657         if (!fwd_entry_ref)
658                 return ERR_PTR(-ENOMEM);
659         fwd_entry = mlxsw_afa_fwd_entry_get(block->afa, local_port);
660         if (IS_ERR(fwd_entry)) {
661                 err = PTR_ERR(fwd_entry);
662                 goto err_fwd_entry_get;
663         }
664         fwd_entry_ref->fwd_entry = fwd_entry;
665         fwd_entry_ref->resource.destructor = mlxsw_afa_fwd_entry_ref_destructor;
666         mlxsw_afa_resource_add(block, &fwd_entry_ref->resource);
667         return fwd_entry_ref;
668
669 err_fwd_entry_get:
670         kfree(fwd_entry_ref);
671         return ERR_PTR(err);
672 }
673
674 struct mlxsw_afa_counter {
675         struct mlxsw_afa_resource resource;
676         u32 counter_index;
677 };
678
679 static void
680 mlxsw_afa_counter_destroy(struct mlxsw_afa_block *block,
681                           struct mlxsw_afa_counter *counter)
682 {
683         mlxsw_afa_resource_del(&counter->resource);
684         block->afa->ops->counter_index_put(block->afa->ops_priv,
685                                            counter->counter_index);
686         kfree(counter);
687 }
688
689 static void
690 mlxsw_afa_counter_destructor(struct mlxsw_afa_block *block,
691                              struct mlxsw_afa_resource *resource)
692 {
693         struct mlxsw_afa_counter *counter;
694
695         counter = container_of(resource, struct mlxsw_afa_counter, resource);
696         mlxsw_afa_counter_destroy(block, counter);
697 }
698
699 static struct mlxsw_afa_counter *
700 mlxsw_afa_counter_create(struct mlxsw_afa_block *block)
701 {
702         struct mlxsw_afa_counter *counter;
703         int err;
704
705         counter = kzalloc(sizeof(*counter), GFP_KERNEL);
706         if (!counter)
707                 return ERR_PTR(-ENOMEM);
708
709         err = block->afa->ops->counter_index_get(block->afa->ops_priv,
710                                                  &counter->counter_index);
711         if (err)
712                 goto err_counter_index_get;
713         counter->resource.destructor = mlxsw_afa_counter_destructor;
714         mlxsw_afa_resource_add(block, &counter->resource);
715         return counter;
716
717 err_counter_index_get:
718         kfree(counter);
719         return ERR_PTR(err);
720 }
721
722 /* 20 bits is a maximum that hardware can handle in trap with userdef action
723  * and carry along with the trapped packet.
724  */
725 #define MLXSW_AFA_COOKIE_INDEX_BITS 20
726 #define MLXSW_AFA_COOKIE_INDEX_MAX ((1 << MLXSW_AFA_COOKIE_INDEX_BITS) - 1)
727
728 static struct mlxsw_afa_cookie *
729 mlxsw_afa_cookie_create(struct mlxsw_afa *mlxsw_afa,
730                         const struct flow_action_cookie *fa_cookie)
731 {
732         struct mlxsw_afa_cookie *cookie;
733         u32 cookie_index;
734         int err;
735
736         cookie = kzalloc(sizeof(*cookie) + fa_cookie->cookie_len, GFP_KERNEL);
737         if (!cookie)
738                 return ERR_PTR(-ENOMEM);
739         refcount_set(&cookie->ref_count, 1);
740         cookie->fa_cookie = *fa_cookie;
741         memcpy(cookie->fa_cookie.cookie, fa_cookie->cookie,
742                fa_cookie->cookie_len);
743
744         err = rhashtable_insert_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node,
745                                      mlxsw_afa_cookie_ht_params);
746         if (err)
747                 goto err_rhashtable_insert;
748
749         /* Start cookie indexes with 1. Leave the 0 index unused. Packets
750          * that come from the HW which are not dropped by drop-with-cookie
751          * action are going to pass cookie_index 0 to lookup.
752          */
753         cookie_index = 1;
754         err = idr_alloc_u32(&mlxsw_afa->cookie_idr, cookie, &cookie_index,
755                             MLXSW_AFA_COOKIE_INDEX_MAX, GFP_KERNEL);
756         if (err)
757                 goto err_idr_alloc;
758         cookie->cookie_index = cookie_index;
759         return cookie;
760
761 err_idr_alloc:
762         rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node,
763                                mlxsw_afa_cookie_ht_params);
764 err_rhashtable_insert:
765         kfree(cookie);
766         return ERR_PTR(err);
767 }
768
769 static void mlxsw_afa_cookie_destroy(struct mlxsw_afa *mlxsw_afa,
770                                      struct mlxsw_afa_cookie *cookie)
771 {
772         idr_remove(&mlxsw_afa->cookie_idr, cookie->cookie_index);
773         rhashtable_remove_fast(&mlxsw_afa->cookie_ht, &cookie->ht_node,
774                                mlxsw_afa_cookie_ht_params);
775         kfree_rcu(cookie, rcu);
776 }
777
778 static struct mlxsw_afa_cookie *
779 mlxsw_afa_cookie_get(struct mlxsw_afa *mlxsw_afa,
780                      const struct flow_action_cookie *fa_cookie)
781 {
782         struct mlxsw_afa_cookie *cookie;
783
784         cookie = rhashtable_lookup_fast(&mlxsw_afa->cookie_ht, fa_cookie,
785                                         mlxsw_afa_cookie_ht_params);
786         if (cookie) {
787                 refcount_inc(&cookie->ref_count);
788                 return cookie;
789         }
790         return mlxsw_afa_cookie_create(mlxsw_afa, fa_cookie);
791 }
792
793 static void mlxsw_afa_cookie_put(struct mlxsw_afa *mlxsw_afa,
794                                  struct mlxsw_afa_cookie *cookie)
795 {
796         if (!refcount_dec_and_test(&cookie->ref_count))
797                 return;
798         mlxsw_afa_cookie_destroy(mlxsw_afa, cookie);
799 }
800
801 /* RCU read lock must be held */
802 const struct flow_action_cookie *
803 mlxsw_afa_cookie_lookup(struct mlxsw_afa *mlxsw_afa, u32 cookie_index)
804 {
805         struct mlxsw_afa_cookie *cookie;
806
807         /* 0 index means no cookie */
808         if (!cookie_index)
809                 return NULL;
810         cookie = idr_find(&mlxsw_afa->cookie_idr, cookie_index);
811         if (!cookie)
812                 return NULL;
813         return &cookie->fa_cookie;
814 }
815 EXPORT_SYMBOL(mlxsw_afa_cookie_lookup);
816
817 struct mlxsw_afa_cookie_ref {
818         struct mlxsw_afa_resource resource;
819         struct mlxsw_afa_cookie *cookie;
820 };
821
822 static void
823 mlxsw_afa_cookie_ref_destroy(struct mlxsw_afa_block *block,
824                              struct mlxsw_afa_cookie_ref *cookie_ref)
825 {
826         mlxsw_afa_resource_del(&cookie_ref->resource);
827         mlxsw_afa_cookie_put(block->afa, cookie_ref->cookie);
828         kfree(cookie_ref);
829 }
830
831 static void
832 mlxsw_afa_cookie_ref_destructor(struct mlxsw_afa_block *block,
833                                 struct mlxsw_afa_resource *resource)
834 {
835         struct mlxsw_afa_cookie_ref *cookie_ref;
836
837         cookie_ref = container_of(resource, struct mlxsw_afa_cookie_ref,
838                                   resource);
839         mlxsw_afa_cookie_ref_destroy(block, cookie_ref);
840 }
841
842 static struct mlxsw_afa_cookie_ref *
843 mlxsw_afa_cookie_ref_create(struct mlxsw_afa_block *block,
844                             const struct flow_action_cookie *fa_cookie)
845 {
846         struct mlxsw_afa_cookie_ref *cookie_ref;
847         struct mlxsw_afa_cookie *cookie;
848         int err;
849
850         cookie_ref = kzalloc(sizeof(*cookie_ref), GFP_KERNEL);
851         if (!cookie_ref)
852                 return ERR_PTR(-ENOMEM);
853         cookie = mlxsw_afa_cookie_get(block->afa, fa_cookie);
854         if (IS_ERR(cookie)) {
855                 err = PTR_ERR(cookie);
856                 goto err_cookie_get;
857         }
858         cookie_ref->cookie = cookie;
859         cookie_ref->resource.destructor = mlxsw_afa_cookie_ref_destructor;
860         mlxsw_afa_resource_add(block, &cookie_ref->resource);
861         return cookie_ref;
862
863 err_cookie_get:
864         kfree(cookie_ref);
865         return ERR_PTR(err);
866 }
867
868 static struct mlxsw_afa_policer *
869 mlxsw_afa_policer_create(struct mlxsw_afa *mlxsw_afa, u32 fa_index,
870                          u64 rate_bytes_ps, u32 burst,
871                          struct netlink_ext_ack *extack)
872 {
873         struct mlxsw_afa_policer *policer;
874         int err;
875
876         policer = kzalloc(sizeof(*policer), GFP_KERNEL);
877         if (!policer)
878                 return ERR_PTR(-ENOMEM);
879
880         err = mlxsw_afa->ops->policer_add(mlxsw_afa->ops_priv, rate_bytes_ps,
881                                           burst, &policer->policer_index,
882                                           extack);
883         if (err)
884                 goto err_policer_add;
885
886         refcount_set(&policer->ref_count, 1);
887         policer->fa_index = fa_index;
888
889         err = rhashtable_insert_fast(&mlxsw_afa->policer_ht, &policer->ht_node,
890                                      mlxsw_afa_policer_ht_params);
891         if (err)
892                 goto err_rhashtable_insert;
893
894         list_add_tail(&policer->list, &mlxsw_afa->policer_list);
895
896         return policer;
897
898 err_rhashtable_insert:
899         mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv,
900                                     policer->policer_index);
901 err_policer_add:
902         kfree(policer);
903         return ERR_PTR(err);
904 }
905
906 static void mlxsw_afa_policer_destroy(struct mlxsw_afa *mlxsw_afa,
907                                       struct mlxsw_afa_policer *policer)
908 {
909         list_del(&policer->list);
910         rhashtable_remove_fast(&mlxsw_afa->policer_ht, &policer->ht_node,
911                                mlxsw_afa_policer_ht_params);
912         mlxsw_afa->ops->policer_del(mlxsw_afa->ops_priv,
913                                     policer->policer_index);
914         kfree(policer);
915 }
916
917 static struct mlxsw_afa_policer *
918 mlxsw_afa_policer_get(struct mlxsw_afa *mlxsw_afa, u32 fa_index,
919                       u64 rate_bytes_ps, u32 burst,
920                       struct netlink_ext_ack *extack)
921 {
922         struct mlxsw_afa_policer *policer;
923
924         policer = rhashtable_lookup_fast(&mlxsw_afa->policer_ht, &fa_index,
925                                          mlxsw_afa_policer_ht_params);
926         if (policer) {
927                 refcount_inc(&policer->ref_count);
928                 return policer;
929         }
930
931         return mlxsw_afa_policer_create(mlxsw_afa, fa_index, rate_bytes_ps,
932                                         burst, extack);
933 }
934
935 static void mlxsw_afa_policer_put(struct mlxsw_afa *mlxsw_afa,
936                                   struct mlxsw_afa_policer *policer)
937 {
938         if (!refcount_dec_and_test(&policer->ref_count))
939                 return;
940         mlxsw_afa_policer_destroy(mlxsw_afa, policer);
941 }
942
943 struct mlxsw_afa_policer_ref {
944         struct mlxsw_afa_resource resource;
945         struct mlxsw_afa_policer *policer;
946 };
947
948 static void
949 mlxsw_afa_policer_ref_destroy(struct mlxsw_afa_block *block,
950                               struct mlxsw_afa_policer_ref *policer_ref)
951 {
952         mlxsw_afa_resource_del(&policer_ref->resource);
953         mlxsw_afa_policer_put(block->afa, policer_ref->policer);
954         kfree(policer_ref);
955 }
956
957 static void
958 mlxsw_afa_policer_ref_destructor(struct mlxsw_afa_block *block,
959                                  struct mlxsw_afa_resource *resource)
960 {
961         struct mlxsw_afa_policer_ref *policer_ref;
962
963         policer_ref = container_of(resource, struct mlxsw_afa_policer_ref,
964                                    resource);
965         mlxsw_afa_policer_ref_destroy(block, policer_ref);
966 }
967
968 static struct mlxsw_afa_policer_ref *
969 mlxsw_afa_policer_ref_create(struct mlxsw_afa_block *block, u32 fa_index,
970                              u64 rate_bytes_ps, u32 burst,
971                              struct netlink_ext_ack *extack)
972 {
973         struct mlxsw_afa_policer_ref *policer_ref;
974         struct mlxsw_afa_policer *policer;
975         int err;
976
977         policer_ref = kzalloc(sizeof(*policer_ref), GFP_KERNEL);
978         if (!policer_ref)
979                 return ERR_PTR(-ENOMEM);
980
981         policer = mlxsw_afa_policer_get(block->afa, fa_index, rate_bytes_ps,
982                                         burst, extack);
983         if (IS_ERR(policer)) {
984                 err = PTR_ERR(policer);
985                 goto err_policer_get;
986         }
987
988         policer_ref->policer = policer;
989         policer_ref->resource.destructor = mlxsw_afa_policer_ref_destructor;
990         mlxsw_afa_resource_add(block, &policer_ref->resource);
991
992         return policer_ref;
993
994 err_policer_get:
995         kfree(policer_ref);
996         return ERR_PTR(err);
997 }
998
999 #define MLXSW_AFA_ONE_ACTION_LEN 32
1000 #define MLXSW_AFA_PAYLOAD_OFFSET 4
1001
1002 enum mlxsw_afa_action_type {
1003         MLXSW_AFA_ACTION_TYPE_TRAP,
1004         MLXSW_AFA_ACTION_TYPE_POLICE,
1005         MLXSW_AFA_ACTION_TYPE_OTHER,
1006 };
1007
1008 static bool
1009 mlxsw_afa_block_need_split(const struct mlxsw_afa_block *block,
1010                            enum mlxsw_afa_action_type type)
1011 {
1012         struct mlxsw_afa_set *cur_set = block->cur_set;
1013
1014         /* Due to a hardware limitation, police action cannot be in the same
1015          * action set with MLXSW_AFA_TRAP_CODE or MLXSW_AFA_TRAPWU_CODE
1016          * actions. Work around this limitation by creating a new action set
1017          * and place the new action there.
1018          */
1019         return (cur_set->has_trap && type == MLXSW_AFA_ACTION_TYPE_POLICE) ||
1020                (cur_set->has_police && type == MLXSW_AFA_ACTION_TYPE_TRAP);
1021 }
1022
1023 static char *mlxsw_afa_block_append_action_ext(struct mlxsw_afa_block *block,
1024                                                u8 action_code, u8 action_size,
1025                                                enum mlxsw_afa_action_type type)
1026 {
1027         char *oneact;
1028         char *actions;
1029
1030         if (block->finished)
1031                 return ERR_PTR(-EINVAL);
1032         if (block->cur_act_index + action_size > block->afa->max_acts_per_set ||
1033             mlxsw_afa_block_need_split(block, type)) {
1034                 struct mlxsw_afa_set *set;
1035
1036                 /* The appended action won't fit into the current action set,
1037                  * so create a new set.
1038                  */
1039                 set = mlxsw_afa_set_create(false);
1040                 if (!set)
1041                         return ERR_PTR(-ENOBUFS);
1042                 set->prev = block->cur_set;
1043                 block->cur_act_index = 0;
1044                 block->cur_set->next = set;
1045                 block->cur_set = set;
1046         }
1047
1048         switch (type) {
1049         case MLXSW_AFA_ACTION_TYPE_TRAP:
1050                 block->cur_set->has_trap = true;
1051                 break;
1052         case MLXSW_AFA_ACTION_TYPE_POLICE:
1053                 block->cur_set->has_police = true;
1054                 break;
1055         default:
1056                 break;
1057         }
1058
1059         actions = block->cur_set->ht_key.enc_actions;
1060         oneact = actions + block->cur_act_index * MLXSW_AFA_ONE_ACTION_LEN;
1061         block->cur_act_index += action_size;
1062         mlxsw_afa_all_action_type_set(oneact, action_code);
1063         return oneact + MLXSW_AFA_PAYLOAD_OFFSET;
1064 }
1065
1066 static char *mlxsw_afa_block_append_action(struct mlxsw_afa_block *block,
1067                                            u8 action_code, u8 action_size)
1068 {
1069         return mlxsw_afa_block_append_action_ext(block, action_code,
1070                                                  action_size,
1071                                                  MLXSW_AFA_ACTION_TYPE_OTHER);
1072 }
1073
1074 /* VLAN Action
1075  * -----------
1076  * VLAN action is used for manipulating VLANs. It can be used to implement QinQ,
1077  * VLAN translation, change of PCP bits of the VLAN tag, push, pop as swap VLANs
1078  * and more.
1079  */
1080
1081 #define MLXSW_AFA_VLAN_CODE 0x02
1082 #define MLXSW_AFA_VLAN_SIZE 1
1083
1084 enum mlxsw_afa_vlan_vlan_tag_cmd {
1085         MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP,
1086         MLXSW_AFA_VLAN_VLAN_TAG_CMD_PUSH_TAG,
1087         MLXSW_AFA_VLAN_VLAN_TAG_CMD_POP_TAG,
1088 };
1089
1090 enum mlxsw_afa_vlan_cmd {
1091         MLXSW_AFA_VLAN_CMD_NOP,
1092         MLXSW_AFA_VLAN_CMD_SET_OUTER,
1093         MLXSW_AFA_VLAN_CMD_SET_INNER,
1094         MLXSW_AFA_VLAN_CMD_COPY_OUTER_TO_INNER,
1095         MLXSW_AFA_VLAN_CMD_COPY_INNER_TO_OUTER,
1096         MLXSW_AFA_VLAN_CMD_SWAP,
1097 };
1098
1099 /* afa_vlan_vlan_tag_cmd
1100  * Tag command: push, pop, nop VLAN header.
1101  */
1102 MLXSW_ITEM32(afa, vlan, vlan_tag_cmd, 0x00, 29, 3);
1103
1104 /* afa_vlan_vid_cmd */
1105 MLXSW_ITEM32(afa, vlan, vid_cmd, 0x04, 29, 3);
1106
1107 /* afa_vlan_vid */
1108 MLXSW_ITEM32(afa, vlan, vid, 0x04, 0, 12);
1109
1110 /* afa_vlan_ethertype_cmd */
1111 MLXSW_ITEM32(afa, vlan, ethertype_cmd, 0x08, 29, 3);
1112
1113 /* afa_vlan_ethertype
1114  * Index to EtherTypes in Switch VLAN EtherType Register (SVER).
1115  */
1116 MLXSW_ITEM32(afa, vlan, ethertype, 0x08, 24, 3);
1117
1118 /* afa_vlan_pcp_cmd */
1119 MLXSW_ITEM32(afa, vlan, pcp_cmd, 0x08, 13, 3);
1120
1121 /* afa_vlan_pcp */
1122 MLXSW_ITEM32(afa, vlan, pcp, 0x08, 8, 3);
1123
1124 static inline void
1125 mlxsw_afa_vlan_pack(char *payload,
1126                     enum mlxsw_afa_vlan_vlan_tag_cmd vlan_tag_cmd,
1127                     enum mlxsw_afa_vlan_cmd vid_cmd, u16 vid,
1128                     enum mlxsw_afa_vlan_cmd pcp_cmd, u8 pcp,
1129                     enum mlxsw_afa_vlan_cmd ethertype_cmd, u8 ethertype)
1130 {
1131         mlxsw_afa_vlan_vlan_tag_cmd_set(payload, vlan_tag_cmd);
1132         mlxsw_afa_vlan_vid_cmd_set(payload, vid_cmd);
1133         mlxsw_afa_vlan_vid_set(payload, vid);
1134         mlxsw_afa_vlan_pcp_cmd_set(payload, pcp_cmd);
1135         mlxsw_afa_vlan_pcp_set(payload, pcp);
1136         mlxsw_afa_vlan_ethertype_cmd_set(payload, ethertype_cmd);
1137         mlxsw_afa_vlan_ethertype_set(payload, ethertype);
1138 }
1139
1140 int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block,
1141                                        u16 vid, u8 pcp, u8 et,
1142                                        struct netlink_ext_ack *extack)
1143 {
1144         char *act = mlxsw_afa_block_append_action(block,
1145                                                   MLXSW_AFA_VLAN_CODE,
1146                                                   MLXSW_AFA_VLAN_SIZE);
1147
1148         if (IS_ERR(act)) {
1149                 NL_SET_ERR_MSG_MOD(extack, "Cannot append vlan_modify action");
1150                 return PTR_ERR(act);
1151         }
1152         mlxsw_afa_vlan_pack(act, MLXSW_AFA_VLAN_VLAN_TAG_CMD_NOP,
1153                             MLXSW_AFA_VLAN_CMD_SET_OUTER, vid,
1154                             MLXSW_AFA_VLAN_CMD_SET_OUTER, pcp,
1155                             MLXSW_AFA_VLAN_CMD_SET_OUTER, et);
1156         return 0;
1157 }
1158 EXPORT_SYMBOL(mlxsw_afa_block_append_vlan_modify);
1159
1160 /* Trap Action / Trap With Userdef Action
1161  * --------------------------------------
1162  * The Trap action enables trapping / mirroring packets to the CPU
1163  * as well as discarding packets.
1164  * The ACL Trap / Discard separates the forward/discard control from CPU
1165  * trap control. In addition, the Trap / Discard action enables activating
1166  * SPAN (port mirroring).
1167  *
1168  * The Trap with userdef action has the same functionality as
1169  * the Trap action with addition of user defined value that can be set
1170  * and used by higher layer applications.
1171  */
1172
1173 #define MLXSW_AFA_TRAP_CODE 0x03
1174 #define MLXSW_AFA_TRAP_SIZE 1
1175
1176 #define MLXSW_AFA_TRAPWU_CODE 0x04
1177 #define MLXSW_AFA_TRAPWU_SIZE 2
1178
1179 enum mlxsw_afa_trap_trap_action {
1180         MLXSW_AFA_TRAP_TRAP_ACTION_NOP = 0,
1181         MLXSW_AFA_TRAP_TRAP_ACTION_TRAP = 2,
1182 };
1183
1184 /* afa_trap_trap_action
1185  * Trap Action.
1186  */
1187 MLXSW_ITEM32(afa, trap, trap_action, 0x00, 24, 4);
1188
1189 enum mlxsw_afa_trap_forward_action {
1190         MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD = 1,
1191         MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD = 3,
1192 };
1193
1194 /* afa_trap_forward_action
1195  * Forward Action.
1196  */
1197 MLXSW_ITEM32(afa, trap, forward_action, 0x00, 0, 4);
1198
1199 /* afa_trap_trap_id
1200  * Trap ID to configure.
1201  */
1202 MLXSW_ITEM32(afa, trap, trap_id, 0x04, 0, 9);
1203
1204 /* afa_trap_mirror_agent
1205  * Mirror agent.
1206  */
1207 MLXSW_ITEM32(afa, trap, mirror_agent, 0x08, 29, 3);
1208
1209 /* afa_trap_mirror_enable
1210  * Mirror enable.
1211  */
1212 MLXSW_ITEM32(afa, trap, mirror_enable, 0x08, 24, 1);
1213
1214 /* user_def_val
1215  * Value for the SW usage. Can be used to pass information of which
1216  * rule has caused a trap. This may be overwritten by later traps.
1217  * This field does a set on the packet's user_def_val only if this
1218  * is the first trap_id or if the trap_id has replaced the previous
1219  * packet's trap_id.
1220  */
1221 MLXSW_ITEM32(afa, trap, user_def_val, 0x0C, 0, 20);
1222
1223 static inline void
1224 mlxsw_afa_trap_pack(char *payload,
1225                     enum mlxsw_afa_trap_trap_action trap_action,
1226                     enum mlxsw_afa_trap_forward_action forward_action,
1227                     u16 trap_id)
1228 {
1229         mlxsw_afa_trap_trap_action_set(payload, trap_action);
1230         mlxsw_afa_trap_forward_action_set(payload, forward_action);
1231         mlxsw_afa_trap_trap_id_set(payload, trap_id);
1232 }
1233
1234 static inline void
1235 mlxsw_afa_trapwu_pack(char *payload,
1236                       enum mlxsw_afa_trap_trap_action trap_action,
1237                       enum mlxsw_afa_trap_forward_action forward_action,
1238                       u16 trap_id, u32 user_def_val)
1239 {
1240         mlxsw_afa_trap_pack(payload, trap_action, forward_action, trap_id);
1241         mlxsw_afa_trap_user_def_val_set(payload, user_def_val);
1242 }
1243
1244 static inline void
1245 mlxsw_afa_trap_mirror_pack(char *payload, bool mirror_enable,
1246                            u8 mirror_agent)
1247 {
1248         mlxsw_afa_trap_mirror_enable_set(payload, mirror_enable);
1249         mlxsw_afa_trap_mirror_agent_set(payload, mirror_agent);
1250 }
1251
1252 static char *mlxsw_afa_block_append_action_trap(struct mlxsw_afa_block *block,
1253                                                 u8 action_code, u8 action_size)
1254 {
1255         return mlxsw_afa_block_append_action_ext(block, action_code,
1256                                                  action_size,
1257                                                  MLXSW_AFA_ACTION_TYPE_TRAP);
1258 }
1259
1260 static int mlxsw_afa_block_append_drop_plain(struct mlxsw_afa_block *block,
1261                                              bool ingress)
1262 {
1263         char *act = mlxsw_afa_block_append_action_trap(block,
1264                                                        MLXSW_AFA_TRAP_CODE,
1265                                                        MLXSW_AFA_TRAP_SIZE);
1266
1267         if (IS_ERR(act))
1268                 return PTR_ERR(act);
1269         mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP,
1270                             MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD,
1271                             ingress ? MLXSW_TRAP_ID_DISCARD_INGRESS_ACL :
1272                                       MLXSW_TRAP_ID_DISCARD_EGRESS_ACL);
1273         return 0;
1274 }
1275
1276 static int
1277 mlxsw_afa_block_append_drop_with_cookie(struct mlxsw_afa_block *block,
1278                                         bool ingress,
1279                                         const struct flow_action_cookie *fa_cookie,
1280                                         struct netlink_ext_ack *extack)
1281 {
1282         struct mlxsw_afa_cookie_ref *cookie_ref;
1283         u32 cookie_index;
1284         char *act;
1285         int err;
1286
1287         cookie_ref = mlxsw_afa_cookie_ref_create(block, fa_cookie);
1288         if (IS_ERR(cookie_ref)) {
1289                 NL_SET_ERR_MSG_MOD(extack, "Cannot create cookie for drop action");
1290                 return PTR_ERR(cookie_ref);
1291         }
1292         cookie_index = cookie_ref->cookie->cookie_index;
1293
1294         act = mlxsw_afa_block_append_action_trap(block, MLXSW_AFA_TRAPWU_CODE,
1295                                                  MLXSW_AFA_TRAPWU_SIZE);
1296         if (IS_ERR(act)) {
1297                 NL_SET_ERR_MSG_MOD(extack, "Cannot append drop with cookie action");
1298                 err = PTR_ERR(act);
1299                 goto err_append_action;
1300         }
1301         mlxsw_afa_trapwu_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP,
1302                               MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD,
1303                               ingress ? MLXSW_TRAP_ID_DISCARD_INGRESS_ACL :
1304                                         MLXSW_TRAP_ID_DISCARD_EGRESS_ACL,
1305                               cookie_index);
1306         return 0;
1307
1308 err_append_action:
1309         mlxsw_afa_cookie_ref_destroy(block, cookie_ref);
1310         return err;
1311 }
1312
1313 int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block, bool ingress,
1314                                 const struct flow_action_cookie *fa_cookie,
1315                                 struct netlink_ext_ack *extack)
1316 {
1317         return fa_cookie ?
1318                mlxsw_afa_block_append_drop_with_cookie(block, ingress,
1319                                                        fa_cookie, extack) :
1320                mlxsw_afa_block_append_drop_plain(block, ingress);
1321 }
1322 EXPORT_SYMBOL(mlxsw_afa_block_append_drop);
1323
1324 int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id)
1325 {
1326         char *act = mlxsw_afa_block_append_action_trap(block,
1327                                                        MLXSW_AFA_TRAP_CODE,
1328                                                        MLXSW_AFA_TRAP_SIZE);
1329
1330         if (IS_ERR(act))
1331                 return PTR_ERR(act);
1332         mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP,
1333                             MLXSW_AFA_TRAP_FORWARD_ACTION_DISCARD, trap_id);
1334         return 0;
1335 }
1336 EXPORT_SYMBOL(mlxsw_afa_block_append_trap);
1337
1338 int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block,
1339                                             u16 trap_id)
1340 {
1341         char *act = mlxsw_afa_block_append_action_trap(block,
1342                                                        MLXSW_AFA_TRAP_CODE,
1343                                                        MLXSW_AFA_TRAP_SIZE);
1344
1345         if (IS_ERR(act))
1346                 return PTR_ERR(act);
1347         mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_TRAP,
1348                             MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD, trap_id);
1349         return 0;
1350 }
1351 EXPORT_SYMBOL(mlxsw_afa_block_append_trap_and_forward);
1352
1353 struct mlxsw_afa_mirror {
1354         struct mlxsw_afa_resource resource;
1355         int span_id;
1356         u16 local_in_port;
1357         bool ingress;
1358 };
1359
1360 static void
1361 mlxsw_afa_mirror_destroy(struct mlxsw_afa_block *block,
1362                          struct mlxsw_afa_mirror *mirror)
1363 {
1364         mlxsw_afa_resource_del(&mirror->resource);
1365         block->afa->ops->mirror_del(block->afa->ops_priv,
1366                                     mirror->local_in_port,
1367                                     mirror->span_id,
1368                                     mirror->ingress);
1369         kfree(mirror);
1370 }
1371
1372 static void
1373 mlxsw_afa_mirror_destructor(struct mlxsw_afa_block *block,
1374                             struct mlxsw_afa_resource *resource)
1375 {
1376         struct mlxsw_afa_mirror *mirror;
1377
1378         mirror = container_of(resource, struct mlxsw_afa_mirror, resource);
1379         mlxsw_afa_mirror_destroy(block, mirror);
1380 }
1381
1382 static struct mlxsw_afa_mirror *
1383 mlxsw_afa_mirror_create(struct mlxsw_afa_block *block, u16 local_in_port,
1384                         const struct net_device *out_dev, bool ingress)
1385 {
1386         struct mlxsw_afa_mirror *mirror;
1387         int err;
1388
1389         mirror = kzalloc(sizeof(*mirror), GFP_KERNEL);
1390         if (!mirror)
1391                 return ERR_PTR(-ENOMEM);
1392
1393         err = block->afa->ops->mirror_add(block->afa->ops_priv,
1394                                           local_in_port, out_dev,
1395                                           ingress, &mirror->span_id);
1396         if (err)
1397                 goto err_mirror_add;
1398
1399         mirror->ingress = ingress;
1400         mirror->local_in_port = local_in_port;
1401         mirror->resource.destructor = mlxsw_afa_mirror_destructor;
1402         mlxsw_afa_resource_add(block, &mirror->resource);
1403         return mirror;
1404
1405 err_mirror_add:
1406         kfree(mirror);
1407         return ERR_PTR(err);
1408 }
1409
1410 static int
1411 mlxsw_afa_block_append_allocated_mirror(struct mlxsw_afa_block *block,
1412                                         u8 mirror_agent)
1413 {
1414         char *act = mlxsw_afa_block_append_action_trap(block,
1415                                                        MLXSW_AFA_TRAP_CODE,
1416                                                        MLXSW_AFA_TRAP_SIZE);
1417
1418         if (IS_ERR(act))
1419                 return PTR_ERR(act);
1420         mlxsw_afa_trap_pack(act, MLXSW_AFA_TRAP_TRAP_ACTION_NOP,
1421                             MLXSW_AFA_TRAP_FORWARD_ACTION_FORWARD, 0);
1422         mlxsw_afa_trap_mirror_pack(act, true, mirror_agent);
1423         return 0;
1424 }
1425
1426 int
1427 mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, u16 local_in_port,
1428                               const struct net_device *out_dev, bool ingress,
1429                               struct netlink_ext_ack *extack)
1430 {
1431         struct mlxsw_afa_mirror *mirror;
1432         int err;
1433
1434         mirror = mlxsw_afa_mirror_create(block, local_in_port, out_dev,
1435                                          ingress);
1436         if (IS_ERR(mirror)) {
1437                 NL_SET_ERR_MSG_MOD(extack, "Cannot create mirror action");
1438                 return PTR_ERR(mirror);
1439         }
1440         err = mlxsw_afa_block_append_allocated_mirror(block, mirror->span_id);
1441         if (err) {
1442                 NL_SET_ERR_MSG_MOD(extack, "Cannot append mirror action");
1443                 goto err_append_allocated_mirror;
1444         }
1445
1446         return 0;
1447
1448 err_append_allocated_mirror:
1449         mlxsw_afa_mirror_destroy(block, mirror);
1450         return err;
1451 }
1452 EXPORT_SYMBOL(mlxsw_afa_block_append_mirror);
1453
1454 /* QoS Action
1455  * ----------
1456  * The QOS_ACTION is used for manipulating the QoS attributes of a packet. It
1457  * can be used to change the DCSP, ECN, Color and Switch Priority of the packet.
1458  * Note that PCP field can be changed using the VLAN action.
1459  */
1460
1461 #define MLXSW_AFA_QOS_CODE 0x06
1462 #define MLXSW_AFA_QOS_SIZE 1
1463
1464 enum mlxsw_afa_qos_ecn_cmd {
1465         /* Do nothing */
1466         MLXSW_AFA_QOS_ECN_CMD_NOP,
1467         /* Set ECN to afa_qos_ecn */
1468         MLXSW_AFA_QOS_ECN_CMD_SET,
1469 };
1470
1471 /* afa_qos_ecn_cmd
1472  */
1473 MLXSW_ITEM32(afa, qos, ecn_cmd, 0x04, 29, 3);
1474
1475 /* afa_qos_ecn
1476  * ECN value.
1477  */
1478 MLXSW_ITEM32(afa, qos, ecn, 0x04, 24, 2);
1479
1480 enum mlxsw_afa_qos_dscp_cmd {
1481         /* Do nothing */
1482         MLXSW_AFA_QOS_DSCP_CMD_NOP,
1483         /* Set DSCP 3 LSB bits according to dscp[2:0] */
1484         MLXSW_AFA_QOS_DSCP_CMD_SET_3LSB,
1485         /* Set DSCP 3 MSB bits according to dscp[5:3] */
1486         MLXSW_AFA_QOS_DSCP_CMD_SET_3MSB,
1487         /* Set DSCP 6 bits according to dscp[5:0] */
1488         MLXSW_AFA_QOS_DSCP_CMD_SET_ALL,
1489 };
1490
1491 /* afa_qos_dscp_cmd
1492  * DSCP command.
1493  */
1494 MLXSW_ITEM32(afa, qos, dscp_cmd, 0x04, 14, 2);
1495
1496 /* afa_qos_dscp
1497  * DSCP value.
1498  */
1499 MLXSW_ITEM32(afa, qos, dscp, 0x04, 0, 6);
1500
1501 enum mlxsw_afa_qos_switch_prio_cmd {
1502         /* Do nothing */
1503         MLXSW_AFA_QOS_SWITCH_PRIO_CMD_NOP,
1504         /* Set Switch Priority to afa_qos_switch_prio */
1505         MLXSW_AFA_QOS_SWITCH_PRIO_CMD_SET,
1506 };
1507
1508 /* afa_qos_switch_prio_cmd
1509  */
1510 MLXSW_ITEM32(afa, qos, switch_prio_cmd, 0x08, 14, 2);
1511
1512 /* afa_qos_switch_prio
1513  * Switch Priority.
1514  */
1515 MLXSW_ITEM32(afa, qos, switch_prio, 0x08, 0, 4);
1516
1517 enum mlxsw_afa_qos_dscp_rw {
1518         MLXSW_AFA_QOS_DSCP_RW_PRESERVE,
1519         MLXSW_AFA_QOS_DSCP_RW_SET,
1520         MLXSW_AFA_QOS_DSCP_RW_CLEAR,
1521 };
1522
1523 /* afa_qos_dscp_rw
1524  * DSCP Re-write Enable. Controlling the rewrite_enable for DSCP.
1525  */
1526 MLXSW_ITEM32(afa, qos, dscp_rw, 0x0C, 30, 2);
1527
1528 static inline void
1529 mlxsw_afa_qos_ecn_pack(char *payload,
1530                        enum mlxsw_afa_qos_ecn_cmd ecn_cmd, u8 ecn)
1531 {
1532         mlxsw_afa_qos_ecn_cmd_set(payload, ecn_cmd);
1533         mlxsw_afa_qos_ecn_set(payload, ecn);
1534 }
1535
1536 static inline void
1537 mlxsw_afa_qos_dscp_pack(char *payload,
1538                         enum mlxsw_afa_qos_dscp_cmd dscp_cmd, u8 dscp)
1539 {
1540         mlxsw_afa_qos_dscp_cmd_set(payload, dscp_cmd);
1541         mlxsw_afa_qos_dscp_set(payload, dscp);
1542 }
1543
1544 static inline void
1545 mlxsw_afa_qos_switch_prio_pack(char *payload,
1546                                enum mlxsw_afa_qos_switch_prio_cmd prio_cmd,
1547                                u8 prio)
1548 {
1549         mlxsw_afa_qos_switch_prio_cmd_set(payload, prio_cmd);
1550         mlxsw_afa_qos_switch_prio_set(payload, prio);
1551 }
1552
1553 static int __mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block *block,
1554                                                 bool set_dscp, u8 dscp,
1555                                                 bool set_ecn, u8 ecn,
1556                                                 struct netlink_ext_ack *extack)
1557 {
1558         char *act = mlxsw_afa_block_append_action(block,
1559                                                   MLXSW_AFA_QOS_CODE,
1560                                                   MLXSW_AFA_QOS_SIZE);
1561
1562         if (IS_ERR(act)) {
1563                 NL_SET_ERR_MSG_MOD(extack, "Cannot append QOS action");
1564                 return PTR_ERR(act);
1565         }
1566
1567         if (set_ecn)
1568                 mlxsw_afa_qos_ecn_pack(act, MLXSW_AFA_QOS_ECN_CMD_SET, ecn);
1569         if (set_dscp) {
1570                 mlxsw_afa_qos_dscp_pack(act, MLXSW_AFA_QOS_DSCP_CMD_SET_ALL,
1571                                         dscp);
1572                 mlxsw_afa_qos_dscp_rw_set(act, MLXSW_AFA_QOS_DSCP_RW_CLEAR);
1573         }
1574
1575         return 0;
1576 }
1577
1578 int mlxsw_afa_block_append_qos_dsfield(struct mlxsw_afa_block *block,
1579                                        u8 dsfield,
1580                                        struct netlink_ext_ack *extack)
1581 {
1582         return __mlxsw_afa_block_append_qos_dsfield(block,
1583                                                     true, dsfield >> 2,
1584                                                     true, dsfield & 0x03,
1585                                                     extack);
1586 }
1587 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dsfield);
1588
1589 int mlxsw_afa_block_append_qos_dscp(struct mlxsw_afa_block *block,
1590                                     u8 dscp, struct netlink_ext_ack *extack)
1591 {
1592         return __mlxsw_afa_block_append_qos_dsfield(block,
1593                                                     true, dscp,
1594                                                     false, 0,
1595                                                     extack);
1596 }
1597 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_dscp);
1598
1599 int mlxsw_afa_block_append_qos_ecn(struct mlxsw_afa_block *block,
1600                                    u8 ecn, struct netlink_ext_ack *extack)
1601 {
1602         return __mlxsw_afa_block_append_qos_dsfield(block,
1603                                                     false, 0,
1604                                                     true, ecn,
1605                                                     extack);
1606 }
1607 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_ecn);
1608
1609 int mlxsw_afa_block_append_qos_switch_prio(struct mlxsw_afa_block *block,
1610                                            u8 prio,
1611                                            struct netlink_ext_ack *extack)
1612 {
1613         char *act = mlxsw_afa_block_append_action(block,
1614                                                   MLXSW_AFA_QOS_CODE,
1615                                                   MLXSW_AFA_QOS_SIZE);
1616
1617         if (IS_ERR(act)) {
1618                 NL_SET_ERR_MSG_MOD(extack, "Cannot append QOS action");
1619                 return PTR_ERR(act);
1620         }
1621         mlxsw_afa_qos_switch_prio_pack(act, MLXSW_AFA_QOS_SWITCH_PRIO_CMD_SET,
1622                                        prio);
1623         return 0;
1624 }
1625 EXPORT_SYMBOL(mlxsw_afa_block_append_qos_switch_prio);
1626
1627 /* Forwarding Action
1628  * -----------------
1629  * Forwarding Action can be used to implement Policy Based Switching (PBS)
1630  * as well as OpenFlow related "Output" action.
1631  */
1632
1633 #define MLXSW_AFA_FORWARD_CODE 0x07
1634 #define MLXSW_AFA_FORWARD_SIZE 1
1635
1636 enum mlxsw_afa_forward_type {
1637         /* PBS, Policy Based Switching */
1638         MLXSW_AFA_FORWARD_TYPE_PBS,
1639         /* Output, OpenFlow output type */
1640         MLXSW_AFA_FORWARD_TYPE_OUTPUT,
1641 };
1642
1643 /* afa_forward_type */
1644 MLXSW_ITEM32(afa, forward, type, 0x00, 24, 2);
1645
1646 /* afa_forward_pbs_ptr
1647  * A pointer to the PBS entry configured by PPBS register.
1648  * Reserved when in_port is set.
1649  */
1650 MLXSW_ITEM32(afa, forward, pbs_ptr, 0x08, 0, 24);
1651
1652 /* afa_forward_in_port
1653  * Packet is forwarded back to the ingress port.
1654  */
1655 MLXSW_ITEM32(afa, forward, in_port, 0x0C, 0, 1);
1656
1657 static inline void
1658 mlxsw_afa_forward_pack(char *payload, enum mlxsw_afa_forward_type type,
1659                        u32 pbs_ptr, bool in_port)
1660 {
1661         mlxsw_afa_forward_type_set(payload, type);
1662         mlxsw_afa_forward_pbs_ptr_set(payload, pbs_ptr);
1663         mlxsw_afa_forward_in_port_set(payload, in_port);
1664 }
1665
1666 int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block,
1667                                u16 local_port, bool in_port,
1668                                struct netlink_ext_ack *extack)
1669 {
1670         struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref;
1671         u32 kvdl_index;
1672         char *act;
1673         int err;
1674
1675         if (in_port) {
1676                 NL_SET_ERR_MSG_MOD(extack, "Forwarding to ingress port is not supported");
1677                 return -EOPNOTSUPP;
1678         }
1679         fwd_entry_ref = mlxsw_afa_fwd_entry_ref_create(block, local_port);
1680         if (IS_ERR(fwd_entry_ref)) {
1681                 NL_SET_ERR_MSG_MOD(extack, "Cannot create forward action");
1682                 return PTR_ERR(fwd_entry_ref);
1683         }
1684         kvdl_index = fwd_entry_ref->fwd_entry->kvdl_index;
1685
1686         act = mlxsw_afa_block_append_action(block, MLXSW_AFA_FORWARD_CODE,
1687                                             MLXSW_AFA_FORWARD_SIZE);
1688         if (IS_ERR(act)) {
1689                 NL_SET_ERR_MSG_MOD(extack, "Cannot append forward action");
1690                 err = PTR_ERR(act);
1691                 goto err_append_action;
1692         }
1693         mlxsw_afa_forward_pack(act, MLXSW_AFA_FORWARD_TYPE_PBS,
1694                                kvdl_index, in_port);
1695         return 0;
1696
1697 err_append_action:
1698         mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref);
1699         return err;
1700 }
1701 EXPORT_SYMBOL(mlxsw_afa_block_append_fwd);
1702
1703 /* Policing and Counting Action
1704  * ----------------------------
1705  * Policing and Counting action is used for binding policer and counter
1706  * to ACL rules.
1707  */
1708
1709 #define MLXSW_AFA_POLCNT_CODE 0x08
1710 #define MLXSW_AFA_POLCNT_SIZE 1
1711
1712 enum {
1713         MLXSW_AFA_POLCNT_COUNTER,
1714         MLXSW_AFA_POLCNT_POLICER,
1715 };
1716
1717 /* afa_polcnt_c_p
1718  * Counter or policer.
1719  * Indicates whether the action binds a policer or a counter to the flow.
1720  * 0: Counter
1721  * 1: Policer
1722  */
1723 MLXSW_ITEM32(afa, polcnt, c_p, 0x00, 31, 1);
1724
1725 enum mlxsw_afa_polcnt_counter_set_type {
1726         /* No count */
1727         MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_NO_COUNT = 0x00,
1728         /* Count packets and bytes */
1729         MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03,
1730         /* Count only packets */
1731         MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS = 0x05,
1732 };
1733
1734 /* afa_polcnt_counter_set_type
1735  * Counter set type for flow counters.
1736  */
1737 MLXSW_ITEM32(afa, polcnt, counter_set_type, 0x04, 24, 8);
1738
1739 /* afa_polcnt_counter_index
1740  * Counter index for flow counters.
1741  */
1742 MLXSW_ITEM32(afa, polcnt, counter_index, 0x04, 0, 24);
1743
1744 /* afa_polcnt_pid
1745  * Policer ID.
1746  * Reserved when c_p = 0
1747  */
1748 MLXSW_ITEM32(afa, polcnt, pid, 0x08, 0, 14);
1749
1750 static inline void
1751 mlxsw_afa_polcnt_pack(char *payload,
1752                       enum mlxsw_afa_polcnt_counter_set_type set_type,
1753                       u32 counter_index)
1754 {
1755         mlxsw_afa_polcnt_c_p_set(payload, MLXSW_AFA_POLCNT_COUNTER);
1756         mlxsw_afa_polcnt_counter_set_type_set(payload, set_type);
1757         mlxsw_afa_polcnt_counter_index_set(payload, counter_index);
1758 }
1759
1760 static void mlxsw_afa_polcnt_policer_pack(char *payload, u16 policer_index)
1761 {
1762         mlxsw_afa_polcnt_c_p_set(payload, MLXSW_AFA_POLCNT_POLICER);
1763         mlxsw_afa_polcnt_pid_set(payload, policer_index);
1764 }
1765
1766 int mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block *block,
1767                                              u32 counter_index)
1768 {
1769         char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_POLCNT_CODE,
1770                                                   MLXSW_AFA_POLCNT_SIZE);
1771         if (IS_ERR(act))
1772                 return PTR_ERR(act);
1773         mlxsw_afa_polcnt_pack(act, MLXSW_AFA_POLCNT_COUNTER_SET_TYPE_PACKETS_BYTES,
1774                               counter_index);
1775         return 0;
1776 }
1777 EXPORT_SYMBOL(mlxsw_afa_block_append_allocated_counter);
1778
1779 int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block,
1780                                    u32 *p_counter_index,
1781                                    struct netlink_ext_ack *extack)
1782 {
1783         struct mlxsw_afa_counter *counter;
1784         u32 counter_index;
1785         int err;
1786
1787         counter = mlxsw_afa_counter_create(block);
1788         if (IS_ERR(counter)) {
1789                 NL_SET_ERR_MSG_MOD(extack, "Cannot create count action");
1790                 return PTR_ERR(counter);
1791         }
1792         counter_index = counter->counter_index;
1793
1794         err = mlxsw_afa_block_append_allocated_counter(block, counter_index);
1795         if (err) {
1796                 NL_SET_ERR_MSG_MOD(extack, "Cannot append count action");
1797                 goto err_append_allocated_counter;
1798         }
1799         if (p_counter_index)
1800                 *p_counter_index = counter_index;
1801         return 0;
1802
1803 err_append_allocated_counter:
1804         mlxsw_afa_counter_destroy(block, counter);
1805         return err;
1806 }
1807 EXPORT_SYMBOL(mlxsw_afa_block_append_counter);
1808
1809 int mlxsw_afa_block_append_police(struct mlxsw_afa_block *block,
1810                                   u32 fa_index, u64 rate_bytes_ps, u32 burst,
1811                                   u16 *p_policer_index,
1812                                   struct netlink_ext_ack *extack)
1813 {
1814         struct mlxsw_afa_policer_ref *policer_ref;
1815         char *act;
1816         int err;
1817
1818         policer_ref = mlxsw_afa_policer_ref_create(block, fa_index,
1819                                                    rate_bytes_ps,
1820                                                    burst, extack);
1821         if (IS_ERR(policer_ref))
1822                 return PTR_ERR(policer_ref);
1823         *p_policer_index = policer_ref->policer->policer_index;
1824
1825         act = mlxsw_afa_block_append_action_ext(block, MLXSW_AFA_POLCNT_CODE,
1826                                                 MLXSW_AFA_POLCNT_SIZE,
1827                                                 MLXSW_AFA_ACTION_TYPE_POLICE);
1828         if (IS_ERR(act)) {
1829                 NL_SET_ERR_MSG_MOD(extack, "Cannot append police action");
1830                 err = PTR_ERR(act);
1831                 goto err_append_action;
1832         }
1833         mlxsw_afa_polcnt_policer_pack(act, *p_policer_index);
1834
1835         return 0;
1836
1837 err_append_action:
1838         mlxsw_afa_policer_ref_destroy(block, policer_ref);
1839         return err;
1840 }
1841 EXPORT_SYMBOL(mlxsw_afa_block_append_police);
1842
1843 /* Virtual Router and Forwarding Domain Action
1844  * -------------------------------------------
1845  * Virtual Switch action is used for manipulate the Virtual Router (VR),
1846  * MPLS label space and the Forwarding Identifier (FID).
1847  */
1848
1849 #define MLXSW_AFA_VIRFWD_CODE 0x0E
1850 #define MLXSW_AFA_VIRFWD_SIZE 1
1851
1852 enum mlxsw_afa_virfwd_fid_cmd {
1853         /* Do nothing */
1854         MLXSW_AFA_VIRFWD_FID_CMD_NOOP,
1855         /* Set the Forwarding Identifier (FID) to fid */
1856         MLXSW_AFA_VIRFWD_FID_CMD_SET,
1857 };
1858
1859 /* afa_virfwd_fid_cmd */
1860 MLXSW_ITEM32(afa, virfwd, fid_cmd, 0x08, 29, 3);
1861
1862 /* afa_virfwd_fid
1863  * The FID value.
1864  */
1865 MLXSW_ITEM32(afa, virfwd, fid, 0x08, 0, 16);
1866
1867 static inline void mlxsw_afa_virfwd_pack(char *payload,
1868                                          enum mlxsw_afa_virfwd_fid_cmd fid_cmd,
1869                                          u16 fid)
1870 {
1871         mlxsw_afa_virfwd_fid_cmd_set(payload, fid_cmd);
1872         mlxsw_afa_virfwd_fid_set(payload, fid);
1873 }
1874
1875 int mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block *block, u16 fid,
1876                                    struct netlink_ext_ack *extack)
1877 {
1878         char *act = mlxsw_afa_block_append_action(block,
1879                                                   MLXSW_AFA_VIRFWD_CODE,
1880                                                   MLXSW_AFA_VIRFWD_SIZE);
1881         if (IS_ERR(act)) {
1882                 NL_SET_ERR_MSG_MOD(extack, "Cannot append fid_set action");
1883                 return PTR_ERR(act);
1884         }
1885         mlxsw_afa_virfwd_pack(act, MLXSW_AFA_VIRFWD_FID_CMD_SET, fid);
1886         return 0;
1887 }
1888 EXPORT_SYMBOL(mlxsw_afa_block_append_fid_set);
1889
1890 /* Ignore Action
1891  * -------------
1892  * The ignore action is used to ignore basic switching functions such as
1893  * learning on a per-packet basis.
1894  */
1895
1896 #define MLXSW_AFA_IGNORE_CODE 0x0F
1897 #define MLXSW_AFA_IGNORE_SIZE 1
1898
1899 /* afa_ignore_disable_learning
1900  * Disable learning on ingress.
1901  */
1902 MLXSW_ITEM32(afa, ignore, disable_learning, 0x00, 29, 1);
1903
1904 /* afa_ignore_disable_security
1905  * Disable security lookup on ingress.
1906  * Reserved when Spectrum-1.
1907  */
1908 MLXSW_ITEM32(afa, ignore, disable_security, 0x00, 28, 1);
1909
1910 static void mlxsw_afa_ignore_pack(char *payload, bool disable_learning,
1911                                   bool disable_security)
1912 {
1913         mlxsw_afa_ignore_disable_learning_set(payload, disable_learning);
1914         mlxsw_afa_ignore_disable_security_set(payload, disable_security);
1915 }
1916
1917 int mlxsw_afa_block_append_ignore(struct mlxsw_afa_block *block,
1918                                   bool disable_learning, bool disable_security)
1919 {
1920         char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_IGNORE_CODE,
1921                                                   MLXSW_AFA_IGNORE_SIZE);
1922
1923         if (IS_ERR(act))
1924                 return PTR_ERR(act);
1925         mlxsw_afa_ignore_pack(act, disable_learning, disable_security);
1926         return 0;
1927 }
1928 EXPORT_SYMBOL(mlxsw_afa_block_append_ignore);
1929
1930 /* MC Routing Action
1931  * -----------------
1932  * The Multicast router action. Can be used by RMFT_V2 - Router Multicast
1933  * Forwarding Table Version 2 Register.
1934  */
1935
1936 #define MLXSW_AFA_MCROUTER_CODE 0x10
1937 #define MLXSW_AFA_MCROUTER_SIZE 2
1938
1939 enum mlxsw_afa_mcrouter_rpf_action {
1940         MLXSW_AFA_MCROUTER_RPF_ACTION_NOP,
1941         MLXSW_AFA_MCROUTER_RPF_ACTION_TRAP,
1942         MLXSW_AFA_MCROUTER_RPF_ACTION_DISCARD_ERROR,
1943 };
1944
1945 /* afa_mcrouter_rpf_action */
1946 MLXSW_ITEM32(afa, mcrouter, rpf_action, 0x00, 28, 3);
1947
1948 /* afa_mcrouter_expected_irif */
1949 MLXSW_ITEM32(afa, mcrouter, expected_irif, 0x00, 0, 16);
1950
1951 /* afa_mcrouter_min_mtu */
1952 MLXSW_ITEM32(afa, mcrouter, min_mtu, 0x08, 0, 16);
1953
1954 enum mlxsw_afa_mrouter_vrmid {
1955         MLXSW_AFA_MCROUTER_VRMID_INVALID,
1956         MLXSW_AFA_MCROUTER_VRMID_VALID
1957 };
1958
1959 /* afa_mcrouter_vrmid
1960  * Valid RMID: rigr_rmid_index is used as RMID
1961  */
1962 MLXSW_ITEM32(afa, mcrouter, vrmid, 0x0C, 31, 1);
1963
1964 /* afa_mcrouter_rigr_rmid_index
1965  * When the vrmid field is set to invalid, the field is used as pointer to
1966  * Router Interface Group (RIGR) Table in the KVD linear.
1967  * When the vrmid is set to valid, the field is used as RMID index, ranged
1968  * from 0 to max_mid - 1. The index is to the Port Group Table.
1969  */
1970 MLXSW_ITEM32(afa, mcrouter, rigr_rmid_index, 0x0C, 0, 24);
1971
1972 static inline void
1973 mlxsw_afa_mcrouter_pack(char *payload,
1974                         enum mlxsw_afa_mcrouter_rpf_action rpf_action,
1975                         u16 expected_irif, u16 min_mtu,
1976                         enum mlxsw_afa_mrouter_vrmid vrmid, u32 rigr_rmid_index)
1977
1978 {
1979         mlxsw_afa_mcrouter_rpf_action_set(payload, rpf_action);
1980         mlxsw_afa_mcrouter_expected_irif_set(payload, expected_irif);
1981         mlxsw_afa_mcrouter_min_mtu_set(payload, min_mtu);
1982         mlxsw_afa_mcrouter_vrmid_set(payload, vrmid);
1983         mlxsw_afa_mcrouter_rigr_rmid_index_set(payload, rigr_rmid_index);
1984 }
1985
1986 int mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block *block,
1987                                     u16 expected_irif, u16 min_mtu,
1988                                     bool rmid_valid, u32 kvdl_index)
1989 {
1990         char *act = mlxsw_afa_block_append_action(block,
1991                                                   MLXSW_AFA_MCROUTER_CODE,
1992                                                   MLXSW_AFA_MCROUTER_SIZE);
1993         if (IS_ERR(act))
1994                 return PTR_ERR(act);
1995         mlxsw_afa_mcrouter_pack(act, MLXSW_AFA_MCROUTER_RPF_ACTION_TRAP,
1996                                 expected_irif, min_mtu, rmid_valid, kvdl_index);
1997         return 0;
1998 }
1999 EXPORT_SYMBOL(mlxsw_afa_block_append_mcrouter);
2000
2001 /* SIP DIP Action
2002  * --------------
2003  * The SIP_DIP_ACTION is used for modifying the SIP and DIP fields of the
2004  * packet, e.g. for NAT. The L3 checksum is updated. Also, if the L4 is TCP or
2005  * if the L4 is UDP and the checksum field is not zero, then the L4 checksum is
2006  * updated.
2007  */
2008
2009 #define MLXSW_AFA_IP_CODE 0x11
2010 #define MLXSW_AFA_IP_SIZE 2
2011
2012 enum mlxsw_afa_ip_s_d {
2013         /* ip refers to dip */
2014         MLXSW_AFA_IP_S_D_DIP,
2015         /* ip refers to sip */
2016         MLXSW_AFA_IP_S_D_SIP,
2017 };
2018
2019 /* afa_ip_s_d
2020  * Source or destination.
2021  */
2022 MLXSW_ITEM32(afa, ip, s_d, 0x00, 31, 1);
2023
2024 enum mlxsw_afa_ip_m_l {
2025         /* LSB: ip[63:0] refers to ip[63:0] */
2026         MLXSW_AFA_IP_M_L_LSB,
2027         /* MSB: ip[63:0] refers to ip[127:64] */
2028         MLXSW_AFA_IP_M_L_MSB,
2029 };
2030
2031 /* afa_ip_m_l
2032  * MSB or LSB.
2033  */
2034 MLXSW_ITEM32(afa, ip, m_l, 0x00, 30, 1);
2035
2036 /* afa_ip_ip_63_32
2037  * Bits [63:32] in the IP address to change to.
2038  */
2039 MLXSW_ITEM32(afa, ip, ip_63_32, 0x08, 0, 32);
2040
2041 /* afa_ip_ip_31_0
2042  * Bits [31:0] in the IP address to change to.
2043  */
2044 MLXSW_ITEM32(afa, ip, ip_31_0, 0x0C, 0, 32);
2045
2046 static void mlxsw_afa_ip_pack(char *payload, enum mlxsw_afa_ip_s_d s_d,
2047                               enum mlxsw_afa_ip_m_l m_l, u32 ip_31_0,
2048                               u32 ip_63_32)
2049 {
2050         mlxsw_afa_ip_s_d_set(payload, s_d);
2051         mlxsw_afa_ip_m_l_set(payload, m_l);
2052         mlxsw_afa_ip_ip_31_0_set(payload, ip_31_0);
2053         mlxsw_afa_ip_ip_63_32_set(payload, ip_63_32);
2054 }
2055
2056 int mlxsw_afa_block_append_ip(struct mlxsw_afa_block *block, bool is_dip,
2057                               bool is_lsb, u32 val_31_0, u32 val_63_32,
2058                               struct netlink_ext_ack *extack)
2059 {
2060         enum mlxsw_afa_ip_s_d s_d = is_dip ? MLXSW_AFA_IP_S_D_DIP :
2061                                              MLXSW_AFA_IP_S_D_SIP;
2062         enum mlxsw_afa_ip_m_l m_l = is_lsb ? MLXSW_AFA_IP_M_L_LSB :
2063                                              MLXSW_AFA_IP_M_L_MSB;
2064         char *act = mlxsw_afa_block_append_action(block,
2065                                                   MLXSW_AFA_IP_CODE,
2066                                                   MLXSW_AFA_IP_SIZE);
2067
2068         if (IS_ERR(act)) {
2069                 NL_SET_ERR_MSG_MOD(extack, "Cannot append IP action");
2070                 return PTR_ERR(act);
2071         }
2072
2073         mlxsw_afa_ip_pack(act, s_d, m_l, val_31_0, val_63_32);
2074         return 0;
2075 }
2076 EXPORT_SYMBOL(mlxsw_afa_block_append_ip);
2077
2078 /* L4 Port Action
2079  * --------------
2080  * The L4_PORT_ACTION is used for modifying the sport and dport fields of the packet, e.g. for NAT.
2081  * If (the L4 is TCP) or if (the L4 is UDP and checksum field!=0) then the L4 checksum is updated.
2082  */
2083
2084 #define MLXSW_AFA_L4PORT_CODE 0x12
2085 #define MLXSW_AFA_L4PORT_SIZE 1
2086
2087 enum mlxsw_afa_l4port_s_d {
2088         /* configure src_l4_port */
2089         MLXSW_AFA_L4PORT_S_D_SRC,
2090         /* configure dst_l4_port */
2091         MLXSW_AFA_L4PORT_S_D_DST,
2092 };
2093
2094 /* afa_l4port_s_d
2095  * Source or destination.
2096  */
2097 MLXSW_ITEM32(afa, l4port, s_d, 0x00, 31, 1);
2098
2099 /* afa_l4port_l4_port
2100  * Number of port to change to.
2101  */
2102 MLXSW_ITEM32(afa, l4port, l4_port, 0x08, 0, 16);
2103
2104 static void mlxsw_afa_l4port_pack(char *payload, enum mlxsw_afa_l4port_s_d s_d, u16 l4_port)
2105 {
2106         mlxsw_afa_l4port_s_d_set(payload, s_d);
2107         mlxsw_afa_l4port_l4_port_set(payload, l4_port);
2108 }
2109
2110 int mlxsw_afa_block_append_l4port(struct mlxsw_afa_block *block, bool is_dport, u16 l4_port,
2111                                   struct netlink_ext_ack *extack)
2112 {
2113         enum mlxsw_afa_l4port_s_d s_d = is_dport ? MLXSW_AFA_L4PORT_S_D_DST :
2114                                                    MLXSW_AFA_L4PORT_S_D_SRC;
2115         char *act = mlxsw_afa_block_append_action(block,
2116                                                   MLXSW_AFA_L4PORT_CODE,
2117                                                   MLXSW_AFA_L4PORT_SIZE);
2118
2119         if (IS_ERR(act)) {
2120                 NL_SET_ERR_MSG_MOD(extack, "Cannot append L4_PORT action");
2121                 return PTR_ERR(act);
2122         }
2123
2124         mlxsw_afa_l4port_pack(act, s_d, l4_port);
2125         return 0;
2126 }
2127 EXPORT_SYMBOL(mlxsw_afa_block_append_l4port);
2128
2129 /* Mirror Sampler Action
2130  * ---------------------
2131  * The SAMPLER_ACTION is used to mirror packets with a probability (sampling).
2132  */
2133
2134 #define MLXSW_AFA_SAMPLER_CODE 0x13
2135 #define MLXSW_AFA_SAMPLER_SIZE 1
2136
2137 /* afa_sampler_mirror_agent
2138  * Mirror (SPAN) agent.
2139  */
2140 MLXSW_ITEM32(afa, sampler, mirror_agent, 0x04, 0, 3);
2141
2142 #define MLXSW_AFA_SAMPLER_RATE_MAX (BIT(24) - 1)
2143
2144 /* afa_sampler_mirror_probability_rate
2145  * Mirroring probability.
2146  * Valid values are 1 to 2^24 - 1
2147  */
2148 MLXSW_ITEM32(afa, sampler, mirror_probability_rate, 0x08, 0, 24);
2149
2150 static void mlxsw_afa_sampler_pack(char *payload, u8 mirror_agent, u32 rate)
2151 {
2152         mlxsw_afa_sampler_mirror_agent_set(payload, mirror_agent);
2153         mlxsw_afa_sampler_mirror_probability_rate_set(payload, rate);
2154 }
2155
2156 struct mlxsw_afa_sampler {
2157         struct mlxsw_afa_resource resource;
2158         int span_id;
2159         u16 local_port;
2160         bool ingress;
2161 };
2162
2163 static void mlxsw_afa_sampler_destroy(struct mlxsw_afa_block *block,
2164                                       struct mlxsw_afa_sampler *sampler)
2165 {
2166         mlxsw_afa_resource_del(&sampler->resource);
2167         block->afa->ops->sampler_del(block->afa->ops_priv, sampler->local_port,
2168                                      sampler->span_id, sampler->ingress);
2169         kfree(sampler);
2170 }
2171
2172 static void mlxsw_afa_sampler_destructor(struct mlxsw_afa_block *block,
2173                                          struct mlxsw_afa_resource *resource)
2174 {
2175         struct mlxsw_afa_sampler *sampler;
2176
2177         sampler = container_of(resource, struct mlxsw_afa_sampler, resource);
2178         mlxsw_afa_sampler_destroy(block, sampler);
2179 }
2180
2181 static struct mlxsw_afa_sampler *
2182 mlxsw_afa_sampler_create(struct mlxsw_afa_block *block, u16 local_port,
2183                          struct psample_group *psample_group, u32 rate,
2184                          u32 trunc_size, bool truncate, bool ingress,
2185                          struct netlink_ext_ack *extack)
2186 {
2187         struct mlxsw_afa_sampler *sampler;
2188         int err;
2189
2190         sampler = kzalloc(sizeof(*sampler), GFP_KERNEL);
2191         if (!sampler)
2192                 return ERR_PTR(-ENOMEM);
2193
2194         err = block->afa->ops->sampler_add(block->afa->ops_priv, local_port,
2195                                            psample_group, rate, trunc_size,
2196                                            truncate, ingress, &sampler->span_id,
2197                                            extack);
2198         if (err)
2199                 goto err_sampler_add;
2200
2201         sampler->ingress = ingress;
2202         sampler->local_port = local_port;
2203         sampler->resource.destructor = mlxsw_afa_sampler_destructor;
2204         mlxsw_afa_resource_add(block, &sampler->resource);
2205         return sampler;
2206
2207 err_sampler_add:
2208         kfree(sampler);
2209         return ERR_PTR(err);
2210 }
2211
2212 static int
2213 mlxsw_afa_block_append_allocated_sampler(struct mlxsw_afa_block *block,
2214                                          u8 mirror_agent, u32 rate)
2215 {
2216         char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_SAMPLER_CODE,
2217                                                   MLXSW_AFA_SAMPLER_SIZE);
2218
2219         if (IS_ERR(act))
2220                 return PTR_ERR(act);
2221         mlxsw_afa_sampler_pack(act, mirror_agent, rate);
2222         return 0;
2223 }
2224
2225 int mlxsw_afa_block_append_sampler(struct mlxsw_afa_block *block, u16 local_port,
2226                                    struct psample_group *psample_group,
2227                                    u32 rate, u32 trunc_size, bool truncate,
2228                                    bool ingress,
2229                                    struct netlink_ext_ack *extack)
2230 {
2231         struct mlxsw_afa_sampler *sampler;
2232         int err;
2233
2234         if (rate > MLXSW_AFA_SAMPLER_RATE_MAX) {
2235                 NL_SET_ERR_MSG_MOD(extack, "Sampling rate is too high");
2236                 return -EINVAL;
2237         }
2238
2239         sampler = mlxsw_afa_sampler_create(block, local_port, psample_group,
2240                                            rate, trunc_size, truncate, ingress,
2241                                            extack);
2242         if (IS_ERR(sampler))
2243                 return PTR_ERR(sampler);
2244
2245         err = mlxsw_afa_block_append_allocated_sampler(block, sampler->span_id,
2246                                                        rate);
2247         if (err) {
2248                 NL_SET_ERR_MSG_MOD(extack, "Cannot append sampler action");
2249                 goto err_append_allocated_sampler;
2250         }
2251
2252         return 0;
2253
2254 err_append_allocated_sampler:
2255         mlxsw_afa_sampler_destroy(block, sampler);
2256         return err;
2257 }
2258 EXPORT_SYMBOL(mlxsw_afa_block_append_sampler);