drm/nouveau: fence: fix undefined fence state after emit
[platform/kernel/linux-rpi.git] / drivers / net / ethernet / mellanox / mlx5 / core / lib / fs_chains.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2020 Mellanox Technologies.
3
4 #include <linux/mlx5/driver.h>
5 #include <linux/mlx5/mlx5_ifc.h>
6 #include <linux/mlx5/fs.h>
7
8 #include "lib/fs_chains.h"
9 #include "fs_ft_pool.h"
10 #include "en/mapping.h"
11 #include "fs_core.h"
12 #include "en_tc.h"
13
14 #define chains_lock(chains) ((chains)->lock)
15 #define chains_ht(chains) ((chains)->chains_ht)
16 #define prios_ht(chains) ((chains)->prios_ht)
17 #define chains_default_ft(chains) ((chains)->chains_default_ft)
18 #define chains_end_ft(chains) ((chains)->chains_end_ft)
19 #define FT_TBL_SZ (64 * 1024)
20
21 struct mlx5_fs_chains {
22         struct mlx5_core_dev *dev;
23
24         struct rhashtable chains_ht;
25         struct rhashtable prios_ht;
26         /* Protects above chains_ht and prios_ht */
27         struct mutex lock;
28
29         struct mlx5_flow_table *chains_default_ft;
30         struct mlx5_flow_table *chains_end_ft;
31         struct mapping_ctx *chains_mapping;
32
33         enum mlx5_flow_namespace_type ns;
34         u32 group_num;
35         u32 flags;
36         int fs_base_prio;
37         int fs_base_level;
38 };
39
40 struct fs_chain {
41         struct rhash_head node;
42
43         u32 chain;
44
45         int ref;
46         int id;
47
48         struct mlx5_fs_chains *chains;
49         struct list_head prios_list;
50         struct mlx5_flow_handle *restore_rule;
51         struct mlx5_modify_hdr *miss_modify_hdr;
52 };
53
54 struct prio_key {
55         u32 chain;
56         u32 prio;
57         u32 level;
58 };
59
60 struct prio {
61         struct rhash_head node;
62         struct list_head list;
63
64         struct prio_key key;
65
66         int ref;
67
68         struct fs_chain *chain;
69         struct mlx5_flow_table *ft;
70         struct mlx5_flow_table *next_ft;
71         struct mlx5_flow_group *miss_group;
72         struct mlx5_flow_handle *miss_rule;
73 };
74
75 static const struct rhashtable_params chain_params = {
76         .head_offset = offsetof(struct fs_chain, node),
77         .key_offset = offsetof(struct fs_chain, chain),
78         .key_len = sizeof_field(struct fs_chain, chain),
79         .automatic_shrinking = true,
80 };
81
82 static const struct rhashtable_params prio_params = {
83         .head_offset = offsetof(struct prio, node),
84         .key_offset = offsetof(struct prio, key),
85         .key_len = sizeof_field(struct prio, key),
86         .automatic_shrinking = true,
87 };
88
89 bool mlx5_chains_prios_supported(struct mlx5_fs_chains *chains)
90 {
91         return chains->flags & MLX5_CHAINS_AND_PRIOS_SUPPORTED;
92 }
93
94 bool mlx5_chains_ignore_flow_level_supported(struct mlx5_fs_chains *chains)
95 {
96         return chains->flags & MLX5_CHAINS_IGNORE_FLOW_LEVEL_SUPPORTED;
97 }
98
99 bool mlx5_chains_backwards_supported(struct mlx5_fs_chains *chains)
100 {
101         return mlx5_chains_prios_supported(chains) &&
102                mlx5_chains_ignore_flow_level_supported(chains);
103 }
104
105 u32 mlx5_chains_get_chain_range(struct mlx5_fs_chains *chains)
106 {
107         if (!mlx5_chains_prios_supported(chains))
108                 return 1;
109
110         if (mlx5_chains_ignore_flow_level_supported(chains))
111                 return UINT_MAX - 1;
112
113         /* We should get here only for eswitch case */
114         return FDB_TC_MAX_CHAIN;
115 }
116
117 u32 mlx5_chains_get_nf_ft_chain(struct mlx5_fs_chains *chains)
118 {
119         return mlx5_chains_get_chain_range(chains) + 1;
120 }
121
122 u32 mlx5_chains_get_prio_range(struct mlx5_fs_chains *chains)
123 {
124         if (mlx5_chains_ignore_flow_level_supported(chains))
125                 return UINT_MAX;
126
127         if (!chains->dev->priv.eswitch ||
128             chains->dev->priv.eswitch->mode != MLX5_ESWITCH_OFFLOADS)
129                 return 1;
130
131         /* We should get here only for eswitch case */
132         return FDB_TC_MAX_PRIO;
133 }
134
135 static unsigned int mlx5_chains_get_level_range(struct mlx5_fs_chains *chains)
136 {
137         if (mlx5_chains_ignore_flow_level_supported(chains))
138                 return UINT_MAX;
139
140         /* Same value for FDB and NIC RX tables */
141         return FDB_TC_LEVELS_PER_PRIO;
142 }
143
144 void
145 mlx5_chains_set_end_ft(struct mlx5_fs_chains *chains,
146                        struct mlx5_flow_table *ft)
147 {
148         chains_end_ft(chains) = ft;
149 }
150
151 static struct mlx5_flow_table *
152 mlx5_chains_create_table(struct mlx5_fs_chains *chains,
153                          u32 chain, u32 prio, u32 level)
154 {
155         struct mlx5_flow_table_attr ft_attr = {};
156         struct mlx5_flow_namespace *ns;
157         struct mlx5_flow_table *ft;
158         int sz;
159
160         if (chains->flags & MLX5_CHAINS_FT_TUNNEL_SUPPORTED)
161                 ft_attr.flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
162                                   MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
163
164         sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ? FT_TBL_SZ : POOL_NEXT_SIZE;
165         ft_attr.max_fte = sz;
166
167         /* We use chains_default_ft(chains) as the table's next_ft till
168          * ignore_flow_level is allowed on FT creation and not just for FTEs.
169          * Instead caller should add an explicit miss rule if needed.
170          */
171         ft_attr.next_ft = chains_default_ft(chains);
172
173         /* The root table(chain 0, prio 1, level 0) is required to be
174          * connected to the previous fs_core managed prio.
175          * We always create it, as a managed table, in order to align with
176          * fs_core logic.
177          */
178         if (!mlx5_chains_ignore_flow_level_supported(chains) ||
179             (chain == 0 && prio == 1 && level == 0)) {
180                 ft_attr.level = chains->fs_base_level;
181                 ft_attr.prio = chains->fs_base_prio;
182                 ns = (chains->ns == MLX5_FLOW_NAMESPACE_FDB) ?
183                         mlx5_get_fdb_sub_ns(chains->dev, chain) :
184                         mlx5_get_flow_namespace(chains->dev, chains->ns);
185         } else {
186                 ft_attr.flags |= MLX5_FLOW_TABLE_UNMANAGED;
187                 ft_attr.prio = chains->fs_base_prio;
188                 /* Firmware doesn't allow us to create another level 0 table,
189                  * so we create all unmanaged tables as level 1 (base + 1).
190                  *
191                  * To connect them, we use explicit miss rules with
192                  * ignore_flow_level. Caller is responsible to create
193                  * these rules (if needed).
194                  */
195                 ft_attr.level = chains->fs_base_level + 1;
196                 ns = mlx5_get_flow_namespace(chains->dev, chains->ns);
197         }
198
199         ft_attr.autogroup.num_reserved_entries = 2;
200         ft_attr.autogroup.max_num_groups = chains->group_num;
201         ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
202         if (IS_ERR(ft)) {
203                 mlx5_core_warn(chains->dev, "Failed to create chains table err %d (chain: %d, prio: %d, level: %d, size: %d)\n",
204                                (int)PTR_ERR(ft), chain, prio, level, sz);
205                 return ft;
206         }
207
208         return ft;
209 }
210
211 static int
212 create_chain_restore(struct fs_chain *chain)
213 {
214         struct mlx5_eswitch *esw = chain->chains->dev->priv.eswitch;
215         u8 modact[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
216         struct mlx5_fs_chains *chains = chain->chains;
217         enum mlx5e_tc_attr_to_reg mapped_obj_to_reg;
218         struct mlx5_modify_hdr *mod_hdr;
219         u32 index;
220         int err;
221
222         if (chain->chain == mlx5_chains_get_nf_ft_chain(chains) ||
223             !mlx5_chains_prios_supported(chains) ||
224             !chains->chains_mapping)
225                 return 0;
226
227         err = mlx5_chains_get_chain_mapping(chains, chain->chain, &index);
228         if (err)
229                 return err;
230         if (index == MLX5_FS_DEFAULT_FLOW_TAG) {
231                 /* we got the special default flow tag id, so we won't know
232                  * if we actually marked the packet with the restore rule
233                  * we create.
234                  *
235                  * This case isn't possible with MLX5_FS_DEFAULT_FLOW_TAG = 0.
236                  */
237                 err = mlx5_chains_get_chain_mapping(chains, chain->chain, &index);
238                 mapping_remove(chains->chains_mapping, MLX5_FS_DEFAULT_FLOW_TAG);
239                 if (err)
240                         return err;
241         }
242
243         chain->id = index;
244
245         if (chains->ns == MLX5_FLOW_NAMESPACE_FDB) {
246                 mapped_obj_to_reg = MAPPED_OBJ_TO_REG;
247                 chain->restore_rule = esw_add_restore_rule(esw, chain->id);
248                 if (IS_ERR(chain->restore_rule)) {
249                         err = PTR_ERR(chain->restore_rule);
250                         goto err_rule;
251                 }
252         } else if (chains->ns == MLX5_FLOW_NAMESPACE_KERNEL) {
253                 /* For NIC RX we don't need a restore rule
254                  * since we write the metadata to reg_b
255                  * that is passed to SW directly.
256                  */
257                 mapped_obj_to_reg = NIC_MAPPED_OBJ_TO_REG;
258         } else {
259                 err = -EINVAL;
260                 goto err_rule;
261         }
262
263         MLX5_SET(set_action_in, modact, action_type, MLX5_ACTION_TYPE_SET);
264         MLX5_SET(set_action_in, modact, field,
265                  mlx5e_tc_attr_to_reg_mappings[mapped_obj_to_reg].mfield);
266         MLX5_SET(set_action_in, modact, offset,
267                  mlx5e_tc_attr_to_reg_mappings[mapped_obj_to_reg].moffset);
268         MLX5_SET(set_action_in, modact, length,
269                  mlx5e_tc_attr_to_reg_mappings[mapped_obj_to_reg].mlen == 32 ?
270                  0 : mlx5e_tc_attr_to_reg_mappings[mapped_obj_to_reg].mlen);
271         MLX5_SET(set_action_in, modact, data, chain->id);
272         mod_hdr = mlx5_modify_header_alloc(chains->dev, chains->ns,
273                                            1, modact);
274         if (IS_ERR(mod_hdr)) {
275                 err = PTR_ERR(mod_hdr);
276                 goto err_mod_hdr;
277         }
278         chain->miss_modify_hdr = mod_hdr;
279
280         return 0;
281
282 err_mod_hdr:
283         if (!IS_ERR_OR_NULL(chain->restore_rule))
284                 mlx5_del_flow_rules(chain->restore_rule);
285 err_rule:
286         /* Datapath can't find this mapping, so we can safely remove it */
287         mapping_remove(chains->chains_mapping, chain->id);
288         return err;
289 }
290
291 static void destroy_chain_restore(struct fs_chain *chain)
292 {
293         struct mlx5_fs_chains *chains = chain->chains;
294
295         if (!chain->miss_modify_hdr)
296                 return;
297
298         if (chain->restore_rule)
299                 mlx5_del_flow_rules(chain->restore_rule);
300
301         mlx5_modify_header_dealloc(chains->dev, chain->miss_modify_hdr);
302         mapping_remove(chains->chains_mapping, chain->id);
303 }
304
305 static struct fs_chain *
306 mlx5_chains_create_chain(struct mlx5_fs_chains *chains, u32 chain)
307 {
308         struct fs_chain *chain_s = NULL;
309         int err;
310
311         chain_s = kvzalloc(sizeof(*chain_s), GFP_KERNEL);
312         if (!chain_s)
313                 return ERR_PTR(-ENOMEM);
314
315         chain_s->chains = chains;
316         chain_s->chain = chain;
317         INIT_LIST_HEAD(&chain_s->prios_list);
318
319         err = create_chain_restore(chain_s);
320         if (err)
321                 goto err_restore;
322
323         err = rhashtable_insert_fast(&chains_ht(chains), &chain_s->node,
324                                      chain_params);
325         if (err)
326                 goto err_insert;
327
328         return chain_s;
329
330 err_insert:
331         destroy_chain_restore(chain_s);
332 err_restore:
333         kvfree(chain_s);
334         return ERR_PTR(err);
335 }
336
337 static void
338 mlx5_chains_destroy_chain(struct fs_chain *chain)
339 {
340         struct mlx5_fs_chains *chains = chain->chains;
341
342         rhashtable_remove_fast(&chains_ht(chains), &chain->node,
343                                chain_params);
344
345         destroy_chain_restore(chain);
346         kvfree(chain);
347 }
348
349 static struct fs_chain *
350 mlx5_chains_get_chain(struct mlx5_fs_chains *chains, u32 chain)
351 {
352         struct fs_chain *chain_s;
353
354         chain_s = rhashtable_lookup_fast(&chains_ht(chains), &chain,
355                                          chain_params);
356         if (!chain_s) {
357                 chain_s = mlx5_chains_create_chain(chains, chain);
358                 if (IS_ERR(chain_s))
359                         return chain_s;
360         }
361
362         chain_s->ref++;
363
364         return chain_s;
365 }
366
367 static struct mlx5_flow_handle *
368 mlx5_chains_add_miss_rule(struct fs_chain *chain,
369                           struct mlx5_flow_table *ft,
370                           struct mlx5_flow_table *next_ft)
371 {
372         struct mlx5_fs_chains *chains = chain->chains;
373         struct mlx5_flow_destination dest = {};
374         struct mlx5_flow_act act = {};
375
376         act.flags  = FLOW_ACT_NO_APPEND;
377         if (mlx5_chains_ignore_flow_level_supported(chain->chains))
378                 act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
379
380         act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
381         dest.type  = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
382         dest.ft = next_ft;
383
384         if (chains->chains_mapping && next_ft == chains_end_ft(chains) &&
385             chain->chain != mlx5_chains_get_nf_ft_chain(chains) &&
386             mlx5_chains_prios_supported(chains)) {
387                 act.modify_hdr = chain->miss_modify_hdr;
388                 act.action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
389         }
390
391         return mlx5_add_flow_rules(ft, NULL, &act, &dest, 1);
392 }
393
394 static int
395 mlx5_chains_update_prio_prevs(struct prio *prio,
396                               struct mlx5_flow_table *next_ft)
397 {
398         struct mlx5_flow_handle *miss_rules[FDB_TC_LEVELS_PER_PRIO + 1] = {};
399         struct fs_chain *chain = prio->chain;
400         struct prio *pos;
401         int n = 0, err;
402
403         if (prio->key.level)
404                 return 0;
405
406         /* Iterate in reverse order until reaching the level 0 rule of
407          * the previous priority, adding all the miss rules first, so we can
408          * revert them if any of them fails.
409          */
410         pos = prio;
411         list_for_each_entry_continue_reverse(pos,
412                                              &chain->prios_list,
413                                              list) {
414                 miss_rules[n] = mlx5_chains_add_miss_rule(chain,
415                                                           pos->ft,
416                                                           next_ft);
417                 if (IS_ERR(miss_rules[n])) {
418                         err = PTR_ERR(miss_rules[n]);
419                         goto err_prev_rule;
420                 }
421
422                 n++;
423                 if (!pos->key.level)
424                         break;
425         }
426
427         /* Success, delete old miss rules, and update the pointers. */
428         n = 0;
429         pos = prio;
430         list_for_each_entry_continue_reverse(pos,
431                                              &chain->prios_list,
432                                              list) {
433                 mlx5_del_flow_rules(pos->miss_rule);
434
435                 pos->miss_rule = miss_rules[n];
436                 pos->next_ft = next_ft;
437
438                 n++;
439                 if (!pos->key.level)
440                         break;
441         }
442
443         return 0;
444
445 err_prev_rule:
446         while (--n >= 0)
447                 mlx5_del_flow_rules(miss_rules[n]);
448
449         return err;
450 }
451
452 static void
453 mlx5_chains_put_chain(struct fs_chain *chain)
454 {
455         if (--chain->ref == 0)
456                 mlx5_chains_destroy_chain(chain);
457 }
458
459 static struct prio *
460 mlx5_chains_create_prio(struct mlx5_fs_chains *chains,
461                         u32 chain, u32 prio, u32 level)
462 {
463         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
464         struct mlx5_flow_handle *miss_rule;
465         struct mlx5_flow_group *miss_group;
466         struct mlx5_flow_table *next_ft;
467         struct mlx5_flow_table *ft;
468         struct fs_chain *chain_s;
469         struct list_head *pos;
470         struct prio *prio_s;
471         u32 *flow_group_in;
472         int err;
473
474         chain_s = mlx5_chains_get_chain(chains, chain);
475         if (IS_ERR(chain_s))
476                 return ERR_CAST(chain_s);
477
478         prio_s = kvzalloc(sizeof(*prio_s), GFP_KERNEL);
479         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
480         if (!prio_s || !flow_group_in) {
481                 err = -ENOMEM;
482                 goto err_alloc;
483         }
484
485         /* Chain's prio list is sorted by prio and level.
486          * And all levels of some prio point to the next prio's level 0.
487          * Example list (prio, level):
488          * (3,0)->(3,1)->(5,0)->(5,1)->(6,1)->(7,0)
489          * In hardware, we will we have the following pointers:
490          * (3,0) -> (5,0) -> (7,0) -> Slow path
491          * (3,1) -> (5,0)
492          * (5,1) -> (7,0)
493          * (6,1) -> (7,0)
494          */
495
496         /* Default miss for each chain: */
497         next_ft = (chain == mlx5_chains_get_nf_ft_chain(chains)) ?
498                   chains_default_ft(chains) :
499                   chains_end_ft(chains);
500         list_for_each(pos, &chain_s->prios_list) {
501                 struct prio *p = list_entry(pos, struct prio, list);
502
503                 /* exit on first pos that is larger */
504                 if (prio < p->key.prio || (prio == p->key.prio &&
505                                            level < p->key.level)) {
506                         /* Get next level 0 table */
507                         next_ft = p->key.level == 0 ? p->ft : p->next_ft;
508                         break;
509                 }
510         }
511
512         ft = mlx5_chains_create_table(chains, chain, prio, level);
513         if (IS_ERR(ft)) {
514                 err = PTR_ERR(ft);
515                 goto err_create;
516         }
517
518         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index,
519                  ft->max_fte - 2);
520         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
521                  ft->max_fte - 1);
522         miss_group = mlx5_create_flow_group(ft, flow_group_in);
523         if (IS_ERR(miss_group)) {
524                 err = PTR_ERR(miss_group);
525                 goto err_group;
526         }
527
528         /* Add miss rule to next_ft */
529         miss_rule = mlx5_chains_add_miss_rule(chain_s, ft, next_ft);
530         if (IS_ERR(miss_rule)) {
531                 err = PTR_ERR(miss_rule);
532                 goto err_miss_rule;
533         }
534
535         prio_s->miss_group = miss_group;
536         prio_s->miss_rule = miss_rule;
537         prio_s->next_ft = next_ft;
538         prio_s->chain = chain_s;
539         prio_s->key.chain = chain;
540         prio_s->key.prio = prio;
541         prio_s->key.level = level;
542         prio_s->ft = ft;
543
544         err = rhashtable_insert_fast(&prios_ht(chains), &prio_s->node,
545                                      prio_params);
546         if (err)
547                 goto err_insert;
548
549         list_add(&prio_s->list, pos->prev);
550
551         /* Table is ready, connect it */
552         err = mlx5_chains_update_prio_prevs(prio_s, ft);
553         if (err)
554                 goto err_update;
555
556         kvfree(flow_group_in);
557         return prio_s;
558
559 err_update:
560         list_del(&prio_s->list);
561         rhashtable_remove_fast(&prios_ht(chains), &prio_s->node,
562                                prio_params);
563 err_insert:
564         mlx5_del_flow_rules(miss_rule);
565 err_miss_rule:
566         mlx5_destroy_flow_group(miss_group);
567 err_group:
568         mlx5_destroy_flow_table(ft);
569 err_create:
570 err_alloc:
571         kvfree(prio_s);
572         kvfree(flow_group_in);
573         mlx5_chains_put_chain(chain_s);
574         return ERR_PTR(err);
575 }
576
577 static void
578 mlx5_chains_destroy_prio(struct mlx5_fs_chains *chains,
579                          struct prio *prio)
580 {
581         struct fs_chain *chain = prio->chain;
582
583         WARN_ON(mlx5_chains_update_prio_prevs(prio,
584                                               prio->next_ft));
585
586         list_del(&prio->list);
587         rhashtable_remove_fast(&prios_ht(chains), &prio->node,
588                                prio_params);
589         mlx5_del_flow_rules(prio->miss_rule);
590         mlx5_destroy_flow_group(prio->miss_group);
591         mlx5_destroy_flow_table(prio->ft);
592         mlx5_chains_put_chain(chain);
593         kvfree(prio);
594 }
595
596 struct mlx5_flow_table *
597 mlx5_chains_get_table(struct mlx5_fs_chains *chains, u32 chain, u32 prio,
598                       u32 level)
599 {
600         struct mlx5_flow_table *prev_fts;
601         struct prio *prio_s;
602         struct prio_key key;
603         int l = 0;
604
605         if ((chain > mlx5_chains_get_chain_range(chains) &&
606              chain != mlx5_chains_get_nf_ft_chain(chains)) ||
607             prio > mlx5_chains_get_prio_range(chains) ||
608             level > mlx5_chains_get_level_range(chains))
609                 return ERR_PTR(-EOPNOTSUPP);
610
611         /* create earlier levels for correct fs_core lookup when
612          * connecting tables.
613          */
614         for (l = 0; l < level; l++) {
615                 prev_fts = mlx5_chains_get_table(chains, chain, prio, l);
616                 if (IS_ERR(prev_fts)) {
617                         prio_s = ERR_CAST(prev_fts);
618                         goto err_get_prevs;
619                 }
620         }
621
622         key.chain = chain;
623         key.prio = prio;
624         key.level = level;
625
626         mutex_lock(&chains_lock(chains));
627         prio_s = rhashtable_lookup_fast(&prios_ht(chains), &key,
628                                         prio_params);
629         if (!prio_s) {
630                 prio_s = mlx5_chains_create_prio(chains, chain,
631                                                  prio, level);
632                 if (IS_ERR(prio_s))
633                         goto err_create_prio;
634         }
635
636         ++prio_s->ref;
637         mutex_unlock(&chains_lock(chains));
638
639         return prio_s->ft;
640
641 err_create_prio:
642         mutex_unlock(&chains_lock(chains));
643 err_get_prevs:
644         while (--l >= 0)
645                 mlx5_chains_put_table(chains, chain, prio, l);
646         return ERR_CAST(prio_s);
647 }
648
649 void
650 mlx5_chains_put_table(struct mlx5_fs_chains *chains, u32 chain, u32 prio,
651                       u32 level)
652 {
653         struct prio *prio_s;
654         struct prio_key key;
655
656         key.chain = chain;
657         key.prio = prio;
658         key.level = level;
659
660         mutex_lock(&chains_lock(chains));
661         prio_s = rhashtable_lookup_fast(&prios_ht(chains), &key,
662                                         prio_params);
663         if (!prio_s)
664                 goto err_get_prio;
665
666         if (--prio_s->ref == 0)
667                 mlx5_chains_destroy_prio(chains, prio_s);
668         mutex_unlock(&chains_lock(chains));
669
670         while (level-- > 0)
671                 mlx5_chains_put_table(chains, chain, prio, level);
672
673         return;
674
675 err_get_prio:
676         mutex_unlock(&chains_lock(chains));
677         WARN_ONCE(1,
678                   "Couldn't find table: (chain: %d prio: %d level: %d)",
679                   chain, prio, level);
680 }
681
682 struct mlx5_flow_table *
683 mlx5_chains_get_tc_end_ft(struct mlx5_fs_chains *chains)
684 {
685         return chains_end_ft(chains);
686 }
687
688 struct mlx5_flow_table *
689 mlx5_chains_create_global_table(struct mlx5_fs_chains *chains)
690 {
691         u32 chain, prio, level;
692         int err;
693
694         if (!mlx5_chains_ignore_flow_level_supported(chains)) {
695                 err = -EOPNOTSUPP;
696
697                 mlx5_core_warn(chains->dev,
698                                "Couldn't create global flow table, ignore_flow_level not supported.");
699                 goto err_ignore;
700         }
701
702         chain = mlx5_chains_get_chain_range(chains),
703         prio = mlx5_chains_get_prio_range(chains);
704         level = mlx5_chains_get_level_range(chains);
705
706         return mlx5_chains_create_table(chains, chain, prio, level);
707
708 err_ignore:
709         return ERR_PTR(err);
710 }
711
712 void
713 mlx5_chains_destroy_global_table(struct mlx5_fs_chains *chains,
714                                  struct mlx5_flow_table *ft)
715 {
716         mlx5_destroy_flow_table(ft);
717 }
718
719 static struct mlx5_fs_chains *
720 mlx5_chains_init(struct mlx5_core_dev *dev, struct mlx5_chains_attr *attr)
721 {
722         struct mlx5_fs_chains *chains;
723         int err;
724
725         chains = kzalloc(sizeof(*chains), GFP_KERNEL);
726         if (!chains)
727                 return ERR_PTR(-ENOMEM);
728
729         chains->dev = dev;
730         chains->flags = attr->flags;
731         chains->ns = attr->ns;
732         chains->group_num = attr->max_grp_num;
733         chains->chains_mapping = attr->mapping;
734         chains->fs_base_prio = attr->fs_base_prio;
735         chains->fs_base_level = attr->fs_base_level;
736         chains_default_ft(chains) = chains_end_ft(chains) = attr->default_ft;
737
738         err = rhashtable_init(&chains_ht(chains), &chain_params);
739         if (err)
740                 goto init_chains_ht_err;
741
742         err = rhashtable_init(&prios_ht(chains), &prio_params);
743         if (err)
744                 goto init_prios_ht_err;
745
746         mutex_init(&chains_lock(chains));
747
748         return chains;
749
750 init_prios_ht_err:
751         rhashtable_destroy(&chains_ht(chains));
752 init_chains_ht_err:
753         kfree(chains);
754         return ERR_PTR(err);
755 }
756
757 static void
758 mlx5_chains_cleanup(struct mlx5_fs_chains *chains)
759 {
760         mutex_destroy(&chains_lock(chains));
761         rhashtable_destroy(&prios_ht(chains));
762         rhashtable_destroy(&chains_ht(chains));
763
764         kfree(chains);
765 }
766
767 struct mlx5_fs_chains *
768 mlx5_chains_create(struct mlx5_core_dev *dev, struct mlx5_chains_attr *attr)
769 {
770         struct mlx5_fs_chains *chains;
771
772         chains = mlx5_chains_init(dev, attr);
773
774         return chains;
775 }
776
777 void
778 mlx5_chains_destroy(struct mlx5_fs_chains *chains)
779 {
780         mlx5_chains_cleanup(chains);
781 }
782
783 int
784 mlx5_chains_get_chain_mapping(struct mlx5_fs_chains *chains, u32 chain,
785                               u32 *chain_mapping)
786 {
787         struct mapping_ctx *ctx = chains->chains_mapping;
788         struct mlx5_mapped_obj mapped_obj = {};
789
790         mapped_obj.type = MLX5_MAPPED_OBJ_CHAIN;
791         mapped_obj.chain = chain;
792         return mapping_add(ctx, &mapped_obj, chain_mapping);
793 }
794
795 int
796 mlx5_chains_put_chain_mapping(struct mlx5_fs_chains *chains, u32 chain_mapping)
797 {
798         struct mapping_ctx *ctx = chains->chains_mapping;
799
800         return mapping_remove(ctx, chain_mapping);
801 }
802
803 void
804 mlx5_chains_print_info(struct mlx5_fs_chains *chains)
805 {
806         mlx5_core_dbg(chains->dev, "Flow table chains groups(%d)\n", chains->group_num);
807 }