xref: /dpdk/drivers/net/mlx5/hws/mlx5dr_matcher.c (revision 665b49c51639a10c553433bc2bcd85c7331c631e)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3  */
4 
5 #include "mlx5dr_internal.h"
6 
7 enum mlx5dr_matcher_rtc_type {
8 	DR_MATCHER_RTC_TYPE_MATCH,
9 	DR_MATCHER_RTC_TYPE_STE_ARRAY,
10 	DR_MATCHER_RTC_TYPE_MAX,
11 };
12 
13 static const char * const mlx5dr_matcher_rtc_type_str[] = {
14 	[DR_MATCHER_RTC_TYPE_MATCH] = "MATCH",
15 	[DR_MATCHER_RTC_TYPE_STE_ARRAY] = "STE_ARRAY",
16 	[DR_MATCHER_RTC_TYPE_MAX] = "UNKNOWN",
17 };
18 
19 static const char *mlx5dr_matcher_rtc_type_to_str(enum mlx5dr_matcher_rtc_type rtc_type)
20 {
21 	if (rtc_type > DR_MATCHER_RTC_TYPE_MAX)
22 		rtc_type = DR_MATCHER_RTC_TYPE_MAX;
23 	return mlx5dr_matcher_rtc_type_str[rtc_type];
24 }
25 
26 static bool mlx5dr_matcher_requires_col_tbl(uint8_t log_num_of_rules)
27 {
28 	/* Collision table concatenation is done only for large rule tables */
29 	return log_num_of_rules > MLX5DR_MATCHER_ASSURED_RULES_TH;
30 }
31 
32 static uint8_t mlx5dr_matcher_rules_to_tbl_depth(uint8_t log_num_of_rules)
33 {
34 	if (mlx5dr_matcher_requires_col_tbl(log_num_of_rules))
35 		return MLX5DR_MATCHER_ASSURED_MAIN_TBL_DEPTH;
36 
37 	/* For small rule tables we use a single deep table to assure insertion */
38 	return RTE_MIN(log_num_of_rules, MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH);
39 }
40 
41 static void mlx5dr_matcher_destroy_end_ft(struct mlx5dr_matcher *matcher)
42 {
43 	mlx5dr_table_destroy_default_ft(matcher->tbl, matcher->end_ft);
44 }
45 
46 static int mlx5dr_matcher_free_rtc_pointing(struct mlx5dr_context *ctx,
47 					    uint32_t fw_ft_type,
48 					    enum mlx5dr_table_type type,
49 					    struct mlx5dr_devx_obj *devx_obj)
50 {
51 	struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
52 	int ret;
53 
54 	if (type != MLX5DR_TABLE_TYPE_FDB && !mlx5dr_context_shared_gvmi_used(ctx))
55 		return 0;
56 
57 	ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID;
58 	ft_attr.type = fw_ft_type;
59 	ft_attr.rtc_id_0 = 0;
60 	ft_attr.rtc_id_1 = 0;
61 
62 	ret = mlx5dr_cmd_flow_table_modify(devx_obj, &ft_attr);
63 	if (ret) {
64 		DR_LOG(ERR, "Failed to disconnect previous RTC");
65 		return ret;
66 	}
67 
68 	return 0;
69 }
70 
71 static int mlx5dr_matcher_shared_point_end_ft(struct mlx5dr_matcher *matcher)
72 {
73 	struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
74 	int ret;
75 
76 	mlx5dr_cmd_set_attr_connect_miss_tbl(matcher->tbl->ctx,
77 					     matcher->tbl->fw_ft_type,
78 					     matcher->tbl->type,
79 					     &ft_attr);
80 
81 	ret = mlx5dr_cmd_flow_table_modify(matcher->end_ft, &ft_attr);
82 	if (ret) {
83 		DR_LOG(ERR, "Failed to connect new matcher to default miss alias RTC");
84 		return ret;
85 	}
86 
87 	ret = mlx5dr_matcher_free_rtc_pointing(matcher->tbl->ctx,
88 					       matcher->tbl->fw_ft_type,
89 					       matcher->tbl->type,
90 					       matcher->end_ft);
91 
92 	return ret;
93 }
94 
95 static int mlx5dr_matcher_shared_create_alias_rtc(struct mlx5dr_matcher *matcher)
96 {
97 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
98 	int ret;
99 
100 	ret = mlx5dr_matcher_create_aliased_obj(ctx,
101 						ctx->ibv_ctx,
102 						ctx->local_ibv_ctx,
103 						ctx->caps->shared_vhca_id,
104 						matcher->match_ste.rtc_0->id,
105 						MLX5_GENERAL_OBJ_TYPE_RTC,
106 						&matcher->match_ste.aliased_rtc_0);
107 	if (ret) {
108 		DR_LOG(ERR, "Failed to allocate alias RTC");
109 		return ret;
110 	}
111 	return 0;
112 }
113 
114 static int mlx5dr_matcher_create_init_shared(struct mlx5dr_matcher *matcher)
115 {
116 	if (!mlx5dr_context_shared_gvmi_used(matcher->tbl->ctx))
117 		return 0;
118 
119 	if (mlx5dr_matcher_shared_point_end_ft(matcher)) {
120 		DR_LOG(ERR, "Failed to point shared matcher end flow table");
121 		return rte_errno;
122 	}
123 
124 	if (mlx5dr_matcher_shared_create_alias_rtc(matcher)) {
125 		DR_LOG(ERR, "Failed to create alias RTC");
126 		return rte_errno;
127 	}
128 
129 	return 0;
130 }
131 
132 static void mlx5dr_matcher_create_uninit_shared(struct mlx5dr_matcher *matcher)
133 {
134 	if (!mlx5dr_context_shared_gvmi_used(matcher->tbl->ctx))
135 		return;
136 
137 	if (matcher->match_ste.aliased_rtc_0) {
138 		mlx5dr_cmd_destroy_obj(matcher->match_ste.aliased_rtc_0);
139 		matcher->match_ste.aliased_rtc_0 = NULL;
140 	}
141 }
142 
143 static int mlx5dr_matcher_create_end_ft(struct mlx5dr_matcher *matcher)
144 {
145 	struct mlx5dr_table *tbl = matcher->tbl;
146 
147 	matcher->end_ft = mlx5dr_table_create_default_ft(tbl->ctx->ibv_ctx, tbl);
148 	if (!matcher->end_ft) {
149 		DR_LOG(ERR, "Failed to create matcher end flow table");
150 		return rte_errno;
151 	}
152 	return 0;
153 }
154 
155 static uint32_t
156 mlx5dr_matcher_connect_get_rtc0(struct mlx5dr_matcher *matcher)
157 {
158 	if (!matcher->match_ste.aliased_rtc_0)
159 		return matcher->match_ste.rtc_0->id;
160 	else
161 		return matcher->match_ste.aliased_rtc_0->id;
162 }
163 
164 /* The function updates tbl->local_ft to the first RTC or 0 if no more matchers */
165 static int mlx5dr_matcher_shared_update_local_ft(struct mlx5dr_table *tbl)
166 {
167 	struct mlx5dr_cmd_ft_modify_attr cur_ft_attr = {0};
168 	struct mlx5dr_matcher *first_matcher;
169 	int ret;
170 
171 	if (!mlx5dr_context_shared_gvmi_used(tbl->ctx))
172 		return 0;
173 
174 	first_matcher = LIST_FIRST(&tbl->head);
175 	if (!first_matcher) {
176 		/* local ft no longer points to any RTC, drop refcount */
177 		ret = mlx5dr_matcher_free_rtc_pointing(tbl->ctx,
178 						       tbl->fw_ft_type,
179 						       tbl->type,
180 						       tbl->local_ft);
181 		if (ret)
182 			DR_LOG(ERR, "Failed to clear local FT to prev alias RTC");
183 
184 		return ret;
185 	}
186 
187 	/* point local_ft to the first RTC */
188 	cur_ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID;
189 	cur_ft_attr.type = tbl->fw_ft_type;
190 	cur_ft_attr.rtc_id_0 = mlx5dr_matcher_connect_get_rtc0(first_matcher);
191 
192 	ret = mlx5dr_cmd_flow_table_modify(tbl->local_ft, &cur_ft_attr);
193 	if (ret) {
194 		DR_LOG(ERR, "Failed to point local FT to alias RTC");
195 		return ret;
196 	}
197 
198 	return 0;
199 }
200 
201 static int mlx5dr_matcher_connect(struct mlx5dr_matcher *matcher)
202 {
203 	struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
204 	struct mlx5dr_table *tbl = matcher->tbl;
205 	struct mlx5dr_matcher *prev = NULL;
206 	struct mlx5dr_matcher *next = NULL;
207 	struct mlx5dr_matcher *tmp_matcher;
208 	struct mlx5dr_devx_obj *ft;
209 	int ret;
210 
211 	/* Find location in matcher list */
212 	if (LIST_EMPTY(&tbl->head)) {
213 		LIST_INSERT_HEAD(&tbl->head, matcher, next);
214 		goto connect;
215 	}
216 
217 	LIST_FOREACH(tmp_matcher, &tbl->head, next) {
218 		if (tmp_matcher->attr.priority > matcher->attr.priority) {
219 			next = tmp_matcher;
220 			break;
221 		}
222 		prev = tmp_matcher;
223 	}
224 
225 	if (next)
226 		LIST_INSERT_BEFORE(next, matcher, next);
227 	else
228 		LIST_INSERT_AFTER(prev, matcher, next);
229 
230 connect:
231 	ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID;
232 	ft_attr.type = tbl->fw_ft_type;
233 
234 	/* Connect to next */
235 	if (next) {
236 		if (next->match_ste.rtc_0)
237 			ft_attr.rtc_id_0 = next->match_ste.rtc_0->id;
238 		if (next->match_ste.rtc_1)
239 			ft_attr.rtc_id_1 = next->match_ste.rtc_1->id;
240 
241 		ret = mlx5dr_cmd_flow_table_modify(matcher->end_ft, &ft_attr);
242 		if (ret) {
243 			DR_LOG(ERR, "Failed to connect new matcher to next RTC");
244 			goto remove_from_list;
245 		}
246 	}
247 
248 	/* Connect to previous */
249 	ft = prev ? prev->end_ft : tbl->ft;
250 
251 	if (matcher->match_ste.rtc_0)
252 		ft_attr.rtc_id_0 = matcher->match_ste.rtc_0->id;
253 	if (matcher->match_ste.rtc_1)
254 		ft_attr.rtc_id_1 = matcher->match_ste.rtc_1->id;
255 
256 	ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
257 	if (ret) {
258 		DR_LOG(ERR, "Failed to connect new matcher to previous FT");
259 		goto remove_from_list;
260 	}
261 
262 	ret = mlx5dr_matcher_shared_update_local_ft(tbl);
263 	if (ret) {
264 		DR_LOG(ERR, "Failed to update local_ft anchor in shared table");
265 		goto remove_from_list;
266 	}
267 
268 	return 0;
269 
270 remove_from_list:
271 	LIST_REMOVE(matcher, next);
272 	return ret;
273 }
274 
275 static int mlx5dr_matcher_disconnect(struct mlx5dr_matcher *matcher)
276 {
277 	struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
278 	struct mlx5dr_table *tbl = matcher->tbl;
279 	struct mlx5dr_matcher *tmp_matcher;
280 	struct mlx5dr_devx_obj *prev_ft;
281 	struct mlx5dr_matcher *next;
282 	int ret;
283 
284 	prev_ft = matcher->tbl->ft;
285 	LIST_FOREACH(tmp_matcher, &tbl->head, next) {
286 		if (tmp_matcher == matcher)
287 			break;
288 
289 		prev_ft = tmp_matcher->end_ft;
290 	}
291 
292 	next = matcher->next.le_next;
293 
294 	ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID;
295 	ft_attr.type = matcher->tbl->fw_ft_type;
296 
297 	if (next) {
298 		/* Connect previous end FT to next RTC if exists */
299 		if (next->match_ste.rtc_0)
300 			ft_attr.rtc_id_0 = next->match_ste.rtc_0->id;
301 		if (next->match_ste.rtc_1)
302 			ft_attr.rtc_id_1 = next->match_ste.rtc_1->id;
303 	} else {
304 		/* Matcher is last, point prev end FT to default miss */
305 		mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx,
306 						     tbl->fw_ft_type,
307 						     tbl->type,
308 						     &ft_attr);
309 	}
310 
311 	ret = mlx5dr_cmd_flow_table_modify(prev_ft, &ft_attr);
312 	if (ret) {
313 		DR_LOG(ERR, "Failed to disconnect matcher");
314 		return ret;
315 	}
316 
317 	LIST_REMOVE(matcher, next);
318 
319 	if (!next) {
320 		/* ft no longer points to any RTC, drop refcount */
321 		ret = mlx5dr_matcher_free_rtc_pointing(tbl->ctx,
322 						       tbl->fw_ft_type,
323 						       tbl->type,
324 						       prev_ft);
325 		if (ret) {
326 			DR_LOG(ERR, "Failed to reset last RTC refcount");
327 			return ret;
328 		}
329 	}
330 
331 	ret = mlx5dr_matcher_shared_update_local_ft(tbl);
332 	if (ret) {
333 		DR_LOG(ERR, "Failed to update local_ft in shared table");
334 		return ret;
335 	}
336 
337 	if (!next) {
338 		/* ft no longer points to any RTC, drop refcount */
339 		ret = mlx5dr_matcher_free_rtc_pointing(tbl->ctx,
340 						       tbl->fw_ft_type,
341 						       tbl->type,
342 						       prev_ft);
343 		if (ret) {
344 			DR_LOG(ERR, "Failed to reset last RTC refcount");
345 			return ret;
346 		}
347 	}
348 
349 	return 0;
350 }
351 
352 static bool mlx5dr_matcher_supp_fw_wqe(struct mlx5dr_matcher *matcher)
353 {
354 	struct mlx5dr_cmd_query_caps *caps = matcher->tbl->ctx->caps;
355 
356 	if (matcher->flags & MLX5DR_MATCHER_FLAGS_HASH_DEFINER) {
357 		if (matcher->hash_definer->type == MLX5DR_DEFINER_TYPE_MATCH &&
358 		    !IS_BIT_SET(caps->supp_ste_format_gen_wqe, MLX5_IFC_RTC_STE_FORMAT_8DW)) {
359 			DR_LOG(ERR, "Gen WQE MATCH format not supported");
360 			return false;
361 		}
362 
363 		if (matcher->hash_definer->type == MLX5DR_DEFINER_TYPE_JUMBO) {
364 			DR_LOG(ERR, "Gen WQE JUMBO format not supported");
365 			return false;
366 		}
367 	}
368 
369 	if (matcher->attr.insert_mode != MLX5DR_MATCHER_INSERT_BY_HASH ||
370 	    matcher->attr.distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) {
371 		DR_LOG(ERR, "Gen WQE must be inserted and distribute by hash");
372 		return false;
373 	}
374 
375 	if ((matcher->flags & MLX5DR_MATCHER_FLAGS_RANGE_DEFINER) &&
376 	    !IS_BIT_SET(caps->supp_ste_format_gen_wqe, MLX5_IFC_RTC_STE_FORMAT_RANGE)) {
377 		DR_LOG(INFO, "Extended match gen wqe RANGE format not supported");
378 		return false;
379 	}
380 
381 	if (!(caps->supp_type_gen_wqe & MLX5_GENERATE_WQE_TYPE_FLOW_UPDATE)) {
382 		DR_LOG(ERR, "Gen WQE command not supporting GTA");
383 		return false;
384 	}
385 
386 	if (!caps->rtc_max_hash_def_gen_wqe) {
387 		DR_LOG(ERR, "Hash definer not supported");
388 		return false;
389 	}
390 
391 	return true;
392 }
393 
394 static void mlx5dr_matcher_set_rtc_attr_sz(struct mlx5dr_matcher *matcher,
395 					   struct mlx5dr_cmd_rtc_create_attr *rtc_attr,
396 					   enum mlx5dr_matcher_rtc_type rtc_type,
397 					   bool is_mirror)
398 {
399 	enum mlx5dr_matcher_flow_src flow_src = matcher->attr.optimize_flow_src;
400 	bool is_match_rtc = rtc_type == DR_MATCHER_RTC_TYPE_MATCH;
401 	struct mlx5dr_pool_chunk *ste = &matcher->action_ste.ste;
402 
403 	if ((flow_src == MLX5DR_MATCHER_FLOW_SRC_VPORT && !is_mirror) ||
404 	    (flow_src == MLX5DR_MATCHER_FLOW_SRC_WIRE && is_mirror)) {
405 		/* Optimize FDB RTC */
406 		rtc_attr->log_size = 0;
407 		rtc_attr->log_depth = 0;
408 	} else {
409 		/* Keep original values */
410 		rtc_attr->log_size = is_match_rtc ? matcher->attr.table.sz_row_log : ste->order;
411 		rtc_attr->log_depth = is_match_rtc ? matcher->attr.table.sz_col_log : 0;
412 	}
413 }
414 
415 int mlx5dr_matcher_create_aliased_obj(struct mlx5dr_context *ctx,
416 				      struct ibv_context *ibv_owner,
417 				      struct ibv_context *ibv_allowed,
418 				      uint16_t vhca_id_to_be_accessed,
419 				      uint32_t aliased_object_id,
420 				      uint16_t object_type,
421 				      struct mlx5dr_devx_obj **obj)
422 {
423 	struct mlx5dr_cmd_allow_other_vhca_access_attr allow_attr = {0};
424 	struct mlx5dr_cmd_alias_obj_create_attr alias_attr = {0};
425 	char key[ACCESS_KEY_LEN];
426 	int ret;
427 	int i;
428 
429 	if (!mlx5dr_context_shared_gvmi_used(ctx))
430 		return 0;
431 
432 	for (i = 0; i < ACCESS_KEY_LEN; i++)
433 		key[i] = rte_rand() & 0xFF;
434 
435 	memcpy(allow_attr.access_key, key, ACCESS_KEY_LEN);
436 	allow_attr.obj_type = object_type;
437 	allow_attr.obj_id = aliased_object_id;
438 
439 	ret = mlx5dr_cmd_allow_other_vhca_access(ibv_owner, &allow_attr);
440 	if (ret) {
441 		DR_LOG(ERR, "Failed to allow RTC to be aliased");
442 		return ret;
443 	}
444 
445 	memcpy(alias_attr.access_key, key, ACCESS_KEY_LEN);
446 	alias_attr.obj_id = aliased_object_id;
447 	alias_attr.obj_type = object_type;
448 	alias_attr.vhca_id = vhca_id_to_be_accessed;
449 	*obj = mlx5dr_cmd_alias_obj_create(ibv_allowed, &alias_attr);
450 	if (!*obj) {
451 		DR_LOG(ERR, "Failed to create alias object");
452 		return rte_errno;
453 	}
454 
455 	return 0;
456 }
457 
458 static int mlx5dr_matcher_create_rtc(struct mlx5dr_matcher *matcher,
459 				     enum mlx5dr_matcher_rtc_type rtc_type)
460 {
461 	struct mlx5dr_matcher_attr *attr = &matcher->attr;
462 	struct mlx5dr_cmd_rtc_create_attr rtc_attr = {0};
463 	struct mlx5dr_match_template *mt = matcher->mt;
464 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
465 	struct mlx5dr_action_default_stc *default_stc;
466 	struct mlx5dr_table *tbl = matcher->tbl;
467 	struct mlx5dr_devx_obj **rtc_0, **rtc_1;
468 	struct mlx5dr_pool *ste_pool, *stc_pool;
469 	struct mlx5dr_devx_obj *devx_obj;
470 	struct mlx5dr_pool_chunk *ste;
471 	int ret;
472 
473 	switch (rtc_type) {
474 	case DR_MATCHER_RTC_TYPE_MATCH:
475 		rtc_0 = &matcher->match_ste.rtc_0;
476 		rtc_1 = &matcher->match_ste.rtc_1;
477 		ste_pool = matcher->match_ste.pool;
478 		ste = &matcher->match_ste.ste;
479 		ste->order = attr->table.sz_col_log + attr->table.sz_row_log;
480 
481 		/* Add additional rows due to additional range STE */
482 		if (mlx5dr_matcher_mt_is_range(mt))
483 			ste->order++;
484 
485 		rtc_attr.log_size = attr->table.sz_row_log;
486 		rtc_attr.log_depth = attr->table.sz_col_log;
487 		rtc_attr.is_frst_jumbo = mlx5dr_matcher_mt_is_jumbo(mt);
488 		rtc_attr.is_scnd_range = mlx5dr_matcher_mt_is_range(mt);
489 		rtc_attr.miss_ft_id = matcher->end_ft->id;
490 
491 		if (attr->insert_mode == MLX5DR_MATCHER_INSERT_BY_HASH) {
492 			/* The usual Hash Table */
493 			rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH;
494 
495 			if (matcher->hash_definer) {
496 				/* Specify definer_id_0 is used for hashing */
497 				rtc_attr.fw_gen_wqe = true;
498 				rtc_attr.num_hash_definer = 1;
499 				rtc_attr.match_definer_0 =
500 					mlx5dr_definer_get_id(matcher->hash_definer);
501 			} else {
502 				/* The first mt is used since all share the same definer */
503 				rtc_attr.match_definer_0 = mlx5dr_definer_get_id(mt->definer);
504 
505 				/* This is tricky, instead of passing two definers for
506 				 * match and range, we specify that this RTC uses a hash
507 				 * definer, this will allow us to use any range definer
508 				 * since only first STE is used for hashing anyways.
509 				 */
510 				if (matcher->flags & MLX5DR_MATCHER_FLAGS_RANGE_DEFINER) {
511 					rtc_attr.fw_gen_wqe = true;
512 					rtc_attr.num_hash_definer = 1;
513 				}
514 			}
515 		} else if (attr->insert_mode == MLX5DR_MATCHER_INSERT_BY_INDEX) {
516 			rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET;
517 			rtc_attr.num_hash_definer = 1;
518 
519 			if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) {
520 				/* Hash Split Table */
521 				rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH;
522 				rtc_attr.match_definer_0 = mlx5dr_definer_get_id(mt->definer);
523 			} else if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_LINEAR) {
524 				/* Linear Lookup Table */
525 				rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR;
526 				rtc_attr.match_definer_0 = ctx->caps->linear_match_definer;
527 			}
528 		}
529 
530 		/* Match pool requires implicit allocation */
531 		ret = mlx5dr_pool_chunk_alloc(ste_pool, ste);
532 		if (ret) {
533 			DR_LOG(ERR, "Failed to allocate STE for %s RTC",
534 			       mlx5dr_matcher_rtc_type_to_str(rtc_type));
535 			return ret;
536 		}
537 		break;
538 
539 	case DR_MATCHER_RTC_TYPE_STE_ARRAY:
540 		rtc_0 = &matcher->action_ste.rtc_0;
541 		rtc_1 = &matcher->action_ste.rtc_1;
542 		ste_pool = matcher->action_ste.pool;
543 		ste = &matcher->action_ste.ste;
544 		ste->order = rte_log2_u32(matcher->action_ste.max_stes) +
545 			     attr->table.sz_row_log;
546 		rtc_attr.log_size = ste->order;
547 		rtc_attr.log_depth = 0;
548 		rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET;
549 		/* The action STEs use the default always hit definer */
550 		rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer;
551 		rtc_attr.is_frst_jumbo = false;
552 		rtc_attr.miss_ft_id = 0;
553 		break;
554 
555 	default:
556 		DR_LOG(ERR, "HWS Invalid RTC type");
557 		rte_errno = EINVAL;
558 		return rte_errno;
559 	}
560 
561 	devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(ste_pool, ste);
562 
563 	rtc_attr.pd = ctx->pd_num;
564 	rtc_attr.ste_base = devx_obj->id;
565 	rtc_attr.ste_offset = ste->offset;
566 	rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, false);
567 	mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, false);
568 
569 	/* STC is a single resource (devx_obj), use any STC for the ID */
570 	stc_pool = ctx->stc_pool[tbl->type];
571 	default_stc = ctx->common_res[tbl->type].default_stc;
572 	devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, &default_stc->default_hit);
573 	rtc_attr.stc_base = devx_obj->id;
574 
575 	*rtc_0 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr);
576 	if (!*rtc_0) {
577 		DR_LOG(ERR, "Failed to create matcher RTC of type %s",
578 		       mlx5dr_matcher_rtc_type_to_str(rtc_type));
579 		goto free_ste;
580 	}
581 
582 	if (tbl->type == MLX5DR_TABLE_TYPE_FDB) {
583 		devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(ste_pool, ste);
584 		rtc_attr.ste_base = devx_obj->id;
585 		rtc_attr.table_type = mlx5dr_table_get_res_fw_ft_type(tbl->type, true);
586 
587 		devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, &default_stc->default_hit);
588 		rtc_attr.stc_base = devx_obj->id;
589 		mlx5dr_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, true);
590 
591 		*rtc_1 = mlx5dr_cmd_rtc_create(ctx->ibv_ctx, &rtc_attr);
592 		if (!*rtc_1) {
593 			DR_LOG(ERR, "Failed to create peer matcher RTC of type %s",
594 			       mlx5dr_matcher_rtc_type_to_str(rtc_type));
595 			goto destroy_rtc_0;
596 		}
597 	}
598 
599 	return 0;
600 
601 destroy_rtc_0:
602 	mlx5dr_cmd_destroy_obj(*rtc_0);
603 free_ste:
604 	if (rtc_type == DR_MATCHER_RTC_TYPE_MATCH)
605 		mlx5dr_pool_chunk_free(ste_pool, ste);
606 	return rte_errno;
607 }
608 
609 static void mlx5dr_matcher_destroy_rtc(struct mlx5dr_matcher *matcher,
610 				       enum mlx5dr_matcher_rtc_type rtc_type)
611 {
612 	struct mlx5dr_table *tbl = matcher->tbl;
613 	struct mlx5dr_devx_obj *rtc_0, *rtc_1;
614 	struct mlx5dr_pool_chunk *ste;
615 	struct mlx5dr_pool *ste_pool;
616 
617 	switch (rtc_type) {
618 	case DR_MATCHER_RTC_TYPE_MATCH:
619 		rtc_0 = matcher->match_ste.rtc_0;
620 		rtc_1 = matcher->match_ste.rtc_1;
621 		ste_pool = matcher->match_ste.pool;
622 		ste = &matcher->match_ste.ste;
623 		break;
624 	case DR_MATCHER_RTC_TYPE_STE_ARRAY:
625 		rtc_0 = matcher->action_ste.rtc_0;
626 		rtc_1 = matcher->action_ste.rtc_1;
627 		ste_pool = matcher->action_ste.pool;
628 		ste = &matcher->action_ste.ste;
629 		break;
630 	default:
631 		return;
632 	}
633 
634 	if (tbl->type == MLX5DR_TABLE_TYPE_FDB)
635 		mlx5dr_cmd_destroy_obj(rtc_1);
636 
637 	mlx5dr_cmd_destroy_obj(rtc_0);
638 	if (rtc_type == DR_MATCHER_RTC_TYPE_MATCH)
639 		mlx5dr_pool_chunk_free(ste_pool, ste);
640 }
641 
642 static int
643 mlx5dr_matcher_check_attr_sz(struct mlx5dr_cmd_query_caps *caps,
644 			     struct mlx5dr_matcher_attr *attr)
645 {
646 	if (attr->table.sz_col_log > caps->rtc_log_depth_max) {
647 		DR_LOG(ERR, "Matcher depth exceeds limit %d", caps->rtc_log_depth_max);
648 		goto not_supported;
649 	}
650 
651 	if (attr->table.sz_col_log + attr->table.sz_row_log > caps->ste_alloc_log_max) {
652 		DR_LOG(ERR, "Total matcher size exceeds limit %d", caps->ste_alloc_log_max);
653 		goto not_supported;
654 	}
655 
656 	if (attr->table.sz_col_log + attr->table.sz_row_log < caps->ste_alloc_log_gran) {
657 		DR_LOG(ERR, "Total matcher size below limit %d", caps->ste_alloc_log_gran);
658 		goto not_supported;
659 	}
660 
661 	return 0;
662 
663 not_supported:
664 	rte_errno = EOPNOTSUPP;
665 	return rte_errno;
666 }
667 
668 static void mlx5dr_matcher_set_pool_attr(struct mlx5dr_pool_attr *attr,
669 					 struct mlx5dr_matcher *matcher)
670 {
671 	switch (matcher->attr.optimize_flow_src) {
672 	case MLX5DR_MATCHER_FLOW_SRC_VPORT:
673 		attr->opt_type = MLX5DR_POOL_OPTIMIZE_ORIG;
674 		break;
675 	case MLX5DR_MATCHER_FLOW_SRC_WIRE:
676 		attr->opt_type = MLX5DR_POOL_OPTIMIZE_MIRROR;
677 		break;
678 	default:
679 		break;
680 	}
681 }
682 
683 static int mlx5dr_matcher_bind_at(struct mlx5dr_matcher *matcher)
684 {
685 	bool is_jumbo = mlx5dr_matcher_mt_is_jumbo(matcher->mt);
686 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
687 	struct mlx5dr_table *tbl = matcher->tbl;
688 	struct mlx5dr_pool_attr pool_attr = {0};
689 	struct mlx5dr_context *ctx = tbl->ctx;
690 	uint32_t required_stes;
691 	int i, ret;
692 	bool valid;
693 
694 	for (i = 0; i < matcher->num_of_at; i++) {
695 		struct mlx5dr_action_template *at = &matcher->at[i];
696 
697 		/* Check if action combinabtion is valid */
698 		valid = mlx5dr_action_check_combo(at->action_type_arr, matcher->tbl->type);
699 		if (!valid) {
700 			DR_LOG(ERR, "Invalid combination in action template %d", i);
701 			return rte_errno;
702 		}
703 
704 		/* Process action template to setters */
705 		ret = mlx5dr_action_template_process(at);
706 		if (ret) {
707 			DR_LOG(ERR, "Failed to process action template %d", i);
708 			return rte_errno;
709 		}
710 
711 		required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term);
712 		matcher->action_ste.max_stes = RTE_MAX(matcher->action_ste.max_stes, required_stes);
713 
714 		/* Future: Optimize reparse */
715 	}
716 
717 	/* There are no additioanl STEs required for matcher */
718 	if (!matcher->action_ste.max_stes)
719 		return 0;
720 
721 	if (mlx5dr_matcher_req_fw_wqe(matcher)) {
722 		DR_LOG(ERR, "FW extended matcher cannot be binded to complex at");
723 		rte_errno = ENOTSUP;
724 		return rte_errno;
725 	}
726 
727 	/* Allocate action STE mempool */
728 	pool_attr.table_type = tbl->type;
729 	pool_attr.pool_type = MLX5DR_POOL_TYPE_STE;
730 	pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_STE_ACTION_POOL;
731 	pool_attr.alloc_log_sz = rte_log2_u32(matcher->action_ste.max_stes) +
732 				 matcher->attr.table.sz_row_log;
733 	mlx5dr_matcher_set_pool_attr(&pool_attr, matcher);
734 	matcher->action_ste.pool = mlx5dr_pool_create(ctx, &pool_attr);
735 	if (!matcher->action_ste.pool) {
736 		DR_LOG(ERR, "Failed to create action ste pool");
737 		return rte_errno;
738 	}
739 
740 	/* Allocate action RTC */
741 	ret = mlx5dr_matcher_create_rtc(matcher, DR_MATCHER_RTC_TYPE_STE_ARRAY);
742 	if (ret) {
743 		DR_LOG(ERR, "Failed to create action RTC");
744 		goto free_ste_pool;
745 	}
746 
747 	/* Allocate STC for jumps to STE */
748 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
749 	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE;
750 	stc_attr.ste_table.ste = matcher->action_ste.ste;
751 	stc_attr.ste_table.ste_pool = matcher->action_ste.pool;
752 	stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer;
753 
754 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl->type,
755 					     &matcher->action_ste.stc);
756 	if (ret) {
757 		DR_LOG(ERR, "Failed to create action jump to table STC");
758 		goto free_rtc;
759 	}
760 
761 	return 0;
762 
763 free_rtc:
764 	mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_STE_ARRAY);
765 free_ste_pool:
766 	mlx5dr_pool_destroy(matcher->action_ste.pool);
767 	return rte_errno;
768 }
769 
770 static void mlx5dr_matcher_unbind_at(struct mlx5dr_matcher *matcher)
771 {
772 	struct mlx5dr_table *tbl = matcher->tbl;
773 
774 	if (!matcher->action_ste.max_stes)
775 		return;
776 
777 	mlx5dr_action_free_single_stc(tbl->ctx, tbl->type, &matcher->action_ste.stc);
778 	mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_STE_ARRAY);
779 	mlx5dr_pool_destroy(matcher->action_ste.pool);
780 }
781 
782 static int mlx5dr_matcher_bind_mt(struct mlx5dr_matcher *matcher)
783 {
784 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
785 	struct mlx5dr_pool_attr pool_attr = {0};
786 	int ret;
787 
788 	/* Calculate match, range and hash definers */
789 	ret = mlx5dr_definer_matcher_init(ctx, matcher);
790 	if (ret) {
791 		DR_LOG(ERR, "Failed to set matcher templates with match definers");
792 		return ret;
793 	}
794 
795 	if (mlx5dr_matcher_req_fw_wqe(matcher) &&
796 	    !mlx5dr_matcher_supp_fw_wqe(matcher)) {
797 		DR_LOG(ERR, "Matcher requires FW WQE which is not supported");
798 		rte_errno = ENOTSUP;
799 		ret = rte_errno;
800 		goto uninit_match_definer;
801 	}
802 
803 	/* Create an STE pool per matcher*/
804 	pool_attr.table_type = matcher->tbl->type;
805 	pool_attr.pool_type = MLX5DR_POOL_TYPE_STE;
806 	pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_MATCHER_STE_POOL;
807 	pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log +
808 				 matcher->attr.table.sz_row_log;
809 	/* Add additional rows due to additional range STE */
810 	if (matcher->flags & MLX5DR_MATCHER_FLAGS_RANGE_DEFINER)
811 		pool_attr.alloc_log_sz++;
812 	mlx5dr_matcher_set_pool_attr(&pool_attr, matcher);
813 
814 	matcher->match_ste.pool = mlx5dr_pool_create(ctx, &pool_attr);
815 	if (!matcher->match_ste.pool) {
816 		DR_LOG(ERR, "Failed to allocate matcher STE pool");
817 		ret = ENOTSUP;
818 		goto uninit_match_definer;
819 	}
820 
821 	return 0;
822 
823 uninit_match_definer:
824 	mlx5dr_definer_matcher_uninit(matcher);
825 	return ret;
826 }
827 
828 static void mlx5dr_matcher_unbind_mt(struct mlx5dr_matcher *matcher)
829 {
830 	mlx5dr_pool_destroy(matcher->match_ste.pool);
831 	mlx5dr_definer_matcher_uninit(matcher);
832 }
833 
834 static int
835 mlx5dr_matcher_validate_insert_mode(struct mlx5dr_cmd_query_caps *caps,
836 				    struct mlx5dr_matcher *matcher,
837 				    bool is_root)
838 {
839 	struct mlx5dr_matcher_attr *attr = &matcher->attr;
840 
841 	if (is_root) {
842 		if (attr->mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE) {
843 			DR_LOG(ERR, "Root matcher supports only rule resource mode");
844 			goto not_supported;
845 		}
846 		if (attr->insert_mode != MLX5DR_MATCHER_INSERT_BY_HASH) {
847 			DR_LOG(ERR, "Root matcher supports only insert by hash mode");
848 			goto not_supported;
849 		}
850 		if (attr->distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) {
851 			DR_LOG(ERR, "Root matcher supports only distribute by hash mode");
852 			goto not_supported;
853 		}
854 		if (attr->optimize_flow_src) {
855 			DR_LOG(ERR, "Root matcher can't specify FDB direction");
856 			goto not_supported;
857 		}
858 	}
859 
860 	switch (attr->insert_mode) {
861 	case MLX5DR_MATCHER_INSERT_BY_HASH:
862 		if (matcher->attr.distribute_mode != MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) {
863 			DR_LOG(ERR, "Invalid matcher distribute mode");
864 			goto not_supported;
865 		}
866 		break;
867 
868 	case MLX5DR_MATCHER_INSERT_BY_INDEX:
869 		if (attr->table.sz_col_log) {
870 			DR_LOG(ERR, "Matcher with INSERT_BY_INDEX supports only Nx1 table size");
871 			goto not_supported;
872 		}
873 
874 		if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_HASH) {
875 			/* Hash Split Table */
876 			if (!caps->rtc_hash_split_table) {
877 				DR_LOG(ERR, "FW doesn't support insert by index and hash distribute");
878 				goto not_supported;
879 			}
880 		} else if (attr->distribute_mode == MLX5DR_MATCHER_DISTRIBUTE_BY_LINEAR) {
881 			/* Linear Lookup Table */
882 			if (!caps->rtc_linear_lookup_table ||
883 			    !IS_BIT_SET(caps->access_index_mode,
884 					MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR)) {
885 				DR_LOG(ERR, "FW doesn't support insert by index and linear distribute");
886 				goto not_supported;
887 			}
888 
889 			if (attr->table.sz_row_log > MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX) {
890 				DR_LOG(ERR, "Matcher with linear distribute: rows exceed limit %d",
891 				       MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX);
892 				goto not_supported;
893 			}
894 		} else {
895 			DR_LOG(ERR, "Matcher has unsupported distribute mode");
896 			goto not_supported;
897 		}
898 		break;
899 
900 	default:
901 		DR_LOG(ERR, "Matcher has unsupported insert mode");
902 		goto not_supported;
903 	}
904 
905 	return 0;
906 
907 not_supported:
908 	rte_errno = EOPNOTSUPP;
909 	return rte_errno;
910 }
911 
912 static int
913 mlx5dr_matcher_process_attr(struct mlx5dr_cmd_query_caps *caps,
914 			    struct mlx5dr_matcher *matcher,
915 			    bool is_root)
916 {
917 	struct mlx5dr_matcher_attr *attr = &matcher->attr;
918 
919 	if (mlx5dr_matcher_validate_insert_mode(caps, matcher, is_root))
920 		goto not_supported;
921 
922 	if (is_root) {
923 		if (attr->optimize_flow_src) {
924 			DR_LOG(ERR, "Root matcher can't specify FDB direction");
925 			goto not_supported;
926 		}
927 		return 0;
928 	}
929 
930 	if (matcher->tbl->type != MLX5DR_TABLE_TYPE_FDB  && attr->optimize_flow_src) {
931 		DR_LOG(ERR, "NIC domain doesn't support flow_src");
932 		goto not_supported;
933 	}
934 
935 	/* Convert number of rules to the required depth */
936 	if (attr->mode == MLX5DR_MATCHER_RESOURCE_MODE_RULE &&
937 	    attr->insert_mode == MLX5DR_MATCHER_INSERT_BY_HASH)
938 		attr->table.sz_col_log = mlx5dr_matcher_rules_to_tbl_depth(attr->rule.num_log);
939 
940 	return mlx5dr_matcher_check_attr_sz(caps, attr);
941 
942 not_supported:
943 	rte_errno = EOPNOTSUPP;
944 	return rte_errno;
945 }
946 
947 static int mlx5dr_matcher_create_and_connect(struct mlx5dr_matcher *matcher)
948 {
949 	int ret;
950 
951 	/* Select and create the definers for current matcher */
952 	ret = mlx5dr_matcher_bind_mt(matcher);
953 	if (ret)
954 		return ret;
955 
956 	/* Calculate and verify action combination */
957 	ret = mlx5dr_matcher_bind_at(matcher);
958 	if (ret)
959 		goto unbind_mt;
960 
961 	/* Create matcher end flow table anchor */
962 	ret = mlx5dr_matcher_create_end_ft(matcher);
963 	if (ret)
964 		goto unbind_at;
965 
966 	/* Allocate the RTC for the new matcher */
967 	ret = mlx5dr_matcher_create_rtc(matcher, DR_MATCHER_RTC_TYPE_MATCH);
968 	if (ret)
969 		goto destroy_end_ft;
970 
971 	/* Allocate and set shared resources */
972 	ret = mlx5dr_matcher_create_init_shared(matcher);
973 	if (ret)
974 		goto destroy_rtc;
975 
976 	/* Connect the matcher to the matcher list */
977 	ret = mlx5dr_matcher_connect(matcher);
978 	if (ret)
979 		goto destroy_shared;
980 
981 	return 0;
982 
983 destroy_shared:
984 	mlx5dr_matcher_create_uninit_shared(matcher);
985 destroy_rtc:
986 	mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_MATCH);
987 destroy_end_ft:
988 	mlx5dr_matcher_destroy_end_ft(matcher);
989 unbind_at:
990 	mlx5dr_matcher_unbind_at(matcher);
991 unbind_mt:
992 	mlx5dr_matcher_unbind_mt(matcher);
993 	return ret;
994 }
995 
996 static void mlx5dr_matcher_destroy_and_disconnect(struct mlx5dr_matcher *matcher)
997 {
998 	mlx5dr_matcher_disconnect(matcher);
999 	mlx5dr_matcher_create_uninit_shared(matcher);
1000 	mlx5dr_matcher_destroy_rtc(matcher, DR_MATCHER_RTC_TYPE_MATCH);
1001 	mlx5dr_matcher_destroy_end_ft(matcher);
1002 	mlx5dr_matcher_unbind_at(matcher);
1003 	mlx5dr_matcher_unbind_mt(matcher);
1004 }
1005 
1006 static int
1007 mlx5dr_matcher_create_col_matcher(struct mlx5dr_matcher *matcher)
1008 {
1009 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
1010 	struct mlx5dr_matcher *col_matcher;
1011 	int ret;
1012 
1013 	if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE ||
1014 	    matcher->attr.insert_mode == MLX5DR_MATCHER_INSERT_BY_INDEX)
1015 		return 0;
1016 
1017 	if (!mlx5dr_matcher_requires_col_tbl(matcher->attr.rule.num_log))
1018 		return 0;
1019 
1020 	col_matcher = simple_calloc(1, sizeof(*matcher));
1021 	if (!col_matcher) {
1022 		rte_errno = ENOMEM;
1023 		return rte_errno;
1024 	}
1025 
1026 	col_matcher->tbl = matcher->tbl;
1027 	col_matcher->mt = matcher->mt;
1028 	col_matcher->at = matcher->at;
1029 	col_matcher->num_of_at = matcher->num_of_at;
1030 	col_matcher->num_of_mt = matcher->num_of_mt;
1031 	col_matcher->hash_definer = matcher->hash_definer;
1032 	col_matcher->attr.priority = matcher->attr.priority;
1033 	col_matcher->flags = matcher->flags;
1034 	col_matcher->flags |= MLX5DR_MATCHER_FLAGS_COLLISION;
1035 	col_matcher->attr.mode = MLX5DR_MATCHER_RESOURCE_MODE_HTABLE;
1036 	col_matcher->attr.optimize_flow_src = matcher->attr.optimize_flow_src;
1037 	col_matcher->attr.table.sz_row_log = matcher->attr.rule.num_log;
1038 	col_matcher->attr.table.sz_col_log = MLX5DR_MATCHER_ASSURED_COL_TBL_DEPTH;
1039 	if (col_matcher->attr.table.sz_row_log > MLX5DR_MATCHER_ASSURED_ROW_RATIO)
1040 		col_matcher->attr.table.sz_row_log -= MLX5DR_MATCHER_ASSURED_ROW_RATIO;
1041 
1042 	ret = mlx5dr_matcher_process_attr(ctx->caps, col_matcher, false);
1043 	if (ret)
1044 		goto free_col_matcher;
1045 
1046 	ret = mlx5dr_matcher_create_and_connect(col_matcher);
1047 	if (ret)
1048 		goto free_col_matcher;
1049 
1050 	matcher->col_matcher = col_matcher;
1051 
1052 	return 0;
1053 
1054 free_col_matcher:
1055 	simple_free(col_matcher);
1056 	DR_LOG(ERR, "Failed to create assured collision matcher");
1057 	return ret;
1058 }
1059 
1060 static void
1061 mlx5dr_matcher_destroy_col_matcher(struct mlx5dr_matcher *matcher)
1062 {
1063 	if (matcher->attr.mode != MLX5DR_MATCHER_RESOURCE_MODE_RULE ||
1064 	    matcher->attr.insert_mode == MLX5DR_MATCHER_INSERT_BY_INDEX)
1065 		return;
1066 
1067 	if (matcher->col_matcher) {
1068 		mlx5dr_matcher_destroy_and_disconnect(matcher->col_matcher);
1069 		simple_free(matcher->col_matcher);
1070 	}
1071 }
1072 
1073 static int mlx5dr_matcher_init(struct mlx5dr_matcher *matcher)
1074 {
1075 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
1076 	int ret;
1077 
1078 	pthread_spin_lock(&ctx->ctrl_lock);
1079 
1080 	/* Allocate matcher resource and connect to the packet pipe */
1081 	ret = mlx5dr_matcher_create_and_connect(matcher);
1082 	if (ret)
1083 		goto unlock_err;
1084 
1085 	/* Create additional matcher for collision handling */
1086 	ret = mlx5dr_matcher_create_col_matcher(matcher);
1087 	if (ret)
1088 		goto destory_and_disconnect;
1089 
1090 	pthread_spin_unlock(&ctx->ctrl_lock);
1091 
1092 	return 0;
1093 
1094 destory_and_disconnect:
1095 	mlx5dr_matcher_destroy_and_disconnect(matcher);
1096 unlock_err:
1097 	pthread_spin_unlock(&ctx->ctrl_lock);
1098 	return ret;
1099 }
1100 
1101 static int mlx5dr_matcher_uninit(struct mlx5dr_matcher *matcher)
1102 {
1103 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
1104 
1105 	pthread_spin_lock(&ctx->ctrl_lock);
1106 	mlx5dr_matcher_destroy_col_matcher(matcher);
1107 	mlx5dr_matcher_destroy_and_disconnect(matcher);
1108 	pthread_spin_unlock(&ctx->ctrl_lock);
1109 
1110 	return 0;
1111 }
1112 
1113 static int mlx5dr_matcher_init_root(struct mlx5dr_matcher *matcher)
1114 {
1115 	enum mlx5dr_table_type type = matcher->tbl->type;
1116 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
1117 	struct mlx5dv_flow_matcher_attr attr = {0};
1118 	struct mlx5dv_flow_match_parameters *mask;
1119 	struct mlx5_flow_attr flow_attr = {0};
1120 	struct rte_flow_error rte_error;
1121 	uint8_t match_criteria;
1122 	int ret;
1123 
1124 #ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE
1125 	attr.comp_mask = MLX5DV_FLOW_MATCHER_MASK_FT_TYPE;
1126 
1127 	switch (type) {
1128 	case MLX5DR_TABLE_TYPE_NIC_RX:
1129 		attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
1130 		break;
1131 	case MLX5DR_TABLE_TYPE_NIC_TX:
1132 		attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
1133 		break;
1134 	case MLX5DR_TABLE_TYPE_FDB:
1135 		attr.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
1136 		break;
1137 	default:
1138 		assert(0);
1139 		break;
1140 	}
1141 #endif
1142 
1143 	if (matcher->attr.priority > UINT16_MAX) {
1144 		DR_LOG(ERR, "Root matcher priority exceeds allowed limit");
1145 		rte_errno = EINVAL;
1146 		return rte_errno;
1147 	}
1148 
1149 	mask = simple_calloc(1, MLX5_ST_SZ_BYTES(fte_match_param) +
1150 			     offsetof(struct mlx5dv_flow_match_parameters, match_buf));
1151 	if (!mask) {
1152 		rte_errno = ENOMEM;
1153 		return rte_errno;
1154 	}
1155 
1156 	flow_attr.tbl_type = type;
1157 
1158 	/* On root table matcher, only a single match template is supported */
1159 	ret = flow_dv_translate_items_hws(matcher->mt[0].items,
1160 					  &flow_attr, mask->match_buf,
1161 					  MLX5_SET_MATCHER_HS_M, NULL,
1162 					  &match_criteria,
1163 					  &rte_error);
1164 	if (ret) {
1165 		DR_LOG(ERR, "Failed to convert items to PRM [%s]", rte_error.message);
1166 		goto free_mask;
1167 	}
1168 
1169 	mask->match_sz = MLX5_ST_SZ_BYTES(fte_match_param);
1170 	attr.match_mask = mask;
1171 	attr.match_criteria_enable = match_criteria;
1172 	attr.type = IBV_FLOW_ATTR_NORMAL;
1173 	attr.priority = matcher->attr.priority;
1174 
1175 	matcher->dv_matcher =
1176 		mlx5_glue->dv_create_flow_matcher_root(mlx5dr_context_get_local_ibv(ctx),
1177 						       &attr);
1178 	if (!matcher->dv_matcher) {
1179 		DR_LOG(ERR, "Failed to create DV flow matcher");
1180 		rte_errno = errno;
1181 		goto free_mask;
1182 	}
1183 
1184 	simple_free(mask);
1185 
1186 	pthread_spin_lock(&ctx->ctrl_lock);
1187 	LIST_INSERT_HEAD(&matcher->tbl->head, matcher, next);
1188 	pthread_spin_unlock(&ctx->ctrl_lock);
1189 
1190 	return 0;
1191 
1192 free_mask:
1193 	simple_free(mask);
1194 	return rte_errno;
1195 }
1196 
1197 static int mlx5dr_matcher_uninit_root(struct mlx5dr_matcher *matcher)
1198 {
1199 	struct mlx5dr_context *ctx = matcher->tbl->ctx;
1200 	int ret;
1201 
1202 	pthread_spin_lock(&ctx->ctrl_lock);
1203 	LIST_REMOVE(matcher, next);
1204 	pthread_spin_unlock(&ctx->ctrl_lock);
1205 
1206 	ret = mlx5_glue->dv_destroy_flow_matcher_root(matcher->dv_matcher);
1207 	if (ret) {
1208 		DR_LOG(ERR, "Failed to Destroy DV flow matcher");
1209 		rte_errno = errno;
1210 	}
1211 
1212 	return ret;
1213 }
1214 
1215 static int
1216 mlx5dr_matcher_set_templates(struct mlx5dr_matcher *matcher,
1217 			     struct mlx5dr_match_template *mt[],
1218 			     uint8_t num_of_mt,
1219 			     struct mlx5dr_action_template *at[],
1220 			     uint8_t num_of_at)
1221 {
1222 	bool is_root = mlx5dr_table_is_root(matcher->tbl);
1223 	int i;
1224 
1225 	if (!num_of_mt || !num_of_at) {
1226 		DR_LOG(ERR, "Number of action/match template cannot be zero");
1227 		rte_errno = ENOTSUP;
1228 		return rte_errno;
1229 	}
1230 
1231 	if (is_root && num_of_mt > MLX5DR_MATCHER_MAX_MT_ROOT) {
1232 		DR_LOG(ERR, "Number of match templates exceeds limit");
1233 		rte_errno = ENOTSUP;
1234 		return rte_errno;
1235 	}
1236 
1237 	matcher->mt = simple_calloc(num_of_mt, sizeof(*matcher->mt));
1238 	if (!matcher->mt) {
1239 		DR_LOG(ERR, "Failed to allocate match template array");
1240 		rte_errno = ENOMEM;
1241 		return rte_errno;
1242 	}
1243 
1244 	matcher->at = simple_calloc(num_of_at, sizeof(*matcher->at));
1245 	if (!matcher->at) {
1246 		DR_LOG(ERR, "Failed to allocate action template array");
1247 		rte_errno = ENOMEM;
1248 		goto free_mt;
1249 	}
1250 
1251 	for (i = 0; i < num_of_mt; i++)
1252 		matcher->mt[i] = *mt[i];
1253 
1254 	for (i = 0; i < num_of_at; i++)
1255 		matcher->at[i] = *at[i];
1256 
1257 	matcher->num_of_mt = num_of_mt;
1258 	matcher->num_of_at = num_of_at;
1259 
1260 	return 0;
1261 
1262 free_mt:
1263 	simple_free(matcher->mt);
1264 	return rte_errno;
1265 }
1266 
1267 static void
1268 mlx5dr_matcher_unset_templates(struct mlx5dr_matcher *matcher)
1269 {
1270 	simple_free(matcher->at);
1271 	simple_free(matcher->mt);
1272 }
1273 
1274 struct mlx5dr_matcher *
1275 mlx5dr_matcher_create(struct mlx5dr_table *tbl,
1276 		      struct mlx5dr_match_template *mt[],
1277 		      uint8_t num_of_mt,
1278 		      struct mlx5dr_action_template *at[],
1279 		      uint8_t num_of_at,
1280 		      struct mlx5dr_matcher_attr *attr)
1281 {
1282 	bool is_root = mlx5dr_table_is_root(tbl);
1283 	struct mlx5dr_matcher *matcher;
1284 	int ret;
1285 
1286 	matcher = simple_calloc(1, sizeof(*matcher));
1287 	if (!matcher) {
1288 		rte_errno = ENOMEM;
1289 		return NULL;
1290 	}
1291 
1292 	matcher->tbl = tbl;
1293 	matcher->attr = *attr;
1294 
1295 	ret = mlx5dr_matcher_process_attr(tbl->ctx->caps, matcher, is_root);
1296 	if (ret)
1297 		goto free_matcher;
1298 
1299 	ret = mlx5dr_matcher_set_templates(matcher, mt, num_of_mt, at, num_of_at);
1300 	if (ret)
1301 		goto free_matcher;
1302 
1303 	if (is_root)
1304 		ret = mlx5dr_matcher_init_root(matcher);
1305 	else
1306 		ret = mlx5dr_matcher_init(matcher);
1307 
1308 	if (ret) {
1309 		DR_LOG(ERR, "Failed to initialise matcher: %d", ret);
1310 		goto unset_templates;
1311 	}
1312 
1313 	return matcher;
1314 
1315 unset_templates:
1316 	mlx5dr_matcher_unset_templates(matcher);
1317 free_matcher:
1318 	simple_free(matcher);
1319 	return NULL;
1320 }
1321 
1322 int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher)
1323 {
1324 	if (mlx5dr_table_is_root(matcher->tbl))
1325 		mlx5dr_matcher_uninit_root(matcher);
1326 	else
1327 		mlx5dr_matcher_uninit(matcher);
1328 
1329 	mlx5dr_matcher_unset_templates(matcher);
1330 	simple_free(matcher);
1331 	return 0;
1332 }
1333 
1334 struct mlx5dr_match_template *
1335 mlx5dr_match_template_create(const struct rte_flow_item items[],
1336 			     enum mlx5dr_match_template_flags flags)
1337 {
1338 	struct mlx5dr_match_template *mt;
1339 	struct rte_flow_error error;
1340 	int ret, len;
1341 
1342 	if (flags > MLX5DR_MATCH_TEMPLATE_FLAG_RELAXED_MATCH) {
1343 		DR_LOG(ERR, "Unsupported match template flag provided");
1344 		rte_errno = EINVAL;
1345 		return NULL;
1346 	}
1347 
1348 	mt = simple_calloc(1, sizeof(*mt));
1349 	if (!mt) {
1350 		DR_LOG(ERR, "Failed to allocate match template");
1351 		rte_errno = ENOMEM;
1352 		return NULL;
1353 	}
1354 
1355 	mt->flags = flags;
1356 
1357 	/* Duplicate the user given items */
1358 	ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, NULL, 0, items, &error);
1359 	if (ret <= 0) {
1360 		DR_LOG(ERR, "Unable to process items (%s): %s",
1361 		       error.message ? error.message : "unspecified",
1362 		       strerror(rte_errno));
1363 		goto free_template;
1364 	}
1365 
1366 	len = RTE_ALIGN(ret, 16);
1367 	mt->items = simple_calloc(1, len);
1368 	if (!mt->items) {
1369 		DR_LOG(ERR, "Failed to allocate item copy");
1370 		rte_errno = ENOMEM;
1371 		goto free_template;
1372 	}
1373 
1374 	ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN, mt->items, ret, items, &error);
1375 	if (ret <= 0)
1376 		goto free_dst;
1377 
1378 	return mt;
1379 
1380 free_dst:
1381 	simple_free(mt->items);
1382 free_template:
1383 	simple_free(mt);
1384 	return NULL;
1385 }
1386 
1387 int mlx5dr_match_template_destroy(struct mlx5dr_match_template *mt)
1388 {
1389 	simple_free(mt->items);
1390 	simple_free(mt);
1391 	return 0;
1392 }
1393