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