Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2023 NVIDIA Corporation & Affiliates
3 : : */
4 : :
5 : : #include "mlx5dr_internal.h"
6 : :
7 : : static uint16_t mlx5dr_bwc_queues(struct mlx5dr_context *ctx)
8 : : {
9 : 0 : return (ctx->queues - 1) / 2;
10 : : }
11 : :
12 : : static uint16_t
13 : : mlx5dr_bwc_gen_queue_idx(struct mlx5dr_context *ctx)
14 : : {
15 : : /* assign random queue */
16 : 0 : return rand() % mlx5dr_bwc_queues(ctx);
17 : : }
18 : :
19 : : static uint16_t
20 : : mlx5dr_bwc_get_queue_id(struct mlx5dr_context *ctx, uint16_t idx)
21 : : {
22 : 0 : return idx + mlx5dr_bwc_queues(ctx);
23 : : }
24 : :
25 : : static uint16_t
26 : : mlx5dr_bwc_get_burst_th(struct mlx5dr_context *ctx, uint16_t queue_id)
27 : : {
28 : 0 : return RTE_MIN(ctx->send_queue[queue_id].num_entries / 2,
29 : : MLX5DR_BWC_MATCHER_REHASH_BURST_TH);
30 : : }
31 : :
32 : : static rte_spinlock_t *
33 : : mlx5dr_bwc_get_queue_lock(struct mlx5dr_context *ctx, uint16_t idx)
34 : : {
35 : 0 : return &ctx->bwc_send_queue_locks[idx];
36 : : }
37 : :
38 : 0 : static void mlx5dr_bwc_lock_all_queues(struct mlx5dr_context *ctx)
39 : : {
40 : : uint16_t bwc_queues = mlx5dr_bwc_queues(ctx);
41 : : rte_spinlock_t *queue_lock;
42 : : int i;
43 : :
44 [ # # ]: 0 : for (i = 0; i < bwc_queues; i++) {
45 : 0 : queue_lock = mlx5dr_bwc_get_queue_lock(ctx, i);
46 : : rte_spinlock_lock(queue_lock);
47 : : }
48 : 0 : }
49 : :
50 : : static void mlx5dr_bwc_unlock_all_queues(struct mlx5dr_context *ctx)
51 : : {
52 : : uint16_t bwc_queues = mlx5dr_bwc_queues(ctx);
53 : : rte_spinlock_t *queue_lock;
54 : : int i;
55 : :
56 [ # # # # : 0 : for (i = 0; i < bwc_queues; i++) {
# # # # #
# ]
57 : : queue_lock = mlx5dr_bwc_get_queue_lock(ctx, i);
58 : : rte_spinlock_unlock(queue_lock);
59 : : }
60 : : }
61 : :
62 : : static void mlx5dr_bwc_matcher_init_attr(struct mlx5dr_matcher_attr *attr,
63 : : uint32_t priority,
64 : : uint8_t size_log,
65 : : bool is_root)
66 : : {
67 : : memset(attr, 0, sizeof(*attr));
68 : :
69 : 0 : attr->priority = priority;
70 : : attr->optimize_using_rule_idx = 0;
71 : : attr->mode = MLX5DR_MATCHER_RESOURCE_MODE_RULE;
72 : : attr->optimize_flow_src = MLX5DR_MATCHER_FLOW_SRC_ANY;
73 : : attr->insert_mode = MLX5DR_MATCHER_INSERT_BY_HASH;
74 : : attr->distribute_mode = MLX5DR_MATCHER_DISTRIBUTE_BY_HASH;
75 : 0 : attr->rule.num_log = size_log;
76 : :
77 [ # # ]: 0 : if (!is_root) {
78 : 0 : attr->resizable = true;
79 : 0 : attr->max_num_of_at_attach = MLX5DR_BWC_MATCHER_ATTACH_AT_NUM;
80 : : }
81 : : }
82 : :
83 : : struct mlx5dr_bwc_matcher *
84 : 0 : mlx5dr_bwc_matcher_create(struct mlx5dr_table *table,
85 : : uint32_t priority,
86 : : const struct rte_flow_item flow_items[])
87 : : {
88 : 0 : enum mlx5dr_action_type init_action_types[1] = { MLX5DR_ACTION_TYP_LAST };
89 : 0 : uint16_t bwc_queues = mlx5dr_bwc_queues(table->ctx);
90 : : struct mlx5dr_bwc_matcher *bwc_matcher;
91 [ # # ]: 0 : struct mlx5dr_matcher_attr attr = {0};
92 : : int i;
93 : :
94 [ # # ]: 0 : if (!mlx5dr_context_bwc_supported(table->ctx)) {
95 : 0 : rte_errno = EINVAL;
96 : 0 : DR_LOG(ERR, "BWC rule: Context created w/o BWC API compatibility");
97 : 0 : return NULL;
98 : : }
99 : :
100 : : bwc_matcher = simple_calloc(1, sizeof(*bwc_matcher));
101 [ # # ]: 0 : if (!bwc_matcher) {
102 : 0 : rte_errno = ENOMEM;
103 : 0 : return NULL;
104 : : }
105 : :
106 : 0 : bwc_matcher->rules = simple_calloc(bwc_queues, sizeof(*bwc_matcher->rules));
107 [ # # ]: 0 : if (!bwc_matcher->rules) {
108 : 0 : rte_errno = ENOMEM;
109 : 0 : goto free_bwc_matcher;
110 : : }
111 : :
112 [ # # ]: 0 : for (i = 0; i < bwc_queues; i++)
113 : 0 : LIST_INIT(&bwc_matcher->rules[i]);
114 : :
115 : : mlx5dr_bwc_matcher_init_attr(&attr,
116 : : priority,
117 : : MLX5DR_BWC_MATCHER_INIT_SIZE_LOG,
118 : : mlx5dr_table_is_root(table));
119 : :
120 : 0 : bwc_matcher->mt = mlx5dr_match_template_create(flow_items,
121 : : MLX5DR_MATCH_TEMPLATE_FLAG_NONE);
122 [ # # ]: 0 : if (!bwc_matcher->mt) {
123 : 0 : rte_errno = EINVAL;
124 : 0 : goto free_bwc_matcher_rules;
125 : : }
126 : :
127 : 0 : bwc_matcher->priority = priority;
128 : 0 : bwc_matcher->size_log = MLX5DR_BWC_MATCHER_INIT_SIZE_LOG;
129 : :
130 : : /* create dummy action template */
131 : 0 : bwc_matcher->at[0] = mlx5dr_action_template_create(init_action_types, 0);
132 : 0 : bwc_matcher->num_of_at = 1;
133 : :
134 : 0 : bwc_matcher->matcher = mlx5dr_matcher_create(table,
135 : : &bwc_matcher->mt, 1,
136 : : &bwc_matcher->at[0],
137 : : bwc_matcher->num_of_at,
138 : : &attr);
139 [ # # ]: 0 : if (!bwc_matcher->matcher) {
140 : 0 : rte_errno = EINVAL;
141 : 0 : goto free_at;
142 : : }
143 : :
144 : : return bwc_matcher;
145 : :
146 : : free_at:
147 : 0 : mlx5dr_action_template_destroy(bwc_matcher->at[0]);
148 : 0 : mlx5dr_match_template_destroy(bwc_matcher->mt);
149 : 0 : free_bwc_matcher_rules:
150 : 0 : simple_free(bwc_matcher->rules);
151 : 0 : free_bwc_matcher:
152 : : simple_free(bwc_matcher);
153 : :
154 : 0 : return NULL;
155 : : }
156 : :
157 : 0 : int mlx5dr_bwc_matcher_destroy(struct mlx5dr_bwc_matcher *bwc_matcher)
158 : : {
159 : : int i;
160 : :
161 [ # # ]: 0 : if (bwc_matcher->num_of_rules)
162 : 0 : DR_LOG(ERR, "BWC matcher destroy: matcher still has %d rules",
163 : : bwc_matcher->num_of_rules);
164 : :
165 : 0 : mlx5dr_matcher_destroy(bwc_matcher->matcher);
166 : 0 : bwc_matcher->matcher = NULL;
167 : :
168 [ # # ]: 0 : for (i = 0; i < bwc_matcher->num_of_at; i++)
169 : 0 : mlx5dr_action_template_destroy(bwc_matcher->at[i]);
170 : :
171 : 0 : mlx5dr_match_template_destroy(bwc_matcher->mt);
172 : 0 : simple_free(bwc_matcher->rules);
173 : : simple_free(bwc_matcher);
174 : :
175 : 0 : return 0;
176 : : }
177 : :
178 : : static int
179 : 0 : mlx5dr_bwc_queue_poll(struct mlx5dr_context *ctx,
180 : : uint16_t queue_id,
181 : : uint32_t *pending_rules,
182 : : bool drain)
183 : : {
184 : : struct rte_flow_op_result comp[MLX5DR_BWC_MATCHER_REHASH_BURST_TH];
185 : 0 : uint16_t burst_th = mlx5dr_bwc_get_burst_th(ctx, queue_id);
186 : 0 : bool got_comp = *pending_rules >= burst_th;
187 : : bool queue_full;
188 : : int err = 0;
189 : : int ret;
190 : : int i;
191 : :
192 : : /* Check if there are any completions at all */
193 [ # # ]: 0 : if (!got_comp && !drain)
194 : : return 0;
195 : :
196 : : /* The FULL state of a SQ is always a subcondition of the original 'got_comp'. */
197 : : queue_full = mlx5dr_send_engine_full(&ctx->send_queue[queue_id]);
198 [ # # # # : 0 : while (queue_full || ((got_comp || drain) && *pending_rules)) {
# # ]
199 : 0 : ret = mlx5dr_send_queue_poll(ctx, queue_id, comp, burst_th);
200 [ # # ]: 0 : if (unlikely(ret < 0)) {
201 : 0 : DR_LOG(ERR, "Rehash error: polling queue %d returned %d\n",
202 : : queue_id, ret);
203 : 0 : return -EINVAL;
204 : : }
205 : :
206 [ # # ]: 0 : if (ret) {
207 : 0 : (*pending_rules) -= ret;
208 [ # # ]: 0 : for (i = 0; i < ret; i++) {
209 [ # # ]: 0 : if (unlikely(comp[i].status != RTE_FLOW_OP_SUCCESS)) {
210 : 0 : DR_LOG(ERR,
211 : : "Rehash error: polling queue %d returned completion with error\n",
212 : : queue_id);
213 : : err = -EINVAL;
214 : : }
215 : : }
216 : : queue_full = false;
217 : : }
218 : :
219 : 0 : got_comp = !!ret;
220 : : }
221 : :
222 : : return err;
223 : : }
224 : :
225 : : static void
226 : : mlx5dr_bwc_rule_fill_attr(struct mlx5dr_bwc_matcher *bwc_matcher,
227 : : uint16_t bwc_queue_idx,
228 : : struct mlx5dr_rule_attr *rule_attr)
229 : : {
230 : 0 : struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
231 : :
232 : : /* no use of INSERT_BY_INDEX in bwc rule */
233 : 0 : rule_attr->rule_idx = 0;
234 : :
235 : : /* notify HW at each rule insertion/deletion */
236 : 0 : rule_attr->burst = 0;
237 : :
238 : : /* We don't need user data, but the API requires it to exist */
239 : 0 : rule_attr->user_data = (void *)0xFACADE;
240 : :
241 : 0 : rule_attr->queue_id = mlx5dr_bwc_get_queue_id(ctx, bwc_queue_idx);
242 : : }
243 : :
244 : : static struct mlx5dr_bwc_rule *
245 : 0 : mlx5dr_bwc_rule_alloc(void)
246 : : {
247 : : struct mlx5dr_bwc_rule *bwc_rule;
248 : :
249 : : bwc_rule = simple_calloc(1, sizeof(*bwc_rule));
250 [ # # ]: 0 : if (unlikely(!bwc_rule))
251 : 0 : goto out_err;
252 : :
253 : 0 : bwc_rule->rule = simple_calloc(1, sizeof(*bwc_rule->rule));
254 [ # # ]: 0 : if (unlikely(!bwc_rule->rule))
255 : 0 : goto free_rule;
256 : :
257 : : return bwc_rule;
258 : :
259 : : free_rule:
260 : : simple_free(bwc_rule);
261 : 0 : out_err:
262 : 0 : rte_errno = ENOMEM;
263 : 0 : return NULL;
264 : : }
265 : :
266 : : static void
267 : 0 : mlx5dr_bwc_rule_free(struct mlx5dr_bwc_rule *bwc_rule)
268 : : {
269 [ # # ]: 0 : if (likely(bwc_rule->rule))
270 : : simple_free(bwc_rule->rule);
271 : : simple_free(bwc_rule);
272 : 0 : }
273 : :
274 : : static void
275 : 0 : mlx5dr_bwc_rule_list_add(struct mlx5dr_bwc_rule *bwc_rule, uint16_t idx)
276 : : {
277 : 0 : struct mlx5dr_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher;
278 : :
279 : 0 : rte_atomic_fetch_add_explicit(&bwc_matcher->num_of_rules, 1, rte_memory_order_relaxed);
280 : 0 : bwc_rule->bwc_queue_idx = idx;
281 [ # # ]: 0 : LIST_INSERT_HEAD(&bwc_matcher->rules[idx], bwc_rule, next);
282 : 0 : }
283 : :
284 : 0 : static void mlx5dr_bwc_rule_list_remove(struct mlx5dr_bwc_rule *bwc_rule)
285 : : {
286 : 0 : struct mlx5dr_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher;
287 : :
288 : 0 : rte_atomic_fetch_sub_explicit(&bwc_matcher->num_of_rules, 1, rte_memory_order_relaxed);
289 [ # # ]: 0 : LIST_REMOVE(bwc_rule, next);
290 : 0 : }
291 : :
292 : : static int
293 : : mlx5dr_bwc_rule_destroy_hws_async(struct mlx5dr_bwc_rule *bwc_rule,
294 : : struct mlx5dr_rule_attr *attr)
295 : : {
296 : 0 : return mlx5dr_rule_destroy(bwc_rule->rule, attr);
297 : : }
298 : :
299 : : static int
300 : 0 : mlx5dr_bwc_rule_destroy_hws_sync(struct mlx5dr_bwc_rule *bwc_rule,
301 : : struct mlx5dr_rule_attr *rule_attr)
302 : : {
303 : 0 : struct mlx5dr_context *ctx = bwc_rule->bwc_matcher->matcher->tbl->ctx;
304 : : struct rte_flow_op_result completion;
305 : : int ret;
306 : :
307 : : ret = mlx5dr_bwc_rule_destroy_hws_async(bwc_rule, rule_attr);
308 [ # # ]: 0 : if (unlikely(ret))
309 : : return ret;
310 : :
311 : : do {
312 : 0 : ret = mlx5dr_send_queue_poll(ctx, rule_attr->queue_id, &completion, 1);
313 [ # # ]: 0 : } while (ret != 1);
314 : :
315 [ # # # # ]: 0 : if (unlikely(completion.status != RTE_FLOW_OP_SUCCESS ||
316 : : (bwc_rule->rule->status != MLX5DR_RULE_STATUS_DELETED &&
317 : : bwc_rule->rule->status != MLX5DR_RULE_STATUS_DELETING))) {
318 : 0 : DR_LOG(ERR, "Failed destroying BWC rule: completion %d, rule status %d",
319 : : completion.status, bwc_rule->rule->status);
320 : 0 : rte_errno = EINVAL;
321 : 0 : return rte_errno;
322 : : }
323 : :
324 : : return 0;
325 : : }
326 : :
327 : 0 : static int mlx5dr_bwc_rule_destroy_hws(struct mlx5dr_bwc_rule *bwc_rule)
328 : : {
329 : 0 : struct mlx5dr_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher;
330 : 0 : struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
331 : 0 : uint16_t idx = bwc_rule->bwc_queue_idx;
332 : : struct mlx5dr_rule_attr attr;
333 : : rte_spinlock_t *queue_lock;
334 : : int ret;
335 : :
336 : : mlx5dr_bwc_rule_fill_attr(bwc_matcher, idx, &attr);
337 : :
338 : : queue_lock = mlx5dr_bwc_get_queue_lock(ctx, idx);
339 : :
340 : : rte_spinlock_lock(queue_lock);
341 : :
342 : 0 : ret = mlx5dr_bwc_rule_destroy_hws_sync(bwc_rule, &attr);
343 : 0 : mlx5dr_bwc_rule_list_remove(bwc_rule);
344 : :
345 : : rte_spinlock_unlock(queue_lock);
346 : :
347 : 0 : mlx5dr_bwc_rule_free(bwc_rule);
348 : :
349 : 0 : return ret;
350 : : }
351 : :
352 : : static int mlx5dr_bwc_rule_destroy_root(struct mlx5dr_bwc_rule *bwc_rule)
353 : : {
354 : : int ret;
355 : :
356 : 0 : ret = mlx5dr_rule_destroy_root_no_comp(bwc_rule->rule);
357 : :
358 : 0 : mlx5dr_bwc_rule_free(bwc_rule);
359 : :
360 : : return ret;
361 : : }
362 : :
363 : 0 : int mlx5dr_bwc_rule_destroy(struct mlx5dr_bwc_rule *bwc_rule)
364 : : {
365 [ # # ]: 0 : if (unlikely(mlx5dr_table_is_root(bwc_rule->bwc_matcher->matcher->tbl)))
366 : 0 : return mlx5dr_bwc_rule_destroy_root(bwc_rule);
367 : :
368 : 0 : return mlx5dr_bwc_rule_destroy_hws(bwc_rule);
369 : : }
370 : :
371 : : static struct mlx5dr_bwc_rule *
372 : 0 : mlx5dr_bwc_rule_create_hws_async(struct mlx5dr_bwc_matcher *bwc_matcher,
373 : : const struct rte_flow_item flow_items[],
374 : : uint8_t at_idx,
375 : : struct mlx5dr_rule_action rule_actions[],
376 : : struct mlx5dr_rule_attr *rule_attr)
377 : : {
378 : : struct mlx5dr_bwc_rule *bwc_rule;
379 : : int ret;
380 : :
381 : 0 : bwc_rule = mlx5dr_bwc_rule_alloc();
382 [ # # ]: 0 : if (unlikely(!bwc_rule))
383 : : return NULL;
384 : :
385 : 0 : bwc_rule->bwc_matcher = bwc_matcher;
386 : :
387 : 0 : ret = mlx5dr_rule_create(bwc_matcher->matcher,
388 : : 0, /* only one match template supported */
389 : : flow_items,
390 : : at_idx,
391 : : rule_actions,
392 : : rule_attr,
393 : : bwc_rule->rule);
394 : :
395 [ # # ]: 0 : if (unlikely(ret)) {
396 : 0 : mlx5dr_bwc_rule_free(bwc_rule);
397 : 0 : rte_errno = EINVAL;
398 : 0 : return NULL;
399 : : }
400 : :
401 : : return bwc_rule;
402 : : }
403 : :
404 : : static struct mlx5dr_bwc_rule *
405 : 0 : mlx5dr_bwc_rule_create_root_sync(struct mlx5dr_bwc_matcher *bwc_matcher,
406 : : const struct rte_flow_item flow_items[],
407 : : uint8_t num_actions,
408 : : struct mlx5dr_rule_action rule_actions[])
409 : : {
410 : : struct mlx5dr_bwc_rule *bwc_rule;
411 : : int ret;
412 : :
413 : 0 : bwc_rule = mlx5dr_bwc_rule_alloc();
414 [ # # ]: 0 : if (unlikely(!bwc_rule)) {
415 : 0 : rte_errno = ENOMEM;
416 : 0 : return NULL;
417 : : }
418 : :
419 : 0 : bwc_rule->bwc_matcher = bwc_matcher;
420 : 0 : bwc_rule->rule->matcher = bwc_matcher->matcher;
421 : :
422 : 0 : ret = mlx5dr_rule_create_root_no_comp(bwc_rule->rule,
423 : : flow_items,
424 : : num_actions,
425 : : rule_actions);
426 [ # # ]: 0 : if (unlikely(ret)) {
427 : 0 : mlx5dr_bwc_rule_free(bwc_rule);
428 : 0 : rte_errno = EINVAL;
429 : 0 : return NULL;
430 : : }
431 : :
432 : : return bwc_rule;
433 : : }
434 : :
435 : : static struct mlx5dr_bwc_rule *
436 : 0 : mlx5dr_bwc_rule_create_hws_sync(struct mlx5dr_bwc_matcher *bwc_matcher,
437 : : const struct rte_flow_item flow_items[],
438 : : uint8_t at_idx,
439 : : struct mlx5dr_rule_action rule_actions[],
440 : : struct mlx5dr_rule_attr *rule_attr)
441 : :
442 : : {
443 : 0 : struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
444 : : struct rte_flow_op_result completion;
445 : : struct mlx5dr_bwc_rule *bwc_rule;
446 : : int ret;
447 : :
448 : 0 : bwc_rule = mlx5dr_bwc_rule_create_hws_async(bwc_matcher, flow_items,
449 : : at_idx, rule_actions,
450 : : rule_attr);
451 [ # # ]: 0 : if (unlikely(!bwc_rule))
452 : : return NULL;
453 : :
454 : : do {
455 : 0 : ret = mlx5dr_send_queue_poll(ctx, rule_attr->queue_id, &completion, 1);
456 [ # # ]: 0 : } while (ret != 1);
457 : :
458 [ # # # # ]: 0 : if (unlikely(completion.status != RTE_FLOW_OP_SUCCESS ||
459 : : (bwc_rule->rule->status != MLX5DR_RULE_STATUS_CREATED &&
460 : : bwc_rule->rule->status != MLX5DR_RULE_STATUS_CREATING))) {
461 : 0 : DR_LOG(ERR, "Failed creating BWC rule: completion %d, rule status %d",
462 : : completion.status, bwc_rule->rule->status);
463 : 0 : mlx5dr_bwc_rule_free(bwc_rule);
464 : 0 : return NULL;
465 : : }
466 : :
467 : : return bwc_rule;
468 : : }
469 : :
470 : : static bool
471 : : mlx5dr_bwc_matcher_size_maxed_out(struct mlx5dr_bwc_matcher *bwc_matcher)
472 : : {
473 : 0 : struct mlx5dr_cmd_query_caps *caps = bwc_matcher->matcher->tbl->ctx->caps;
474 : :
475 : 0 : return bwc_matcher->size_log + MLX5DR_MATCHER_ASSURED_MAIN_TBL_DEPTH >=
476 : 0 : caps->ste_alloc_log_max - 1;
477 : : }
478 : :
479 : : static bool
480 : : mlx5dr_bwc_matcher_rehash_size_needed(struct mlx5dr_bwc_matcher *bwc_matcher,
481 : : uint32_t num_of_rules)
482 : : {
483 : : /* size-based rehash for root table is kernel's responsibility */
484 : 0 : if (unlikely(mlx5dr_table_is_root(bwc_matcher->matcher->tbl)))
485 : : return false;
486 : :
487 [ # # # # ]: 0 : if (unlikely(mlx5dr_bwc_matcher_size_maxed_out(bwc_matcher)))
488 : : return false;
489 : :
490 [ # # # # ]: 0 : if (unlikely((num_of_rules * 100 / MLX5DR_BWC_MATCHER_REHASH_PERCENT_TH) >=
491 : : (1UL << bwc_matcher->size_log)))
492 : 0 : return true;
493 : :
494 : : return false;
495 : : }
496 : :
497 : : static void
498 : : mlx5dr_bwc_rule_actions_to_action_types(struct mlx5dr_rule_action rule_actions[],
499 : : enum mlx5dr_action_type action_types[])
500 : : {
501 : : int i = 0;
502 : :
503 : 0 : for (i = 0;
504 [ # # # # ]: 0 : rule_actions[i].action && (rule_actions[i].action->type != MLX5DR_ACTION_TYP_LAST);
505 : 0 : i++) {
506 : 0 : action_types[i] = (enum mlx5dr_action_type)rule_actions[i].action->type;
507 : : }
508 : :
509 : 0 : action_types[i] = MLX5DR_ACTION_TYP_LAST;
510 : : }
511 : :
512 : : static int
513 : : mlx5dr_bwc_rule_actions_num(struct mlx5dr_rule_action rule_actions[])
514 : : {
515 : : int i = 0;
516 : :
517 [ # # ]: 0 : while (rule_actions[i].action &&
518 [ # # ]: 0 : (rule_actions[i].action->type != MLX5DR_ACTION_TYP_LAST))
519 : 0 : i++;
520 : :
521 : : return i;
522 : : }
523 : :
524 : : static int
525 : 0 : mlx5dr_bwc_matcher_extend_at(struct mlx5dr_bwc_matcher *bwc_matcher,
526 : : struct mlx5dr_rule_action rule_actions[])
527 : : {
528 : : enum mlx5dr_action_type action_types[MLX5_HW_MAX_ACTS];
529 : :
530 : : mlx5dr_bwc_rule_actions_to_action_types(rule_actions, action_types);
531 : :
532 : 0 : bwc_matcher->at[bwc_matcher->num_of_at] =
533 : 0 : mlx5dr_action_template_create(action_types, 0);
534 : :
535 [ # # ]: 0 : if (unlikely(!bwc_matcher->at[bwc_matcher->num_of_at])) {
536 : 0 : rte_errno = ENOMEM;
537 : 0 : return rte_errno;
538 : : }
539 : :
540 : 0 : bwc_matcher->num_of_at++;
541 : 0 : return 0;
542 : : }
543 : :
544 : : static int
545 : 0 : mlx5dr_bwc_matcher_extend_size(struct mlx5dr_bwc_matcher *bwc_matcher)
546 : : {
547 : 0 : struct mlx5dr_cmd_query_caps *caps = bwc_matcher->matcher->tbl->ctx->caps;
548 : :
549 [ # # ]: 0 : if (unlikely(mlx5dr_bwc_matcher_size_maxed_out(bwc_matcher))) {
550 : 0 : DR_LOG(ERR, "Can't resize matcher: depth exceeds limit %d",
551 : : caps->rtc_log_depth_max);
552 : 0 : return -ENOMEM;
553 : : }
554 : :
555 : 0 : bwc_matcher->size_log =
556 : 0 : RTE_MIN(bwc_matcher->size_log + MLX5DR_BWC_MATCHER_SIZE_LOG_STEP,
557 : : caps->ste_alloc_log_max - MLX5DR_MATCHER_ASSURED_MAIN_TBL_DEPTH);
558 : :
559 : 0 : return 0;
560 : : }
561 : :
562 : : static int
563 : 0 : mlx5dr_bwc_matcher_find_at(struct mlx5dr_bwc_matcher *bwc_matcher,
564 : : struct mlx5dr_rule_action rule_actions[])
565 : : {
566 : : enum mlx5dr_action_type *action_type_arr;
567 : : int i, j;
568 : :
569 : : /* start from index 1 - first action template is a dummy */
570 [ # # ]: 0 : for (i = 1; i < bwc_matcher->num_of_at; i++) {
571 : : j = 0;
572 : 0 : action_type_arr = bwc_matcher->at[i]->action_type_arr;
573 : :
574 [ # # ]: 0 : while (rule_actions[j].action &&
575 [ # # ]: 0 : rule_actions[j].action->type != MLX5DR_ACTION_TYP_LAST) {
576 [ # # ]: 0 : if (action_type_arr[j] != rule_actions[j].action->type)
577 : : break;
578 : 0 : j++;
579 : : }
580 : :
581 [ # # # # ]: 0 : if (action_type_arr[j] == MLX5DR_ACTION_TYP_LAST &&
582 : 0 : (!rule_actions[j].action ||
583 [ # # ]: 0 : rule_actions[j].action->type == MLX5DR_ACTION_TYP_LAST))
584 : 0 : return i;
585 : : }
586 : :
587 : : return -1;
588 : : }
589 : :
590 : : static int
591 : 0 : mlx5dr_bwc_matcher_move_all(struct mlx5dr_bwc_matcher *bwc_matcher)
592 : : {
593 [ # # ]: 0 : struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
594 : : uint16_t bwc_queues = mlx5dr_bwc_queues(ctx);
595 : : struct mlx5dr_bwc_rule **bwc_rules;
596 : : struct mlx5dr_rule_attr rule_attr;
597 : : uint32_t *pending_rules;
598 : : uint16_t burst_th;
599 : : bool all_done;
600 : : int i, j, ret;
601 : :
602 [ # # ]: 0 : if (mlx5dr_table_is_root(bwc_matcher->matcher->tbl)) {
603 : 0 : rte_errno = EINVAL;
604 : 0 : return -rte_errno;
605 : : }
606 : :
607 : : mlx5dr_bwc_rule_fill_attr(bwc_matcher, 0, &rule_attr);
608 : :
609 : : pending_rules = simple_calloc(bwc_queues, sizeof(*pending_rules));
610 [ # # ]: 0 : if (!pending_rules) {
611 : 0 : rte_errno = ENOMEM;
612 : 0 : return -rte_errno;
613 : : }
614 : :
615 : : bwc_rules = simple_calloc(bwc_queues, sizeof(*bwc_rules));
616 [ # # ]: 0 : if (!bwc_rules) {
617 : 0 : rte_errno = ENOMEM;
618 : 0 : goto free_pending_rules;
619 : : }
620 : :
621 [ # # ]: 0 : for (i = 0; i < bwc_queues; i++) {
622 [ # # ]: 0 : if (LIST_EMPTY(&bwc_matcher->rules[i]))
623 : 0 : bwc_rules[i] = NULL;
624 : : else
625 : 0 : bwc_rules[i] = LIST_FIRST(&bwc_matcher->rules[i]);
626 : : }
627 : :
628 : : do {
629 : : all_done = true;
630 : :
631 [ # # ]: 0 : for (i = 0; i < bwc_queues; i++) {
632 : 0 : rule_attr.queue_id = mlx5dr_bwc_get_queue_id(ctx, i);
633 : : burst_th = mlx5dr_bwc_get_burst_th(ctx, rule_attr.queue_id);
634 : :
635 [ # # # # ]: 0 : for (j = 0; j < burst_th && bwc_rules[i]; j++) {
636 : 0 : rule_attr.burst = !!((j + 1) % burst_th);
637 : 0 : ret = mlx5dr_matcher_resize_rule_move(bwc_matcher->matcher,
638 : 0 : bwc_rules[i]->rule,
639 : : &rule_attr);
640 [ # # ]: 0 : if (unlikely(ret)) {
641 : 0 : DR_LOG(ERR, "Moving BWC rule failed during rehash - %d",
642 : : ret);
643 : 0 : rte_errno = ENOMEM;
644 : 0 : goto free_bwc_rules;
645 : : }
646 : :
647 : : all_done = false;
648 : 0 : pending_rules[i]++;
649 : 0 : bwc_rules[i] = LIST_NEXT(bwc_rules[i], next);
650 : :
651 : 0 : ret = mlx5dr_bwc_queue_poll(ctx, rule_attr.queue_id,
652 : : &pending_rules[i], false);
653 [ # # ]: 0 : if (unlikely(ret)) {
654 : 0 : rte_errno = EINVAL;
655 : 0 : goto free_bwc_rules;
656 : : }
657 : : }
658 : : }
659 [ # # ]: 0 : } while (!all_done);
660 : :
661 : : /* drain all the bwc queues */
662 [ # # ]: 0 : for (i = 0; i < bwc_queues; i++) {
663 [ # # ]: 0 : if (pending_rules[i]) {
664 : 0 : uint16_t queue_id = mlx5dr_bwc_get_queue_id(ctx, i);
665 : 0 : mlx5dr_send_engine_flush_queue(&ctx->send_queue[queue_id]);
666 : 0 : ret = mlx5dr_bwc_queue_poll(ctx, queue_id,
667 : : &pending_rules[i], true);
668 [ # # ]: 0 : if (unlikely(ret)) {
669 : 0 : rte_errno = EINVAL;
670 : 0 : goto free_bwc_rules;
671 : : }
672 : : }
673 : : }
674 : :
675 : 0 : rte_errno = 0;
676 : :
677 : 0 : free_bwc_rules:
678 : : simple_free(bwc_rules);
679 : 0 : free_pending_rules:
680 : : simple_free(pending_rules);
681 : :
682 : 0 : return -rte_errno;
683 : : }
684 : :
685 : : static int
686 : 0 : mlx5dr_bwc_matcher_move(struct mlx5dr_bwc_matcher *bwc_matcher)
687 : : {
688 : 0 : struct mlx5dr_matcher_attr matcher_attr = {0};
689 : : struct mlx5dr_matcher *old_matcher;
690 : : struct mlx5dr_matcher *new_matcher;
691 : : int ret;
692 : :
693 : 0 : mlx5dr_bwc_matcher_init_attr(&matcher_attr,
694 : : bwc_matcher->priority,
695 [ # # ]: 0 : bwc_matcher->size_log,
696 [ # # ]: 0 : mlx5dr_table_is_root(bwc_matcher->matcher->tbl));
697 : :
698 : : old_matcher = bwc_matcher->matcher;
699 : 0 : new_matcher = mlx5dr_matcher_create(old_matcher->tbl,
700 : : &bwc_matcher->mt, 1,
701 : 0 : bwc_matcher->at,
702 : 0 : bwc_matcher->num_of_at,
703 : : &matcher_attr);
704 [ # # ]: 0 : if (!new_matcher) {
705 : 0 : DR_LOG(ERR, "Rehash error: matcher creation failed");
706 : 0 : return -ENOMEM;
707 : : }
708 : :
709 : 0 : ret = mlx5dr_matcher_resize_set_target(old_matcher, new_matcher);
710 [ # # ]: 0 : if (ret) {
711 : 0 : DR_LOG(ERR, "Rehash error: failed setting resize target");
712 : 0 : return ret;
713 : : }
714 : :
715 : 0 : ret = mlx5dr_bwc_matcher_move_all(bwc_matcher);
716 [ # # ]: 0 : if (ret) {
717 : 0 : DR_LOG(ERR, "Rehash error: moving rules failed");
718 : 0 : return -ENOMEM;
719 : : }
720 : :
721 : 0 : bwc_matcher->matcher = new_matcher;
722 : 0 : mlx5dr_matcher_destroy(old_matcher);
723 : :
724 : 0 : return 0;
725 : : }
726 : :
727 : : static int
728 : 0 : mlx5dr_bwc_matcher_rehash_size(struct mlx5dr_bwc_matcher *bwc_matcher)
729 : : {
730 : : uint32_t num_of_rules;
731 : : int ret;
732 : :
733 : : /* If the current matcher size is already at its max size, we can't
734 : : * do the rehash. Skip it and try adding the rule again - perhaps
735 : : * there was some change.
736 : : */
737 [ # # ]: 0 : if (mlx5dr_bwc_matcher_size_maxed_out(bwc_matcher))
738 : : return 0;
739 : :
740 : : /* It is possible that other rule has already performed rehash.
741 : : * Need to check again if we really need rehash.
742 : : * If the reason for rehash was size, but not any more - skip rehash.
743 : : */
744 [ # # ]: 0 : num_of_rules = rte_atomic_load_explicit(&bwc_matcher->num_of_rules,
745 : : rte_memory_order_relaxed);
746 : : if (!mlx5dr_bwc_matcher_rehash_size_needed(bwc_matcher, num_of_rules))
747 : : return 0;
748 : :
749 : : /* Now we're done all the checking - do the rehash:
750 : : * - extend match RTC size
751 : : * - create new matcher
752 : : * - move all the rules to the new matcher
753 : : * - destroy the old matcher
754 : : */
755 : :
756 : 0 : ret = mlx5dr_bwc_matcher_extend_size(bwc_matcher);
757 [ # # ]: 0 : if (ret)
758 : : return ret;
759 : :
760 : 0 : return mlx5dr_bwc_matcher_move(bwc_matcher);
761 : : }
762 : :
763 : : static int
764 : : mlx5dr_bwc_matcher_rehash_at(struct mlx5dr_bwc_matcher *bwc_matcher)
765 : : {
766 : : /* Rehash by action template doesn't require any additional checking.
767 : : * The bwc_matcher already contains the new action template.
768 : : * Just do the usual rehash:
769 : : * - create new matcher
770 : : * - move all the rules to the new matcher
771 : : * - destroy the old matcher
772 : : */
773 : 0 : return mlx5dr_bwc_matcher_move(bwc_matcher);
774 : : }
775 : :
776 : : static struct mlx5dr_bwc_rule *
777 : 0 : mlx5dr_bwc_rule_create_root(struct mlx5dr_bwc_matcher *bwc_matcher,
778 : : const struct rte_flow_item flow_items[],
779 : : struct mlx5dr_rule_action rule_actions[])
780 : : {
781 : : struct mlx5dr_bwc_rule *bwc_rule;
782 : :
783 : 0 : bwc_rule = mlx5dr_bwc_rule_create_root_sync(bwc_matcher,
784 : : flow_items,
785 : : mlx5dr_bwc_rule_actions_num(rule_actions),
786 : : rule_actions);
787 : :
788 [ # # ]: 0 : if (unlikely(!bwc_rule))
789 : 0 : DR_LOG(ERR, "BWC rule: failed creating rule on root tbl");
790 : :
791 : 0 : return bwc_rule;
792 : : }
793 : :
794 : : static struct mlx5dr_bwc_rule *
795 : 0 : mlx5dr_bwc_rule_create_hws(struct mlx5dr_bwc_matcher *bwc_matcher,
796 : : const struct rte_flow_item flow_items[],
797 : : struct mlx5dr_rule_action rule_actions[])
798 : : {
799 : 0 : struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
800 : : struct mlx5dr_bwc_rule *bwc_rule = NULL;
801 : : struct mlx5dr_rule_attr rule_attr;
802 : : rte_spinlock_t *queue_lock;
803 : : uint32_t num_of_rules;
804 : : uint16_t idx;
805 : : int at_idx;
806 : : int ret;
807 : :
808 : : idx = mlx5dr_bwc_gen_queue_idx(ctx);
809 : :
810 : : mlx5dr_bwc_rule_fill_attr(bwc_matcher, idx, &rule_attr);
811 : :
812 : : queue_lock = mlx5dr_bwc_get_queue_lock(ctx, idx);
813 : :
814 : : rte_spinlock_lock(queue_lock);
815 : :
816 : : /* check if rehash needed due to missing action template */
817 : 0 : at_idx = mlx5dr_bwc_matcher_find_at(bwc_matcher, rule_actions);
818 [ # # ]: 0 : if (unlikely(at_idx < 0)) {
819 : : /* we need to extend BWC matcher action templates array */
820 : : rte_spinlock_unlock(queue_lock);
821 : 0 : mlx5dr_bwc_lock_all_queues(ctx);
822 : :
823 : 0 : ret = mlx5dr_bwc_matcher_extend_at(bwc_matcher, rule_actions);
824 [ # # ]: 0 : if (unlikely(ret)) {
825 : : mlx5dr_bwc_unlock_all_queues(ctx);
826 : 0 : rte_errno = EINVAL;
827 : 0 : DR_LOG(ERR, "BWC rule: failed extending action template - %d", ret);
828 : 0 : return NULL;
829 : : }
830 : :
831 : : /* action templates array was extended, we need the last idx */
832 : 0 : at_idx = bwc_matcher->num_of_at - 1;
833 : :
834 : 0 : ret = mlx5dr_matcher_attach_at(bwc_matcher->matcher,
835 : : bwc_matcher->at[at_idx]);
836 [ # # ]: 0 : if (unlikely(ret)) {
837 : : /* Action template attach failed, possibly due to
838 : : * requiring more action STEs.
839 : : * Need to attempt creating new matcher with all
840 : : * the action templates, including the new one.
841 : : */
842 : : ret = mlx5dr_bwc_matcher_rehash_at(bwc_matcher);
843 [ # # ]: 0 : if (unlikely(ret)) {
844 : 0 : mlx5dr_action_template_destroy(bwc_matcher->at[at_idx]);
845 : 0 : bwc_matcher->at[at_idx] = NULL;
846 : 0 : bwc_matcher->num_of_at--;
847 : :
848 : : mlx5dr_bwc_unlock_all_queues(ctx);
849 : :
850 : 0 : DR_LOG(ERR, "BWC rule insertion: rehash AT failed - %d", ret);
851 : 0 : return NULL;
852 : : }
853 : : }
854 : :
855 : : mlx5dr_bwc_unlock_all_queues(ctx);
856 : : rte_spinlock_lock(queue_lock);
857 : : }
858 : :
859 : : /* check if number of rules require rehash */
860 [ # # ]: 0 : num_of_rules = rte_atomic_load_explicit(&bwc_matcher->num_of_rules,
861 : : rte_memory_order_relaxed);
862 [ # # ]: 0 : if (unlikely(mlx5dr_bwc_matcher_rehash_size_needed(bwc_matcher, num_of_rules))) {
863 : : rte_spinlock_unlock(queue_lock);
864 : :
865 : 0 : mlx5dr_bwc_lock_all_queues(ctx);
866 : 0 : ret = mlx5dr_bwc_matcher_rehash_size(bwc_matcher);
867 : : mlx5dr_bwc_unlock_all_queues(ctx);
868 : :
869 [ # # ]: 0 : if (ret) {
870 : 0 : DR_LOG(ERR, "BWC rule insertion: rehash size [%d -> %d] failed - %d",
871 : : bwc_matcher->size_log - MLX5DR_BWC_MATCHER_SIZE_LOG_STEP,
872 : : bwc_matcher->size_log,
873 : : ret);
874 : 0 : return NULL;
875 : : }
876 : :
877 : : rte_spinlock_lock(queue_lock);
878 : : }
879 : :
880 : 0 : bwc_rule = mlx5dr_bwc_rule_create_hws_sync(bwc_matcher,
881 : : flow_items,
882 : : at_idx,
883 : : rule_actions,
884 : : &rule_attr);
885 : :
886 [ # # ]: 0 : if (likely(bwc_rule)) {
887 : 0 : mlx5dr_bwc_rule_list_add(bwc_rule, idx);
888 : : rte_spinlock_unlock(queue_lock);
889 : 0 : return bwc_rule; /* rule inserted successfully */
890 : : }
891 : :
892 : : /* At this point the rule wasn't added.
893 : : * It could be because there was collision, or some other problem.
894 : : * If we don't dive deeper than API, the only thing we know is that
895 : : * the status of completion is RTE_FLOW_OP_ERROR.
896 : : * Try rehash by size and insert rule again - last chance.
897 : : */
898 : :
899 : : rte_spinlock_unlock(queue_lock);
900 : :
901 : 0 : mlx5dr_bwc_lock_all_queues(ctx);
902 : 0 : ret = mlx5dr_bwc_matcher_rehash_size(bwc_matcher);
903 : : mlx5dr_bwc_unlock_all_queues(ctx);
904 : :
905 [ # # ]: 0 : if (ret) {
906 : 0 : DR_LOG(ERR, "BWC rule insertion: rehash failed - %d", ret);
907 : 0 : return NULL;
908 : : }
909 : :
910 : : /* Rehash done, but we still have that pesky rule to add */
911 : : rte_spinlock_lock(queue_lock);
912 : :
913 : 0 : bwc_rule = mlx5dr_bwc_rule_create_hws_sync(bwc_matcher,
914 : : flow_items,
915 : : at_idx,
916 : : rule_actions,
917 : : &rule_attr);
918 : :
919 [ # # ]: 0 : if (unlikely(!bwc_rule)) {
920 : : rte_spinlock_unlock(queue_lock);
921 : 0 : DR_LOG(ERR, "BWC rule insertion failed");
922 : 0 : return NULL;
923 : : }
924 : :
925 : 0 : mlx5dr_bwc_rule_list_add(bwc_rule, idx);
926 : : rte_spinlock_unlock(queue_lock);
927 : :
928 : 0 : return bwc_rule;
929 : : }
930 : :
931 : : struct mlx5dr_bwc_rule *
932 : 0 : mlx5dr_bwc_rule_create(struct mlx5dr_bwc_matcher *bwc_matcher,
933 : : const struct rte_flow_item flow_items[],
934 : : struct mlx5dr_rule_action rule_actions[])
935 : : {
936 [ # # ]: 0 : struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
937 : :
938 [ # # ]: 0 : if (unlikely(!mlx5dr_context_bwc_supported(ctx))) {
939 : 0 : rte_errno = EINVAL;
940 : 0 : DR_LOG(ERR, "BWC rule: Context created w/o BWC API compatibility");
941 : 0 : return NULL;
942 : : }
943 : :
944 [ # # ]: 0 : if (unlikely(mlx5dr_table_is_root(bwc_matcher->matcher->tbl)))
945 : 0 : return mlx5dr_bwc_rule_create_root(bwc_matcher,
946 : : flow_items,
947 : : rule_actions);
948 : :
949 : 0 : return mlx5dr_bwc_rule_create_hws(bwc_matcher,
950 : : flow_items,
951 : : rule_actions);
952 : : }
|