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