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