1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
3 
4 #include "internal.h"
5 
6 enum mlx5hws_matcher_rtc_type {
7 	HWS_MATCHER_RTC_TYPE_MATCH,
8 	HWS_MATCHER_RTC_TYPE_STE_ARRAY,
9 	HWS_MATCHER_RTC_TYPE_MAX,
10 };
11 
12 static const char * const mlx5hws_matcher_rtc_type_str[] = {
13 	[HWS_MATCHER_RTC_TYPE_MATCH] = "MATCH",
14 	[HWS_MATCHER_RTC_TYPE_STE_ARRAY] = "STE_ARRAY",
15 	[HWS_MATCHER_RTC_TYPE_MAX] = "UNKNOWN",
16 };
17 
hws_matcher_rtc_type_to_str(enum mlx5hws_matcher_rtc_type rtc_type)18 static const char *hws_matcher_rtc_type_to_str(enum mlx5hws_matcher_rtc_type rtc_type)
19 {
20 	if (rtc_type > HWS_MATCHER_RTC_TYPE_MAX)
21 		rtc_type = HWS_MATCHER_RTC_TYPE_MAX;
22 	return mlx5hws_matcher_rtc_type_str[rtc_type];
23 }
24 
hws_matcher_requires_col_tbl(u8 log_num_of_rules)25 static bool hws_matcher_requires_col_tbl(u8 log_num_of_rules)
26 {
27 	/* Collision table concatenation is done only for large rule tables */
28 	return log_num_of_rules > MLX5HWS_MATCHER_ASSURED_RULES_TH;
29 }
30 
hws_matcher_rules_to_tbl_depth(u8 log_num_of_rules)31 static u8 hws_matcher_rules_to_tbl_depth(u8 log_num_of_rules)
32 {
33 	if (hws_matcher_requires_col_tbl(log_num_of_rules))
34 		return MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH;
35 
36 	/* For small rule tables we use a single deep table to assure insertion */
37 	return min(log_num_of_rules, MLX5HWS_MATCHER_ASSURED_COL_TBL_DEPTH);
38 }
39 
hws_matcher_destroy_end_ft(struct mlx5hws_matcher * matcher)40 static void hws_matcher_destroy_end_ft(struct mlx5hws_matcher *matcher)
41 {
42 	mlx5hws_table_destroy_default_ft(matcher->tbl, matcher->end_ft_id);
43 }
44 
hws_matcher_create_end_ft(struct mlx5hws_matcher * matcher)45 static int hws_matcher_create_end_ft(struct mlx5hws_matcher *matcher)
46 {
47 	struct mlx5hws_table *tbl = matcher->tbl;
48 	int ret;
49 
50 	ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, tbl, &matcher->end_ft_id);
51 	if (ret) {
52 		mlx5hws_err(tbl->ctx, "Failed to create matcher end flow table\n");
53 		return ret;
54 	}
55 	return 0;
56 }
57 
hws_matcher_connect(struct mlx5hws_matcher * matcher)58 static int hws_matcher_connect(struct mlx5hws_matcher *matcher)
59 {
60 	struct mlx5hws_table *tbl = matcher->tbl;
61 	struct mlx5hws_context *ctx = tbl->ctx;
62 	struct mlx5hws_matcher *prev = NULL;
63 	struct mlx5hws_matcher *next = NULL;
64 	struct mlx5hws_matcher *tmp_matcher;
65 	int ret;
66 
67 	/* Find location in matcher list */
68 	if (list_empty(&tbl->matchers_list)) {
69 		list_add(&matcher->list_node, &tbl->matchers_list);
70 		goto connect;
71 	}
72 
73 	list_for_each_entry(tmp_matcher, &tbl->matchers_list, list_node) {
74 		if (tmp_matcher->attr.priority > matcher->attr.priority) {
75 			next = tmp_matcher;
76 			break;
77 		}
78 		prev = tmp_matcher;
79 	}
80 
81 	if (next)
82 		/* insert before next */
83 		list_add_tail(&matcher->list_node, &next->list_node);
84 	else
85 		/* insert after prev */
86 		list_add(&matcher->list_node, &prev->list_node);
87 
88 connect:
89 	if (next) {
90 		/* Connect to next RTC */
91 		ret = mlx5hws_table_ft_set_next_rtc(ctx,
92 						    matcher->end_ft_id,
93 						    tbl->fw_ft_type,
94 						    next->match_ste.rtc_0_id,
95 						    next->match_ste.rtc_1_id);
96 		if (ret) {
97 			mlx5hws_err(ctx, "Failed to connect new matcher to next RTC\n");
98 			goto remove_from_list;
99 		}
100 	} else {
101 		/* Connect last matcher to next miss_tbl if exists */
102 		ret = mlx5hws_table_connect_to_miss_table(tbl, tbl->default_miss.miss_tbl);
103 		if (ret) {
104 			mlx5hws_err(ctx, "Failed connect new matcher to miss_tbl\n");
105 			goto remove_from_list;
106 		}
107 	}
108 
109 	/* Connect to previous FT */
110 	ret = mlx5hws_table_ft_set_next_rtc(ctx,
111 					    prev ? prev->end_ft_id : tbl->ft_id,
112 					    tbl->fw_ft_type,
113 					    matcher->match_ste.rtc_0_id,
114 					    matcher->match_ste.rtc_1_id);
115 	if (ret) {
116 		mlx5hws_err(ctx, "Failed to connect new matcher to previous FT\n");
117 		goto remove_from_list;
118 	}
119 
120 	/* Reset prev matcher FT default miss (drop refcount) */
121 	ret = mlx5hws_table_ft_set_default_next_ft(tbl, prev ? prev->end_ft_id : tbl->ft_id);
122 	if (ret) {
123 		mlx5hws_err(ctx, "Failed to reset matcher ft default miss\n");
124 		goto remove_from_list;
125 	}
126 
127 	if (!prev) {
128 		/* Update tables missing to current matcher in the table */
129 		ret = mlx5hws_table_update_connected_miss_tables(tbl);
130 		if (ret) {
131 			mlx5hws_err(ctx, "Fatal error, failed to update connected miss table\n");
132 			goto remove_from_list;
133 		}
134 	}
135 
136 	return 0;
137 
138 remove_from_list:
139 	list_del_init(&matcher->list_node);
140 	return ret;
141 }
142 
hws_matcher_disconnect(struct mlx5hws_matcher * matcher)143 static int hws_matcher_disconnect(struct mlx5hws_matcher *matcher)
144 {
145 	struct mlx5hws_matcher *next = NULL, *prev = NULL;
146 	struct mlx5hws_table *tbl = matcher->tbl;
147 	u32 prev_ft_id = tbl->ft_id;
148 	int ret;
149 
150 	if (!list_is_first(&matcher->list_node, &tbl->matchers_list)) {
151 		prev = list_prev_entry(matcher, list_node);
152 		prev_ft_id = prev->end_ft_id;
153 	}
154 
155 	if (!list_is_last(&matcher->list_node, &tbl->matchers_list))
156 		next = list_next_entry(matcher, list_node);
157 
158 	list_del_init(&matcher->list_node);
159 
160 	if (next) {
161 		/* Connect previous end FT to next RTC */
162 		ret = mlx5hws_table_ft_set_next_rtc(tbl->ctx,
163 						    prev_ft_id,
164 						    tbl->fw_ft_type,
165 						    next->match_ste.rtc_0_id,
166 						    next->match_ste.rtc_1_id);
167 		if (ret) {
168 			mlx5hws_err(tbl->ctx, "Fatal error, failed to disconnect matcher\n");
169 			return ret;
170 		}
171 	} else {
172 		ret = mlx5hws_table_connect_to_miss_table(tbl, tbl->default_miss.miss_tbl);
173 		if (ret) {
174 			mlx5hws_err(tbl->ctx, "Fatal error, failed to disconnect last matcher\n");
175 			return ret;
176 		}
177 	}
178 
179 	/* Removing first matcher, update connected miss tables if exists */
180 	if (prev_ft_id == tbl->ft_id) {
181 		ret = mlx5hws_table_update_connected_miss_tables(tbl);
182 		if (ret) {
183 			mlx5hws_err(tbl->ctx,
184 				    "Fatal error, failed to update connected miss table\n");
185 			return ret;
186 		}
187 	}
188 
189 	ret = mlx5hws_table_ft_set_default_next_ft(tbl, prev_ft_id);
190 	if (ret) {
191 		mlx5hws_err(tbl->ctx, "Fatal error, failed to restore matcher ft default miss\n");
192 		return ret;
193 	}
194 
195 	return 0;
196 }
197 
hws_matcher_set_rtc_attr_sz(struct mlx5hws_matcher * matcher,struct mlx5hws_cmd_rtc_create_attr * rtc_attr,enum mlx5hws_matcher_rtc_type rtc_type,bool is_mirror)198 static void hws_matcher_set_rtc_attr_sz(struct mlx5hws_matcher *matcher,
199 					struct mlx5hws_cmd_rtc_create_attr *rtc_attr,
200 					enum mlx5hws_matcher_rtc_type rtc_type,
201 					bool is_mirror)
202 {
203 	struct mlx5hws_pool_chunk *ste = &matcher->action_ste.ste;
204 	enum mlx5hws_matcher_flow_src flow_src = matcher->attr.optimize_flow_src;
205 	bool is_match_rtc = rtc_type == HWS_MATCHER_RTC_TYPE_MATCH;
206 
207 	if ((flow_src == MLX5HWS_MATCHER_FLOW_SRC_VPORT && !is_mirror) ||
208 	    (flow_src == MLX5HWS_MATCHER_FLOW_SRC_WIRE && is_mirror)) {
209 		/* Optimize FDB RTC */
210 		rtc_attr->log_size = 0;
211 		rtc_attr->log_depth = 0;
212 	} else {
213 		/* Keep original values */
214 		rtc_attr->log_size = is_match_rtc ? matcher->attr.table.sz_row_log : ste->order;
215 		rtc_attr->log_depth = is_match_rtc ? matcher->attr.table.sz_col_log : 0;
216 	}
217 }
218 
hws_matcher_create_rtc(struct mlx5hws_matcher * matcher,enum mlx5hws_matcher_rtc_type rtc_type)219 static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
220 				  enum mlx5hws_matcher_rtc_type rtc_type)
221 {
222 	struct mlx5hws_matcher_attr *attr = &matcher->attr;
223 	struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0};
224 	struct mlx5hws_match_template *mt = matcher->mt;
225 	struct mlx5hws_context *ctx = matcher->tbl->ctx;
226 	struct mlx5hws_action_default_stc *default_stc;
227 	struct mlx5hws_matcher_action_ste *action_ste;
228 	struct mlx5hws_table *tbl = matcher->tbl;
229 	struct mlx5hws_pool *ste_pool, *stc_pool;
230 	struct mlx5hws_pool_chunk *ste;
231 	u32 *rtc_0_id, *rtc_1_id;
232 	u32 obj_id;
233 	int ret;
234 
235 	switch (rtc_type) {
236 	case HWS_MATCHER_RTC_TYPE_MATCH:
237 		rtc_0_id = &matcher->match_ste.rtc_0_id;
238 		rtc_1_id = &matcher->match_ste.rtc_1_id;
239 		ste_pool = matcher->match_ste.pool;
240 		ste = &matcher->match_ste.ste;
241 		ste->order = attr->table.sz_col_log + attr->table.sz_row_log;
242 
243 		rtc_attr.log_size = attr->table.sz_row_log;
244 		rtc_attr.log_depth = attr->table.sz_col_log;
245 		rtc_attr.is_frst_jumbo = mlx5hws_matcher_mt_is_jumbo(mt);
246 		rtc_attr.is_scnd_range = 0;
247 		rtc_attr.miss_ft_id = matcher->end_ft_id;
248 
249 		if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_HASH) {
250 			/* The usual Hash Table */
251 			rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH;
252 
253 			/* The first mt is used since all share the same definer */
254 			rtc_attr.match_definer_0 = mlx5hws_definer_get_id(mt->definer);
255 		} else if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX) {
256 			rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET;
257 			rtc_attr.num_hash_definer = 1;
258 
259 			if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) {
260 				/* Hash Split Table */
261 				rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH;
262 				rtc_attr.match_definer_0 = mlx5hws_definer_get_id(mt->definer);
263 			} else if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_LINEAR) {
264 				/* Linear Lookup Table */
265 				rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR;
266 				rtc_attr.match_definer_0 = ctx->caps->linear_match_definer;
267 			}
268 		}
269 
270 		/* Match pool requires implicit allocation */
271 		ret = mlx5hws_pool_chunk_alloc(ste_pool, ste);
272 		if (ret) {
273 			mlx5hws_err(ctx, "Failed to allocate STE for %s RTC",
274 				    hws_matcher_rtc_type_to_str(rtc_type));
275 			return ret;
276 		}
277 		break;
278 
279 	case HWS_MATCHER_RTC_TYPE_STE_ARRAY:
280 		action_ste = &matcher->action_ste;
281 
282 		rtc_0_id = &action_ste->rtc_0_id;
283 		rtc_1_id = &action_ste->rtc_1_id;
284 		ste_pool = action_ste->pool;
285 		ste = &action_ste->ste;
286 		/* Action RTC size calculation:
287 		 * log((max number of rules in matcher) *
288 		 *     (max number of action STEs per rule) *
289 		 *     (2 to support writing new STEs for update rule))
290 		 */
291 		ste->order = ilog2(roundup_pow_of_two(action_ste->max_stes)) +
292 			     attr->table.sz_row_log +
293 			     MLX5HWS_MATCHER_ACTION_RTC_UPDATE_MULT;
294 		rtc_attr.log_size = ste->order;
295 		rtc_attr.log_depth = 0;
296 		rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET;
297 		/* The action STEs use the default always hit definer */
298 		rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer;
299 		rtc_attr.is_frst_jumbo = false;
300 		rtc_attr.miss_ft_id = 0;
301 		break;
302 
303 	default:
304 		mlx5hws_err(ctx, "HWS Invalid RTC type\n");
305 		return -EINVAL;
306 	}
307 
308 	obj_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste);
309 
310 	rtc_attr.pd = ctx->pd_num;
311 	rtc_attr.ste_base = obj_id;
312 	rtc_attr.ste_offset = ste->offset;
313 	rtc_attr.reparse_mode = mlx5hws_context_get_reparse_mode(ctx);
314 	rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(tbl->type, false);
315 	hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, false);
316 
317 	/* STC is a single resource (obj_id), use any STC for the ID */
318 	stc_pool = ctx->stc_pool;
319 	default_stc = ctx->common_res.default_stc;
320 	obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit);
321 	rtc_attr.stc_base = obj_id;
322 
323 	ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_0_id);
324 	if (ret) {
325 		mlx5hws_err(ctx, "Failed to create matcher RTC of type %s",
326 			    hws_matcher_rtc_type_to_str(rtc_type));
327 		goto free_ste;
328 	}
329 
330 	if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) {
331 		obj_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste);
332 		rtc_attr.ste_base = obj_id;
333 		rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(tbl->type, true);
334 
335 		obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, &default_stc->default_hit);
336 		rtc_attr.stc_base = obj_id;
337 		hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, true);
338 
339 		ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_1_id);
340 		if (ret) {
341 			mlx5hws_err(ctx, "Failed to create peer matcher RTC of type %s",
342 				    hws_matcher_rtc_type_to_str(rtc_type));
343 			goto destroy_rtc_0;
344 		}
345 	}
346 
347 	return 0;
348 
349 destroy_rtc_0:
350 	mlx5hws_cmd_rtc_destroy(ctx->mdev, *rtc_0_id);
351 free_ste:
352 	if (rtc_type == HWS_MATCHER_RTC_TYPE_MATCH)
353 		mlx5hws_pool_chunk_free(ste_pool, ste);
354 	return ret;
355 }
356 
hws_matcher_destroy_rtc(struct mlx5hws_matcher * matcher,enum mlx5hws_matcher_rtc_type rtc_type)357 static void hws_matcher_destroy_rtc(struct mlx5hws_matcher *matcher,
358 				    enum mlx5hws_matcher_rtc_type rtc_type)
359 {
360 	struct mlx5hws_matcher_action_ste *action_ste;
361 	struct mlx5hws_table *tbl = matcher->tbl;
362 	struct mlx5hws_pool_chunk *ste;
363 	struct mlx5hws_pool *ste_pool;
364 	u32 rtc_0_id, rtc_1_id;
365 
366 	switch (rtc_type) {
367 	case HWS_MATCHER_RTC_TYPE_MATCH:
368 		rtc_0_id = matcher->match_ste.rtc_0_id;
369 		rtc_1_id = matcher->match_ste.rtc_1_id;
370 		ste_pool = matcher->match_ste.pool;
371 		ste = &matcher->match_ste.ste;
372 		break;
373 	case HWS_MATCHER_RTC_TYPE_STE_ARRAY:
374 		action_ste = &matcher->action_ste;
375 		rtc_0_id = action_ste->rtc_0_id;
376 		rtc_1_id = action_ste->rtc_1_id;
377 		ste_pool = action_ste->pool;
378 		ste = &action_ste->ste;
379 		break;
380 	default:
381 		return;
382 	}
383 
384 	if (tbl->type == MLX5HWS_TABLE_TYPE_FDB)
385 		mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_1_id);
386 
387 	mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_0_id);
388 	if (rtc_type == HWS_MATCHER_RTC_TYPE_MATCH)
389 		mlx5hws_pool_chunk_free(ste_pool, ste);
390 }
391 
392 static int
hws_matcher_check_attr_sz(struct mlx5hws_cmd_query_caps * caps,struct mlx5hws_matcher * matcher)393 hws_matcher_check_attr_sz(struct mlx5hws_cmd_query_caps *caps,
394 			  struct mlx5hws_matcher *matcher)
395 {
396 	struct mlx5hws_matcher_attr *attr = &matcher->attr;
397 
398 	if (attr->table.sz_col_log > caps->rtc_log_depth_max) {
399 		mlx5hws_err(matcher->tbl->ctx, "Matcher depth exceeds limit %d\n",
400 			    caps->rtc_log_depth_max);
401 		return -EOPNOTSUPP;
402 	}
403 
404 	if (attr->table.sz_col_log + attr->table.sz_row_log > caps->ste_alloc_log_max) {
405 		mlx5hws_err(matcher->tbl->ctx, "Total matcher size exceeds limit %d\n",
406 			    caps->ste_alloc_log_max);
407 		return -EOPNOTSUPP;
408 	}
409 
410 	if (attr->table.sz_col_log + attr->table.sz_row_log < caps->ste_alloc_log_gran) {
411 		mlx5hws_err(matcher->tbl->ctx, "Total matcher size below limit %d\n",
412 			    caps->ste_alloc_log_gran);
413 		return -EOPNOTSUPP;
414 	}
415 
416 	return 0;
417 }
418 
hws_matcher_set_pool_attr(struct mlx5hws_pool_attr * attr,struct mlx5hws_matcher * matcher)419 static void hws_matcher_set_pool_attr(struct mlx5hws_pool_attr *attr,
420 				      struct mlx5hws_matcher *matcher)
421 {
422 	switch (matcher->attr.optimize_flow_src) {
423 	case MLX5HWS_MATCHER_FLOW_SRC_VPORT:
424 		attr->opt_type = MLX5HWS_POOL_OPTIMIZE_ORIG;
425 		break;
426 	case MLX5HWS_MATCHER_FLOW_SRC_WIRE:
427 		attr->opt_type = MLX5HWS_POOL_OPTIMIZE_MIRROR;
428 		break;
429 	default:
430 		break;
431 	}
432 }
433 
hws_matcher_check_and_process_at(struct mlx5hws_matcher * matcher,struct mlx5hws_action_template * at)434 static int hws_matcher_check_and_process_at(struct mlx5hws_matcher *matcher,
435 					    struct mlx5hws_action_template *at)
436 {
437 	struct mlx5hws_context *ctx = matcher->tbl->ctx;
438 	bool valid;
439 	int ret;
440 
441 	valid = mlx5hws_action_check_combo(ctx, at->action_type_arr, matcher->tbl->type);
442 	if (!valid) {
443 		mlx5hws_err(ctx, "Invalid combination in action template\n");
444 		return -EINVAL;
445 	}
446 
447 	/* Process action template to setters */
448 	ret = mlx5hws_action_template_process(at);
449 	if (ret) {
450 		mlx5hws_err(ctx, "Failed to process action template\n");
451 		return ret;
452 	}
453 
454 	return 0;
455 }
456 
hws_matcher_resize_init(struct mlx5hws_matcher * src_matcher)457 static int hws_matcher_resize_init(struct mlx5hws_matcher *src_matcher)
458 {
459 	struct mlx5hws_matcher_resize_data *resize_data;
460 
461 	resize_data = kzalloc(sizeof(*resize_data), GFP_KERNEL);
462 	if (!resize_data)
463 		return -ENOMEM;
464 
465 	resize_data->max_stes = src_matcher->action_ste.max_stes;
466 
467 	resize_data->stc = src_matcher->action_ste.stc;
468 	resize_data->rtc_0_id = src_matcher->action_ste.rtc_0_id;
469 	resize_data->rtc_1_id = src_matcher->action_ste.rtc_1_id;
470 	resize_data->pool = src_matcher->action_ste.max_stes ?
471 			    src_matcher->action_ste.pool : NULL;
472 
473 	/* Place the new resized matcher on the dst matcher's list */
474 	list_add(&resize_data->list_node, &src_matcher->resize_dst->resize_data);
475 
476 	/* Move all the previous resized matchers to the dst matcher's list */
477 	while (!list_empty(&src_matcher->resize_data)) {
478 		resize_data = list_first_entry(&src_matcher->resize_data,
479 					       struct mlx5hws_matcher_resize_data,
480 					       list_node);
481 		list_del_init(&resize_data->list_node);
482 		list_add(&resize_data->list_node, &src_matcher->resize_dst->resize_data);
483 	}
484 
485 	return 0;
486 }
487 
hws_matcher_resize_uninit(struct mlx5hws_matcher * matcher)488 static void hws_matcher_resize_uninit(struct mlx5hws_matcher *matcher)
489 {
490 	struct mlx5hws_matcher_resize_data *resize_data;
491 
492 	if (!mlx5hws_matcher_is_resizable(matcher))
493 		return;
494 
495 	while (!list_empty(&matcher->resize_data)) {
496 		resize_data = list_first_entry(&matcher->resize_data,
497 					       struct mlx5hws_matcher_resize_data,
498 					       list_node);
499 		list_del_init(&resize_data->list_node);
500 
501 		if (resize_data->max_stes) {
502 			mlx5hws_action_free_single_stc(matcher->tbl->ctx,
503 						       matcher->tbl->type,
504 						       &resize_data->stc);
505 
506 			if (matcher->tbl->type == MLX5HWS_TABLE_TYPE_FDB)
507 				mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev,
508 							resize_data->rtc_1_id);
509 
510 			mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev,
511 						resize_data->rtc_0_id);
512 
513 			if (resize_data->pool)
514 				mlx5hws_pool_destroy(resize_data->pool);
515 		}
516 
517 		kfree(resize_data);
518 	}
519 }
520 
hws_matcher_bind_at(struct mlx5hws_matcher * matcher)521 static int hws_matcher_bind_at(struct mlx5hws_matcher *matcher)
522 {
523 	bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt);
524 	struct mlx5hws_cmd_stc_modify_attr stc_attr = {0};
525 	struct mlx5hws_matcher_action_ste *action_ste;
526 	struct mlx5hws_table *tbl = matcher->tbl;
527 	struct mlx5hws_pool_attr pool_attr = {0};
528 	struct mlx5hws_context *ctx = tbl->ctx;
529 	u32 required_stes;
530 	u8 max_stes = 0;
531 	int i, ret;
532 
533 	if (matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)
534 		return 0;
535 
536 	for (i = 0; i < matcher->num_of_at; i++) {
537 		struct mlx5hws_action_template *at = &matcher->at[i];
538 
539 		ret = hws_matcher_check_and_process_at(matcher, at);
540 		if (ret) {
541 			mlx5hws_err(ctx, "Invalid at %d", i);
542 			return ret;
543 		}
544 
545 		required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term);
546 		max_stes = max(max_stes, required_stes);
547 
548 		/* Future: Optimize reparse */
549 	}
550 
551 	/* There are no additional STEs required for matcher */
552 	if (!max_stes)
553 		return 0;
554 
555 	matcher->action_ste.max_stes = max_stes;
556 
557 	action_ste = &matcher->action_ste;
558 
559 	/* Allocate action STE mempool */
560 	pool_attr.table_type = tbl->type;
561 	pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE;
562 	pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL;
563 	/* Pool size is similar to action RTC size */
564 	pool_attr.alloc_log_sz = ilog2(roundup_pow_of_two(action_ste->max_stes)) +
565 				 matcher->attr.table.sz_row_log +
566 				 MLX5HWS_MATCHER_ACTION_RTC_UPDATE_MULT;
567 	hws_matcher_set_pool_attr(&pool_attr, matcher);
568 	action_ste->pool = mlx5hws_pool_create(ctx, &pool_attr);
569 	if (!action_ste->pool) {
570 		mlx5hws_err(ctx, "Failed to create action ste pool\n");
571 		return -EINVAL;
572 	}
573 
574 	/* Allocate action RTC */
575 	ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY);
576 	if (ret) {
577 		mlx5hws_err(ctx, "Failed to create action RTC\n");
578 		goto free_ste_pool;
579 	}
580 
581 	/* Allocate STC for jumps to STE */
582 	stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT;
583 	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE;
584 	stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE;
585 	stc_attr.ste_table.ste = action_ste->ste;
586 	stc_attr.ste_table.ste_pool = action_ste->pool;
587 	stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer;
588 
589 	ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl->type,
590 					      &action_ste->stc);
591 	if (ret) {
592 		mlx5hws_err(ctx, "Failed to create action jump to table STC\n");
593 		goto free_rtc;
594 	}
595 
596 	return 0;
597 
598 free_rtc:
599 	hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY);
600 free_ste_pool:
601 	mlx5hws_pool_destroy(action_ste->pool);
602 	return ret;
603 }
604 
hws_matcher_unbind_at(struct mlx5hws_matcher * matcher)605 static void hws_matcher_unbind_at(struct mlx5hws_matcher *matcher)
606 {
607 	struct mlx5hws_matcher_action_ste *action_ste;
608 	struct mlx5hws_table *tbl = matcher->tbl;
609 
610 	action_ste = &matcher->action_ste;
611 
612 	if (!action_ste->max_stes ||
613 	    matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION ||
614 	    mlx5hws_matcher_is_in_resize(matcher))
615 		return;
616 
617 	mlx5hws_action_free_single_stc(tbl->ctx, tbl->type, &action_ste->stc);
618 	hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY);
619 	mlx5hws_pool_destroy(action_ste->pool);
620 }
621 
hws_matcher_bind_mt(struct mlx5hws_matcher * matcher)622 static int hws_matcher_bind_mt(struct mlx5hws_matcher *matcher)
623 {
624 	struct mlx5hws_context *ctx = matcher->tbl->ctx;
625 	struct mlx5hws_pool_attr pool_attr = {0};
626 	int ret;
627 
628 	/* Calculate match, range and hash definers */
629 	if (!(matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)) {
630 		ret = mlx5hws_definer_mt_init(ctx, matcher->mt);
631 		if (ret) {
632 			if (ret == -E2BIG)
633 				mlx5hws_err(ctx, "Failed to set matcher templates with match definers\n");
634 			return ret;
635 		}
636 	}
637 
638 	/* Create an STE pool per matcher*/
639 	pool_attr.table_type = matcher->tbl->type;
640 	pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE;
641 	pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_MATCHER_STE_POOL;
642 	pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log +
643 				 matcher->attr.table.sz_row_log;
644 	hws_matcher_set_pool_attr(&pool_attr, matcher);
645 
646 	matcher->match_ste.pool = mlx5hws_pool_create(ctx, &pool_attr);
647 	if (!matcher->match_ste.pool) {
648 		mlx5hws_err(ctx, "Failed to allocate matcher STE pool\n");
649 		ret = -EOPNOTSUPP;
650 		goto uninit_match_definer;
651 	}
652 
653 	return 0;
654 
655 uninit_match_definer:
656 	if (!(matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION))
657 		mlx5hws_definer_mt_uninit(ctx, matcher->mt);
658 	return ret;
659 }
660 
hws_matcher_unbind_mt(struct mlx5hws_matcher * matcher)661 static void hws_matcher_unbind_mt(struct mlx5hws_matcher *matcher)
662 {
663 	mlx5hws_pool_destroy(matcher->match_ste.pool);
664 	if (!(matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION))
665 		mlx5hws_definer_mt_uninit(matcher->tbl->ctx, matcher->mt);
666 }
667 
668 static int
hws_matcher_validate_insert_mode(struct mlx5hws_cmd_query_caps * caps,struct mlx5hws_matcher * matcher)669 hws_matcher_validate_insert_mode(struct mlx5hws_cmd_query_caps *caps,
670 				 struct mlx5hws_matcher *matcher)
671 {
672 	struct mlx5hws_matcher_attr *attr = &matcher->attr;
673 	struct mlx5hws_context *ctx = matcher->tbl->ctx;
674 
675 	switch (attr->insert_mode) {
676 	case MLX5HWS_MATCHER_INSERT_BY_HASH:
677 		if (matcher->attr.distribute_mode != MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) {
678 			mlx5hws_err(ctx, "Invalid matcher distribute mode\n");
679 			return -EOPNOTSUPP;
680 		}
681 		break;
682 
683 	case MLX5HWS_MATCHER_INSERT_BY_INDEX:
684 		if (attr->table.sz_col_log) {
685 			mlx5hws_err(ctx, "Matcher with INSERT_BY_INDEX supports only Nx1 table size\n");
686 			return -EOPNOTSUPP;
687 		}
688 
689 		if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) {
690 			/* Hash Split Table */
691 			if (!caps->rtc_hash_split_table) {
692 				mlx5hws_err(ctx, "FW doesn't support insert by index and hash distribute\n");
693 				return -EOPNOTSUPP;
694 			}
695 		} else if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_LINEAR) {
696 			/* Linear Lookup Table */
697 			if (!caps->rtc_linear_lookup_table ||
698 			    !IS_BIT_SET(caps->access_index_mode,
699 					MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR)) {
700 				mlx5hws_err(ctx, "FW doesn't support insert by index and linear distribute\n");
701 				return -EOPNOTSUPP;
702 			}
703 
704 			if (attr->table.sz_row_log > MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX) {
705 				mlx5hws_err(ctx, "Matcher with linear distribute: rows exceed limit %d",
706 					    MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX);
707 				return -EOPNOTSUPP;
708 			}
709 		} else {
710 			mlx5hws_err(ctx, "Matcher has unsupported distribute mode\n");
711 			return -EOPNOTSUPP;
712 		}
713 		break;
714 
715 	default:
716 		mlx5hws_err(ctx, "Matcher has unsupported insert mode\n");
717 		return -EOPNOTSUPP;
718 	}
719 
720 	return 0;
721 }
722 
723 static int
hws_matcher_process_attr(struct mlx5hws_cmd_query_caps * caps,struct mlx5hws_matcher * matcher)724 hws_matcher_process_attr(struct mlx5hws_cmd_query_caps *caps,
725 			 struct mlx5hws_matcher *matcher)
726 {
727 	struct mlx5hws_matcher_attr *attr = &matcher->attr;
728 
729 	if (hws_matcher_validate_insert_mode(caps, matcher))
730 		return -EOPNOTSUPP;
731 
732 	if (matcher->tbl->type != MLX5HWS_TABLE_TYPE_FDB && attr->optimize_flow_src) {
733 		mlx5hws_err(matcher->tbl->ctx, "NIC domain doesn't support flow_src\n");
734 		return -EOPNOTSUPP;
735 	}
736 
737 	/* Convert number of rules to the required depth */
738 	if (attr->mode == MLX5HWS_MATCHER_RESOURCE_MODE_RULE &&
739 	    attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_HASH)
740 		attr->table.sz_col_log = hws_matcher_rules_to_tbl_depth(attr->rule.num_log);
741 
742 	matcher->flags |= attr->resizable ? MLX5HWS_MATCHER_FLAGS_RESIZABLE : 0;
743 
744 	return hws_matcher_check_attr_sz(caps, matcher);
745 }
746 
hws_matcher_create_and_connect(struct mlx5hws_matcher * matcher)747 static int hws_matcher_create_and_connect(struct mlx5hws_matcher *matcher)
748 {
749 	int ret;
750 
751 	/* Select and create the definers for current matcher */
752 	ret = hws_matcher_bind_mt(matcher);
753 	if (ret)
754 		return ret;
755 
756 	/* Calculate and verify action combination */
757 	ret = hws_matcher_bind_at(matcher);
758 	if (ret)
759 		goto unbind_mt;
760 
761 	/* Create matcher end flow table anchor */
762 	ret = hws_matcher_create_end_ft(matcher);
763 	if (ret)
764 		goto unbind_at;
765 
766 	/* Allocate the RTC for the new matcher */
767 	ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH);
768 	if (ret)
769 		goto destroy_end_ft;
770 
771 	/* Connect the matcher to the matcher list */
772 	ret = hws_matcher_connect(matcher);
773 	if (ret)
774 		goto destroy_rtc;
775 
776 	return 0;
777 
778 destroy_rtc:
779 	hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH);
780 destroy_end_ft:
781 	hws_matcher_destroy_end_ft(matcher);
782 unbind_at:
783 	hws_matcher_unbind_at(matcher);
784 unbind_mt:
785 	hws_matcher_unbind_mt(matcher);
786 	return ret;
787 }
788 
hws_matcher_destroy_and_disconnect(struct mlx5hws_matcher * matcher)789 static void hws_matcher_destroy_and_disconnect(struct mlx5hws_matcher *matcher)
790 {
791 	hws_matcher_resize_uninit(matcher);
792 	hws_matcher_disconnect(matcher);
793 	hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH);
794 	hws_matcher_destroy_end_ft(matcher);
795 	hws_matcher_unbind_at(matcher);
796 	hws_matcher_unbind_mt(matcher);
797 }
798 
799 static int
hws_matcher_create_col_matcher(struct mlx5hws_matcher * matcher)800 hws_matcher_create_col_matcher(struct mlx5hws_matcher *matcher)
801 {
802 	struct mlx5hws_context *ctx = matcher->tbl->ctx;
803 	struct mlx5hws_matcher *col_matcher;
804 	int ret;
805 
806 	if (matcher->attr.mode != MLX5HWS_MATCHER_RESOURCE_MODE_RULE ||
807 	    matcher->attr.insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX)
808 		return 0;
809 
810 	if (!hws_matcher_requires_col_tbl(matcher->attr.rule.num_log))
811 		return 0;
812 
813 	col_matcher = kzalloc(sizeof(*matcher), GFP_KERNEL);
814 	if (!col_matcher)
815 		return -ENOMEM;
816 
817 	INIT_LIST_HEAD(&col_matcher->resize_data);
818 
819 	col_matcher->tbl = matcher->tbl;
820 	col_matcher->mt = matcher->mt;
821 	col_matcher->at = matcher->at;
822 	col_matcher->num_of_at = matcher->num_of_at;
823 	col_matcher->num_of_mt = matcher->num_of_mt;
824 	col_matcher->attr.priority = matcher->attr.priority;
825 	col_matcher->flags = matcher->flags;
826 	col_matcher->flags |= MLX5HWS_MATCHER_FLAGS_COLLISION;
827 	col_matcher->attr.mode = MLX5HWS_MATCHER_RESOURCE_MODE_HTABLE;
828 	col_matcher->attr.optimize_flow_src = matcher->attr.optimize_flow_src;
829 	col_matcher->attr.table.sz_row_log = matcher->attr.rule.num_log;
830 	col_matcher->attr.table.sz_col_log = MLX5HWS_MATCHER_ASSURED_COL_TBL_DEPTH;
831 	if (col_matcher->attr.table.sz_row_log > MLX5HWS_MATCHER_ASSURED_ROW_RATIO)
832 		col_matcher->attr.table.sz_row_log -= MLX5HWS_MATCHER_ASSURED_ROW_RATIO;
833 
834 	col_matcher->attr.max_num_of_at_attach = matcher->attr.max_num_of_at_attach;
835 
836 	ret = hws_matcher_process_attr(ctx->caps, col_matcher);
837 	if (ret)
838 		goto free_col_matcher;
839 
840 	ret = hws_matcher_create_and_connect(col_matcher);
841 	if (ret)
842 		goto free_col_matcher;
843 
844 	matcher->col_matcher = col_matcher;
845 
846 	return 0;
847 
848 free_col_matcher:
849 	kfree(col_matcher);
850 	mlx5hws_err(ctx, "Failed to create assured collision matcher\n");
851 	return ret;
852 }
853 
854 static void
hws_matcher_destroy_col_matcher(struct mlx5hws_matcher * matcher)855 hws_matcher_destroy_col_matcher(struct mlx5hws_matcher *matcher)
856 {
857 	if (matcher->attr.mode != MLX5HWS_MATCHER_RESOURCE_MODE_RULE ||
858 	    matcher->attr.insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX)
859 		return;
860 
861 	if (matcher->col_matcher) {
862 		hws_matcher_destroy_and_disconnect(matcher->col_matcher);
863 		kfree(matcher->col_matcher);
864 	}
865 }
866 
hws_matcher_init(struct mlx5hws_matcher * matcher)867 static int hws_matcher_init(struct mlx5hws_matcher *matcher)
868 {
869 	struct mlx5hws_context *ctx = matcher->tbl->ctx;
870 	int ret;
871 
872 	INIT_LIST_HEAD(&matcher->resize_data);
873 
874 	mutex_lock(&ctx->ctrl_lock);
875 
876 	/* Allocate matcher resource and connect to the packet pipe */
877 	ret = hws_matcher_create_and_connect(matcher);
878 	if (ret)
879 		goto unlock_err;
880 
881 	/* Create additional matcher for collision handling */
882 	ret = hws_matcher_create_col_matcher(matcher);
883 	if (ret)
884 		goto destory_and_disconnect;
885 	mutex_unlock(&ctx->ctrl_lock);
886 
887 	return 0;
888 
889 destory_and_disconnect:
890 	hws_matcher_destroy_and_disconnect(matcher);
891 unlock_err:
892 	mutex_unlock(&ctx->ctrl_lock);
893 	return ret;
894 }
895 
hws_matcher_uninit(struct mlx5hws_matcher * matcher)896 static int hws_matcher_uninit(struct mlx5hws_matcher *matcher)
897 {
898 	struct mlx5hws_context *ctx = matcher->tbl->ctx;
899 
900 	mutex_lock(&ctx->ctrl_lock);
901 	hws_matcher_destroy_col_matcher(matcher);
902 	hws_matcher_destroy_and_disconnect(matcher);
903 	mutex_unlock(&ctx->ctrl_lock);
904 
905 	return 0;
906 }
907 
mlx5hws_matcher_attach_at(struct mlx5hws_matcher * matcher,struct mlx5hws_action_template * at)908 int mlx5hws_matcher_attach_at(struct mlx5hws_matcher *matcher,
909 			      struct mlx5hws_action_template *at)
910 {
911 	bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt);
912 	struct mlx5hws_context *ctx = matcher->tbl->ctx;
913 	u32 required_stes;
914 	int ret;
915 
916 	if (!matcher->attr.max_num_of_at_attach) {
917 		mlx5hws_dbg(ctx, "Num of current at (%d) exceed allowed value\n",
918 			    matcher->num_of_at);
919 		return -EOPNOTSUPP;
920 	}
921 
922 	ret = hws_matcher_check_and_process_at(matcher, at);
923 	if (ret)
924 		return ret;
925 
926 	required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term);
927 	if (matcher->action_ste.max_stes < required_stes) {
928 		mlx5hws_dbg(ctx, "Required STEs [%d] exceeds initial action template STE [%d]\n",
929 			    required_stes, matcher->action_ste.max_stes);
930 		return -ENOMEM;
931 	}
932 
933 	matcher->at[matcher->num_of_at] = *at;
934 	matcher->num_of_at += 1;
935 	matcher->attr.max_num_of_at_attach -= 1;
936 
937 	if (matcher->col_matcher)
938 		matcher->col_matcher->num_of_at = matcher->num_of_at;
939 
940 	return 0;
941 }
942 
943 static int
hws_matcher_set_templates(struct mlx5hws_matcher * matcher,struct mlx5hws_match_template * mt[],u8 num_of_mt,struct mlx5hws_action_template * at[],u8 num_of_at)944 hws_matcher_set_templates(struct mlx5hws_matcher *matcher,
945 			  struct mlx5hws_match_template *mt[],
946 			  u8 num_of_mt,
947 			  struct mlx5hws_action_template *at[],
948 			  u8 num_of_at)
949 {
950 	struct mlx5hws_context *ctx = matcher->tbl->ctx;
951 	int ret = 0;
952 	int i;
953 
954 	if (!num_of_mt || !num_of_at) {
955 		mlx5hws_err(ctx, "Number of action/match template cannot be zero\n");
956 		return -EOPNOTSUPP;
957 	}
958 
959 	matcher->mt = kcalloc(num_of_mt, sizeof(*matcher->mt), GFP_KERNEL);
960 	if (!matcher->mt)
961 		return -ENOMEM;
962 
963 	matcher->at = kvcalloc(num_of_at + matcher->attr.max_num_of_at_attach,
964 			       sizeof(*matcher->at),
965 			       GFP_KERNEL);
966 	if (!matcher->at) {
967 		mlx5hws_err(ctx, "Failed to allocate action template array\n");
968 		ret = -ENOMEM;
969 		goto free_mt;
970 	}
971 
972 	for (i = 0; i < num_of_mt; i++)
973 		matcher->mt[i] = *mt[i];
974 
975 	for (i = 0; i < num_of_at; i++)
976 		matcher->at[i] = *at[i];
977 
978 	matcher->num_of_mt = num_of_mt;
979 	matcher->num_of_at = num_of_at;
980 
981 	return 0;
982 
983 free_mt:
984 	kfree(matcher->mt);
985 	return ret;
986 }
987 
988 static void
hws_matcher_unset_templates(struct mlx5hws_matcher * matcher)989 hws_matcher_unset_templates(struct mlx5hws_matcher *matcher)
990 {
991 	kvfree(matcher->at);
992 	kfree(matcher->mt);
993 }
994 
995 struct mlx5hws_matcher *
mlx5hws_matcher_create(struct mlx5hws_table * tbl,struct mlx5hws_match_template * mt[],u8 num_of_mt,struct mlx5hws_action_template * at[],u8 num_of_at,struct mlx5hws_matcher_attr * attr)996 mlx5hws_matcher_create(struct mlx5hws_table *tbl,
997 		       struct mlx5hws_match_template *mt[],
998 		       u8 num_of_mt,
999 		       struct mlx5hws_action_template *at[],
1000 		       u8 num_of_at,
1001 		       struct mlx5hws_matcher_attr *attr)
1002 {
1003 	struct mlx5hws_context *ctx = tbl->ctx;
1004 	struct mlx5hws_matcher *matcher;
1005 	int ret;
1006 
1007 	matcher = kzalloc(sizeof(*matcher), GFP_KERNEL);
1008 	if (!matcher)
1009 		return NULL;
1010 
1011 	matcher->tbl = tbl;
1012 	matcher->attr = *attr;
1013 
1014 	ret = hws_matcher_process_attr(tbl->ctx->caps, matcher);
1015 	if (ret)
1016 		goto free_matcher;
1017 
1018 	ret = hws_matcher_set_templates(matcher, mt, num_of_mt, at, num_of_at);
1019 	if (ret)
1020 		goto free_matcher;
1021 
1022 	ret = hws_matcher_init(matcher);
1023 	if (ret) {
1024 		mlx5hws_err(ctx, "Failed to initialise matcher: %d\n", ret);
1025 		goto unset_templates;
1026 	}
1027 
1028 	return matcher;
1029 
1030 unset_templates:
1031 	hws_matcher_unset_templates(matcher);
1032 free_matcher:
1033 	kfree(matcher);
1034 	return NULL;
1035 }
1036 
mlx5hws_matcher_destroy(struct mlx5hws_matcher * matcher)1037 int mlx5hws_matcher_destroy(struct mlx5hws_matcher *matcher)
1038 {
1039 	hws_matcher_uninit(matcher);
1040 	hws_matcher_unset_templates(matcher);
1041 	kfree(matcher);
1042 	return 0;
1043 }
1044 
1045 struct mlx5hws_match_template *
mlx5hws_match_template_create(struct mlx5hws_context * ctx,u32 * match_param,u32 match_param_sz,u8 match_criteria_enable)1046 mlx5hws_match_template_create(struct mlx5hws_context *ctx,
1047 			      u32 *match_param,
1048 			      u32 match_param_sz,
1049 			      u8 match_criteria_enable)
1050 {
1051 	struct mlx5hws_match_template *mt;
1052 
1053 	mt = kzalloc(sizeof(*mt), GFP_KERNEL);
1054 	if (!mt)
1055 		return NULL;
1056 
1057 	mt->match_param = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
1058 	if (!mt->match_param)
1059 		goto free_template;
1060 
1061 	memcpy(mt->match_param, match_param, match_param_sz);
1062 	mt->match_criteria_enable = match_criteria_enable;
1063 
1064 	return mt;
1065 
1066 free_template:
1067 	kfree(mt);
1068 	return NULL;
1069 }
1070 
mlx5hws_match_template_destroy(struct mlx5hws_match_template * mt)1071 int mlx5hws_match_template_destroy(struct mlx5hws_match_template *mt)
1072 {
1073 	kfree(mt->match_param);
1074 	kfree(mt);
1075 	return 0;
1076 }
1077 
hws_matcher_resize_precheck(struct mlx5hws_matcher * src_matcher,struct mlx5hws_matcher * dst_matcher)1078 static int hws_matcher_resize_precheck(struct mlx5hws_matcher *src_matcher,
1079 				       struct mlx5hws_matcher *dst_matcher)
1080 {
1081 	struct mlx5hws_context *ctx = src_matcher->tbl->ctx;
1082 	int i;
1083 
1084 	if (src_matcher->tbl->type != dst_matcher->tbl->type) {
1085 		mlx5hws_err(ctx, "Table type mismatch for src/dst matchers\n");
1086 		return -EINVAL;
1087 	}
1088 
1089 	if (!mlx5hws_matcher_is_resizable(src_matcher) ||
1090 	    !mlx5hws_matcher_is_resizable(dst_matcher)) {
1091 		mlx5hws_err(ctx, "Src/dst matcher is not resizable\n");
1092 		return -EINVAL;
1093 	}
1094 
1095 	if (mlx5hws_matcher_is_insert_by_idx(src_matcher) !=
1096 	    mlx5hws_matcher_is_insert_by_idx(dst_matcher)) {
1097 		mlx5hws_err(ctx, "Src/dst matchers insert mode mismatch\n");
1098 		return -EINVAL;
1099 	}
1100 
1101 	if (mlx5hws_matcher_is_in_resize(src_matcher) ||
1102 	    mlx5hws_matcher_is_in_resize(dst_matcher)) {
1103 		mlx5hws_err(ctx, "Src/dst matcher is already in resize\n");
1104 		return -EINVAL;
1105 	}
1106 
1107 	/* Compare match templates - make sure the definers are equivalent */
1108 	if (src_matcher->num_of_mt != dst_matcher->num_of_mt) {
1109 		mlx5hws_err(ctx, "Src/dst matcher match templates mismatch\n");
1110 		return -EINVAL;
1111 	}
1112 
1113 	if (src_matcher->action_ste.max_stes > dst_matcher->action_ste.max_stes) {
1114 		mlx5hws_err(ctx, "Src/dst matcher max STEs mismatch\n");
1115 		return -EINVAL;
1116 	}
1117 
1118 	for (i = 0; i < src_matcher->num_of_mt; i++) {
1119 		if (mlx5hws_definer_compare(src_matcher->mt[i].definer,
1120 					    dst_matcher->mt[i].definer)) {
1121 			mlx5hws_err(ctx, "Src/dst matcher definers mismatch\n");
1122 			return -EINVAL;
1123 		}
1124 	}
1125 
1126 	return 0;
1127 }
1128 
mlx5hws_matcher_resize_set_target(struct mlx5hws_matcher * src_matcher,struct mlx5hws_matcher * dst_matcher)1129 int mlx5hws_matcher_resize_set_target(struct mlx5hws_matcher *src_matcher,
1130 				      struct mlx5hws_matcher *dst_matcher)
1131 {
1132 	int ret = 0;
1133 
1134 	mutex_lock(&src_matcher->tbl->ctx->ctrl_lock);
1135 
1136 	ret = hws_matcher_resize_precheck(src_matcher, dst_matcher);
1137 	if (ret)
1138 		goto out;
1139 
1140 	src_matcher->resize_dst = dst_matcher;
1141 
1142 	ret = hws_matcher_resize_init(src_matcher);
1143 	if (ret)
1144 		src_matcher->resize_dst = NULL;
1145 
1146 out:
1147 	mutex_unlock(&src_matcher->tbl->ctx->ctrl_lock);
1148 	return ret;
1149 }
1150 
mlx5hws_matcher_resize_rule_move(struct mlx5hws_matcher * src_matcher,struct mlx5hws_rule * rule,struct mlx5hws_rule_attr * attr)1151 int mlx5hws_matcher_resize_rule_move(struct mlx5hws_matcher *src_matcher,
1152 				     struct mlx5hws_rule *rule,
1153 				     struct mlx5hws_rule_attr *attr)
1154 {
1155 	struct mlx5hws_context *ctx = src_matcher->tbl->ctx;
1156 
1157 	if (unlikely(!mlx5hws_matcher_is_in_resize(src_matcher))) {
1158 		mlx5hws_err(ctx, "Matcher is not resizable or not in resize\n");
1159 		return -EINVAL;
1160 	}
1161 
1162 	if (unlikely(src_matcher != rule->matcher)) {
1163 		mlx5hws_err(ctx, "Rule doesn't belong to src matcher\n");
1164 		return -EINVAL;
1165 	}
1166 
1167 	return mlx5hws_rule_move_hws_add(rule, attr);
1168 }
1169