xref: /dpdk/drivers/net/mlx5/hws/mlx5dr_matcher.c (revision 4b53e9802b6b6040ad5622b1414aaa93d9581d0c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3  */
4 
5 #include "mlx5dr_internal.h"
6 
7 static bool mlx5dr_matcher_requires_col_tbl(uint8_t log_num_of_rules)
8 {
9 	/* Collision table concatenation is done only for large rule tables */
10 	return log_num_of_rules > MLX5DR_MATCHER_ASSURED_RULES_TH;
11 }
12 
13 static uint8_t mlx5dr_matcher_rules_to_tbl_depth(uint8_t log_num_of_rules)
14 {
15 	if (mlx5dr_matcher_requires_col_tbl(log_num_of_rules))
16 		return MLX5DR_MATCHER_ASSURED_MAIN_TBL_DEPTH;
17 
18 	/* For small rule tables we use a single deep table to assure insertion */
19 	return RTE_MIN(log_num_of_rules, MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH);
20 }
21 
22 static int mlx5dr_matcher_create_end_ft(struct mlx5dr_matcher *matcher)
23 {
24 	struct mlx5dr_table *tbl = matcher->tbl;
25 
26 	matcher->end_ft = mlx5dr_table_create_default_ft(tbl);
27 	if (!matcher->end_ft) {
28 		DR_LOG(ERR, "Failed to create matcher end flow table");
29 		return rte_errno;
30 	}
31 	return 0;
32 }
33 
34 static void mlx5dr_matcher_destroy_end_ft(struct mlx5dr_matcher *matcher)
35 {
36 	mlx5dr_table_destroy_default_ft(matcher->tbl, matcher->end_ft);
37 }
38 
39 static int mlx5dr_matcher_connect(struct mlx5dr_matcher *matcher)
40 {
41 	struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
42 	struct mlx5dr_table *tbl = matcher->tbl;
43 	struct mlx5dr_matcher *prev = NULL;
44 	struct mlx5dr_matcher *next = NULL;
45 	struct mlx5dr_matcher *tmp_matcher;
46 	struct mlx5dr_devx_obj *ft;
47 	int ret;
48 
49 	/* Find location in matcher list */
50 	if (LIST_EMPTY(&tbl->head)) {
51 		LIST_INSERT_HEAD(&tbl->head, matcher, next);
52 		goto connect;
53 	}
54 
55 	LIST_FOREACH(tmp_matcher, &tbl->head, next) {
56 		if (tmp_matcher->attr.priority > matcher->attr.priority) {
57 			next = tmp_matcher;
58 			break;
59 		}
60 		prev = tmp_matcher;
61 	}
62 
63 	if (next)
64 		LIST_INSERT_BEFORE(next, matcher, next);
65 	else
66 		LIST_INSERT_AFTER(prev, matcher, next);
67 
68 connect:
69 	ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID;
70 	ft_attr.type = tbl->fw_ft_type;
71 
72 	/* Connect to next */
73 	if (next) {
74 		if (next->match_ste.rtc_0)
75 			ft_attr.rtc_id_0 = next->match_ste.rtc_0->id;
76 		if (next->match_ste.rtc_1)
77 			ft_attr.rtc_id_1 = next->match_ste.rtc_1->id;
78 
79 		ret = mlx5dr_cmd_flow_table_modify(matcher->end_ft, &ft_attr);
80 		if (ret) {
81 			DR_LOG(ERR, "Failed to connect new matcher to next RTC");
82 			goto remove_from_list;
83 		}
84 	}
85 
86 	/* Connect to previous */
87 	ft = prev ? prev->end_ft : tbl->ft;
88 
89 	if (matcher->match_ste.rtc_0)
90 		ft_attr.rtc_id_0 = matcher->match_ste.rtc_0->id;
91 	if (matcher->match_ste.rtc_1)
92 		ft_attr.rtc_id_1 = matcher->match_ste.rtc_1->id;
93 
94 	ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
95 	if (ret) {
96 		DR_LOG(ERR, "Failed to connect new matcher to previous FT");
97 		goto remove_from_list;
98 	}
99 
100 	return 0;
101 
102 remove_from_list:
103 	LIST_REMOVE(matcher, next);
104 	return ret;
105 }
106 
107 static int mlx5dr_matcher_disconnect(struct mlx5dr_matcher *matcher)
108 {
109 	struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
110 	struct mlx5dr_table *tbl = matcher->tbl;
111 	struct mlx5dr_matcher *tmp_matcher;
112 	struct mlx5dr_devx_obj *prev_ft;
113 	struct mlx5dr_matcher *next;
114 	int ret;
115 
116 	prev_ft = matcher->tbl->ft;
117 	LIST_FOREACH(tmp_matcher, &tbl->head, next) {
118 		if (tmp_matcher == matcher)
119 			break;
120 
121 		prev_ft = tmp_matcher->end_ft;
122 	}
123 
124 	next = matcher->next.le_next;
125 
126 	ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID;
127 	ft_attr.type = matcher->tbl->fw_ft_type;
128 
129 	if (next) {
130 		/* Connect previous end FT to next RTC if exists */
131 		if (next->match_ste.rtc_0)
132 			ft_attr.rtc_id_0 = next->match_ste.rtc_0->id;
133 		if (next->match_ste.rtc_1)
134 			ft_attr.rtc_id_1 = next->match_ste.rtc_1->id;
135 	} else {
136 		/* Matcher is last, point prev end FT to default miss */
137 		mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx,
138 						     tbl->fw_ft_type,
139 						     tbl->type,
140 						     &ft_attr);
141 	}
142 
143 	ret = mlx5dr_cmd_flow_table_modify(prev_ft, &ft_attr);
144 	if (ret) {
145 		DR_LOG(ERR, "Failed to disconnect matcher");
146 		return ret;
147 	}
148 
149 	LIST_REMOVE(matcher, next);
150 
151 	return 0;
152 }
153 
154 static void mlx5dr_matcher_set_rtc_attr_sz(struct mlx5dr_matcher *matcher,
155 					   struct mlx5dr_cmd_rtc_create_attr *rtc_attr,
156 					   bool is_match_rtc,
157 					   bool is_mirror)
158 {
159 	enum mlx5dr_matcher_flow_src flow_src = matcher->attr.optimize_flow_src;
160 	struct mlx5dr_pool_chunk *ste = &matcher->action_ste.ste;
161 
162 	if ((flow_src == MLX5DR_MATCHER_FLOW_SRC_VPORT && !is_mirror) ||
163 	    (flow_src == MLX5DR_MATCHER_FLOW_SRC_WIRE && is_mirror)) {
164 		/* Optimize FDB RTC */
165 		rtc_attr->log_size = 0;
166 		rtc_attr->log_depth = 0;
167 	} else {
168 		/* Keep original values */
169 		rtc_attr->log_size = is_match_rtc ? matcher->attr.table.sz_row_log : ste->order;
170 		rtc_attr->log_depth = is_match_rtc ? matcher->attr.table.sz_col_log : 0;
171 	}
172 }
173 
174 static int mlx5dr_matcher_create_rtc(struct mlx5dr_matcher *matcher,
175 				     bool is_match_rtc)
176 {
177 	const char *rtc_type_str = is_match_rtc ? "match" : "action";
178 	struct mlx5dr_cmd_rtc_create_attr rtc_attr = {0};
179 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
180 	struct mlx5dr_action_default_stc *default_stc;
181 	struct mlx5dr_table *tbl = matcher->tbl;
182 	struct mlx5dr_devx_obj **rtc_0, **rtc_1;
183 	struct mlx5dr_pool *ste_pool, *stc_pool;
184 	struct mlx5dr_devx_obj *devx_obj;
185 	struct mlx5dr_pool_chunk *ste;
186 	int ret;
187 
188 	if (is_match_rtc) {
189 		rtc_0 = &matcher->match_ste.rtc_0;
190 		rtc_1 = &matcher->match_ste.rtc_1;
191 		ste_pool = matcher->match_ste.pool;
192 		ste = &matcher->match_ste.ste;
193 		ste->order = matcher->attr.table.sz_col_log +
194 			     matcher->attr.table.sz_row_log;
195 		rtc_attr.log_size = matcher->attr.table.sz_row_log;
196 		rtc_attr.log_depth = matcher->attr.table.sz_col_log;
197 		rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH;
198 		/* The first match template is used since all share the same definer */
199 		rtc_attr.definer_id = mlx5dr_definer_get_id(matcher->mt[0]->definer);
200 		rtc_attr.is_jumbo = mlx5dr_definer_is_jumbo(matcher->mt[0]->definer);
201 		rtc_attr.miss_ft_id = matcher->end_ft->id;
202 		/* Match pool requires implicit allocation */
203 		ret = mlx5dr_pool_chunk_alloc(ste_pool, ste);
204 		if (ret) {
205 			DR_LOG(ERR, "Failed to allocate STE for %s RTC", rtc_type_str);
206 			return ret;
207 		}
208 	} else {
209 		rtc_0 = &matcher->action_ste.rtc_0;
210 		rtc_1 = &matcher->action_ste.rtc_1;
211 		ste_pool = matcher->action_ste.pool;
212 		ste = &matcher->action_ste.ste;
213 		ste->order = rte_log2_u32(matcher->action_ste.max_stes) +
214 			     matcher->attr.table.sz_row_log;
215 		rtc_attr.log_size = ste->order;
216 		rtc_attr.log_depth = 0;
217 		rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET;
218 		/* The action STEs use the default always hit definer */
219 		rtc_attr.definer_id = ctx->caps->trivial_match_definer;
220 		rtc_attr.is_jumbo = false;
221 		rtc_attr.miss_ft_id = 0;
222 	}
223 
224 	devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(ste_pool, ste);
225 
226 	rtc_attr.pd = ctx->pd_num;
227 	rtc_attr.ste_base = devx_obj->id;
228 	rtc_attr.ste_offset = ste->offset;
229 	rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, false);
230 	mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, is_match_rtc, false);
231 
232 	/* STC is a single resource (devx_obj), use any STC for the ID */
233 	stc_pool = ctx->stc_pool[tbl->type];
234 	default_stc = ctx->common_res[tbl->type].default_stc;
235 	devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, &default_stc->default_hit);
236 	rtc_attr.stc_base = devx_obj->id;
237 
238 	*rtc_0 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr);
239 	if (!*rtc_0) {
240 		DR_LOG(ERR, "Failed to create matcher %s RTC", rtc_type_str);
241 		goto free_ste;
242 	}
243 
244 	if (tbl->type == MLX5DR_TABLE_TYPE_FDB) {
245 		devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(ste_pool, ste);
246 		rtc_attr.ste_base = devx_obj->id;
247 		rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, true);
248 
249 		devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, &default_stc->default_hit);
250 		rtc_attr.stc_base = devx_obj->id;
251 		mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, is_match_rtc, true);
252 
253 		*rtc_1 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr);
254 		if (!*rtc_1) {
255 			DR_LOG(ERR, "Failed to create peer matcher %s RTC0", rtc_type_str);
256 			goto destroy_rtc_0;
257 		}
258 	}
259 
260 	return 0;
261 
262 destroy_rtc_0:
263 	mlx5dr_cmd_destroy_obj(*rtc_0);
264 free_ste:
265 	if (is_match_rtc)
266 		mlx5dr_pool_chunk_free(ste_pool, ste);
267 	return rte_errno;
268 }
269 
270 static void mlx5dr_matcher_destroy_rtc(struct mlx5dr_matcher *matcher,
271 				       bool is_match_rtc)
272 {
273 	struct mlx5dr_table *tbl = matcher->tbl;
274 	struct mlx5dr_devx_obj *rtc_0, *rtc_1;
275 	struct mlx5dr_pool_chunk *ste;
276 	struct mlx5dr_pool *ste_pool;
277 
278 	if (is_match_rtc) {
279 		rtc_0 = matcher->match_ste.rtc_0;
280 		rtc_1 = matcher->match_ste.rtc_1;
281 		ste_pool = matcher->match_ste.pool;
282 		ste = &matcher->match_ste.ste;
283 	} else {
284 		rtc_0 = matcher->action_ste.rtc_0;
285 		rtc_1 = matcher->action_ste.rtc_1;
286 		ste_pool = matcher->action_ste.pool;
287 		ste = &matcher->action_ste.ste;
288 	}
289 
290 	if (tbl->type == MLX5DR_TABLE_TYPE_FDB)
291 		mlx5dr_cmd_destroy_obj(rtc_1);
292 
293 	mlx5dr_cmd_destroy_obj(rtc_0);
294 	if (is_match_rtc)
295 		mlx5dr_pool_chunk_free(ste_pool, ste);
296 }
297 
298 static void mlx5dr_matcher_set_pool_attr(struct mlx5dr_pool_attr *attr,
299 					 struct mlx5dr_matcher *matcher)
300 {
301 	switch (matcher->attr.optimize_flow_src) {
302 	case MLX5DR_MATCHER_FLOW_SRC_VPORT:
303 		attr->opt_type = MLX5DR_POOL_OPTIMIZE_ORIG;
304 		break;
305 	case MLX5DR_MATCHER_FLOW_SRC_WIRE:
306 		attr->opt_type = MLX5DR_POOL_OPTIMIZE_MIRROR;
307 		break;
308 	default:
309 		break;
310 	}
311 }
312 
313 static int mlx5dr_matcher_bind_at(struct mlx5dr_matcher *matcher)
314 {
315 	bool is_jumbo = mlx5dr_definer_is_jumbo(matcher->mt[0]->definer);
316 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
317 	struct mlx5dr_table *tbl = matcher->tbl;
318 	struct mlx5dr_pool_attr pool_attr = {0};
319 	struct mlx5dr_context *ctx = tbl->ctx;
320 	uint32_t required_stes;
321 	int i, ret;
322 	bool valid;
323 
324 	for (i = 0; i < matcher->num_of_at; i++) {
325 		struct mlx5dr_action_template *at = matcher->at[i];
326 
327 		/* Check if action combinabtion is valid */
328 		valid = mlx5dr_action_check_combo(at->action_type_arr, matcher->tbl->type);
329 		if (!valid) {
330 			DR_LOG(ERR, "Invalid combination in action template %d", i);
331 			return rte_errno;
332 		}
333 
334 		/* Process action template to setters */
335 		ret = mlx5dr_action_template_process(at);
336 		if (ret) {
337 			DR_LOG(ERR, "Failed to process action template %d", i);
338 			return rte_errno;
339 		}
340 
341 		required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term);
342 		matcher->action_ste.max_stes = RTE_MAX(matcher->action_ste.max_stes, required_stes);
343 
344 		/* Future: Optimize reparse */
345 	}
346 
347 	/* There are no additioanl STEs required for matcher */
348 	if (!matcher->action_ste.max_stes)
349 		return 0;
350 
351 	/* Allocate action STE mempool */
352 	pool_attr.table_type = tbl->type;
353 	pool_attr.pool_type = MLX5DR_POOL_TYPE_STE;
354 	pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_STE_ACTION_POOL;
355 	pool_attr.alloc_log_sz = rte_log2_u32(matcher->action_ste.max_stes) +
356 				 matcher->attr.table.sz_row_log;
357 	mlx5dr_matcher_set_pool_attr(&pool_attr, matcher);
358 	matcher->action_ste.pool = mlx5dr_pool_create(ctx, &pool_attr);
359 	if (!matcher->action_ste.pool) {
360 		DR_LOG(ERR, "Failed to create action ste pool");
361 		return rte_errno;
362 	}
363 
364 	/* Allocate action RTC */
365 	ret = mlx5dr_matcher_create_rtc(matcher, false);
366 	if (ret) {
367 		DR_LOG(ERR, "Failed to create action RTC");
368 		goto free_ste_pool;
369 	}
370 
371 	/* Allocate STC for jumps to STE */
372 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
373 	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE;
374 	stc_attr.ste_table.ste = matcher->action_ste.ste;
375 	stc_attr.ste_table.ste_pool = matcher->action_ste.pool;
376 	stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer;
377 
378 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl->type,
379 					     &matcher->action_ste.stc);
380 	if (ret) {
381 		DR_LOG(ERR, "Failed to create action jump to table STC");
382 		goto free_rtc;
383 	}
384 
385 	return 0;
386 
387 free_rtc:
388 	mlx5dr_matcher_destroy_rtc(matcher, false);
389 free_ste_pool:
390 	mlx5dr_pool_destroy(matcher->action_ste.pool);
391 	return rte_errno;
392 }
393 
394 static void mlx5dr_matcher_unbind_at(struct mlx5dr_matcher *matcher)
395 {
396 	struct mlx5dr_table *tbl = matcher->tbl;
397 
398 	if (!matcher->action_ste.max_stes)
399 		return;
400 
401 	mlx5dr_action_free_single_stc(tbl->ctx, tbl->type, &matcher->action_ste.stc);
402 	mlx5dr_matcher_destroy_rtc(matcher, false);
403 	mlx5dr_pool_destroy(matcher->action_ste.pool);
404 }
405 
406 static int mlx5dr_matcher_bind_mt(struct mlx5dr_matcher *matcher)
407 {
408 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
409 	struct mlx5dr_pool_attr pool_attr = {0};
410 	int i, created = 0;
411 	int ret = -1;
412 
413 	for (i = 0; i < matcher->num_of_mt; i++) {
414 		/* Get a definer for each match template */
415 		ret = mlx5dr_definer_get(ctx, matcher->mt[i]);
416 		if (ret)
417 			goto definer_put;
418 
419 		created++;
420 
421 		/* Verify all templates produce the same definer */
422 		if (i == 0)
423 			continue;
424 
425 		ret = mlx5dr_definer_compare(matcher->mt[i]->definer,
426 					     matcher->mt[i - 1]->definer);
427 		if (ret) {
428 			DR_LOG(ERR, "Match templates cannot be used on the same matcher");
429 			rte_errno = ENOTSUP;
430 			goto definer_put;
431 		}
432 	}
433 
434 	/* Create an STE pool per matcher*/
435 	pool_attr.pool_type = MLX5DR_POOL_TYPE_STE;
436 	pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_MATCHER_STE_POOL;
437 	pool_attr.table_type = matcher->tbl->type;
438 	pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log +
439 				 matcher->attr.table.sz_row_log;
440 	mlx5dr_matcher_set_pool_attr(&pool_attr, matcher);
441 
442 	matcher->match_ste.pool = mlx5dr_pool_create(ctx, &pool_attr);
443 	if (!matcher->match_ste.pool) {
444 		DR_LOG(ERR, "Failed to allocate matcher STE pool");
445 		goto definer_put;
446 	}
447 
448 	return 0;
449 
450 definer_put:
451 	while (created--)
452 		mlx5dr_definer_put(matcher->mt[created]);
453 
454 	return ret;
455 }
456 
457 static void mlx5dr_matcher_unbind_mt(struct mlx5dr_matcher *matcher)
458 {
459 	int i;
460 
461 	for (i = 0; i < matcher->num_of_mt; i++)
462 		mlx5dr_definer_put(matcher->mt[i]);
463 
464 	mlx5dr_pool_destroy(matcher->match_ste.pool);
465 }
466 
467 static int
468 mlx5dr_matcher_process_attr(struct mlx5dr_cmd_query_caps *caps,
469 			    struct mlx5dr_matcher *matcher,
470 			    bool is_root)
471 {
472 	struct mlx5dr_matcher_attr *attr = &matcher->attr;
473 
474 	if (matcher->tbl->type != MLX5DR_TABLE_TYPE_FDB  && attr->optimize_flow_src) {
475 		DR_LOG(ERR, "NIC domain doesn't support flow_src");
476 		goto not_supported;
477 	}
478 
479 	if (is_root) {
480 		if (attr->mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE) {
481 			DR_LOG(ERR, "Root matcher supports only rule resource mode");
482 			goto not_supported;
483 		}
484 		if (attr->optimize_flow_src) {
485 			DR_LOG(ERR, "Root matcher can't specify FDB direction");
486 			goto not_supported;
487 		}
488 		return 0;
489 	}
490 
491 	/* Convert number of rules to the required depth */
492 	if (attr->mode == MLX5DR_MATCHER_RESOURCE_MODE_RULE)
493 		attr->table.sz_col_log = mlx5dr_matcher_rules_to_tbl_depth(attr->rule.num_log);
494 
495 	if (attr->table.sz_col_log > caps->rtc_log_depth_max) {
496 		DR_LOG(ERR, "Matcher depth exceeds limit %d", caps->rtc_log_depth_max);
497 		goto not_supported;
498 	}
499 
500 	if (attr->table.sz_col_log + attr->table.sz_row_log > caps->ste_alloc_log_max) {
501 		DR_LOG(ERR, "Total matcher size exceeds limit %d", caps->ste_alloc_log_max);
502 		goto not_supported;
503 	}
504 
505 	if (attr->table.sz_col_log + attr->table.sz_row_log < caps->ste_alloc_log_gran) {
506 		DR_LOG(ERR, "Total matcher size below limit %d", caps->ste_alloc_log_gran);
507 		goto not_supported;
508 	}
509 
510 	return 0;
511 
512 not_supported:
513 	rte_errno = EOPNOTSUPP;
514 	return rte_errno;
515 }
516 
517 static int mlx5dr_matcher_create_and_connect(struct mlx5dr_matcher *matcher)
518 {
519 	int ret;
520 
521 	/* Select and create the definers for current matcher */
522 	ret = mlx5dr_matcher_bind_mt(matcher);
523 	if (ret)
524 		return ret;
525 
526 	/* Calculate and verify action combination */
527 	ret = mlx5dr_matcher_bind_at(matcher);
528 	if (ret)
529 		goto unbind_mt;
530 
531 	/* Create matcher end flow table anchor */
532 	ret = mlx5dr_matcher_create_end_ft(matcher);
533 	if (ret)
534 		goto unbind_at;
535 
536 	/* Allocate the RTC for the new matcher */
537 	ret = mlx5dr_matcher_create_rtc(matcher, true);
538 	if (ret)
539 		goto destroy_end_ft;
540 
541 	/* Connect the matcher to the matcher list */
542 	ret = mlx5dr_matcher_connect(matcher);
543 	if (ret)
544 		goto destroy_rtc;
545 
546 	return 0;
547 
548 destroy_rtc:
549 	mlx5dr_matcher_destroy_rtc(matcher, true);
550 destroy_end_ft:
551 	mlx5dr_matcher_destroy_end_ft(matcher);
552 unbind_at:
553 	mlx5dr_matcher_unbind_at(matcher);
554 unbind_mt:
555 	mlx5dr_matcher_unbind_mt(matcher);
556 	return ret;
557 }
558 
559 static void mlx5dr_matcher_destroy_and_disconnect(struct mlx5dr_matcher *matcher)
560 {
561 	mlx5dr_matcher_disconnect(matcher);
562 	mlx5dr_matcher_destroy_rtc(matcher, true);
563 	mlx5dr_matcher_destroy_end_ft(matcher);
564 	mlx5dr_matcher_unbind_at(matcher);
565 	mlx5dr_matcher_unbind_mt(matcher);
566 }
567 
568 static int
569 mlx5dr_matcher_create_col_matcher(struct mlx5dr_matcher *matcher)
570 {
571 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
572 	struct mlx5dr_matcher *col_matcher;
573 	int ret;
574 
575 	if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE)
576 		return 0;
577 
578 	if (!mlx5dr_matcher_requires_col_tbl(matcher->attr.rule.num_log))
579 		return 0;
580 
581 	col_matcher = simple_calloc(1, sizeof(*matcher));
582 	if (!col_matcher) {
583 		rte_errno = ENOMEM;
584 		return rte_errno;
585 	}
586 
587 	col_matcher->tbl = matcher->tbl;
588 	col_matcher->num_of_mt = matcher->num_of_mt;
589 	memcpy(col_matcher->mt, matcher->mt, matcher->num_of_mt * sizeof(*matcher->mt));
590 	col_matcher->num_of_at = matcher->num_of_at;
591 	memcpy(col_matcher->at, matcher->at, matcher->num_of_at * sizeof(*matcher->at));
592 
593 	col_matcher->attr.priority = matcher->attr.priority;
594 	col_matcher->attr.mode = MLX5DR_MATCHER_RESOURCE_MODE_HTABLE;
595 	col_matcher->attr.optimize_flow_src = matcher->attr.optimize_flow_src;
596 	col_matcher->attr.table.sz_row_log = matcher->attr.rule.num_log;
597 	col_matcher->attr.table.sz_col_log = MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH;
598 	if (col_matcher->attr.table.sz_row_log > MLX5DR_MATCHER_ASSURED_ROW_RATIO)
599 		col_matcher->attr.table.sz_row_log -= MLX5DR_MATCHER_ASSURED_ROW_RATIO;
600 
601 	ret = mlx5dr_matcher_process_attr(ctx->caps, col_matcher, false);
602 	if (ret)
603 		goto free_col_matcher;
604 
605 	ret = mlx5dr_matcher_create_and_connect(col_matcher);
606 	if (ret)
607 		goto free_col_matcher;
608 
609 	matcher->col_matcher = col_matcher;
610 
611 	return 0;
612 
613 free_col_matcher:
614 	simple_free(col_matcher);
615 	DR_LOG(ERR, "Failed to create assured collision matcher");
616 	return ret;
617 }
618 
619 static void
620 mlx5dr_matcher_destroy_col_matcher(struct mlx5dr_matcher *matcher)
621 {
622 	if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE)
623 		return;
624 
625 	if (matcher->col_matcher) {
626 		mlx5dr_matcher_destroy_and_disconnect(matcher->col_matcher);
627 		simple_free(matcher->col_matcher);
628 	}
629 }
630 
631 static int mlx5dr_matcher_init(struct mlx5dr_matcher *matcher)
632 {
633 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
634 	int ret;
635 
636 	pthread_spin_lock(&ctx->ctrl_lock);
637 
638 	/* Allocate matcher resource and connect to the packet pipe */
639 	ret = mlx5dr_matcher_create_and_connect(matcher);
640 	if (ret)
641 		goto unlock_err;
642 
643 	/* Create additional matcher for collision handling */
644 	ret = mlx5dr_matcher_create_col_matcher(matcher);
645 	if (ret)
646 		goto destory_and_disconnect;
647 
648 	pthread_spin_unlock(&ctx->ctrl_lock);
649 
650 	return 0;
651 
652 destory_and_disconnect:
653 	mlx5dr_matcher_destroy_and_disconnect(matcher);
654 unlock_err:
655 	pthread_spin_unlock(&ctx->ctrl_lock);
656 	return ret;
657 }
658 
659 static int mlx5dr_matcher_uninit(struct mlx5dr_matcher *matcher)
660 {
661 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
662 
663 	pthread_spin_lock(&ctx->ctrl_lock);
664 	mlx5dr_matcher_destroy_col_matcher(matcher);
665 	mlx5dr_matcher_destroy_and_disconnect(matcher);
666 	pthread_spin_unlock(&ctx->ctrl_lock);
667 
668 	return 0;
669 }
670 
671 static int mlx5dr_matcher_init_root(struct mlx5dr_matcher *matcher)
672 {
673 	enum mlx5dr_table_type type = matcher->tbl->type;
674 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
675 	struct mlx5dv_flow_matcher_attr attr = {0};
676 	struct mlx5dv_flow_match_parameters *mask;
677 	struct mlx5_flow_attr flow_attr = {0};
678 	struct rte_flow_error rte_error;
679 	uint8_t match_criteria;
680 	int ret;
681 
682 #ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE
683 	attr.comp_mask = MLX5DV_FLOW_MATCHER_MASK_FT_TYPE;
684 
685 	switch (type) {
686 	case MLX5DR_TABLE_TYPE_NIC_RX:
687 		attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
688 		break;
689 	case MLX5DR_TABLE_TYPE_NIC_TX:
690 		attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
691 		break;
692 	case MLX5DR_TABLE_TYPE_FDB:
693 		attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
694 		break;
695 	default:
696 		assert(0);
697 		break;
698 	}
699 #endif
700 
701 	if (matcher->attr.priority > UINT16_MAX) {
702 		DR_LOG(ERR, "Root matcher priority exceeds allowed limit");
703 		rte_errno = EINVAL;
704 		return rte_errno;
705 	}
706 
707 	mask = simple_calloc(1, MLX5_ST_SZ_BYTES(fte_match_param) +
708 			     offsetof(struct mlx5dv_flow_match_parameters, match_buf));
709 	if (!mask) {
710 		rte_errno = ENOMEM;
711 		return rte_errno;
712 	}
713 
714 	flow_attr.tbl_type = type;
715 
716 	/* On root table matcher, only a single match template is supported */
717 	ret = flow_dv_translate_items_hws(matcher->mt[0]->items,
718 					  &flow_attr, mask->match_buf,
719 					  MLX5_SET_MATCHER_HS_M, NULL,
720 					  &match_criteria,
721 					  &rte_error);
722 	if (ret) {
723 		DR_LOG(ERR, "Failed to convert items to PRM [%s]", rte_error.message);
724 		goto free_mask;
725 	}
726 
727 	mask->match_sz = MLX5_ST_SZ_BYTES(fte_match_param);
728 	attr.match_mask = mask;
729 	attr.match_criteria_enable = match_criteria;
730 	attr.type = IBV_FLOW_ATTR_NORMAL;
731 	attr.priority = matcher->attr.priority;
732 
733 	matcher->dv_matcher =
734 		mlx5_glue->dv_create_flow_matcher_root(ctx->ibv_ctx, &attr);
735 	if (!matcher->dv_matcher) {
736 		DR_LOG(ERR, "Failed to create DV flow matcher");
737 		rte_errno = errno;
738 		goto free_mask;
739 	}
740 
741 	simple_free(mask);
742 
743 	pthread_spin_lock(&ctx->ctrl_lock);
744 	LIST_INSERT_HEAD(&matcher->tbl->head, matcher, next);
745 	pthread_spin_unlock(&ctx->ctrl_lock);
746 
747 	return 0;
748 
749 free_mask:
750 	simple_free(mask);
751 	return rte_errno;
752 }
753 
754 static int mlx5dr_matcher_uninit_root(struct mlx5dr_matcher *matcher)
755 {
756 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
757 	int ret;
758 
759 	pthread_spin_lock(&ctx->ctrl_lock);
760 	LIST_REMOVE(matcher, next);
761 	pthread_spin_unlock(&ctx->ctrl_lock);
762 
763 	ret = mlx5_glue->dv_destroy_flow_matcher_root(matcher->dv_matcher);
764 	if (ret) {
765 		DR_LOG(ERR, "Failed to Destroy DV flow matcher");
766 		rte_errno = errno;
767 	}
768 
769 	return ret;
770 }
771 
772 static int
773 mlx5dr_matcher_check_template(uint8_t num_of_mt, uint8_t num_of_at, bool is_root)
774 {
775 	uint8_t max_num_of_mt;
776 
777 	max_num_of_mt = is_root ?
778 		MLX5DR_MATCHER_MAX_MT_ROOT :
779 		MLX5DR_MATCHER_MAX_MT;
780 
781 	if (!num_of_mt || !num_of_at) {
782 		DR_LOG(ERR, "Number of action/match template cannot be zero");
783 		goto out_not_sup;
784 	}
785 
786 	if (num_of_at > MLX5DR_MATCHER_MAX_AT) {
787 		DR_LOG(ERR, "Number of action templates exceeds limit");
788 		goto out_not_sup;
789 	}
790 
791 	if (num_of_mt > max_num_of_mt) {
792 		DR_LOG(ERR, "Number of match templates exceeds limit");
793 		goto out_not_sup;
794 	}
795 
796 	return 0;
797 
798 out_not_sup:
799 	rte_errno = ENOTSUP;
800 	return rte_errno;
801 }
802 
803 struct mlx5dr_matcher *
804 mlx5dr_matcher_create(struct mlx5dr_table *tbl,
805 		      struct mlx5dr_match_template *mt[],
806 		      uint8_t num_of_mt,
807 		      struct mlx5dr_action_template *at[],
808 		      uint8_t num_of_at,
809 		      struct mlx5dr_matcher_attr *attr)
810 {
811 	bool is_root = mlx5dr_table_is_root(tbl);
812 	struct mlx5dr_matcher *matcher;
813 	int ret;
814 
815 	ret = mlx5dr_matcher_check_template(num_of_mt, num_of_at, is_root);
816 	if (ret)
817 		return NULL;
818 
819 	matcher = simple_calloc(1, sizeof(*matcher));
820 	if (!matcher) {
821 		rte_errno = ENOMEM;
822 		return NULL;
823 	}
824 
825 	matcher->tbl = tbl;
826 	matcher->attr = *attr;
827 	matcher->num_of_mt = num_of_mt;
828 	memcpy(matcher->mt, mt, num_of_mt * sizeof(*mt));
829 	matcher->num_of_at = num_of_at;
830 	memcpy(matcher->at, at, num_of_at * sizeof(*at));
831 
832 	ret = mlx5dr_matcher_process_attr(tbl->ctx->caps, matcher, is_root);
833 	if (ret)
834 		goto free_matcher;
835 
836 	if (is_root)
837 		ret = mlx5dr_matcher_init_root(matcher);
838 	else
839 		ret = mlx5dr_matcher_init(matcher);
840 
841 	if (ret) {
842 		DR_LOG(ERR, "Failed to initialise matcher: %d", ret);
843 		goto free_matcher;
844 	}
845 
846 	return matcher;
847 
848 free_matcher:
849 	simple_free(matcher);
850 	return NULL;
851 }
852 
853 int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher)
854 {
855 	if (mlx5dr_table_is_root(matcher->tbl))
856 		mlx5dr_matcher_uninit_root(matcher);
857 	else
858 		mlx5dr_matcher_uninit(matcher);
859 
860 	simple_free(matcher);
861 	return 0;
862 }
863 
864 struct mlx5dr_match_template *
865 mlx5dr_match_template_create(const struct rte_flow_item items[],
866 			     enum mlx5dr_match_template_flags flags)
867 {
868 	struct mlx5dr_match_template *mt;
869 	struct rte_flow_error error;
870 	int ret, len;
871 
872 	if (flags > MLX5DR_MATCH_TEMPLATE_FLAG_RELAXED_MATCH) {
873 		DR_LOG(ERR, "Unsupported match template flag provided");
874 		rte_errno = EINVAL;
875 		return NULL;
876 	}
877 
878 	mt = simple_calloc(1, sizeof(*mt));
879 	if (!mt) {
880 		DR_LOG(ERR, "Failed to allocate match template");
881 		rte_errno = ENOMEM;
882 		return NULL;
883 	}
884 
885 	mt->flags = flags;
886 
887 	/* Duplicate the user given items */
888 	ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, NULL, 0, items, &error);
889 	if (ret <= 0) {
890 		DR_LOG(ERR, "Unable to process items (%s): %s",
891 		       error.message ? error.message : "unspecified",
892 		       strerror(rte_errno));
893 		goto free_template;
894 	}
895 
896 	len = RTE_ALIGN(ret, 16);
897 	mt->items = simple_calloc(1, len);
898 	if (!mt->items) {
899 		DR_LOG(ERR, "Failed to allocate item copy");
900 		rte_errno = ENOMEM;
901 		goto free_template;
902 	}
903 
904 	ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, mt->items, ret, items, &error);
905 	if (ret <= 0)
906 		goto free_dst;
907 
908 	return mt;
909 
910 free_dst:
911 	simple_free(mt->items);
912 free_template:
913 	simple_free(mt);
914 	return NULL;
915 }
916 
917 int mlx5dr_match_template_destroy(struct mlx5dr_match_template *mt)
918 {
919 	assert(!mt->refcount);
920 	simple_free(mt->items);
921 	simple_free(mt);
922 	return 0;
923 }
924