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