xref: /freebsd-head/sys/dev/mlx5/mlx5_core/mlx5_fs_chains.c (revision e23731db48ef9c6568d4768b1f87d48514339faa)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2020 Mellanox Technologies.
3 
4 #include <dev/mlx5/driver.h>
5 #include <dev/mlx5/mlx5_ifc.h>
6 #include <dev/mlx5/fs.h>
7 
8 #include "mlx5_core.h"
9 #include "fs_chains.h"
10 #include "fs_ft_pool.h"
11 #include "fs_core.h"
12 
13 #define chains_lock(chains) ((chains)->lock)
14 #define chains_xa(chains) ((chains)->chains_xa)
15 #define prios_xa(chains) ((chains)->prios_xa)
16 #define chains_default_ft(chains) ((chains)->chains_default_ft)
17 #define chains_end_ft(chains) ((chains)->chains_end_ft)
18 #define FT_TBL_SZ (64 * 1024)
19 
20 struct mlx5_fs_chains {
21 	struct mlx5_core_dev *dev;
22 
23 	struct xarray chains_xa;
24 	struct xarray prios_xa;
25 	/* Protects above chains_ht and prios_ht */
26 	struct mutex lock;
27 
28 	struct mlx5_flow_table *chains_default_ft;
29 	struct mlx5_flow_table *chains_end_ft;
30 
31 	enum mlx5_flow_namespace_type ns;
32 	u32 group_num;
33 	u32 flags;
34 	int fs_base_prio;
35 	int fs_base_level;
36 };
37 
38 struct fs_chain {
39 	u32 chain;
40 
41 	int ref;
42 	int id;
43 	uint32_t xa_idx;
44 
45 	struct mlx5_fs_chains *chains;
46 	struct list_head prios_list;
47 	struct mlx5_flow_handle *restore_rule;
48 	struct mlx5_modify_hdr *miss_modify_hdr;
49 };
50 
51 struct prio_key {
52 	u32 chain;
53 	u32 prio;
54 	u32 level;
55 };
56 
57 struct prio {
58 	struct list_head list;
59 
60 	struct prio_key key;
61 	uint32_t xa_idx;
62 
63 	int ref;
64 
65 	struct fs_chain *chain;
66 	struct mlx5_flow_table *ft;
67 	struct mlx5_flow_table *next_ft;
68 	struct mlx5_flow_group *miss_group;
69 	struct mlx5_flow_handle *miss_rule;
70 };
71 
72 /*
73 static const struct rhashtable_params chain_params = {
74 	.head_offset = offsetof(struct fs_chain, node),
75 	.key_offset = offsetof(struct fs_chain, chain),
76 	.key_len = sizeof_field(struct fs_chain, chain),
77 	.automatic_shrinking = true,
78 };
79 
80 static const struct rhashtable_params prio_params = {
81 	.head_offset = offsetof(struct prio, node),
82 	.key_offset = offsetof(struct prio, key),
83 	.key_len = sizeof_field(struct prio, key),
84 	.automatic_shrinking = true,
85 };
86 */
87 
mlx5_chains_prios_supported(struct mlx5_fs_chains * chains)88 bool mlx5_chains_prios_supported(struct mlx5_fs_chains *chains)
89 {
90 	return chains->flags & MLX5_CHAINS_AND_PRIOS_SUPPORTED;
91 }
92 
mlx5_chains_ignore_flow_level_supported(struct mlx5_fs_chains * chains)93 bool mlx5_chains_ignore_flow_level_supported(struct mlx5_fs_chains *chains)
94 {
95 	return chains->flags & MLX5_CHAINS_IGNORE_FLOW_LEVEL_SUPPORTED;
96 }
97 
mlx5_chains_backwards_supported(struct mlx5_fs_chains * chains)98 bool mlx5_chains_backwards_supported(struct mlx5_fs_chains *chains)
99 {
100 	return mlx5_chains_prios_supported(chains) &&
101 	       mlx5_chains_ignore_flow_level_supported(chains);
102 }
103 
mlx5_chains_get_chain_range(struct mlx5_fs_chains * chains)104 u32 mlx5_chains_get_chain_range(struct mlx5_fs_chains *chains)
105 {
106 	if (!mlx5_chains_prios_supported(chains))
107 		return 1;
108 
109 	if (mlx5_chains_ignore_flow_level_supported(chains))
110 		return UINT_MAX - 1;
111 
112 	/* We should get here only for eswitch case */
113 	return FDB_TC_MAX_CHAIN;
114 }
115 
mlx5_chains_get_nf_ft_chain(struct mlx5_fs_chains * chains)116 u32 mlx5_chains_get_nf_ft_chain(struct mlx5_fs_chains *chains)
117 {
118 	return mlx5_chains_get_chain_range(chains) + 1;
119 }
120 
mlx5_chains_get_prio_range(struct mlx5_fs_chains * chains)121 u32 mlx5_chains_get_prio_range(struct mlx5_fs_chains *chains)
122 {
123 	if (mlx5_chains_ignore_flow_level_supported(chains))
124 		return UINT_MAX;
125 
126 	if (!chains->dev->priv.eswitch)
127 		return 1;
128 
129 	/* We should get here only for eswitch case */
130 	return FDB_TC_MAX_PRIO;
131 }
132 
mlx5_chains_get_level_range(struct mlx5_fs_chains * chains)133 static unsigned int mlx5_chains_get_level_range(struct mlx5_fs_chains *chains)
134 {
135 	if (mlx5_chains_ignore_flow_level_supported(chains))
136 		return UINT_MAX;
137 
138 	/* Same value for FDB and NIC RX tables */
139 	return FDB_TC_LEVELS_PER_PRIO;
140 }
141 
142 void
mlx5_chains_set_end_ft(struct mlx5_fs_chains * chains,struct mlx5_flow_table * ft)143 mlx5_chains_set_end_ft(struct mlx5_fs_chains *chains,
144 		       struct mlx5_flow_table *ft)
145 {
146 	chains_end_ft(chains) = ft;
147 }
148 
149 static struct mlx5_flow_table *
mlx5_chains_create_table(struct mlx5_fs_chains * chains,u32 chain,u32 prio,u32 level)150 mlx5_chains_create_table(struct mlx5_fs_chains *chains,
151 			 u32 chain, u32 prio, u32 level)
152 {
153 	struct mlx5_flow_table_attr ft_attr = {};
154 	struct mlx5_flow_namespace *ns;
155 	struct mlx5_flow_table *ft;
156 	int sz;
157 
158 	if (chains->flags & MLX5_CHAINS_FT_TUNNEL_SUPPORTED)
159 		ft_attr.flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
160 				  MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
161 
162 	sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ? FT_TBL_SZ : POOL_NEXT_SIZE;
163 	ft_attr.max_fte = sz;
164 
165 	/* We use chains_default_ft(chains) as the table's next_ft till
166 	 * ignore_flow_level is allowed on FT creation and not just for FTEs.
167 	 * Instead caller should add an explicit miss rule if needed.
168 	 */
169 	ft_attr.next_ft = chains_default_ft(chains);
170 
171 	/* The root table(chain 0, prio 1, level 0) is required to be
172 	 * connected to the previous fs_core managed prio.
173 	 * We always create it, as a managed table, in order to align with
174 	 * fs_core logic.
175 	 */
176 	if (!mlx5_chains_ignore_flow_level_supported(chains) ||
177 	    (chain == 0 && prio == 1 && level == 0)) {
178 		ft_attr.level = chains->fs_base_level;
179 		ft_attr.prio = chains->fs_base_prio;
180 		ns = (chains->ns == MLX5_FLOW_NAMESPACE_FDB) ?
181 			mlx5_get_fdb_sub_ns(chains->dev, chain) :
182 			mlx5_get_flow_namespace(chains->dev, chains->ns);
183 	} else {
184 		ft_attr.flags |= MLX5_FLOW_TABLE_UNMANAGED;
185 		ft_attr.prio = chains->fs_base_prio;
186 		/* Firmware doesn't allow us to create another level 0 table,
187 		 * so we create all unmanaged tables as level 1 (base + 1).
188 		 *
189 		 * To connect them, we use explicit miss rules with
190 		 * ignore_flow_level. Caller is responsible to create
191 		 * these rules (if needed).
192 		 */
193 		ft_attr.level = chains->fs_base_level + 1;
194 		ns = mlx5_get_flow_namespace(chains->dev, chains->ns);
195 	}
196 
197 	ft_attr.autogroup.num_reserved_entries = 2;
198 	ft_attr.autogroup.max_num_groups = chains->group_num;
199 	ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
200 	if (IS_ERR(ft)) {
201 		mlx5_core_warn(chains->dev, "Failed to create chains table err %d (chain: %d, prio: %d, level: %d, size: %d)\n",
202 			       (int)PTR_ERR(ft), chain, prio, level, sz);
203 		return ft;
204 	}
205 
206 	return ft;
207 }
208 
209 static struct fs_chain *
mlx5_chains_create_chain(struct mlx5_fs_chains * chains,u32 chain)210 mlx5_chains_create_chain(struct mlx5_fs_chains *chains, u32 chain)
211 {
212 	struct fs_chain *chain_s = NULL;
213 	int err;
214 
215 	chain_s = kvzalloc(sizeof(*chain_s), GFP_KERNEL);
216 	if (!chain_s)
217 		return ERR_PTR(-ENOMEM);
218 
219 	chain_s->chains = chains;
220 	chain_s->chain = chain;
221 	INIT_LIST_HEAD(&chain_s->prios_list);
222 
223 	err = xa_alloc(&chains_xa(chains), &chain_s->xa_idx, chain_s,
224 		       xa_limit_32b, GFP_KERNEL);
225 	if (err)
226 		goto err_insert;
227 
228 	return chain_s;
229 
230 err_insert:
231 	kvfree(chain_s);
232 	return ERR_PTR(err);
233 }
234 
235 static void
mlx5_chains_destroy_chain(struct fs_chain * chain)236 mlx5_chains_destroy_chain(struct fs_chain *chain)
237 {
238 	struct mlx5_fs_chains *chains = chain->chains;
239 
240 	xa_erase(&chains_xa(chains), chain->xa_idx);
241 	kvfree(chain);
242 }
243 
244 static struct fs_chain *
mlx5_chains_get_chain(struct mlx5_fs_chains * chains,u32 chain)245 mlx5_chains_get_chain(struct mlx5_fs_chains *chains, u32 chain)
246 {
247 	struct fs_chain *chain_s = NULL;
248 	unsigned long idx;
249 
250 	xa_for_each(&chains_xa(chains), idx, chain_s) {
251 		if (chain_s->chain == chain)
252 			break;
253 	}
254 
255 	if (!chain_s) {
256 		chain_s = mlx5_chains_create_chain(chains, chain);
257 		if (IS_ERR(chain_s))
258 			return chain_s;
259 	}
260 
261 	chain_s->ref++;
262 
263 	return chain_s;
264 }
265 
266 static struct mlx5_flow_handle *
mlx5_chains_add_miss_rule(struct fs_chain * chain,struct mlx5_flow_table * ft,struct mlx5_flow_table * next_ft)267 mlx5_chains_add_miss_rule(struct fs_chain *chain,
268 			  struct mlx5_flow_table *ft,
269 			  struct mlx5_flow_table *next_ft)
270 {
271 	struct mlx5_flow_destination dest = {};
272 	struct mlx5_flow_act act = {};
273 
274 	act.flags  = FLOW_ACT_NO_APPEND;
275 	if (mlx5_chains_ignore_flow_level_supported(chain->chains))
276 		act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
277 
278 	act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
279 	dest.type  = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
280 	dest.ft = next_ft;
281 
282 	return mlx5_add_flow_rules(ft, NULL, &act, &dest, 1);
283 }
284 
285 static int
mlx5_chains_update_prio_prevs(struct prio * prio,struct mlx5_flow_table * next_ft)286 mlx5_chains_update_prio_prevs(struct prio *prio,
287 			      struct mlx5_flow_table *next_ft)
288 {
289 	struct mlx5_flow_handle *miss_rules[FDB_TC_LEVELS_PER_PRIO + 1] = {};
290 	struct fs_chain *chain = prio->chain;
291 	struct prio *pos;
292 	int n = 0, err;
293 
294 	if (prio->key.level)
295 		return 0;
296 
297 	/* Iterate in reverse order until reaching the level 0 rule of
298 	 * the previous priority, adding all the miss rules first, so we can
299 	 * revert them if any of them fails.
300 	 */
301 	pos = prio;
302 	list_for_each_entry_continue_reverse(pos,
303 					     &chain->prios_list,
304 					     list) {
305 		miss_rules[n] = mlx5_chains_add_miss_rule(chain,
306 							  pos->ft,
307 							  next_ft);
308 		if (IS_ERR(miss_rules[n])) {
309 			err = PTR_ERR(miss_rules[n]);
310 			goto err_prev_rule;
311 		}
312 
313 		n++;
314 		if (!pos->key.level)
315 			break;
316 	}
317 
318 	/* Success, delete old miss rules, and update the pointers. */
319 	n = 0;
320 	pos = prio;
321 	list_for_each_entry_continue_reverse(pos,
322 					     &chain->prios_list,
323 					     list) {
324 		mlx5_del_flow_rules(&pos->miss_rule);
325 
326 		pos->miss_rule = miss_rules[n];
327 		pos->next_ft = next_ft;
328 
329 		n++;
330 		if (!pos->key.level)
331 			break;
332 	}
333 
334 	return 0;
335 
336 err_prev_rule:
337 	while (--n >= 0)
338 		mlx5_del_flow_rules(&miss_rules[n]);
339 
340 	return err;
341 }
342 
343 static void
mlx5_chains_put_chain(struct fs_chain * chain)344 mlx5_chains_put_chain(struct fs_chain *chain)
345 {
346 	if (--chain->ref == 0)
347 		mlx5_chains_destroy_chain(chain);
348 }
349 
350 static struct prio *
mlx5_chains_create_prio(struct mlx5_fs_chains * chains,u32 chain,u32 prio,u32 level)351 mlx5_chains_create_prio(struct mlx5_fs_chains *chains,
352 			u32 chain, u32 prio, u32 level)
353 {
354 	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
355 	struct mlx5_flow_handle *miss_rule;
356 	struct mlx5_flow_group *miss_group;
357 	struct mlx5_flow_table *next_ft;
358 	struct mlx5_flow_table *ft;
359 	struct fs_chain *chain_s;
360 	struct list_head *pos;
361 	struct prio *prio_s;
362 	u32 *flow_group_in;
363 	int err;
364 
365 	chain_s = mlx5_chains_get_chain(chains, chain);
366 	if (IS_ERR(chain_s))
367 		return ERR_CAST(chain_s);
368 
369 	prio_s = kvzalloc(sizeof(*prio_s), GFP_KERNEL);
370 	flow_group_in = kvzalloc(inlen, GFP_KERNEL);
371 	if (!prio_s || !flow_group_in) {
372 		err = -ENOMEM;
373 		goto err_alloc;
374 	}
375 
376 	/* Chain's prio list is sorted by prio and level.
377 	 * And all levels of some prio point to the next prio's level 0.
378 	 * Example list (prio, level):
379 	 * (3,0)->(3,1)->(5,0)->(5,1)->(6,1)->(7,0)
380 	 * In hardware, we will we have the following pointers:
381 	 * (3,0) -> (5,0) -> (7,0) -> Slow path
382 	 * (3,1) -> (5,0)
383 	 * (5,1) -> (7,0)
384 	 * (6,1) -> (7,0)
385 	 */
386 
387 	/* Default miss for each chain: */
388 	next_ft = (chain == mlx5_chains_get_nf_ft_chain(chains)) ?
389 		  chains_default_ft(chains) :
390 		  chains_end_ft(chains);
391 	list_for_each(pos, &chain_s->prios_list) {
392 		struct prio *p = list_entry(pos, struct prio, list);
393 
394 		/* exit on first pos that is larger */
395 		if (prio < p->key.prio || (prio == p->key.prio &&
396 					   level < p->key.level)) {
397 			/* Get next level 0 table */
398 			next_ft = p->key.level == 0 ? p->ft : p->next_ft;
399 			break;
400 		}
401 	}
402 
403 	ft = mlx5_chains_create_table(chains, chain, prio, level);
404 	if (IS_ERR(ft)) {
405 		err = PTR_ERR(ft);
406 		goto err_create;
407 	}
408 
409 	MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index,
410 		 ft->max_fte - 2);
411 	MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
412 		 ft->max_fte - 1);
413 	miss_group = mlx5_create_flow_group(ft, flow_group_in);
414 	if (IS_ERR(miss_group)) {
415 		err = PTR_ERR(miss_group);
416 		goto err_group;
417 	}
418 
419 	/* Add miss rule to next_ft */
420 	miss_rule = mlx5_chains_add_miss_rule(chain_s, ft, next_ft);
421 	if (IS_ERR(miss_rule)) {
422 		err = PTR_ERR(miss_rule);
423 		goto err_miss_rule;
424 	}
425 
426 	prio_s->miss_group = miss_group;
427 	prio_s->miss_rule = miss_rule;
428 	prio_s->next_ft = next_ft;
429 	prio_s->chain = chain_s;
430 	prio_s->key.chain = chain;
431 	prio_s->key.prio = prio;
432 	prio_s->key.level = level;
433 	prio_s->ft = ft;
434 
435 	err = xa_alloc(&prios_xa(chains), &prio_s->xa_idx, prio_s,
436 		       xa_limit_32b, GFP_KERNEL);
437 	if (err)
438 		goto err_insert;
439 
440 	list_add(&prio_s->list, pos->prev);
441 
442 	/* Table is ready, connect it */
443 	err = mlx5_chains_update_prio_prevs(prio_s, ft);
444 	if (err)
445 		goto err_update;
446 
447 	kvfree(flow_group_in);
448 	return prio_s;
449 
450 err_update:
451 	list_del(&prio_s->list);
452 	xa_erase(&prios_xa(chains), prio_s->xa_idx);
453 err_insert:
454 	mlx5_del_flow_rules(&miss_rule);
455 err_miss_rule:
456 	mlx5_destroy_flow_group(miss_group);
457 err_group:
458 	mlx5_destroy_flow_table(ft);
459 err_create:
460 err_alloc:
461 	kvfree(prio_s);
462 	kvfree(flow_group_in);
463 	mlx5_chains_put_chain(chain_s);
464 	return ERR_PTR(err);
465 }
466 
467 static void
mlx5_chains_destroy_prio(struct mlx5_fs_chains * chains,struct prio * prio)468 mlx5_chains_destroy_prio(struct mlx5_fs_chains *chains,
469 			 struct prio *prio)
470 {
471 	struct fs_chain *chain = prio->chain;
472 
473 	WARN_ON(mlx5_chains_update_prio_prevs(prio,
474 					      prio->next_ft));
475 
476 	list_del(&prio->list);
477 	xa_erase(&prios_xa(chains), prio->xa_idx);
478 	mlx5_del_flow_rules(&prio->miss_rule);
479 	mlx5_destroy_flow_group(prio->miss_group);
480 	mlx5_destroy_flow_table(prio->ft);
481 	mlx5_chains_put_chain(chain);
482 	kvfree(prio);
483 }
484 
485 struct mlx5_flow_table *
mlx5_chains_get_table(struct mlx5_fs_chains * chains,u32 chain,u32 prio,u32 level)486 mlx5_chains_get_table(struct mlx5_fs_chains *chains, u32 chain, u32 prio,
487 		      u32 level)
488 {
489 	struct mlx5_flow_table *prev_fts;
490 	struct prio *prio_s;
491 	unsigned long idx;
492 	int l = 0;
493 
494 	if ((chain > mlx5_chains_get_chain_range(chains) &&
495 	     chain != mlx5_chains_get_nf_ft_chain(chains)) ||
496 	    prio > mlx5_chains_get_prio_range(chains) ||
497 	    level > mlx5_chains_get_level_range(chains))
498 		return ERR_PTR(-EOPNOTSUPP);
499 
500 	/* create earlier levels for correct fs_core lookup when
501 	 * connecting tables.
502 	 */
503 	for (l = 0; l < level; l++) {
504 		prev_fts = mlx5_chains_get_table(chains, chain, prio, l);
505 		if (IS_ERR(prev_fts)) {
506 			prio_s = ERR_CAST(prev_fts);
507 			goto err_get_prevs;
508 		}
509 	}
510 
511 	mutex_lock(&chains_lock(chains));
512 	xa_for_each(&prios_xa(chains), idx, prio_s) {
513 		if (chain == prio_s->key.chain &&
514 		    prio == prio_s->key.prio &&
515 		    level == prio_s->key.level)
516 			break;
517 	}
518 	if (!prio_s) {
519 		prio_s = mlx5_chains_create_prio(chains, chain,
520 						 prio, level);
521 		if (IS_ERR(prio_s))
522 			goto err_create_prio;
523 	}
524 
525 	++prio_s->ref;
526 	mutex_unlock(&chains_lock(chains));
527 
528 	return prio_s->ft;
529 
530 err_create_prio:
531 	mutex_unlock(&chains_lock(chains));
532 err_get_prevs:
533 	while (--l >= 0)
534 		mlx5_chains_put_table(chains, chain, prio, l);
535 	return ERR_CAST(prio_s);
536 }
537 
538 void
mlx5_chains_put_table(struct mlx5_fs_chains * chains,u32 chain,u32 prio,u32 level)539 mlx5_chains_put_table(struct mlx5_fs_chains *chains, u32 chain, u32 prio,
540 		      u32 level)
541 {
542 	struct prio *prio_s;
543 	unsigned long idx;
544 
545 	mutex_lock(&chains_lock(chains));
546 
547 	xa_for_each(&prios_xa(chains), idx, prio_s) {
548 		if (chain == prio_s->key.chain &&
549 		    prio == prio_s->key.prio &&
550 		    level == prio_s->key.level)
551 			break;
552 	}
553 	if (!prio_s)
554 		goto err_get_prio;
555 
556 	if (--prio_s->ref == 0)
557 		mlx5_chains_destroy_prio(chains, prio_s);
558 	mutex_unlock(&chains_lock(chains));
559 
560 	while (level-- > 0)
561 		mlx5_chains_put_table(chains, chain, prio, level);
562 
563 	return;
564 
565 err_get_prio:
566 	mutex_unlock(&chains_lock(chains));
567 	WARN_ONCE(1,
568 		  "Couldn't find table: (chain: %d prio: %d level: %d)",
569 		  chain, prio, level);
570 }
571 
572 struct mlx5_flow_table *
mlx5_chains_get_tc_end_ft(struct mlx5_fs_chains * chains)573 mlx5_chains_get_tc_end_ft(struct mlx5_fs_chains *chains)
574 {
575 	return chains_end_ft(chains);
576 }
577 
578 struct mlx5_flow_table *
mlx5_chains_create_global_table(struct mlx5_fs_chains * chains)579 mlx5_chains_create_global_table(struct mlx5_fs_chains *chains)
580 {
581 	u32 chain, prio, level;
582 	int err;
583 
584 	if (!mlx5_chains_ignore_flow_level_supported(chains)) {
585 		err = -EOPNOTSUPP;
586 
587 		mlx5_core_warn(chains->dev,
588 			       "Couldn't create global flow table, ignore_flow_level not supported.");
589 		goto err_ignore;
590 	}
591 
592 	chain = mlx5_chains_get_chain_range(chains),
593 	prio = mlx5_chains_get_prio_range(chains);
594 	level = mlx5_chains_get_level_range(chains);
595 
596 	return mlx5_chains_create_table(chains, chain, prio, level);
597 
598 err_ignore:
599 	return ERR_PTR(err);
600 }
601 
602 void
mlx5_chains_destroy_global_table(struct mlx5_fs_chains * chains,struct mlx5_flow_table * ft)603 mlx5_chains_destroy_global_table(struct mlx5_fs_chains *chains,
604 				 struct mlx5_flow_table *ft)
605 {
606 	mlx5_destroy_flow_table(ft);
607 }
608 
609 static struct mlx5_fs_chains *
mlx5_chains_init(struct mlx5_core_dev * dev,struct mlx5_chains_attr * attr)610 mlx5_chains_init(struct mlx5_core_dev *dev, struct mlx5_chains_attr *attr)
611 {
612 	struct mlx5_fs_chains *chains;
613 
614 	chains = kzalloc(sizeof(*chains), GFP_KERNEL);
615 	if (!chains)
616 		return ERR_PTR(-ENOMEM);
617 
618 	chains->dev = dev;
619 	chains->flags = attr->flags;
620 	chains->ns = attr->ns;
621 	chains->group_num = attr->max_grp_num;
622 	chains->fs_base_prio = attr->fs_base_prio;
623 	chains->fs_base_level = attr->fs_base_level;
624 	chains_default_ft(chains) = chains_end_ft(chains) = attr->default_ft;
625 
626 	xa_init(&chains_xa(chains));
627 	xa_init(&prios_xa(chains));
628 
629 	mutex_init(&chains_lock(chains));
630 
631 	return chains;
632 }
633 
634 static void
mlx5_chains_cleanup(struct mlx5_fs_chains * chains)635 mlx5_chains_cleanup(struct mlx5_fs_chains *chains)
636 {
637 	mutex_destroy(&chains_lock(chains));
638 	xa_destroy(&prios_xa(chains));
639 	xa_destroy(&chains_xa(chains));
640 
641 	kfree(chains);
642 }
643 
644 struct mlx5_fs_chains *
mlx5_chains_create(struct mlx5_core_dev * dev,struct mlx5_chains_attr * attr)645 mlx5_chains_create(struct mlx5_core_dev *dev, struct mlx5_chains_attr *attr)
646 {
647 	struct mlx5_fs_chains *chains;
648 
649 	chains = mlx5_chains_init(dev, attr);
650 
651 	return chains;
652 }
653 
654 void
mlx5_chains_destroy(struct mlx5_fs_chains * chains)655 mlx5_chains_destroy(struct mlx5_fs_chains *chains)
656 {
657 	mlx5_chains_cleanup(chains);
658 }
659 
660 void
mlx5_chains_print_info(struct mlx5_fs_chains * chains)661 mlx5_chains_print_info(struct mlx5_fs_chains *chains)
662 {
663 	mlx5_core_dbg(chains->dev, "Flow table chains groups(%d)\n", chains->group_num);
664 }
665