]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mlx5/mlx5_core/mlx5_fs_tree.c
MFS r353184, r353186, r353188, r353190, r353192, r353194, r353196, r353198,
[FreeBSD/FreeBSD.git] / sys / dev / mlx5 / mlx5_core / mlx5_fs_tree.c
1 /*-
2  * Copyright (c) 2013-2017, Mellanox Technologies, Ltd.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 #include <linux/module.h>
29 #include <dev/mlx5/driver.h>
30 #include "mlx5_core.h"
31 #include "fs_core.h"
32 #include <linux/string.h>
33 #include <linux/compiler.h>
34
35 #define INIT_TREE_NODE_ARRAY_SIZE(...)  (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\
36                                          sizeof(struct init_tree_node))
37
38 #define ADD_PRIO(name_val, flags_val, min_level_val, max_ft_val, caps_val, \
39                  ...) {.type = FS_TYPE_PRIO,\
40         .name = name_val,\
41         .min_ft_level = min_level_val,\
42         .flags = flags_val,\
43         .max_ft = max_ft_val,\
44         .caps = caps_val,\
45         .children = (struct init_tree_node[]) {__VA_ARGS__},\
46         .ar_size = INIT_TREE_NODE_ARRAY_SIZE(__VA_ARGS__) \
47 }
48
49 #define ADD_FT_PRIO(name_val, flags_val, max_ft_val,  ...)\
50         ADD_PRIO(name_val, flags_val, 0, max_ft_val, {},\
51                  __VA_ARGS__)\
52
53 #define ADD_NS(name_val, ...) {.type = FS_TYPE_NAMESPACE,\
54         .name = name_val,\
55         .children = (struct init_tree_node[]) {__VA_ARGS__},\
56         .ar_size = INIT_TREE_NODE_ARRAY_SIZE(__VA_ARGS__) \
57 }
58
59 #define INIT_CAPS_ARRAY_SIZE(...) (sizeof((long[]){__VA_ARGS__}) /\
60                                    sizeof(long))
61
62 #define FS_CAP(cap) (__mlx5_bit_off(flow_table_nic_cap, cap))
63
64 #define FS_REQUIRED_CAPS(...) {.arr_sz = INIT_CAPS_ARRAY_SIZE(__VA_ARGS__), \
65                                .caps = (long[]) {__VA_ARGS__}}
66
67 #define BYPASS_MAX_FT 5
68 #define BYPASS_PRIO_MAX_FT 1
69 #define KERNEL_MAX_FT 3
70 #define LEFTOVER_MAX_FT 1
71 #define KENREL_MIN_LEVEL 3
72 #define LEFTOVER_MIN_LEVEL KENREL_MIN_LEVEL + 1
73 #define BYPASS_MIN_LEVEL MLX5_NUM_BYPASS_FTS + LEFTOVER_MIN_LEVEL
74 struct node_caps {
75         size_t  arr_sz;
76         long    *caps;
77 };
78
79 struct init_tree_node {
80         enum fs_type    type;
81         const char      *name;
82         struct init_tree_node *children;
83         int ar_size;
84         struct node_caps caps;
85         u8  flags;
86         int min_ft_level;
87         int prio;
88         int max_ft;
89 } root_fs = {
90         .type = FS_TYPE_NAMESPACE,
91         .name = "root",
92         .ar_size = 3,
93         .children = (struct init_tree_node[]) {
94                 ADD_PRIO("by_pass_prio", 0, BYPASS_MIN_LEVEL, 0,
95                          FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en),
96                                           FS_CAP(flow_table_properties_nic_receive.modify_root)),
97                          ADD_NS("by_pass_ns",
98                                 ADD_FT_PRIO("prio0", 0,
99                                             BYPASS_PRIO_MAX_FT),
100                                 ADD_FT_PRIO("prio1", 0,
101                                             BYPASS_PRIO_MAX_FT),
102                                 ADD_FT_PRIO("prio2", 0,
103                                             BYPASS_PRIO_MAX_FT),
104                                 ADD_FT_PRIO("prio3", 0,
105                                             BYPASS_PRIO_MAX_FT),
106                                 ADD_FT_PRIO("prio4", 0,
107                                             BYPASS_PRIO_MAX_FT),
108                                 ADD_FT_PRIO("prio5", 0,
109                                             BYPASS_PRIO_MAX_FT),
110                                 ADD_FT_PRIO("prio6", 0,
111                                             BYPASS_PRIO_MAX_FT),
112                                 ADD_FT_PRIO("prio7", 0,
113                                             BYPASS_PRIO_MAX_FT),
114                                 ADD_FT_PRIO("prio-mcast", 0,
115                                             BYPASS_PRIO_MAX_FT))),
116                 ADD_PRIO("kernel_prio", 0, KENREL_MIN_LEVEL, 0, {},
117                          ADD_NS("kernel_ns",
118                                 ADD_FT_PRIO("prio_kernel-0", 0,
119                                             KERNEL_MAX_FT))),
120                 ADD_PRIO("leftovers_prio", MLX5_CORE_FS_PRIO_SHARED,
121                          LEFTOVER_MIN_LEVEL, 0,
122                          FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en),
123                                           FS_CAP(flow_table_properties_nic_receive.modify_root)),
124                          ADD_NS("leftover_ns",
125                                 ADD_FT_PRIO("leftovers_prio-0",
126                                         MLX5_CORE_FS_PRIO_SHARED,
127                                         LEFTOVER_MAX_FT)))
128         }
129 };
130
131 /* Tree creation functions */
132
133 static struct mlx5_flow_root_namespace *find_root(struct fs_base *node)
134 {
135         struct fs_base *parent;
136
137         /* Make sure we only read it once while we go up the tree */
138         while ((parent = node->parent))
139                 node = parent;
140
141         if (node->type != FS_TYPE_NAMESPACE) {
142                 return NULL;
143         }
144
145         return container_of(container_of(node,
146                                          struct mlx5_flow_namespace,
147                                          base),
148                             struct mlx5_flow_root_namespace,
149                             ns);
150 }
151
152 static inline struct mlx5_core_dev *fs_get_dev(struct fs_base *node)
153 {
154         struct mlx5_flow_root_namespace *root = find_root(node);
155
156         if (root)
157                 return root->dev;
158         return NULL;
159 }
160
161 static void fs_init_node(struct fs_base *node,
162                          unsigned int refcount)
163 {
164         kref_init(&node->refcount);
165         atomic_set(&node->users_refcount, refcount);
166         init_completion(&node->complete);
167         INIT_LIST_HEAD(&node->list);
168         mutex_init(&node->lock);
169 }
170
171 static void _fs_add_node(struct fs_base *node,
172                          const char *name,
173                          struct fs_base *parent)
174 {
175         if (parent)
176                 atomic_inc(&parent->users_refcount);
177         node->name = kstrdup_const(name, GFP_KERNEL);
178         node->parent = parent;
179 }
180
181 static void fs_add_node(struct fs_base *node,
182                         struct fs_base *parent, const char *name,
183                         unsigned int refcount)
184 {
185         fs_init_node(node, refcount);
186         _fs_add_node(node, name, parent);
187 }
188
189 static void _fs_put(struct fs_base *node, void (*kref_cb)(struct kref *kref),
190                     bool parent_locked);
191
192 static void fs_del_dst(struct mlx5_flow_rule *dst);
193 static void _fs_del_ft(struct mlx5_flow_table *ft);
194 static void fs_del_fg(struct mlx5_flow_group *fg);
195 static void fs_del_fte(struct fs_fte *fte);
196
197 static void cmd_remove_node(struct fs_base *base)
198 {
199         switch (base->type) {
200         case FS_TYPE_FLOW_DEST:
201                 fs_del_dst(container_of(base, struct mlx5_flow_rule, base));
202                 break;
203         case FS_TYPE_FLOW_TABLE:
204                 _fs_del_ft(container_of(base, struct mlx5_flow_table, base));
205                 break;
206         case FS_TYPE_FLOW_GROUP:
207                 fs_del_fg(container_of(base, struct mlx5_flow_group, base));
208                 break;
209         case FS_TYPE_FLOW_ENTRY:
210                 fs_del_fte(container_of(base, struct fs_fte, base));
211                 break;
212         default:
213                 break;
214         }
215 }
216
217 static void __fs_remove_node(struct kref *kref)
218 {
219         struct fs_base *node = container_of(kref, struct fs_base, refcount);
220
221         if (node->parent)
222                 mutex_lock(&node->parent->lock);
223         mutex_lock(&node->lock);
224         cmd_remove_node(node);
225         mutex_unlock(&node->lock);
226         complete(&node->complete);
227         if (node->parent) {
228                 mutex_unlock(&node->parent->lock);
229                 _fs_put(node->parent, _fs_remove_node, false);
230         }
231 }
232
233 void _fs_remove_node(struct kref *kref)
234 {
235         struct fs_base *node = container_of(kref, struct fs_base, refcount);
236
237         __fs_remove_node(kref);
238         kfree_const(node->name);
239         kfree(node);
240 }
241
242 static void fs_get(struct fs_base *node)
243 {
244         atomic_inc(&node->users_refcount);
245 }
246
247 static void _fs_put(struct fs_base *node, void (*kref_cb)(struct kref *kref),
248                     bool parent_locked)
249 {
250         struct fs_base *parent_node = node->parent;
251
252         if (parent_node && !parent_locked)
253                 mutex_lock(&parent_node->lock);
254         if (atomic_dec_and_test(&node->users_refcount)) {
255                 if (parent_node) {
256                         /*remove from parent's list*/
257                         list_del_init(&node->list);
258                         mutex_unlock(&parent_node->lock);
259                 }
260                 kref_put(&node->refcount, kref_cb);
261                 if (parent_node && parent_locked)
262                         mutex_lock(&parent_node->lock);
263         } else if (parent_node && !parent_locked) {
264                 mutex_unlock(&parent_node->lock);
265         }
266 }
267
268 static void fs_put(struct fs_base *node)
269 {
270         _fs_put(node, __fs_remove_node, false);
271 }
272
273 static void fs_put_parent_locked(struct fs_base *node)
274 {
275         _fs_put(node, __fs_remove_node, true);
276 }
277
278 static void fs_remove_node(struct fs_base *node)
279 {
280         fs_put(node);
281         wait_for_completion(&node->complete);
282         kfree_const(node->name);
283         kfree(node);
284 }
285
286 static void fs_remove_node_parent_locked(struct fs_base *node)
287 {
288         fs_put_parent_locked(node);
289         wait_for_completion(&node->complete);
290         kfree_const(node->name);
291         kfree(node);
292 }
293
294 static struct fs_fte *fs_alloc_fte(u8 action,
295                                    u32 flow_tag,
296                                    u32 *match_value,
297                                    unsigned int index)
298 {
299         struct fs_fte *fte;
300
301
302         fte = kzalloc(sizeof(*fte), GFP_KERNEL);
303         if (!fte)
304                 return ERR_PTR(-ENOMEM);
305
306         memcpy(fte->val, match_value, sizeof(fte->val));
307         fte->base.type =  FS_TYPE_FLOW_ENTRY;
308         fte->dests_size = 0;
309         fte->flow_tag = flow_tag;
310         fte->index = index;
311         INIT_LIST_HEAD(&fte->dests);
312         fte->action = action;
313
314         return fte;
315 }
316
317 static struct fs_fte *alloc_star_ft_entry(struct mlx5_flow_table *ft,
318                                           struct mlx5_flow_group *fg,
319                                           u32 *match_value,
320                                           unsigned int index)
321 {
322         int err;
323         struct fs_fte *fte;
324         struct mlx5_flow_rule *dst;
325
326         if (fg->num_ftes == fg->max_ftes)
327                 return ERR_PTR(-ENOSPC);
328
329         fte = fs_alloc_fte(MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
330                            MLX5_FS_DEFAULT_FLOW_TAG, match_value, index);
331         if (IS_ERR(fte))
332                 return fte;
333
334         /*create dst*/
335         dst = kzalloc(sizeof(*dst), GFP_KERNEL);
336         if (!dst) {
337                 err = -ENOMEM;
338                 goto free_fte;
339         }
340
341         fte->base.parent = &fg->base;
342         fte->dests_size = 1;
343         dst->dest_attr.type = MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE;
344         dst->base.parent = &fte->base;
345         list_add(&dst->base.list, &fte->dests);
346         /* assumed that the callee creates the star rules sorted by index */
347         list_add_tail(&fte->base.list, &fg->ftes);
348         fg->num_ftes++;
349
350         return fte;
351
352 free_fte:
353         kfree(fte);
354         return ERR_PTR(err);
355 }
356
357 /* assume that fte can't be changed */
358 static void free_star_fte_entry(struct fs_fte *fte)
359 {
360         struct mlx5_flow_group  *fg;
361         struct mlx5_flow_rule   *dst, *temp;
362
363         fs_get_parent(fg, fte);
364
365         list_for_each_entry_safe(dst, temp, &fte->dests, base.list) {
366                 fte->dests_size--;
367                 list_del(&dst->base.list);
368                 kfree(dst);
369         }
370
371         list_del(&fte->base.list);
372         fg->num_ftes--;
373         kfree(fte);
374 }
375
376 static struct mlx5_flow_group *fs_alloc_fg(u32 *create_fg_in)
377 {
378         struct mlx5_flow_group *fg;
379         void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
380                                             create_fg_in, match_criteria);
381         u8 match_criteria_enable = MLX5_GET(create_flow_group_in,
382                                             create_fg_in,
383                                             match_criteria_enable);
384         fg = kzalloc(sizeof(*fg), GFP_KERNEL);
385         if (!fg)
386                 return ERR_PTR(-ENOMEM);
387
388         INIT_LIST_HEAD(&fg->ftes);
389         fg->mask.match_criteria_enable = match_criteria_enable;
390         memcpy(&fg->mask.match_criteria, match_criteria,
391                sizeof(fg->mask.match_criteria));
392         fg->base.type =  FS_TYPE_FLOW_GROUP;
393         fg->start_index = MLX5_GET(create_flow_group_in, create_fg_in,
394                                    start_flow_index);
395         fg->max_ftes = MLX5_GET(create_flow_group_in, create_fg_in,
396                                 end_flow_index) - fg->start_index + 1;
397         return fg;
398 }
399
400 static struct mlx5_flow_table *find_next_ft(struct fs_prio *prio);
401 static struct mlx5_flow_table *find_prev_ft(struct mlx5_flow_table *curr,
402                                             struct fs_prio *prio);
403
404 /* assumed src_ft and dst_ft can't be freed */
405 static int fs_set_star_rule(struct mlx5_core_dev *dev,
406                             struct mlx5_flow_table *src_ft,
407                             struct mlx5_flow_table *dst_ft)
408 {
409         struct mlx5_flow_rule *src_dst;
410         struct fs_fte *src_fte;
411         int err = 0;
412         u32 *match_value;
413         int match_len = MLX5_ST_SZ_BYTES(fte_match_param);
414
415         src_dst = list_first_entry(&src_ft->star_rule.fte->dests,
416                                    struct mlx5_flow_rule, base.list);
417         match_value = mlx5_vzalloc(match_len);
418         if (!match_value) {
419                 mlx5_core_warn(dev, "failed to allocate inbox\n");
420                 return -ENOMEM;
421         }
422         /*Create match context*/
423
424         fs_get_parent(src_fte, src_dst);
425
426         src_dst->dest_attr.ft = dst_ft;
427         if (dst_ft) {
428                 err = mlx5_cmd_fs_set_fte(dev,
429                                           src_ft->vport,
430                                           &src_fte->status,
431                                           match_value, src_ft->type,
432                                           src_ft->id, src_fte->index,
433                                           src_ft->star_rule.fg->id,
434                                           src_fte->flow_tag,
435                                           src_fte->action,
436                                           src_fte->dests_size,
437                                           &src_fte->dests);
438                 if (err)
439                         goto free;
440
441                 fs_get(&dst_ft->base);
442         } else {
443                 mlx5_cmd_fs_delete_fte(dev,
444                                        src_ft->vport,
445                                        &src_fte->status,
446                                        src_ft->type, src_ft->id,
447                                        src_fte->index);
448         }
449
450 free:
451         kvfree(match_value);
452         return err;
453 }
454
455 static int connect_prev_fts(struct fs_prio *locked_prio,
456                             struct fs_prio *prev_prio,
457                             struct mlx5_flow_table *next_ft)
458 {
459         struct mlx5_flow_table *iter;
460         int err = 0;
461         struct mlx5_core_dev *dev = fs_get_dev(&prev_prio->base);
462
463         if (!dev)
464                 return -ENODEV;
465
466         mutex_lock(&prev_prio->base.lock);
467         fs_for_each_ft(iter, prev_prio) {
468                 struct mlx5_flow_rule *src_dst =
469                         list_first_entry(&iter->star_rule.fte->dests,
470                                          struct mlx5_flow_rule, base.list);
471                 struct mlx5_flow_table *prev_ft = src_dst->dest_attr.ft;
472
473                 if (prev_ft == next_ft)
474                         continue;
475
476                 err = fs_set_star_rule(dev, iter, next_ft);
477                 if (err) {
478                         mlx5_core_warn(dev,
479                             "mlx5: flow steering can't connect prev and next\n");
480                         goto unlock;
481                 } else {
482                         /* Assume ft's prio is locked */
483                         if (prev_ft) {
484                                 struct fs_prio *prio;
485
486                                 fs_get_parent(prio, prev_ft);
487                                 if (prio == locked_prio)
488                                         fs_put_parent_locked(&prev_ft->base);
489                                 else
490                                         fs_put(&prev_ft->base);
491                         }
492                 }
493         }
494
495 unlock:
496         mutex_unlock(&prev_prio->base.lock);
497         return 0;
498 }
499
500 static int create_star_rule(struct mlx5_flow_table *ft, struct fs_prio *prio)
501 {
502         struct mlx5_flow_group *fg;
503         int err;
504         u32 *fg_in;
505         u32 *match_value;
506         struct mlx5_flow_table *next_ft;
507         struct mlx5_flow_table *prev_ft;
508         struct mlx5_flow_root_namespace *root = find_root(&prio->base);
509         int fg_inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
510         int match_len = MLX5_ST_SZ_BYTES(fte_match_param);
511
512         fg_in = mlx5_vzalloc(fg_inlen);
513         if (!fg_in) {
514                 mlx5_core_warn(root->dev, "failed to allocate inbox\n");
515                 return -ENOMEM;
516         }
517
518         match_value = mlx5_vzalloc(match_len);
519         if (!match_value) {
520                 mlx5_core_warn(root->dev, "failed to allocate inbox\n");
521                 kvfree(fg_in);
522                 return -ENOMEM;
523         }
524
525         MLX5_SET(create_flow_group_in, fg_in, start_flow_index, ft->max_fte);
526         MLX5_SET(create_flow_group_in, fg_in, end_flow_index, ft->max_fte);
527         fg = fs_alloc_fg(fg_in);
528         if (IS_ERR(fg)) {
529                 err = PTR_ERR(fg);
530                 goto out;
531         }
532         ft->star_rule.fg = fg;
533         err =  mlx5_cmd_fs_create_fg(fs_get_dev(&prio->base),
534                                      fg_in, ft->vport, ft->type,
535                                      ft->id,
536                                      &fg->id);
537         if (err)
538                 goto free_fg;
539
540         ft->star_rule.fte = alloc_star_ft_entry(ft, fg,
541                                                       match_value,
542                                                       ft->max_fte);
543         if (IS_ERR(ft->star_rule.fte))
544                 goto free_star_rule;
545
546         mutex_lock(&root->fs_chain_lock);
547         next_ft = find_next_ft(prio);
548         err = fs_set_star_rule(root->dev, ft, next_ft);
549         if (err) {
550                 mutex_unlock(&root->fs_chain_lock);
551                 goto free_star_rule;
552         }
553         if (next_ft) {
554                 struct fs_prio *parent;
555
556                 fs_get_parent(parent, next_ft);
557                 fs_put(&next_ft->base);
558         }
559         prev_ft = find_prev_ft(ft, prio);
560         if (prev_ft) {
561                 struct fs_prio *prev_parent;
562
563                 fs_get_parent(prev_parent, prev_ft);
564
565                 err = connect_prev_fts(NULL, prev_parent, ft);
566                 if (err) {
567                         mutex_unlock(&root->fs_chain_lock);
568                         goto destroy_chained_star_rule;
569                 }
570                 fs_put(&prev_ft->base);
571         }
572         mutex_unlock(&root->fs_chain_lock);
573         kvfree(fg_in);
574         kvfree(match_value);
575
576         return 0;
577
578 destroy_chained_star_rule:
579         fs_set_star_rule(fs_get_dev(&prio->base), ft, NULL);
580         if (next_ft)
581                 fs_put(&next_ft->base);
582 free_star_rule:
583         free_star_fte_entry(ft->star_rule.fte);
584         mlx5_cmd_fs_destroy_fg(fs_get_dev(&ft->base), ft->vport,
585                                ft->type, ft->id,
586                                fg->id);
587 free_fg:
588         kfree(fg);
589 out:
590         kvfree(fg_in);
591         kvfree(match_value);
592         return err;
593 }
594
595 static void destroy_star_rule(struct mlx5_flow_table *ft, struct fs_prio *prio)
596 {
597         int err;
598         struct mlx5_flow_root_namespace *root;
599         struct mlx5_core_dev *dev = fs_get_dev(&prio->base);
600         struct mlx5_flow_table *prev_ft, *next_ft;
601         struct fs_prio *prev_prio;
602
603         WARN_ON(!dev);
604
605         root = find_root(&prio->base);
606         if (!root)
607                 mlx5_core_err(dev,
608                     "flow steering failed to find root of priority %s",
609                     prio->base.name);
610
611         /* In order to ensure atomic deletion, first update
612          * prev ft to point on the next ft.
613          */
614         mutex_lock(&root->fs_chain_lock);
615         prev_ft = find_prev_ft(ft, prio);
616         next_ft = find_next_ft(prio);
617         if (prev_ft) {
618                 fs_get_parent(prev_prio, prev_ft);
619                 /*Prev is connected to ft, only if ft is the first(last) in the prio*/
620                 err = connect_prev_fts(prio, prev_prio, next_ft);
621                 if (err)
622                         mlx5_core_warn(root->dev,
623                                        "flow steering can't connect prev and next of flow table\n");
624                 fs_put(&prev_ft->base);
625         }
626
627         err = fs_set_star_rule(root->dev, ft, NULL);
628         /*One put is for fs_get in find next ft*/
629         if (next_ft) {
630                 fs_put(&next_ft->base);
631                 if (!err)
632                         fs_put(&next_ft->base);
633         }
634
635         mutex_unlock(&root->fs_chain_lock);
636         err = mlx5_cmd_fs_destroy_fg(dev, ft->vport, ft->type, ft->id,
637                                      ft->star_rule.fg->id);
638         if (err)
639                 mlx5_core_warn(dev,
640                                "flow steering can't destroy star entry group(index:%d) of ft:%s\n", ft->star_rule.fg->start_index,
641                                ft->base.name);
642         free_star_fte_entry(ft->star_rule.fte);
643
644         kfree(ft->star_rule.fg);
645         ft->star_rule.fg = NULL;
646 }
647
648 static struct fs_prio *find_prio(struct mlx5_flow_namespace *ns,
649                                  unsigned int prio)
650 {
651         struct fs_prio *iter_prio;
652
653         fs_for_each_prio(iter_prio, ns) {
654                 if (iter_prio->prio == prio)
655                         return iter_prio;
656         }
657
658         return NULL;
659 }
660
661 static unsigned int _alloc_new_level(struct fs_prio *prio,
662                                      struct mlx5_flow_namespace *match);
663
664 static unsigned int __alloc_new_level(struct mlx5_flow_namespace *ns,
665                                       struct fs_prio *prio)
666 {
667         unsigned int level = 0;
668         struct fs_prio *p;
669
670         if (!ns)
671                 return 0;
672
673         mutex_lock(&ns->base.lock);
674         fs_for_each_prio(p, ns) {
675                 if (p != prio)
676                         level += p->max_ft;
677                 else
678                         break;
679         }
680         mutex_unlock(&ns->base.lock);
681
682         fs_get_parent(prio, ns);
683         if (prio)
684                 WARN_ON(prio->base.type != FS_TYPE_PRIO);
685
686         return level + _alloc_new_level(prio, ns);
687 }
688
689 /* Called under lock of priority, hence locking all upper objects */
690 static unsigned int _alloc_new_level(struct fs_prio *prio,
691                                      struct mlx5_flow_namespace *match)
692 {
693         struct mlx5_flow_namespace *ns;
694         struct fs_base *it;
695         unsigned int level = 0;
696
697         if (!prio)
698                 return 0;
699
700         mutex_lock(&prio->base.lock);
701         fs_for_each_ns_or_ft_reverse(it, prio) {
702                 if (it->type == FS_TYPE_NAMESPACE) {
703                         struct fs_prio *p;
704
705                         fs_get_obj(ns, it);
706
707                         if (match != ns) {
708                                 mutex_lock(&ns->base.lock);
709                                 fs_for_each_prio(p, ns)
710                                         level += p->max_ft;
711                                 mutex_unlock(&ns->base.lock);
712                         } else {
713                                 break;
714                         }
715                 } else {
716                         struct mlx5_flow_table *ft;
717
718                         fs_get_obj(ft, it);
719                         mutex_unlock(&prio->base.lock);
720                         return level + ft->level + 1;
721                 }
722         }
723
724         fs_get_parent(ns, prio);
725         mutex_unlock(&prio->base.lock);
726         return __alloc_new_level(ns, prio) + level;
727 }
728
729 static unsigned int alloc_new_level(struct fs_prio *prio)
730 {
731         return _alloc_new_level(prio, NULL);
732 }
733
734 static int update_root_ft_create(struct mlx5_flow_root_namespace *root,
735                                     struct mlx5_flow_table *ft)
736 {
737         int err = 0;
738         int min_level = INT_MAX;
739
740         if (root->root_ft)
741                 min_level = root->root_ft->level;
742
743         if (ft->level < min_level)
744                 err = mlx5_cmd_update_root_ft(root->dev, ft->type,
745                                               ft->id);
746         else
747                 return err;
748
749         if (err)
750                 mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n",
751                                ft->id);
752         else
753                 root->root_ft = ft;
754
755         return err;
756 }
757
758 static struct mlx5_flow_table *_create_ft_common(struct mlx5_flow_namespace *ns,
759                                                  u16 vport,
760                                                  struct fs_prio *fs_prio,
761                                                  int max_fte,
762                                                  const char *name)
763 {
764         struct mlx5_flow_table *ft;
765         int err;
766         int log_table_sz;
767         int ft_size;
768         char gen_name[20];
769         struct mlx5_flow_root_namespace *root = find_root(&ns->base);
770         struct mlx5_core_dev *dev = fs_get_dev(&ns->base);
771
772         if (!root) {
773                 mlx5_core_err(dev,
774                     "flow steering failed to find root of namespace %s",
775                     ns->base.name);
776                 return ERR_PTR(-ENODEV);
777         }
778
779         if (fs_prio->num_ft == fs_prio->max_ft)
780                 return ERR_PTR(-ENOSPC);
781
782         ft  = kzalloc(sizeof(*ft), GFP_KERNEL);
783         if (!ft)
784                 return ERR_PTR(-ENOMEM);
785
786         fs_init_node(&ft->base, 1);
787         INIT_LIST_HEAD(&ft->fgs);
788
789         /* Temporarily WA until we expose the level set in the API */
790         if (root->table_type == FS_FT_ESW_EGRESS_ACL ||
791                 root->table_type == FS_FT_ESW_INGRESS_ACL)
792                 ft->level = 0;
793         else
794                 ft->level = alloc_new_level(fs_prio);
795
796         ft->base.type = FS_TYPE_FLOW_TABLE;
797         ft->vport = vport;
798         ft->type = root->table_type;
799         /*Two entries are reserved for star rules*/
800         ft_size = roundup_pow_of_two(max_fte + 2);
801         /*User isn't aware to those rules*/
802         ft->max_fte = ft_size - 2;
803         log_table_sz = ilog2(ft_size);
804         err = mlx5_cmd_fs_create_ft(root->dev, ft->vport, ft->type,
805                                     ft->level, log_table_sz, &ft->id);
806         if (err)
807                 goto free_ft;
808
809         err = create_star_rule(ft, fs_prio);
810         if (err)
811                 goto del_ft;
812
813         if ((root->table_type == FS_FT_NIC_RX) && MLX5_CAP_FLOWTABLE(root->dev,
814                                flow_table_properties_nic_receive.modify_root)) {
815                 err = update_root_ft_create(root, ft);
816                 if (err)
817                         goto destroy_star_rule;
818         }
819
820         if (!name || !strlen(name)) {
821                 snprintf(gen_name, 20, "flow_table_%u", ft->id);
822                 _fs_add_node(&ft->base, gen_name, &fs_prio->base);
823         } else {
824                 _fs_add_node(&ft->base, name, &fs_prio->base);
825         }
826         list_add_tail(&ft->base.list, &fs_prio->objs);
827         fs_prio->num_ft++;
828
829         return ft;
830
831 destroy_star_rule:
832         destroy_star_rule(ft, fs_prio);
833 del_ft:
834         mlx5_cmd_fs_destroy_ft(root->dev, ft->vport, ft->type, ft->id);
835 free_ft:
836         kfree(ft);
837         return ERR_PTR(err);
838 }
839
840 static struct mlx5_flow_table *create_ft_common(struct mlx5_flow_namespace *ns,
841                                                 u16 vport,
842                                                 unsigned int prio,
843                                                 int max_fte,
844                                                 const char *name)
845 {
846         struct fs_prio *fs_prio = NULL;
847         fs_prio = find_prio(ns, prio);
848         if (!fs_prio)
849                 return ERR_PTR(-EINVAL);
850
851         return _create_ft_common(ns, vport, fs_prio, max_fte, name);
852 }
853
854
855 static struct mlx5_flow_table *find_first_ft_in_ns(struct mlx5_flow_namespace *ns,
856                                                    struct list_head *start);
857
858 static struct mlx5_flow_table *find_first_ft_in_prio(struct fs_prio *prio,
859                                                      struct list_head *start);
860
861 static struct mlx5_flow_table *mlx5_create_autogrouped_shared_flow_table(struct fs_prio *fs_prio)
862 {
863         struct mlx5_flow_table *ft;
864
865         ft = find_first_ft_in_prio(fs_prio, &fs_prio->objs);
866         if (ft) {
867                 ft->shared_refcount++;
868                 return ft;
869         }
870
871         return NULL;
872 }
873
874 struct mlx5_flow_table *mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace *ns,
875                                                            int prio,
876                                                            const char *name,
877                                                            int num_flow_table_entries,
878                                                            int max_num_groups)
879 {
880         struct mlx5_flow_table *ft = NULL;
881         struct fs_prio *fs_prio;
882         bool is_shared_prio;
883
884         fs_prio = find_prio(ns, prio);
885         if (!fs_prio)
886                 return ERR_PTR(-EINVAL);
887
888         is_shared_prio = fs_prio->flags & MLX5_CORE_FS_PRIO_SHARED;
889         if (is_shared_prio) {
890                 mutex_lock(&fs_prio->shared_lock);
891                 ft = mlx5_create_autogrouped_shared_flow_table(fs_prio);
892         }
893
894         if (ft)
895                 goto return_ft;
896
897         ft = create_ft_common(ns, 0, prio, num_flow_table_entries,
898                               name);
899         if (IS_ERR(ft))
900                 goto return_ft;
901
902         ft->autogroup.active = true;
903         ft->autogroup.max_types = max_num_groups;
904         if (is_shared_prio)
905                 ft->shared_refcount = 1;
906
907 return_ft:
908         if (is_shared_prio)
909                 mutex_unlock(&fs_prio->shared_lock);
910         return ft;
911 }
912 EXPORT_SYMBOL(mlx5_create_auto_grouped_flow_table);
913
914 struct mlx5_flow_table *mlx5_create_vport_flow_table(struct mlx5_flow_namespace *ns,
915                                                      u16 vport,
916                                                      int prio,
917                                                      const char *name,
918                                                      int num_flow_table_entries)
919 {
920         return create_ft_common(ns, vport, prio, num_flow_table_entries, name);
921 }
922 EXPORT_SYMBOL(mlx5_create_vport_flow_table);
923
924 struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,
925                                                int prio,
926                                                const char *name,
927                                                int num_flow_table_entries)
928 {
929         return create_ft_common(ns, 0, prio, num_flow_table_entries, name);
930 }
931 EXPORT_SYMBOL(mlx5_create_flow_table);
932
933 static void _fs_del_ft(struct mlx5_flow_table *ft)
934 {
935         int err;
936         struct mlx5_core_dev *dev = fs_get_dev(&ft->base);
937         struct fs_prio *prio;
938
939         err = mlx5_cmd_fs_destroy_ft(dev, ft->vport, ft->type, ft->id);
940         if (err)
941                 mlx5_core_warn(dev, "flow steering can't destroy ft %s\n",
942                                ft->base.name);
943
944         fs_get_parent(prio, ft);
945         prio->num_ft--;
946 }
947
948 static int update_root_ft_destroy(struct mlx5_flow_root_namespace *root,
949                                     struct mlx5_flow_table *ft)
950 {
951         int err = 0;
952         struct fs_prio *prio;
953         struct mlx5_flow_table *next_ft = NULL;
954         struct mlx5_flow_table *put_ft = NULL;
955
956         if (root->root_ft != ft)
957                 return 0;
958
959         fs_get_parent(prio, ft);
960         /*Assuming objs containis only flow tables and
961          * flow tables are sorted by level.
962          */
963         if (!list_is_last(&ft->base.list, &prio->objs)) {
964                 next_ft = list_next_entry(ft, base.list);
965         } else {
966                 next_ft = find_next_ft(prio);
967                 put_ft = next_ft;
968         }
969
970         if (next_ft) {
971                 err = mlx5_cmd_update_root_ft(root->dev, next_ft->type,
972                                               next_ft->id);
973                 if (err)
974                         mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n",
975                                        ft->id);
976         }
977         if (!err)
978                 root->root_ft = next_ft;
979
980         if (put_ft)
981                 fs_put(&put_ft->base);
982
983         return err;
984 }
985
986 /*Objects in the same prio are destroyed in the reverse order they were createrd*/
987 int mlx5_destroy_flow_table(struct mlx5_flow_table *ft)
988 {
989         int err = 0;
990         struct fs_prio *prio;
991         struct mlx5_flow_root_namespace *root;
992         bool is_shared_prio;
993         struct mlx5_core_dev *dev;
994
995         fs_get_parent(prio, ft);
996         root = find_root(&prio->base);
997         dev = fs_get_dev(&prio->base);
998
999         if (!root) {
1000                 mlx5_core_err(dev,
1001                     "flow steering failed to find root of priority %s",
1002                     prio->base.name);
1003                 return -ENODEV;
1004         }
1005
1006         is_shared_prio = prio->flags & MLX5_CORE_FS_PRIO_SHARED;
1007         if (is_shared_prio) {
1008                 mutex_lock(&prio->shared_lock);
1009                 if (ft->shared_refcount > 1) {
1010                         --ft->shared_refcount;
1011                         fs_put(&ft->base);
1012                         mutex_unlock(&prio->shared_lock);
1013                         return 0;
1014                 }
1015         }
1016
1017         mutex_lock(&prio->base.lock);
1018         mutex_lock(&ft->base.lock);
1019
1020         err = update_root_ft_destroy(root, ft);
1021         if (err)
1022                 goto unlock_ft;
1023
1024         /* delete two last entries */
1025         destroy_star_rule(ft, prio);
1026
1027         mutex_unlock(&ft->base.lock);
1028         fs_remove_node_parent_locked(&ft->base);
1029         mutex_unlock(&prio->base.lock);
1030         if (is_shared_prio)
1031                 mutex_unlock(&prio->shared_lock);
1032
1033         return err;
1034
1035 unlock_ft:
1036         mutex_unlock(&ft->base.lock);
1037         mutex_unlock(&prio->base.lock);
1038         if (is_shared_prio)
1039                 mutex_unlock(&prio->shared_lock);
1040
1041         return err;
1042 }
1043 EXPORT_SYMBOL(mlx5_destroy_flow_table);
1044
1045 static struct mlx5_flow_group *fs_create_fg(struct mlx5_core_dev *dev,
1046                                             struct mlx5_flow_table *ft,
1047                                             struct list_head *prev,
1048                                             u32 *fg_in,
1049                                             int refcount)
1050 {
1051         struct mlx5_flow_group *fg;
1052         int err;
1053         unsigned int end_index;
1054         char name[20];
1055
1056         fg = fs_alloc_fg(fg_in);
1057         if (IS_ERR(fg))
1058                 return fg;
1059
1060         end_index = fg->start_index + fg->max_ftes - 1;
1061         err =  mlx5_cmd_fs_create_fg(dev, fg_in,
1062                                      ft->vport, ft->type, ft->id,
1063                                      &fg->id);
1064         if (err)
1065                 goto free_fg;
1066
1067         mutex_lock(&ft->base.lock);
1068         if (ft->autogroup.active)
1069                 ft->autogroup.num_types++;
1070
1071         snprintf(name, sizeof(name), "group_%u", fg->id);
1072         /*Add node to tree*/
1073         fs_add_node(&fg->base, &ft->base, name, refcount);
1074         /*Add node to group list*/
1075         list_add(&fg->base.list, prev);
1076         mutex_unlock(&ft->base.lock);
1077
1078         return fg;
1079
1080 free_fg:
1081         kfree(fg);
1082         return ERR_PTR(err);
1083 }
1084
1085 struct mlx5_flow_group *mlx5_create_flow_group(struct mlx5_flow_table *ft,
1086                                                u32 *in)
1087 {
1088         struct mlx5_flow_group *fg;
1089         struct mlx5_core_dev *dev = fs_get_dev(&ft->base);
1090
1091         if (!dev)
1092                 return ERR_PTR(-ENODEV);
1093
1094         if (ft->autogroup.active)
1095                 return ERR_PTR(-EPERM);
1096
1097         fg = fs_create_fg(dev, ft, ft->fgs.prev, in, 1);
1098
1099         return fg;
1100 }
1101 EXPORT_SYMBOL(mlx5_create_flow_group);
1102
1103 /*Group is destoyed when all the rules in the group were removed*/
1104 static void fs_del_fg(struct mlx5_flow_group *fg)
1105 {
1106         struct mlx5_flow_table *parent_ft;
1107         struct mlx5_core_dev *dev;
1108
1109         fs_get_parent(parent_ft, fg);
1110         dev = fs_get_dev(&parent_ft->base);
1111         WARN_ON(!dev);
1112
1113         if (parent_ft->autogroup.active)
1114                 parent_ft->autogroup.num_types--;
1115
1116         if (mlx5_cmd_fs_destroy_fg(dev, parent_ft->vport,
1117                                    parent_ft->type,
1118                                    parent_ft->id, fg->id))
1119                 mlx5_core_warn(dev, "flow steering can't destroy fg\n");
1120 }
1121
1122 void mlx5_destroy_flow_group(struct mlx5_flow_group *fg)
1123 {
1124         fs_remove_node(&fg->base);
1125 }
1126 EXPORT_SYMBOL(mlx5_destroy_flow_group);
1127
1128 static bool _fs_match_exact_val(void *mask, void *val1, void *val2, size_t size)
1129 {
1130         unsigned int i;
1131
1132         /* TODO: optimize by comparing 64bits when possible */
1133         for (i = 0; i < size; i++, mask++, val1++, val2++)
1134                 if ((*((u8 *)val1) & (*(u8 *)mask)) !=
1135                     ((*(u8 *)val2) & (*(u8 *)mask)))
1136                         return false;
1137
1138         return true;
1139 }
1140
1141 bool fs_match_exact_val(struct mlx5_core_fs_mask *mask,
1142                                void *val1, void *val2)
1143 {
1144         if (mask->match_criteria_enable &
1145             1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS) {
1146                 void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
1147                                                 val1, outer_headers);
1148                 void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
1149                                                 val2, outer_headers);
1150                 void *fte_mask = MLX5_ADDR_OF(fte_match_param,
1151                                               mask->match_criteria, outer_headers);
1152
1153                 if (!_fs_match_exact_val(fte_mask, fte_match1, fte_match2,
1154                                          MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)))
1155                         return false;
1156         }
1157
1158         if (mask->match_criteria_enable &
1159             1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS) {
1160                 void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
1161                                                 val1, misc_parameters);
1162                 void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
1163                                                 val2, misc_parameters);
1164                 void *fte_mask = MLX5_ADDR_OF(fte_match_param,
1165                                           mask->match_criteria, misc_parameters);
1166
1167                 if (!_fs_match_exact_val(fte_mask, fte_match1, fte_match2,
1168                                          MLX5_ST_SZ_BYTES(fte_match_set_misc)))
1169                         return false;
1170         }
1171         if (mask->match_criteria_enable &
1172             1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_INNER_HEADERS) {
1173                 void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
1174                                                 val1, inner_headers);
1175                 void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
1176                                                 val2, inner_headers);
1177                 void *fte_mask = MLX5_ADDR_OF(fte_match_param,
1178                                           mask->match_criteria, inner_headers);
1179
1180                 if (!_fs_match_exact_val(fte_mask, fte_match1, fte_match2,
1181                                          MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)))
1182                         return false;
1183         }
1184         return true;
1185 }
1186
1187 bool fs_match_exact_mask(u8 match_criteria_enable1,
1188                                 u8 match_criteria_enable2,
1189                                 void *mask1, void *mask2)
1190 {
1191         return match_criteria_enable1 == match_criteria_enable2 &&
1192                 !memcmp(mask1, mask2, MLX5_ST_SZ_BYTES(fte_match_param));
1193 }
1194
1195 static struct mlx5_flow_table *find_first_ft_in_ns_reverse(struct mlx5_flow_namespace *ns,
1196                                                            struct list_head *start);
1197
1198 static struct mlx5_flow_table *_find_first_ft_in_prio_reverse(struct fs_prio *prio,
1199                                                               struct list_head *start)
1200 {
1201         struct fs_base *it = container_of(start, struct fs_base, list);
1202
1203         if (!prio)
1204                 return NULL;
1205
1206         fs_for_each_ns_or_ft_continue_reverse(it, prio) {
1207                 struct mlx5_flow_namespace      *ns;
1208                 struct mlx5_flow_table          *ft;
1209
1210                 if (it->type == FS_TYPE_FLOW_TABLE) {
1211                         fs_get_obj(ft, it);
1212                         fs_get(&ft->base);
1213                         return ft;
1214                 }
1215
1216                 fs_get_obj(ns, it);
1217                 WARN_ON(ns->base.type != FS_TYPE_NAMESPACE);
1218
1219                 ft = find_first_ft_in_ns_reverse(ns, &ns->prios);
1220                 if (ft)
1221                         return ft;
1222         }
1223
1224         return NULL;
1225 }
1226
1227 static struct mlx5_flow_table *find_first_ft_in_prio_reverse(struct fs_prio *prio,
1228                                                              struct list_head *start)
1229 {
1230         struct mlx5_flow_table *ft;
1231
1232         if (!prio)
1233                 return NULL;
1234
1235         mutex_lock(&prio->base.lock);
1236         ft = _find_first_ft_in_prio_reverse(prio, start);
1237         mutex_unlock(&prio->base.lock);
1238
1239         return ft;
1240 }
1241
1242 static struct mlx5_flow_table *find_first_ft_in_ns_reverse(struct mlx5_flow_namespace *ns,
1243                                                            struct list_head *start)
1244 {
1245         struct fs_prio *prio;
1246
1247         if (!ns)
1248                 return NULL;
1249
1250         fs_get_obj(prio, container_of(start, struct fs_base, list));
1251         mutex_lock(&ns->base.lock);
1252         fs_for_each_prio_continue_reverse(prio, ns) {
1253                 struct mlx5_flow_table *ft;
1254
1255                 ft = find_first_ft_in_prio_reverse(prio, &prio->objs);
1256                 if (ft) {
1257                         mutex_unlock(&ns->base.lock);
1258                         return ft;
1259                 }
1260         }
1261         mutex_unlock(&ns->base.lock);
1262
1263         return NULL;
1264 }
1265
1266 /* Returned a held ft, assumed curr is protected, assumed curr's parent is
1267  * locked
1268  */
1269 static struct mlx5_flow_table *find_prev_ft(struct mlx5_flow_table *curr,
1270                                             struct fs_prio *prio)
1271 {
1272         struct mlx5_flow_table *ft = NULL;
1273         struct fs_base *curr_base;
1274
1275         if (!curr)
1276                 return NULL;
1277
1278         /* prio has either namespace or flow-tables, but not both */
1279         if (!list_empty(&prio->objs) &&
1280             list_first_entry(&prio->objs, struct mlx5_flow_table, base.list) !=
1281             curr)
1282                 return NULL;
1283
1284         while (!ft && prio) {
1285                 struct mlx5_flow_namespace *ns;
1286
1287                 fs_get_parent(ns, prio);
1288                 ft = find_first_ft_in_ns_reverse(ns, &prio->base.list);
1289                 curr_base = &ns->base;
1290                 fs_get_parent(prio, ns);
1291
1292                 if (prio && !ft)
1293                         ft = find_first_ft_in_prio_reverse(prio,
1294                                                            &curr_base->list);
1295         }
1296         return ft;
1297 }
1298
1299 static struct mlx5_flow_table *_find_first_ft_in_prio(struct fs_prio *prio,
1300                                                       struct list_head *start)
1301 {
1302         struct fs_base  *it = container_of(start, struct fs_base, list);
1303
1304         if (!prio)
1305                 return NULL;
1306
1307         fs_for_each_ns_or_ft_continue(it, prio) {
1308                 struct mlx5_flow_namespace      *ns;
1309                 struct mlx5_flow_table          *ft;
1310
1311                 if (it->type == FS_TYPE_FLOW_TABLE) {
1312                         fs_get_obj(ft, it);
1313                         fs_get(&ft->base);
1314                         return ft;
1315                 }
1316
1317                 fs_get_obj(ns, it);
1318                 WARN_ON(ns->base.type != FS_TYPE_NAMESPACE);
1319
1320                 ft = find_first_ft_in_ns(ns, &ns->prios);
1321                 if (ft)
1322                         return ft;
1323         }
1324
1325         return NULL;
1326 }
1327
1328 static struct mlx5_flow_table *find_first_ft_in_prio(struct fs_prio *prio,
1329                                                      struct list_head *start)
1330 {
1331         struct mlx5_flow_table *ft;
1332
1333         if (!prio)
1334                 return NULL;
1335
1336         mutex_lock(&prio->base.lock);
1337         ft = _find_first_ft_in_prio(prio, start);
1338         mutex_unlock(&prio->base.lock);
1339
1340         return ft;
1341 }
1342
1343 static struct mlx5_flow_table *find_first_ft_in_ns(struct mlx5_flow_namespace *ns,
1344                                                    struct list_head *start)
1345 {
1346         struct fs_prio *prio;
1347
1348         if (!ns)
1349                 return NULL;
1350
1351         fs_get_obj(prio, container_of(start, struct fs_base, list));
1352         mutex_lock(&ns->base.lock);
1353         fs_for_each_prio_continue(prio, ns) {
1354                 struct mlx5_flow_table *ft;
1355
1356                 ft = find_first_ft_in_prio(prio, &prio->objs);
1357                 if (ft) {
1358                         mutex_unlock(&ns->base.lock);
1359                         return ft;
1360                 }
1361         }
1362         mutex_unlock(&ns->base.lock);
1363
1364         return NULL;
1365 }
1366
1367 /* returned a held ft, assumed curr is protected, assumed curr's parent is
1368  * locked
1369  */
1370 static struct mlx5_flow_table *find_next_ft(struct fs_prio *prio)
1371 {
1372         struct mlx5_flow_table *ft = NULL;
1373         struct fs_base *curr_base;
1374
1375         while (!ft && prio) {
1376                 struct mlx5_flow_namespace *ns;
1377
1378                 fs_get_parent(ns, prio);
1379                 ft = find_first_ft_in_ns(ns, &prio->base.list);
1380                 curr_base = &ns->base;
1381                 fs_get_parent(prio, ns);
1382
1383                 if (!ft && prio)
1384                         ft = _find_first_ft_in_prio(prio, &curr_base->list);
1385         }
1386         return ft;
1387 }
1388
1389
1390 /* called under ft mutex lock */
1391 static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft,
1392                                                 u8 match_criteria_enable,
1393                                                 u32 *match_criteria)
1394 {
1395         unsigned int group_size;
1396         unsigned int candidate_index = 0;
1397         unsigned int candidate_group_num = 0;
1398         struct mlx5_flow_group *g;
1399         struct mlx5_flow_group *ret;
1400         struct list_head *prev = &ft->fgs;
1401         struct mlx5_core_dev *dev;
1402         u32 *in;
1403         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1404         void *match_criteria_addr;
1405
1406         if (!ft->autogroup.active)
1407                 return ERR_PTR(-ENOENT);
1408
1409         dev = fs_get_dev(&ft->base);
1410         if (!dev)
1411                 return ERR_PTR(-ENODEV);
1412
1413         in = mlx5_vzalloc(inlen);
1414         if (!in) {
1415                 mlx5_core_warn(dev, "failed to allocate inbox\n");
1416                 return ERR_PTR(-ENOMEM);
1417         }
1418
1419
1420         if (ft->autogroup.num_types < ft->autogroup.max_types)
1421                 group_size = ft->max_fte / (ft->autogroup.max_types + 1);
1422         else
1423                 group_size = 1;
1424
1425         if (group_size == 0) {
1426                 mlx5_core_warn(dev,
1427                                "flow steering can't create group size of 0\n");
1428                 ret = ERR_PTR(-EINVAL);
1429                 goto out;
1430         }
1431
1432         /* sorted by start_index */
1433         fs_for_each_fg(g, ft) {
1434                 candidate_group_num++;
1435                 if (candidate_index + group_size > g->start_index)
1436                         candidate_index = g->start_index + g->max_ftes;
1437                 else
1438                         break;
1439                 prev = &g->base.list;
1440         }
1441
1442         if (candidate_index + group_size > ft->max_fte) {
1443                 ret = ERR_PTR(-ENOSPC);
1444                 goto out;
1445         }
1446
1447         MLX5_SET(create_flow_group_in, in, match_criteria_enable,
1448                  match_criteria_enable);
1449         MLX5_SET(create_flow_group_in, in, start_flow_index, candidate_index);
1450         MLX5_SET(create_flow_group_in, in, end_flow_index,   candidate_index +
1451                  group_size - 1);
1452         match_criteria_addr = MLX5_ADDR_OF(create_flow_group_in,
1453                                            in, match_criteria);
1454         memcpy(match_criteria_addr, match_criteria,
1455                MLX5_ST_SZ_BYTES(fte_match_param));
1456
1457         ret = fs_create_fg(dev, ft, prev, in, 0);
1458 out:
1459         kvfree(in);
1460         return ret;
1461 }
1462
1463 static struct mlx5_flow_namespace *get_ns_with_notifiers(struct fs_base *node)
1464 {
1465         struct mlx5_flow_namespace *ns = NULL;
1466
1467         while (node  && (node->type != FS_TYPE_NAMESPACE ||
1468                               list_empty(&container_of(node, struct
1469                                                        mlx5_flow_namespace,
1470                                                        base)->list_notifiers)))
1471                 node = node->parent;
1472
1473         if (node)
1474                 fs_get_obj(ns, node);
1475
1476         return ns;
1477 }
1478
1479
1480 /*Assumption- fte is locked*/
1481 static void call_to_add_rule_notifiers(struct mlx5_flow_rule *dst,
1482                                       struct fs_fte *fte)
1483 {
1484         struct mlx5_flow_namespace *ns;
1485         struct mlx5_flow_handler *iter_handler;
1486         struct fs_client_priv_data *iter_client;
1487         void *data;
1488         bool is_new_rule = list_first_entry(&fte->dests,
1489                                             struct mlx5_flow_rule,
1490                                             base.list) == dst;
1491         int err;
1492
1493         ns = get_ns_with_notifiers(&fte->base);
1494         if (!ns)
1495                 return;
1496
1497         down_read(&ns->notifiers_rw_sem);
1498         list_for_each_entry(iter_handler, &ns->list_notifiers,
1499                             list) {
1500                 if (iter_handler->add_dst_cb) {
1501                         data = NULL;
1502                         mutex_lock(&dst->clients_lock);
1503                         list_for_each_entry(
1504                                 iter_client, &dst->clients_data, list) {
1505                                 if (iter_client->fs_handler == iter_handler) {
1506                                         data = iter_client->client_dst_data;
1507                                         break;
1508                                 }
1509                         }
1510                         mutex_unlock(&dst->clients_lock);
1511                         err  = iter_handler->add_dst_cb(dst,
1512                                                         is_new_rule,
1513                                                         NULL,
1514                                                         iter_handler->client_context);
1515                         if (err)
1516                                 break;
1517                 }
1518         }
1519         up_read(&ns->notifiers_rw_sem);
1520 }
1521
1522 static void call_to_del_rule_notifiers(struct mlx5_flow_rule *dst,
1523                                       struct fs_fte *fte)
1524 {
1525         struct mlx5_flow_namespace *ns;
1526         struct mlx5_flow_handler *iter_handler;
1527         struct fs_client_priv_data *iter_client;
1528         void *data;
1529         bool ctx_changed = (fte->dests_size == 0);
1530
1531         ns = get_ns_with_notifiers(&fte->base);
1532         if (!ns)
1533                 return;
1534         down_read(&ns->notifiers_rw_sem);
1535         list_for_each_entry(iter_handler, &ns->list_notifiers,
1536                             list) {
1537                 data = NULL;
1538                 mutex_lock(&dst->clients_lock);
1539                 list_for_each_entry(iter_client, &dst->clients_data, list) {
1540                         if (iter_client->fs_handler == iter_handler) {
1541                                 data = iter_client->client_dst_data;
1542                                 break;
1543                         }
1544                 }
1545                 mutex_unlock(&dst->clients_lock);
1546                 if (iter_handler->del_dst_cb) {
1547                         iter_handler->del_dst_cb(dst, ctx_changed, data,
1548                                                  iter_handler->client_context);
1549                 }
1550         }
1551         up_read(&ns->notifiers_rw_sem);
1552 }
1553
1554 /* fte should not be deleted while calling this function */
1555 static struct mlx5_flow_rule *_fs_add_dst_fte(struct fs_fte *fte,
1556                                               struct mlx5_flow_group *fg,
1557                                               struct mlx5_flow_destination *dest)
1558 {
1559         struct mlx5_flow_table *ft;
1560         struct mlx5_flow_rule *dst;
1561         int err;
1562
1563         dst = kzalloc(sizeof(*dst), GFP_KERNEL);
1564         if (!dst)
1565                 return ERR_PTR(-ENOMEM);
1566
1567         memcpy(&dst->dest_attr, dest, sizeof(*dest));
1568         dst->base.type = FS_TYPE_FLOW_DEST;
1569         INIT_LIST_HEAD(&dst->clients_data);
1570         mutex_init(&dst->clients_lock);
1571         fs_get_parent(ft, fg);
1572         /*Add dest to dests list- added as first element after the head*/
1573         list_add_tail(&dst->base.list, &fte->dests);
1574         fte->dests_size++;
1575         err = mlx5_cmd_fs_set_fte(fs_get_dev(&ft->base),
1576                                   ft->vport,
1577                                   &fte->status,
1578                                   fte->val, ft->type,
1579                                   ft->id, fte->index, fg->id, fte->flow_tag,
1580                                   fte->action, fte->dests_size, &fte->dests);
1581         if (err)
1582                 goto free_dst;
1583
1584         list_del(&dst->base.list);
1585
1586         return dst;
1587
1588 free_dst:
1589         list_del(&dst->base.list);
1590         kfree(dst);
1591         fte->dests_size--;
1592         return ERR_PTR(err);
1593 }
1594
1595 static char *get_dest_name(struct mlx5_flow_destination *dest)
1596 {
1597         char *name = kzalloc(sizeof(char) * 20, GFP_KERNEL);
1598
1599         switch (dest->type) {
1600         case MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE:
1601                 snprintf(name, 20, "dest_%s_%u", "flow_table",
1602                          dest->ft->id);
1603                 return name;
1604         case MLX5_FLOW_CONTEXT_DEST_TYPE_VPORT:
1605                 snprintf(name, 20, "dest_%s_%u", "vport",
1606                          dest->vport_num);
1607                 return name;
1608         case MLX5_FLOW_CONTEXT_DEST_TYPE_TIR:
1609                 snprintf(name, 20, "dest_%s_%u", "tir", dest->tir_num);
1610                 return name;
1611         default:
1612                 kfree(name);
1613                 return NULL;
1614         }
1615 }
1616
1617 /* assumed fg is locked */
1618 static unsigned int fs_get_free_fg_index(struct mlx5_flow_group *fg,
1619                                          struct list_head **prev)
1620 {
1621         struct fs_fte *fte;
1622         unsigned int start = fg->start_index;
1623
1624         if (prev)
1625                 *prev = &fg->ftes;
1626
1627         /* assumed list is sorted by index */
1628         fs_for_each_fte(fte, fg) {
1629                 if (fte->index != start)
1630                         return start;
1631                 start++;
1632                 if (prev)
1633                         *prev = &fte->base.list;
1634         }
1635
1636         return start;
1637 }
1638
1639
1640 static struct fs_fte *fs_create_fte(struct mlx5_flow_group *fg,
1641                              u32 *match_value,
1642                              u8 action,
1643                              u32 flow_tag,
1644                              struct list_head **prev)
1645 {
1646         struct fs_fte *fte;
1647         int index = 0;
1648
1649         index = fs_get_free_fg_index(fg, prev);
1650         fte = fs_alloc_fte(action, flow_tag, match_value, index);
1651         if (IS_ERR(fte))
1652                 return fte;
1653
1654         return fte;
1655 }
1656
1657 static void add_rule_to_tree(struct mlx5_flow_rule *rule,
1658                              struct fs_fte *fte)
1659 {
1660         char *dest_name;
1661
1662         dest_name = get_dest_name(&rule->dest_attr);
1663         fs_add_node(&rule->base, &fte->base, dest_name, 1);
1664         /* re-add to list, since fs_add_node reset our list */
1665         list_add_tail(&rule->base.list, &fte->dests);
1666         kfree(dest_name);
1667         call_to_add_rule_notifiers(rule, fte);
1668 }
1669
1670 static void fs_del_dst(struct mlx5_flow_rule *dst)
1671 {
1672         struct mlx5_flow_table *ft;
1673         struct mlx5_flow_group *fg;
1674         struct fs_fte *fte;
1675         u32     *match_value;
1676         struct mlx5_core_dev *dev = fs_get_dev(&dst->base);
1677         int match_len = MLX5_ST_SZ_BYTES(fte_match_param);
1678         int err;
1679
1680         WARN_ON(!dev);
1681
1682         match_value = mlx5_vzalloc(match_len);
1683         if (!match_value) {
1684                 mlx5_core_warn(dev, "failed to allocate inbox\n");
1685                 return;
1686         }
1687
1688         fs_get_parent(fte, dst);
1689         fs_get_parent(fg, fte);
1690         mutex_lock(&fg->base.lock);
1691         memcpy(match_value, fte->val, sizeof(fte->val));
1692         /* ft can't be changed as fg is locked */
1693         fs_get_parent(ft, fg);
1694         list_del(&dst->base.list);
1695         fte->dests_size--;
1696         if (fte->dests_size) {
1697                 err = mlx5_cmd_fs_set_fte(dev, ft->vport,
1698                                           &fte->status, match_value, ft->type,
1699                                           ft->id, fte->index, fg->id,
1700                                           fte->flow_tag, fte->action,
1701                                           fte->dests_size, &fte->dests);
1702                 if (err) {
1703                         mlx5_core_warn(dev, "%s can't delete dst %s\n",
1704                                        __func__, dst->base.name);
1705                         goto err;
1706                 }
1707         }
1708         call_to_del_rule_notifiers(dst, fte);
1709 err:
1710         mutex_unlock(&fg->base.lock);
1711         kvfree(match_value);
1712 }
1713
1714 static void fs_del_fte(struct fs_fte *fte)
1715 {
1716         struct mlx5_flow_table *ft;
1717         struct mlx5_flow_group *fg;
1718         int err;
1719         struct mlx5_core_dev *dev;
1720
1721         fs_get_parent(fg, fte);
1722         fs_get_parent(ft, fg);
1723
1724         dev = fs_get_dev(&ft->base);
1725         WARN_ON(!dev);
1726
1727         err = mlx5_cmd_fs_delete_fte(dev, ft->vport, &fte->status,
1728                                      ft->type, ft->id, fte->index);
1729         if (err)
1730                 mlx5_core_warn(dev, "flow steering can't delete fte %s\n",
1731                                fte->base.name);
1732
1733         fg->num_ftes--;
1734 }
1735
1736 /* assuming parent fg is locked */
1737 /* Add dst algorithm */
1738 static struct mlx5_flow_rule *fs_add_dst_fg(struct mlx5_flow_group *fg,
1739                                                    u32 *match_value,
1740                                                    u8 action,
1741                                                    u32 flow_tag,
1742                                                    struct mlx5_flow_destination *dest)
1743 {
1744         struct fs_fte *fte;
1745         struct mlx5_flow_rule *dst;
1746         struct mlx5_flow_table *ft;
1747         struct list_head *prev;
1748         char fte_name[20];
1749
1750         mutex_lock(&fg->base.lock);
1751         fs_for_each_fte(fte, fg) {
1752                 /* TODO: Check of size against PRM max size */
1753                 mutex_lock(&fte->base.lock);
1754                 if (fs_match_exact_val(&fg->mask, match_value, &fte->val) &&
1755                     action == fte->action && flow_tag == fte->flow_tag) {
1756                         dst = _fs_add_dst_fte(fte, fg, dest);
1757                         mutex_unlock(&fte->base.lock);
1758                         if (IS_ERR(dst))
1759                                 goto unlock_fg;
1760                         goto add_rule;
1761                 }
1762                 mutex_unlock(&fte->base.lock);
1763         }
1764
1765         fs_get_parent(ft, fg);
1766         if (fg->num_ftes == fg->max_ftes) {
1767                 dst = ERR_PTR(-ENOSPC);
1768                 goto unlock_fg;
1769         }
1770
1771         fte = fs_create_fte(fg, match_value, action, flow_tag, &prev);
1772         if (IS_ERR(fte)) {
1773                 dst = (void *)fte;
1774                 goto unlock_fg;
1775         }
1776         dst = _fs_add_dst_fte(fte, fg, dest);
1777         if (IS_ERR(dst)) {
1778                 kfree(fte);
1779                 goto unlock_fg;
1780         }
1781
1782         fg->num_ftes++;
1783
1784         snprintf(fte_name, sizeof(fte_name), "fte%u", fte->index);
1785         /* Add node to tree */
1786         fs_add_node(&fte->base, &fg->base, fte_name, 0);
1787         list_add(&fte->base.list, prev);
1788 add_rule:
1789         add_rule_to_tree(dst, fte);
1790 unlock_fg:
1791         mutex_unlock(&fg->base.lock);
1792         return dst;
1793 }
1794
1795 static struct mlx5_flow_rule *fs_add_dst_ft(struct mlx5_flow_table *ft,
1796                                             u8 match_criteria_enable,
1797                                             u32 *match_criteria,
1798                                             u32 *match_value,
1799                                             u8 action, u32 flow_tag,
1800                                             struct mlx5_flow_destination *dest)
1801 {
1802         /*? where dst_entry is allocated*/
1803         struct mlx5_flow_group *g;
1804         struct mlx5_flow_rule *dst;
1805
1806         fs_get(&ft->base);
1807         mutex_lock(&ft->base.lock);
1808         fs_for_each_fg(g, ft)
1809                 if (fs_match_exact_mask(g->mask.match_criteria_enable,
1810                                         match_criteria_enable,
1811                                         g->mask.match_criteria,
1812                                         match_criteria)) {
1813                         mutex_unlock(&ft->base.lock);
1814
1815                         dst = fs_add_dst_fg(g, match_value,
1816                                             action, flow_tag, dest);
1817                         if (PTR_ERR(dst) && PTR_ERR(dst) != -ENOSPC)
1818                                 goto unlock;
1819                 }
1820         mutex_unlock(&ft->base.lock);
1821
1822         g = create_autogroup(ft, match_criteria_enable, match_criteria);
1823         if (IS_ERR(g)) {
1824                 dst = (void *)g;
1825                 goto unlock;
1826         }
1827
1828         dst = fs_add_dst_fg(g, match_value,
1829                             action, flow_tag, dest);
1830         if (IS_ERR(dst)) {
1831                 /* Remove assumes refcount > 0 and autogroup creates a group
1832                  * with a refcount = 0.
1833                  */
1834                 fs_get(&g->base);
1835                 fs_remove_node(&g->base);
1836                 goto unlock;
1837         }
1838
1839 unlock:
1840         fs_put(&ft->base);
1841         return dst;
1842 }
1843
1844 struct mlx5_flow_rule *
1845 mlx5_add_flow_rule(struct mlx5_flow_table *ft,
1846                    u8 match_criteria_enable,
1847                    u32 *match_criteria,
1848                    u32 *match_value,
1849                    u32 action,
1850                    u32 flow_tag,
1851                    struct mlx5_flow_destination *dest)
1852 {
1853         struct mlx5_flow_rule *dst;
1854         struct mlx5_flow_namespace *ns;
1855
1856         ns = get_ns_with_notifiers(&ft->base);
1857         if (ns)
1858                 down_read(&ns->dests_rw_sem);
1859         dst =  fs_add_dst_ft(ft, match_criteria_enable, match_criteria,
1860                              match_value, action, flow_tag, dest);
1861         if (ns)
1862                 up_read(&ns->dests_rw_sem);
1863
1864         return dst;
1865
1866
1867 }
1868 EXPORT_SYMBOL(mlx5_add_flow_rule);
1869
1870 void mlx5_del_flow_rule(struct mlx5_flow_rule *dst)
1871 {
1872         struct mlx5_flow_namespace *ns;
1873
1874         ns = get_ns_with_notifiers(&dst->base);
1875         if (ns)
1876                 down_read(&ns->dests_rw_sem);
1877         fs_remove_node(&dst->base);
1878         if (ns)
1879                 up_read(&ns->dests_rw_sem);
1880 }
1881 EXPORT_SYMBOL(mlx5_del_flow_rule);
1882
1883 #define MLX5_CORE_FS_ROOT_NS_NAME "root"
1884 #define MLX5_CORE_FS_ESW_EGRESS_ACL "esw_egress_root"
1885 #define MLX5_CORE_FS_ESW_INGRESS_ACL "esw_ingress_root"
1886 #define MLX5_CORE_FS_FDB_ROOT_NS_NAME "fdb_root"
1887 #define MLX5_CORE_FS_SNIFFER_RX_ROOT_NS_NAME "sniffer_rx_root"
1888 #define MLX5_CORE_FS_SNIFFER_TX_ROOT_NS_NAME "sniffer_tx_root"
1889 #define MLX5_CORE_FS_PRIO_MAX_FT 4
1890 #define MLX5_CORE_FS_PRIO_MAX_NS 1
1891
1892 static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
1893                                       unsigned prio, int max_ft,
1894                                       const char *name, u8 flags)
1895 {
1896         struct fs_prio *fs_prio;
1897
1898         fs_prio = kzalloc(sizeof(*fs_prio), GFP_KERNEL);
1899         if (!fs_prio)
1900                 return ERR_PTR(-ENOMEM);
1901
1902         fs_prio->base.type = FS_TYPE_PRIO;
1903         fs_add_node(&fs_prio->base, &ns->base, name, 1);
1904         fs_prio->max_ft = max_ft;
1905         fs_prio->max_ns = MLX5_CORE_FS_PRIO_MAX_NS;
1906         fs_prio->prio = prio;
1907         fs_prio->flags = flags;
1908         list_add_tail(&fs_prio->base.list, &ns->prios);
1909         INIT_LIST_HEAD(&fs_prio->objs);
1910         mutex_init(&fs_prio->shared_lock);
1911
1912         return fs_prio;
1913 }
1914
1915 static void cleanup_root_ns(struct mlx5_core_dev *dev)
1916 {
1917         struct mlx5_flow_root_namespace *root_ns = dev->root_ns;
1918         struct fs_prio *iter_prio;
1919
1920         if (!root_ns)
1921                 return;
1922
1923         /* stage 1 */
1924         fs_for_each_prio(iter_prio, &root_ns->ns) {
1925                 struct mlx5_flow_namespace *iter_ns;
1926
1927                 fs_for_each_ns(iter_ns, iter_prio) {
1928                         while (!list_empty(&iter_ns->prios)) {
1929                                 struct fs_base *iter_prio2 =
1930                                         list_first_entry(&iter_ns->prios,
1931                                                          struct fs_base,
1932                                                          list);
1933
1934                                 fs_remove_node(iter_prio2);
1935                         }
1936                 }
1937         }
1938
1939         /* stage 2 */
1940         fs_for_each_prio(iter_prio, &root_ns->ns) {
1941                 while (!list_empty(&iter_prio->objs)) {
1942                         struct fs_base *iter_ns =
1943                                 list_first_entry(&iter_prio->objs,
1944                                                  struct fs_base,
1945                                                  list);
1946
1947                                 fs_remove_node(iter_ns);
1948                 }
1949         }
1950         /* stage 3 */
1951         while (!list_empty(&root_ns->ns.prios)) {
1952                 struct fs_base *iter_prio =
1953                         list_first_entry(&root_ns->ns.prios,
1954                                          struct fs_base,
1955                                          list);
1956
1957                 fs_remove_node(iter_prio);
1958         }
1959
1960         fs_remove_node(&root_ns->ns.base);
1961         dev->root_ns = NULL;
1962 }
1963
1964 static void cleanup_single_prio_root_ns(struct mlx5_core_dev *dev,
1965                                         struct mlx5_flow_root_namespace *root_ns)
1966 {
1967         struct fs_base *prio;
1968
1969         if (!root_ns)
1970                 return;
1971
1972         if (!list_empty(&root_ns->ns.prios)) {
1973                 prio = list_first_entry(&root_ns->ns.prios,
1974                                         struct fs_base,
1975                                  list);
1976                 fs_remove_node(prio);
1977         }
1978         fs_remove_node(&root_ns->ns.base);
1979         root_ns = NULL;
1980 }
1981
1982 void mlx5_cleanup_fs(struct mlx5_core_dev *dev)
1983 {
1984         cleanup_root_ns(dev);
1985         cleanup_single_prio_root_ns(dev, dev->sniffer_rx_root_ns);
1986         cleanup_single_prio_root_ns(dev, dev->sniffer_tx_root_ns);
1987         cleanup_single_prio_root_ns(dev, dev->fdb_root_ns);
1988         cleanup_single_prio_root_ns(dev, dev->esw_egress_root_ns);
1989         cleanup_single_prio_root_ns(dev, dev->esw_ingress_root_ns);
1990 }
1991
1992 static struct mlx5_flow_namespace *fs_init_namespace(struct mlx5_flow_namespace
1993                                                  *ns)
1994 {
1995         ns->base.type = FS_TYPE_NAMESPACE;
1996         init_rwsem(&ns->dests_rw_sem);
1997         init_rwsem(&ns->notifiers_rw_sem);
1998         INIT_LIST_HEAD(&ns->prios);
1999         INIT_LIST_HEAD(&ns->list_notifiers);
2000
2001         return ns;
2002 }
2003
2004 static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_core_dev *dev,
2005                                                           enum fs_ft_type
2006                                                           table_type,
2007                                                           char *name)
2008 {
2009         struct mlx5_flow_root_namespace *root_ns;
2010         struct mlx5_flow_namespace *ns;
2011
2012         /* create the root namespace */
2013         root_ns = mlx5_vzalloc(sizeof(*root_ns));
2014         if (!root_ns)
2015                 goto err;
2016
2017         root_ns->dev = dev;
2018         root_ns->table_type = table_type;
2019         mutex_init(&root_ns->fs_chain_lock);
2020
2021         ns = &root_ns->ns;
2022         fs_init_namespace(ns);
2023         fs_add_node(&ns->base, NULL, name, 1);
2024
2025         return root_ns;
2026 err:
2027         return NULL;
2028 }
2029
2030 static int init_fdb_root_ns(struct mlx5_core_dev *dev)
2031 {
2032         struct fs_prio *prio;
2033
2034         dev->fdb_root_ns = create_root_ns(dev, FS_FT_FDB,
2035                                           MLX5_CORE_FS_FDB_ROOT_NS_NAME);
2036         if (!dev->fdb_root_ns)
2037                 return -ENOMEM;
2038
2039         /* create 1 prio*/
2040         prio = fs_create_prio(&dev->fdb_root_ns->ns, 0, 1, "fdb_prio", 0);
2041         if (IS_ERR(prio))
2042                 return PTR_ERR(prio);
2043         else
2044                 return 0;
2045 }
2046
2047 #define MAX_VPORTS 128
2048
2049 static int init_egress_acl_root_ns(struct mlx5_core_dev *dev)
2050 {
2051         struct fs_prio *prio;
2052
2053         dev->esw_egress_root_ns = create_root_ns(dev, FS_FT_ESW_EGRESS_ACL,
2054                                                  MLX5_CORE_FS_ESW_EGRESS_ACL);
2055         if (!dev->esw_egress_root_ns)
2056                 return -ENOMEM;
2057
2058         /* create 1 prio*/
2059         prio = fs_create_prio(&dev->esw_egress_root_ns->ns, 0, MAX_VPORTS,
2060                               "esw_egress_prio", 0);
2061         if (IS_ERR(prio))
2062                 return PTR_ERR(prio);
2063         else
2064                 return 0;
2065 }
2066
2067 static int init_ingress_acl_root_ns(struct mlx5_core_dev *dev)
2068 {
2069         struct fs_prio *prio;
2070
2071         dev->esw_ingress_root_ns = create_root_ns(dev, FS_FT_ESW_INGRESS_ACL,
2072                                                   MLX5_CORE_FS_ESW_INGRESS_ACL);
2073         if (!dev->esw_ingress_root_ns)
2074                 return -ENOMEM;
2075
2076         /* create 1 prio*/
2077         prio = fs_create_prio(&dev->esw_ingress_root_ns->ns, 0, MAX_VPORTS,
2078                               "esw_ingress_prio", 0);
2079         if (IS_ERR(prio))
2080                 return PTR_ERR(prio);
2081         else
2082                 return 0;
2083 }
2084
2085 static int init_sniffer_rx_root_ns(struct mlx5_core_dev *dev)
2086 {
2087         struct fs_prio *prio;
2088
2089         dev->sniffer_rx_root_ns = create_root_ns(dev, FS_FT_SNIFFER_RX,
2090                                      MLX5_CORE_FS_SNIFFER_RX_ROOT_NS_NAME);
2091         if (!dev->sniffer_rx_root_ns)
2092                 return  -ENOMEM;
2093
2094         /* create 1 prio*/
2095         prio = fs_create_prio(&dev->sniffer_rx_root_ns->ns, 0, 1,
2096                               "sniffer_prio", 0);
2097         if (IS_ERR(prio))
2098                 return PTR_ERR(prio);
2099         else
2100                 return 0;
2101 }
2102
2103
2104 static int init_sniffer_tx_root_ns(struct mlx5_core_dev *dev)
2105 {
2106         struct fs_prio *prio;
2107
2108         dev->sniffer_tx_root_ns = create_root_ns(dev, FS_FT_SNIFFER_TX,
2109                                                  MLX5_CORE_FS_SNIFFER_TX_ROOT_NS_NAME);
2110         if (!dev->sniffer_tx_root_ns)
2111                 return  -ENOMEM;
2112
2113         /* create 1 prio*/
2114         prio = fs_create_prio(&dev->sniffer_tx_root_ns->ns, 0, 1,
2115                               "sniffer_prio", 0);
2116         if (IS_ERR(prio))
2117                 return PTR_ERR(prio);
2118         else
2119                 return 0;
2120 }
2121
2122 static struct mlx5_flow_namespace *fs_create_namespace(struct fs_prio *prio,
2123                                                        const char *name)
2124 {
2125         struct mlx5_flow_namespace      *ns;
2126
2127         ns = kzalloc(sizeof(*ns), GFP_KERNEL);
2128         if (!ns)
2129                 return ERR_PTR(-ENOMEM);
2130
2131         fs_init_namespace(ns);
2132         fs_add_node(&ns->base, &prio->base, name, 1);
2133         list_add_tail(&ns->base.list, &prio->objs);
2134
2135         return ns;
2136 }
2137
2138 #define FLOW_TABLE_BIT_SZ 1
2139 #define GET_FLOW_TABLE_CAP(dev, offset) \
2140         ((be32_to_cpu(*((__be32 *)(dev->hca_caps_cur[MLX5_CAP_FLOW_TABLE]) +    \
2141                         offset / 32)) >>                                        \
2142           (32 - FLOW_TABLE_BIT_SZ - (offset & 0x1f))) & FLOW_TABLE_BIT_SZ)
2143
2144 static bool has_required_caps(struct mlx5_core_dev *dev, struct node_caps *caps)
2145 {
2146         int i;
2147
2148         for (i = 0; i < caps->arr_sz; i++) {
2149                 if (!GET_FLOW_TABLE_CAP(dev, caps->caps[i]))
2150                         return false;
2151         }
2152         return true;
2153 }
2154
2155 static int _init_root_tree(struct mlx5_core_dev *dev, int max_ft_level,
2156                     struct init_tree_node *node, struct fs_base *base_parent,
2157                     struct init_tree_node *tree_parent)
2158 {
2159         struct mlx5_flow_namespace *fs_ns;
2160         struct fs_prio *fs_prio;
2161         int priority;
2162         struct fs_base *base;
2163         int i;
2164         int err = 0;
2165
2166         if (node->type == FS_TYPE_PRIO) {
2167                 if ((node->min_ft_level > max_ft_level) ||
2168                     !has_required_caps(dev, &node->caps))
2169                         goto out;
2170
2171                 fs_get_obj(fs_ns, base_parent);
2172                 priority = node - tree_parent->children;
2173                 fs_prio = fs_create_prio(fs_ns, priority,
2174                                          node->max_ft,
2175                                          node->name, node->flags);
2176                 if (IS_ERR(fs_prio)) {
2177                         err = PTR_ERR(fs_prio);
2178                         goto out;
2179                 }
2180                 base = &fs_prio->base;
2181         } else if (node->type == FS_TYPE_NAMESPACE) {
2182                 fs_get_obj(fs_prio, base_parent);
2183                 fs_ns = fs_create_namespace(fs_prio, node->name);
2184                 if (IS_ERR(fs_ns)) {
2185                         err = PTR_ERR(fs_ns);
2186                         goto out;
2187                 }
2188                 base = &fs_ns->base;
2189         } else {
2190                 return -EINVAL;
2191         }
2192         for (i = 0; i < node->ar_size; i++) {
2193                 err = _init_root_tree(dev, max_ft_level, &node->children[i], base,
2194                                       node);
2195                 if (err)
2196                         break;
2197         }
2198 out:
2199         return err;
2200 }
2201
2202 static int init_root_tree(struct mlx5_core_dev *dev, int max_ft_level,
2203                    struct init_tree_node *node, struct fs_base *parent)
2204 {
2205         int i;
2206         struct mlx5_flow_namespace *fs_ns;
2207         int err = 0;
2208
2209         fs_get_obj(fs_ns, parent);
2210         for (i = 0; i < node->ar_size; i++) {
2211                 err = _init_root_tree(dev, max_ft_level,
2212                                       &node->children[i], &fs_ns->base, node);
2213                 if (err)
2214                         break;
2215         }
2216         return err;
2217 }
2218
2219 static int sum_max_ft_in_prio(struct fs_prio *prio);
2220 static int sum_max_ft_in_ns(struct mlx5_flow_namespace *ns)
2221 {
2222         struct fs_prio *prio;
2223         int sum = 0;
2224
2225         fs_for_each_prio(prio, ns) {
2226                 sum += sum_max_ft_in_prio(prio);
2227         }
2228         return  sum;
2229 }
2230
2231 static int sum_max_ft_in_prio(struct fs_prio *prio)
2232 {
2233         int sum = 0;
2234         struct fs_base *it;
2235         struct mlx5_flow_namespace      *ns;
2236
2237         if (prio->max_ft)
2238                 return prio->max_ft;
2239
2240         fs_for_each_ns_or_ft(it, prio) {
2241                 if (it->type == FS_TYPE_FLOW_TABLE)
2242                         continue;
2243
2244                 fs_get_obj(ns, it);
2245                 sum += sum_max_ft_in_ns(ns);
2246         }
2247         prio->max_ft = sum;
2248         return  sum;
2249 }
2250
2251 static void set_max_ft(struct mlx5_flow_namespace *ns)
2252 {
2253         struct fs_prio *prio;
2254
2255         if (!ns)
2256                 return;
2257
2258         fs_for_each_prio(prio, ns)
2259                 sum_max_ft_in_prio(prio);
2260 }
2261
2262 static int init_root_ns(struct mlx5_core_dev *dev)
2263 {
2264         int max_ft_level = MLX5_CAP_FLOWTABLE(dev,
2265                                               flow_table_properties_nic_receive.
2266                                               max_ft_level);
2267
2268         dev->root_ns = create_root_ns(dev, FS_FT_NIC_RX,
2269                                       MLX5_CORE_FS_ROOT_NS_NAME);
2270         if (IS_ERR_OR_NULL(dev->root_ns))
2271                 goto err;
2272
2273
2274         if (init_root_tree(dev, max_ft_level, &root_fs, &dev->root_ns->ns.base))
2275                 goto err;
2276
2277         set_max_ft(&dev->root_ns->ns);
2278
2279         return 0;
2280 err:
2281         return -ENOMEM;
2282 }
2283
2284 u8 mlx5_get_match_criteria_enable(struct mlx5_flow_rule *rule)
2285 {
2286         struct fs_base *pbase;
2287         struct mlx5_flow_group *fg;
2288
2289         pbase = rule->base.parent;
2290         WARN_ON(!pbase);
2291         pbase = pbase->parent;
2292         WARN_ON(!pbase);
2293
2294         fs_get_obj(fg, pbase);
2295         return fg->mask.match_criteria_enable;
2296 }
2297
2298 void mlx5_get_match_value(u32 *match_value,
2299                           struct mlx5_flow_rule *rule)
2300 {
2301         struct fs_base *pbase;
2302         struct fs_fte *fte;
2303
2304         pbase = rule->base.parent;
2305         WARN_ON(!pbase);
2306         fs_get_obj(fte, pbase);
2307
2308         memcpy(match_value, fte->val, sizeof(fte->val));
2309 }
2310
2311 void mlx5_get_match_criteria(u32 *match_criteria,
2312                              struct mlx5_flow_rule *rule)
2313 {
2314         struct fs_base *pbase;
2315         struct mlx5_flow_group *fg;
2316
2317         pbase = rule->base.parent;
2318         WARN_ON(!pbase);
2319         pbase = pbase->parent;
2320         WARN_ON(!pbase);
2321
2322         fs_get_obj(fg, pbase);
2323         memcpy(match_criteria, &fg->mask.match_criteria,
2324                sizeof(fg->mask.match_criteria));
2325 }
2326
2327 int mlx5_init_fs(struct mlx5_core_dev *dev)
2328 {
2329         int err;
2330
2331         if (MLX5_CAP_GEN(dev, nic_flow_table)) {
2332                 err = init_root_ns(dev);
2333                 if (err)
2334                         goto err;
2335         }
2336
2337         err = init_fdb_root_ns(dev);
2338         if (err)
2339                 goto err;
2340
2341         err = init_egress_acl_root_ns(dev);
2342         if (err)
2343                 goto err;
2344
2345         err = init_ingress_acl_root_ns(dev);
2346         if (err)
2347                 goto err;
2348
2349         err = init_sniffer_tx_root_ns(dev);
2350         if (err)
2351                 goto err;
2352
2353         err = init_sniffer_rx_root_ns(dev);
2354         if (err)
2355                 goto err;
2356
2357         return 0;
2358 err:
2359         mlx5_cleanup_fs(dev);
2360         return err;
2361 }
2362
2363 struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
2364                                                   enum mlx5_flow_namespace_type type)
2365 {
2366         struct mlx5_flow_root_namespace *root_ns = dev->root_ns;
2367         int prio;
2368         static struct fs_prio *fs_prio;
2369         struct mlx5_flow_namespace *ns;
2370
2371         switch (type) {
2372         case MLX5_FLOW_NAMESPACE_BYPASS:
2373                 prio = 0;
2374                 break;
2375         case MLX5_FLOW_NAMESPACE_KERNEL:
2376                 prio = 1;
2377                 break;
2378         case MLX5_FLOW_NAMESPACE_LEFTOVERS:
2379                 prio = 2;
2380                 break;
2381         case MLX5_FLOW_NAMESPACE_FDB:
2382                 if (dev->fdb_root_ns)
2383                         return &dev->fdb_root_ns->ns;
2384                 else
2385                         return NULL;
2386         case MLX5_FLOW_NAMESPACE_ESW_EGRESS:
2387                 if (dev->esw_egress_root_ns)
2388                         return &dev->esw_egress_root_ns->ns;
2389                 else
2390                         return NULL;
2391         case MLX5_FLOW_NAMESPACE_ESW_INGRESS:
2392                 if (dev->esw_ingress_root_ns)
2393                         return &dev->esw_ingress_root_ns->ns;
2394                 else
2395                         return NULL;
2396         case MLX5_FLOW_NAMESPACE_SNIFFER_RX:
2397                 if (dev->sniffer_rx_root_ns)
2398                         return &dev->sniffer_rx_root_ns->ns;
2399                 else
2400                         return NULL;
2401         case MLX5_FLOW_NAMESPACE_SNIFFER_TX:
2402                 if (dev->sniffer_tx_root_ns)
2403                         return &dev->sniffer_tx_root_ns->ns;
2404                 else
2405                         return NULL;
2406         default:
2407                 return NULL;
2408         }
2409
2410         if (!root_ns)
2411                 return NULL;
2412
2413         fs_prio = find_prio(&root_ns->ns, prio);
2414         if (!fs_prio)
2415                 return NULL;
2416
2417         ns = list_first_entry(&fs_prio->objs,
2418                               typeof(*ns),
2419                               base.list);
2420
2421         return ns;
2422 }
2423 EXPORT_SYMBOL(mlx5_get_flow_namespace);
2424
2425
2426 int mlx5_set_rule_private_data(struct mlx5_flow_rule *rule,
2427                                   struct mlx5_flow_handler *fs_handler,
2428                                   void  *client_data)
2429 {
2430         struct fs_client_priv_data *priv_data;
2431
2432         mutex_lock(&rule->clients_lock);
2433         /*Check that hanlder isn't exists in the list already*/
2434         list_for_each_entry(priv_data, &rule->clients_data, list) {
2435                 if (priv_data->fs_handler == fs_handler) {
2436                         priv_data->client_dst_data = client_data;
2437                         goto unlock;
2438                 }
2439         }
2440         priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
2441         if (!priv_data) {
2442                 mutex_unlock(&rule->clients_lock);
2443                 return -ENOMEM;
2444         }
2445
2446         priv_data->client_dst_data = client_data;
2447         priv_data->fs_handler = fs_handler;
2448         list_add(&priv_data->list, &rule->clients_data);
2449
2450 unlock:
2451         mutex_unlock(&rule->clients_lock);
2452
2453         return 0;
2454 }
2455
2456 static int remove_from_clients(struct mlx5_flow_rule *rule,
2457                         bool ctx_changed,
2458                         void *client_data,
2459                         void *context)
2460 {
2461         struct fs_client_priv_data *iter_client;
2462         struct fs_client_priv_data *temp_client;
2463         struct mlx5_flow_handler *handler = (struct
2464                                                 mlx5_flow_handler*)context;
2465
2466         mutex_lock(&rule->clients_lock);
2467         list_for_each_entry_safe(iter_client, temp_client,
2468                                  &rule->clients_data, list) {
2469                 if (iter_client->fs_handler == handler) {
2470                         list_del(&iter_client->list);
2471                         kfree(iter_client);
2472                         break;
2473                 }
2474         }
2475         mutex_unlock(&rule->clients_lock);
2476
2477         return 0;
2478 }
2479
2480 struct mlx5_flow_handler *mlx5_register_rule_notifier(struct mlx5_core_dev *dev,
2481                                                                 enum mlx5_flow_namespace_type ns_type,
2482                                                                 rule_event_fn add_cb,
2483                                                                 rule_event_fn del_cb,
2484                                                                 void *context)
2485 {
2486         struct mlx5_flow_namespace *ns;
2487         struct mlx5_flow_handler *handler;
2488
2489         ns = mlx5_get_flow_namespace(dev, ns_type);
2490         if (!ns)
2491                 return ERR_PTR(-EINVAL);
2492
2493         handler = kzalloc(sizeof(*handler), GFP_KERNEL);
2494         if (!handler)
2495                 return ERR_PTR(-ENOMEM);
2496
2497         handler->add_dst_cb = add_cb;
2498         handler->del_dst_cb = del_cb;
2499         handler->client_context = context;
2500         handler->ns = ns;
2501         down_write(&ns->notifiers_rw_sem);
2502         list_add_tail(&handler->list, &ns->list_notifiers);
2503         up_write(&ns->notifiers_rw_sem);
2504
2505         return handler;
2506 }
2507
2508 static void iterate_rules_in_ns(struct mlx5_flow_namespace *ns,
2509                                 rule_event_fn add_rule_cb,
2510                                 void *context);
2511
2512 void mlx5_unregister_rule_notifier(struct mlx5_flow_handler *handler)
2513 {
2514         struct mlx5_flow_namespace *ns = handler->ns;
2515
2516         /*Remove from dst's clients*/
2517         down_write(&ns->dests_rw_sem);
2518         down_write(&ns->notifiers_rw_sem);
2519         iterate_rules_in_ns(ns, remove_from_clients, handler);
2520         list_del(&handler->list);
2521         up_write(&ns->notifiers_rw_sem);
2522         up_write(&ns->dests_rw_sem);
2523         kfree(handler);
2524 }
2525
2526 static void iterate_rules_in_ft(struct mlx5_flow_table *ft,
2527                                 rule_event_fn add_rule_cb,
2528                                 void *context)
2529 {
2530         struct mlx5_flow_group *iter_fg;
2531         struct fs_fte *iter_fte;
2532         struct mlx5_flow_rule *iter_rule;
2533         int err = 0;
2534         bool is_new_rule;
2535
2536         mutex_lock(&ft->base.lock);
2537         fs_for_each_fg(iter_fg, ft) {
2538                 mutex_lock(&iter_fg->base.lock);
2539                 fs_for_each_fte(iter_fte, iter_fg) {
2540                         mutex_lock(&iter_fte->base.lock);
2541                         is_new_rule = true;
2542                         fs_for_each_dst(iter_rule, iter_fte) {
2543                                 fs_get(&iter_rule->base);
2544                                 err = add_rule_cb(iter_rule,
2545                                                  is_new_rule,
2546                                                  NULL,
2547                                                  context);
2548                                 fs_put_parent_locked(&iter_rule->base);
2549                                 if (err)
2550                                         break;
2551                                 is_new_rule = false;
2552                         }
2553                         mutex_unlock(&iter_fte->base.lock);
2554                         if (err)
2555                                 break;
2556                 }
2557                 mutex_unlock(&iter_fg->base.lock);
2558                 if (err)
2559                         break;
2560         }
2561         mutex_unlock(&ft->base.lock);
2562 }
2563
2564 static void iterate_rules_in_prio(struct fs_prio *prio,
2565                                   rule_event_fn add_rule_cb,
2566                                   void *context)
2567 {
2568         struct fs_base *it;
2569
2570         mutex_lock(&prio->base.lock);
2571         fs_for_each_ns_or_ft(it, prio) {
2572                 if (it->type == FS_TYPE_FLOW_TABLE) {
2573                         struct mlx5_flow_table        *ft;
2574
2575                         fs_get_obj(ft, it);
2576                         iterate_rules_in_ft(ft, add_rule_cb, context);
2577                 } else {
2578                         struct mlx5_flow_namespace *ns;
2579
2580                         fs_get_obj(ns, it);
2581                         iterate_rules_in_ns(ns, add_rule_cb, context);
2582                 }
2583         }
2584         mutex_unlock(&prio->base.lock);
2585 }
2586
2587 static void iterate_rules_in_ns(struct mlx5_flow_namespace *ns,
2588                                 rule_event_fn add_rule_cb,
2589                                 void *context)
2590 {
2591         struct fs_prio *iter_prio;
2592
2593         mutex_lock(&ns->base.lock);
2594         fs_for_each_prio(iter_prio, ns) {
2595                 iterate_rules_in_prio(iter_prio, add_rule_cb, context);
2596         }
2597         mutex_unlock(&ns->base.lock);
2598 }
2599
2600 void mlx5_flow_iterate_existing_rules(struct mlx5_flow_namespace *ns,
2601                                          rule_event_fn add_rule_cb,
2602                                          void *context)
2603 {
2604         down_write(&ns->dests_rw_sem);
2605         down_read(&ns->notifiers_rw_sem);
2606         iterate_rules_in_ns(ns, add_rule_cb, context);
2607         up_read(&ns->notifiers_rw_sem);
2608         up_write(&ns->dests_rw_sem);
2609 }
2610
2611
2612 void mlx5_del_flow_rules_list(struct mlx5_flow_rules_list *rules_list)
2613 {
2614         struct mlx5_flow_rule_node *iter_node;
2615         struct mlx5_flow_rule_node *temp_node;
2616
2617         list_for_each_entry_safe(iter_node, temp_node, &rules_list->head, list) {
2618                 list_del(&iter_node->list);
2619                 kfree(iter_node);
2620         }
2621
2622         kfree(rules_list);
2623 }
2624
2625 #define ROCEV1_ETHERTYPE 0x8915
2626 static int set_rocev1_rules(struct list_head *rules_list)
2627 {
2628         struct mlx5_flow_rule_node *rocev1_rule;
2629
2630         rocev1_rule = kzalloc(sizeof(*rocev1_rule), GFP_KERNEL);
2631         if (!rocev1_rule)
2632                 return -ENOMEM;
2633
2634         rocev1_rule->match_criteria_enable =
2635                 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS;
2636         MLX5_SET(fte_match_set_lyr_2_4, rocev1_rule->match_criteria, ethertype,
2637                  0xffff);
2638         MLX5_SET(fte_match_set_lyr_2_4, rocev1_rule->match_value, ethertype,
2639                  ROCEV1_ETHERTYPE);
2640
2641         list_add_tail(&rocev1_rule->list, rules_list);
2642
2643         return 0;
2644 }
2645
2646 #define ROCEV2_UDP_PORT 4791
2647 static int set_rocev2_rules(struct list_head *rules_list)
2648 {
2649         struct mlx5_flow_rule_node *ipv4_rule;
2650         struct mlx5_flow_rule_node *ipv6_rule;
2651
2652         ipv4_rule = kzalloc(sizeof(*ipv4_rule), GFP_KERNEL);
2653         if (!ipv4_rule)
2654                 return -ENOMEM;
2655
2656         ipv6_rule = kzalloc(sizeof(*ipv6_rule), GFP_KERNEL);
2657         if (!ipv6_rule) {
2658                 kfree(ipv4_rule);
2659                 return -ENOMEM;
2660         }
2661
2662         ipv4_rule->match_criteria_enable =
2663                 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS;
2664         MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_criteria, ethertype,
2665                  0xffff);
2666         MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_value, ethertype,
2667                  0x0800);
2668         MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_criteria, ip_protocol,
2669                  0xff);
2670         MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_value, ip_protocol,
2671                  IPPROTO_UDP);
2672         MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_criteria, udp_dport,
2673                  0xffff);
2674         MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_value, udp_dport,
2675                  ROCEV2_UDP_PORT);
2676
2677         ipv6_rule->match_criteria_enable =
2678                 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS;
2679         MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_criteria, ethertype,
2680                  0xffff);
2681         MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_value, ethertype,
2682                  0x86dd);
2683         MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_criteria, ip_protocol,
2684                  0xff);
2685         MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_value, ip_protocol,
2686                  IPPROTO_UDP);
2687         MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_criteria, udp_dport,
2688                  0xffff);
2689         MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_value, udp_dport,
2690                  ROCEV2_UDP_PORT);
2691
2692         list_add_tail(&ipv4_rule->list, rules_list);
2693         list_add_tail(&ipv6_rule->list, rules_list);
2694
2695         return 0;
2696 }
2697
2698
2699 struct mlx5_flow_rules_list *get_roce_flow_rules(u8 roce_mode)
2700 {
2701         int err = 0;
2702         struct mlx5_flow_rules_list *rules_list =
2703                 kzalloc(sizeof(*rules_list), GFP_KERNEL);
2704
2705         if (!rules_list)
2706                 return NULL;
2707
2708         INIT_LIST_HEAD(&rules_list->head);
2709
2710         if (roce_mode & MLX5_ROCE_VERSION_1_CAP) {
2711                 err = set_rocev1_rules(&rules_list->head);
2712                 if (err)
2713                         goto free_list;
2714         }
2715         if (roce_mode & MLX5_ROCE_VERSION_2_CAP)
2716                 err = set_rocev2_rules(&rules_list->head);
2717         if (err)
2718                 goto free_list;
2719
2720         return rules_list;
2721
2722 free_list:
2723         mlx5_del_flow_rules_list(rules_list);
2724         return NULL;
2725 }