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