xref: /dpdk/drivers/net/mlx5/hws/mlx5dr_bwc.c (revision b56ba2139f4dc04b97f69f0d0ece1f28725a100b)
187026d2eSYevgeny Kliteynik /* SPDX-License-Identifier: BSD-3-Clause
287026d2eSYevgeny Kliteynik  * Copyright (c) 2023 NVIDIA Corporation & Affiliates
387026d2eSYevgeny Kliteynik  */
487026d2eSYevgeny Kliteynik 
587026d2eSYevgeny Kliteynik #include "mlx5dr_internal.h"
687026d2eSYevgeny Kliteynik 
787026d2eSYevgeny Kliteynik static uint16_t mlx5dr_bwc_queues(struct mlx5dr_context *ctx)
887026d2eSYevgeny Kliteynik {
987026d2eSYevgeny Kliteynik 	return (ctx->queues - 1) / 2;
1087026d2eSYevgeny Kliteynik }
1187026d2eSYevgeny Kliteynik 
1287026d2eSYevgeny Kliteynik static uint16_t
1387026d2eSYevgeny Kliteynik mlx5dr_bwc_gen_queue_idx(struct mlx5dr_context *ctx)
1487026d2eSYevgeny Kliteynik {
1587026d2eSYevgeny Kliteynik 	/* assign random queue */
1687026d2eSYevgeny Kliteynik 	return rand() % mlx5dr_bwc_queues(ctx);
1787026d2eSYevgeny Kliteynik }
1887026d2eSYevgeny Kliteynik 
1987026d2eSYevgeny Kliteynik static uint16_t
2087026d2eSYevgeny Kliteynik mlx5dr_bwc_get_queue_id(struct mlx5dr_context *ctx, uint16_t idx)
2187026d2eSYevgeny Kliteynik {
2287026d2eSYevgeny Kliteynik 	return idx + mlx5dr_bwc_queues(ctx);
2387026d2eSYevgeny Kliteynik }
2487026d2eSYevgeny Kliteynik 
25f1788d7aSYevgeny Kliteynik static uint16_t
26f1788d7aSYevgeny Kliteynik mlx5dr_bwc_get_burst_th(struct mlx5dr_context *ctx, uint16_t queue_id)
27f1788d7aSYevgeny Kliteynik {
28f1788d7aSYevgeny Kliteynik 	return RTE_MIN(ctx->send_queue[queue_id].num_entries / 2,
29f1788d7aSYevgeny Kliteynik 		       MLX5DR_BWC_MATCHER_REHASH_BURST_TH);
30f1788d7aSYevgeny Kliteynik }
31f1788d7aSYevgeny Kliteynik 
3287026d2eSYevgeny Kliteynik static rte_spinlock_t *
3387026d2eSYevgeny Kliteynik mlx5dr_bwc_get_queue_lock(struct mlx5dr_context *ctx, uint16_t idx)
3487026d2eSYevgeny Kliteynik {
3587026d2eSYevgeny Kliteynik 	return &ctx->bwc_send_queue_locks[idx];
3687026d2eSYevgeny Kliteynik }
3787026d2eSYevgeny Kliteynik 
3887026d2eSYevgeny Kliteynik static void mlx5dr_bwc_lock_all_queues(struct mlx5dr_context *ctx)
3987026d2eSYevgeny Kliteynik {
4087026d2eSYevgeny Kliteynik 	uint16_t bwc_queues = mlx5dr_bwc_queues(ctx);
4187026d2eSYevgeny Kliteynik 	rte_spinlock_t *queue_lock;
4287026d2eSYevgeny Kliteynik 	int i;
4387026d2eSYevgeny Kliteynik 
4487026d2eSYevgeny Kliteynik 	for (i = 0; i < bwc_queues; i++) {
4587026d2eSYevgeny Kliteynik 		queue_lock = mlx5dr_bwc_get_queue_lock(ctx, i);
4687026d2eSYevgeny Kliteynik 		rte_spinlock_lock(queue_lock);
4787026d2eSYevgeny Kliteynik 	}
4887026d2eSYevgeny Kliteynik }
4987026d2eSYevgeny Kliteynik 
5087026d2eSYevgeny Kliteynik static void mlx5dr_bwc_unlock_all_queues(struct mlx5dr_context *ctx)
5187026d2eSYevgeny Kliteynik {
5287026d2eSYevgeny Kliteynik 	uint16_t bwc_queues = mlx5dr_bwc_queues(ctx);
5387026d2eSYevgeny Kliteynik 	rte_spinlock_t *queue_lock;
5487026d2eSYevgeny Kliteynik 	int i;
5587026d2eSYevgeny Kliteynik 
5687026d2eSYevgeny Kliteynik 	for (i = 0; i < bwc_queues; i++) {
5787026d2eSYevgeny Kliteynik 		queue_lock = mlx5dr_bwc_get_queue_lock(ctx, i);
5887026d2eSYevgeny Kliteynik 		rte_spinlock_unlock(queue_lock);
5987026d2eSYevgeny Kliteynik 	}
6087026d2eSYevgeny Kliteynik }
6187026d2eSYevgeny Kliteynik 
6287026d2eSYevgeny Kliteynik static void mlx5dr_bwc_matcher_init_attr(struct mlx5dr_matcher_attr *attr,
6387026d2eSYevgeny Kliteynik 					 uint32_t priority,
6487026d2eSYevgeny Kliteynik 					 uint8_t size_log,
6587026d2eSYevgeny Kliteynik 					 bool is_root)
6687026d2eSYevgeny Kliteynik {
6787026d2eSYevgeny Kliteynik 	memset(attr, 0, sizeof(*attr));
6887026d2eSYevgeny Kliteynik 
6987026d2eSYevgeny Kliteynik 	attr->priority = priority;
7087026d2eSYevgeny Kliteynik 	attr->optimize_using_rule_idx = 0;
7187026d2eSYevgeny Kliteynik 	attr->mode = MLX5DR_MATCHER_RESOURCE_MODE_RULE;
7287026d2eSYevgeny Kliteynik 	attr->optimize_flow_src = MLX5DR_MATCHER_FLOW_SRC_ANY;
7387026d2eSYevgeny Kliteynik 	attr->insert_mode = MLX5DR_MATCHER_INSERT_BY_HASH;
7487026d2eSYevgeny Kliteynik 	attr->distribute_mode = MLX5DR_MATCHER_DISTRIBUTE_BY_HASH;
7587026d2eSYevgeny Kliteynik 	attr->rule.num_log = size_log;
7687026d2eSYevgeny Kliteynik 
7787026d2eSYevgeny Kliteynik 	if (!is_root) {
7887026d2eSYevgeny Kliteynik 		attr->resizable = true;
7987026d2eSYevgeny Kliteynik 		attr->max_num_of_at_attach = MLX5DR_BWC_MATCHER_ATTACH_AT_NUM;
8087026d2eSYevgeny Kliteynik 	}
8187026d2eSYevgeny Kliteynik }
8287026d2eSYevgeny Kliteynik 
8387026d2eSYevgeny Kliteynik struct mlx5dr_bwc_matcher *
8487026d2eSYevgeny Kliteynik mlx5dr_bwc_matcher_create(struct mlx5dr_table *table,
8587026d2eSYevgeny Kliteynik 			  uint32_t priority,
8687026d2eSYevgeny Kliteynik 			  const struct rte_flow_item flow_items[])
8787026d2eSYevgeny Kliteynik {
8887026d2eSYevgeny Kliteynik 	enum mlx5dr_action_type init_action_types[1] = { MLX5DR_ACTION_TYP_LAST };
8987026d2eSYevgeny Kliteynik 	uint16_t bwc_queues = mlx5dr_bwc_queues(table->ctx);
9087026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_matcher *bwc_matcher;
9187026d2eSYevgeny Kliteynik 	struct mlx5dr_matcher_attr attr = {0};
9287026d2eSYevgeny Kliteynik 	int i;
9387026d2eSYevgeny Kliteynik 
9487026d2eSYevgeny Kliteynik 	if (!mlx5dr_context_bwc_supported(table->ctx)) {
9587026d2eSYevgeny Kliteynik 		rte_errno = EINVAL;
9687026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "BWC rule: Context created w/o BWC API compatibility");
9787026d2eSYevgeny Kliteynik 		return NULL;
9887026d2eSYevgeny Kliteynik 	}
9987026d2eSYevgeny Kliteynik 
10087026d2eSYevgeny Kliteynik 	bwc_matcher = simple_calloc(1, sizeof(*bwc_matcher));
10187026d2eSYevgeny Kliteynik 	if (!bwc_matcher) {
10287026d2eSYevgeny Kliteynik 		rte_errno = ENOMEM;
10387026d2eSYevgeny Kliteynik 		return NULL;
10487026d2eSYevgeny Kliteynik 	}
10587026d2eSYevgeny Kliteynik 
10687026d2eSYevgeny Kliteynik 	bwc_matcher->rules = simple_calloc(bwc_queues, sizeof(*bwc_matcher->rules));
10787026d2eSYevgeny Kliteynik 	if (!bwc_matcher->rules) {
10887026d2eSYevgeny Kliteynik 		rte_errno = ENOMEM;
10987026d2eSYevgeny Kliteynik 		goto free_bwc_matcher;
11087026d2eSYevgeny Kliteynik 	}
11187026d2eSYevgeny Kliteynik 
11287026d2eSYevgeny Kliteynik 	for (i = 0; i < bwc_queues; i++)
11387026d2eSYevgeny Kliteynik 		LIST_INIT(&bwc_matcher->rules[i]);
11487026d2eSYevgeny Kliteynik 
11587026d2eSYevgeny Kliteynik 	mlx5dr_bwc_matcher_init_attr(&attr,
11687026d2eSYevgeny Kliteynik 				     priority,
11787026d2eSYevgeny Kliteynik 				     MLX5DR_BWC_MATCHER_INIT_SIZE_LOG,
11887026d2eSYevgeny Kliteynik 				     mlx5dr_table_is_root(table));
11987026d2eSYevgeny Kliteynik 
12087026d2eSYevgeny Kliteynik 	bwc_matcher->mt = mlx5dr_match_template_create(flow_items,
12187026d2eSYevgeny Kliteynik 						       MLX5DR_MATCH_TEMPLATE_FLAG_NONE);
12287026d2eSYevgeny Kliteynik 	if (!bwc_matcher->mt) {
12387026d2eSYevgeny Kliteynik 		rte_errno = EINVAL;
12487026d2eSYevgeny Kliteynik 		goto free_bwc_matcher_rules;
12587026d2eSYevgeny Kliteynik 	}
12687026d2eSYevgeny Kliteynik 
12787026d2eSYevgeny Kliteynik 	bwc_matcher->priority = priority;
12887026d2eSYevgeny Kliteynik 	bwc_matcher->size_log = MLX5DR_BWC_MATCHER_INIT_SIZE_LOG;
12987026d2eSYevgeny Kliteynik 
13087026d2eSYevgeny Kliteynik 	/* create dummy action template */
13187026d2eSYevgeny Kliteynik 	bwc_matcher->at[0] = mlx5dr_action_template_create(init_action_types, 0);
13287026d2eSYevgeny Kliteynik 	bwc_matcher->num_of_at = 1;
13387026d2eSYevgeny Kliteynik 
13487026d2eSYevgeny Kliteynik 	bwc_matcher->matcher = mlx5dr_matcher_create(table,
13587026d2eSYevgeny Kliteynik 						     &bwc_matcher->mt, 1,
13687026d2eSYevgeny Kliteynik 						     &bwc_matcher->at[0],
13787026d2eSYevgeny Kliteynik 						     bwc_matcher->num_of_at,
13887026d2eSYevgeny Kliteynik 						     &attr);
13987026d2eSYevgeny Kliteynik 	if (!bwc_matcher->matcher) {
14087026d2eSYevgeny Kliteynik 		rte_errno = EINVAL;
14187026d2eSYevgeny Kliteynik 		goto free_at;
14287026d2eSYevgeny Kliteynik 	}
14387026d2eSYevgeny Kliteynik 
14487026d2eSYevgeny Kliteynik 	return bwc_matcher;
14587026d2eSYevgeny Kliteynik 
14687026d2eSYevgeny Kliteynik free_at:
14787026d2eSYevgeny Kliteynik 	mlx5dr_action_template_destroy(bwc_matcher->at[0]);
14887026d2eSYevgeny Kliteynik 	mlx5dr_match_template_destroy(bwc_matcher->mt);
14987026d2eSYevgeny Kliteynik free_bwc_matcher_rules:
15087026d2eSYevgeny Kliteynik 	simple_free(bwc_matcher->rules);
15187026d2eSYevgeny Kliteynik free_bwc_matcher:
15287026d2eSYevgeny Kliteynik 	simple_free(bwc_matcher);
15387026d2eSYevgeny Kliteynik 
15487026d2eSYevgeny Kliteynik 	return NULL;
15587026d2eSYevgeny Kliteynik }
15687026d2eSYevgeny Kliteynik 
15787026d2eSYevgeny Kliteynik int mlx5dr_bwc_matcher_destroy(struct mlx5dr_bwc_matcher *bwc_matcher)
15887026d2eSYevgeny Kliteynik {
15987026d2eSYevgeny Kliteynik 	int i;
16087026d2eSYevgeny Kliteynik 
16187026d2eSYevgeny Kliteynik 	if (bwc_matcher->num_of_rules)
16287026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "BWC matcher destroy: matcher still has %d rules",
16387026d2eSYevgeny Kliteynik 		       bwc_matcher->num_of_rules);
16487026d2eSYevgeny Kliteynik 
16587026d2eSYevgeny Kliteynik 	mlx5dr_matcher_destroy(bwc_matcher->matcher);
16687026d2eSYevgeny Kliteynik 	bwc_matcher->matcher = NULL;
16787026d2eSYevgeny Kliteynik 
16887026d2eSYevgeny Kliteynik 	for (i = 0; i < bwc_matcher->num_of_at; i++)
16987026d2eSYevgeny Kliteynik 		mlx5dr_action_template_destroy(bwc_matcher->at[i]);
17087026d2eSYevgeny Kliteynik 
17187026d2eSYevgeny Kliteynik 	mlx5dr_match_template_destroy(bwc_matcher->mt);
17287026d2eSYevgeny Kliteynik 	simple_free(bwc_matcher->rules);
17387026d2eSYevgeny Kliteynik 	simple_free(bwc_matcher);
17487026d2eSYevgeny Kliteynik 
17587026d2eSYevgeny Kliteynik 	return 0;
17687026d2eSYevgeny Kliteynik }
17787026d2eSYevgeny Kliteynik 
17887026d2eSYevgeny Kliteynik static int
17987026d2eSYevgeny Kliteynik mlx5dr_bwc_queue_poll(struct mlx5dr_context *ctx,
18087026d2eSYevgeny Kliteynik 		      uint16_t queue_id,
18187026d2eSYevgeny Kliteynik 		      uint32_t *pending_rules,
18287026d2eSYevgeny Kliteynik 		      bool drain)
18387026d2eSYevgeny Kliteynik {
18487026d2eSYevgeny Kliteynik 	struct rte_flow_op_result comp[MLX5DR_BWC_MATCHER_REHASH_BURST_TH];
185f1788d7aSYevgeny Kliteynik 	uint16_t burst_th = mlx5dr_bwc_get_burst_th(ctx, queue_id);
186f1788d7aSYevgeny Kliteynik 	bool got_comp = *pending_rules >= burst_th;
187*b56ba213SBing Zhao 	bool queue_full;
188d3bf0062SYevgeny Kliteynik 	int err = 0;
18987026d2eSYevgeny Kliteynik 	int ret;
19087026d2eSYevgeny Kliteynik 	int i;
19187026d2eSYevgeny Kliteynik 
19287026d2eSYevgeny Kliteynik 	/* Check if there are any completions at all */
19387026d2eSYevgeny Kliteynik 	if (!got_comp && !drain)
19487026d2eSYevgeny Kliteynik 		return 0;
19587026d2eSYevgeny Kliteynik 
196*b56ba213SBing Zhao 	/* The FULL state of a SQ is always a subcondition of the original 'got_comp'. */
197*b56ba213SBing Zhao 	queue_full = mlx5dr_send_engine_full(&ctx->send_queue[queue_id]);
19887026d2eSYevgeny Kliteynik 	while (queue_full || ((got_comp || drain) && *pending_rules)) {
199f1788d7aSYevgeny Kliteynik 		ret = mlx5dr_send_queue_poll(ctx, queue_id, comp, burst_th);
20087026d2eSYevgeny Kliteynik 		if (unlikely(ret < 0)) {
20187026d2eSYevgeny Kliteynik 			DR_LOG(ERR, "Rehash error: polling queue %d returned %d\n",
20287026d2eSYevgeny Kliteynik 			       queue_id, ret);
20387026d2eSYevgeny Kliteynik 			return -EINVAL;
20487026d2eSYevgeny Kliteynik 		}
20587026d2eSYevgeny Kliteynik 
20687026d2eSYevgeny Kliteynik 		if (ret) {
20787026d2eSYevgeny Kliteynik 			(*pending_rules) -= ret;
20887026d2eSYevgeny Kliteynik 			for (i = 0; i < ret; i++) {
209d3bf0062SYevgeny Kliteynik 				if (unlikely(comp[i].status != RTE_FLOW_OP_SUCCESS)) {
21087026d2eSYevgeny Kliteynik 					DR_LOG(ERR,
21187026d2eSYevgeny Kliteynik 					       "Rehash error: polling queue %d returned completion with error\n",
21287026d2eSYevgeny Kliteynik 					       queue_id);
213d3bf0062SYevgeny Kliteynik 					err = -EINVAL;
214d3bf0062SYevgeny Kliteynik 				}
21587026d2eSYevgeny Kliteynik 			}
21687026d2eSYevgeny Kliteynik 			queue_full = false;
21787026d2eSYevgeny Kliteynik 		}
21887026d2eSYevgeny Kliteynik 
21987026d2eSYevgeny Kliteynik 		got_comp = !!ret;
22087026d2eSYevgeny Kliteynik 	}
22187026d2eSYevgeny Kliteynik 
222d3bf0062SYevgeny Kliteynik 	return err;
22387026d2eSYevgeny Kliteynik }
22487026d2eSYevgeny Kliteynik 
22587026d2eSYevgeny Kliteynik static void
22687026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_fill_attr(struct mlx5dr_bwc_matcher *bwc_matcher,
22787026d2eSYevgeny Kliteynik 			  uint16_t bwc_queue_idx,
22887026d2eSYevgeny Kliteynik 			  struct mlx5dr_rule_attr *rule_attr)
22987026d2eSYevgeny Kliteynik {
23087026d2eSYevgeny Kliteynik 	struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
23187026d2eSYevgeny Kliteynik 
23287026d2eSYevgeny Kliteynik 	/* no use of INSERT_BY_INDEX in bwc rule */
23387026d2eSYevgeny Kliteynik 	rule_attr->rule_idx = 0;
23487026d2eSYevgeny Kliteynik 
23587026d2eSYevgeny Kliteynik 	/* notify HW at each rule insertion/deletion */
23687026d2eSYevgeny Kliteynik 	rule_attr->burst = 0;
23787026d2eSYevgeny Kliteynik 
23887026d2eSYevgeny Kliteynik 	/* We don't need user data, but the API requires it to exist */
23987026d2eSYevgeny Kliteynik 	rule_attr->user_data = (void *)0xFACADE;
24087026d2eSYevgeny Kliteynik 
24187026d2eSYevgeny Kliteynik 	rule_attr->queue_id = mlx5dr_bwc_get_queue_id(ctx, bwc_queue_idx);
24287026d2eSYevgeny Kliteynik }
24387026d2eSYevgeny Kliteynik 
24487026d2eSYevgeny Kliteynik static struct mlx5dr_bwc_rule *
24587026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_alloc(void)
24687026d2eSYevgeny Kliteynik {
24787026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_rule *bwc_rule;
24887026d2eSYevgeny Kliteynik 
24987026d2eSYevgeny Kliteynik 	bwc_rule = simple_calloc(1, sizeof(*bwc_rule));
25087026d2eSYevgeny Kliteynik 	if (unlikely(!bwc_rule))
25187026d2eSYevgeny Kliteynik 		goto out_err;
25287026d2eSYevgeny Kliteynik 
25387026d2eSYevgeny Kliteynik 	bwc_rule->rule = simple_calloc(1, sizeof(*bwc_rule->rule));
25487026d2eSYevgeny Kliteynik 	if (unlikely(!bwc_rule->rule))
25587026d2eSYevgeny Kliteynik 		goto free_rule;
25687026d2eSYevgeny Kliteynik 
25787026d2eSYevgeny Kliteynik 	return bwc_rule;
25887026d2eSYevgeny Kliteynik 
25987026d2eSYevgeny Kliteynik free_rule:
26087026d2eSYevgeny Kliteynik 	simple_free(bwc_rule);
26187026d2eSYevgeny Kliteynik out_err:
26287026d2eSYevgeny Kliteynik 	rte_errno = ENOMEM;
26387026d2eSYevgeny Kliteynik 	return NULL;
26487026d2eSYevgeny Kliteynik }
26587026d2eSYevgeny Kliteynik 
26687026d2eSYevgeny Kliteynik static void
26787026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_free(struct mlx5dr_bwc_rule *bwc_rule)
26887026d2eSYevgeny Kliteynik {
26987026d2eSYevgeny Kliteynik 	if (likely(bwc_rule->rule))
27087026d2eSYevgeny Kliteynik 		simple_free(bwc_rule->rule);
27187026d2eSYevgeny Kliteynik 	simple_free(bwc_rule);
27287026d2eSYevgeny Kliteynik }
27387026d2eSYevgeny Kliteynik 
27487026d2eSYevgeny Kliteynik static void
27587026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_list_add(struct mlx5dr_bwc_rule *bwc_rule, uint16_t idx)
27687026d2eSYevgeny Kliteynik {
27787026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher;
27887026d2eSYevgeny Kliteynik 
27987026d2eSYevgeny Kliteynik 	rte_atomic_fetch_add_explicit(&bwc_matcher->num_of_rules, 1, rte_memory_order_relaxed);
28087026d2eSYevgeny Kliteynik 	bwc_rule->bwc_queue_idx = idx;
28187026d2eSYevgeny Kliteynik 	LIST_INSERT_HEAD(&bwc_matcher->rules[idx], bwc_rule, next);
28287026d2eSYevgeny Kliteynik }
28387026d2eSYevgeny Kliteynik 
28487026d2eSYevgeny Kliteynik static void mlx5dr_bwc_rule_list_remove(struct mlx5dr_bwc_rule *bwc_rule)
28587026d2eSYevgeny Kliteynik {
28687026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher;
28787026d2eSYevgeny Kliteynik 
28887026d2eSYevgeny Kliteynik 	rte_atomic_fetch_sub_explicit(&bwc_matcher->num_of_rules, 1, rte_memory_order_relaxed);
28987026d2eSYevgeny Kliteynik 	LIST_REMOVE(bwc_rule, next);
29087026d2eSYevgeny Kliteynik }
29187026d2eSYevgeny Kliteynik 
29287026d2eSYevgeny Kliteynik static int
29387026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_destroy_hws_async(struct mlx5dr_bwc_rule *bwc_rule,
29487026d2eSYevgeny Kliteynik 				  struct mlx5dr_rule_attr *attr)
29587026d2eSYevgeny Kliteynik {
29687026d2eSYevgeny Kliteynik 	return mlx5dr_rule_destroy(bwc_rule->rule, attr);
29787026d2eSYevgeny Kliteynik }
29887026d2eSYevgeny Kliteynik 
29987026d2eSYevgeny Kliteynik static int
30087026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_destroy_hws_sync(struct mlx5dr_bwc_rule *bwc_rule,
30187026d2eSYevgeny Kliteynik 				 struct mlx5dr_rule_attr *rule_attr)
30287026d2eSYevgeny Kliteynik {
30387026d2eSYevgeny Kliteynik 	struct mlx5dr_context *ctx = bwc_rule->bwc_matcher->matcher->tbl->ctx;
30487026d2eSYevgeny Kliteynik 	struct rte_flow_op_result completion;
30587026d2eSYevgeny Kliteynik 	int ret;
30687026d2eSYevgeny Kliteynik 
30787026d2eSYevgeny Kliteynik 	ret = mlx5dr_bwc_rule_destroy_hws_async(bwc_rule, rule_attr);
30887026d2eSYevgeny Kliteynik 	if (unlikely(ret))
30987026d2eSYevgeny Kliteynik 		return ret;
31087026d2eSYevgeny Kliteynik 
31187026d2eSYevgeny Kliteynik 	do {
31287026d2eSYevgeny Kliteynik 		ret = mlx5dr_send_queue_poll(ctx, rule_attr->queue_id, &completion, 1);
31387026d2eSYevgeny Kliteynik 	} while (ret != 1);
31487026d2eSYevgeny Kliteynik 
31587026d2eSYevgeny Kliteynik 	if (unlikely(completion.status != RTE_FLOW_OP_SUCCESS ||
31687026d2eSYevgeny Kliteynik 		     (bwc_rule->rule->status != MLX5DR_RULE_STATUS_DELETED &&
31787026d2eSYevgeny Kliteynik 		      bwc_rule->rule->status != MLX5DR_RULE_STATUS_DELETING))) {
31887026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "Failed destroying BWC rule: completion %d, rule status %d",
31987026d2eSYevgeny Kliteynik 		       completion.status, bwc_rule->rule->status);
32087026d2eSYevgeny Kliteynik 		rte_errno = EINVAL;
32187026d2eSYevgeny Kliteynik 		return rte_errno;
32287026d2eSYevgeny Kliteynik 	}
32387026d2eSYevgeny Kliteynik 
32487026d2eSYevgeny Kliteynik 	return 0;
32587026d2eSYevgeny Kliteynik }
32687026d2eSYevgeny Kliteynik 
32787026d2eSYevgeny Kliteynik static int mlx5dr_bwc_rule_destroy_hws(struct mlx5dr_bwc_rule *bwc_rule)
32887026d2eSYevgeny Kliteynik {
32987026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher;
33087026d2eSYevgeny Kliteynik 	struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
33187026d2eSYevgeny Kliteynik 	uint16_t idx = bwc_rule->bwc_queue_idx;
33287026d2eSYevgeny Kliteynik 	struct mlx5dr_rule_attr attr;
33387026d2eSYevgeny Kliteynik 	rte_spinlock_t *queue_lock;
33487026d2eSYevgeny Kliteynik 	int ret;
33587026d2eSYevgeny Kliteynik 
33687026d2eSYevgeny Kliteynik 	mlx5dr_bwc_rule_fill_attr(bwc_matcher, idx, &attr);
33787026d2eSYevgeny Kliteynik 
33887026d2eSYevgeny Kliteynik 	queue_lock = mlx5dr_bwc_get_queue_lock(ctx, idx);
33987026d2eSYevgeny Kliteynik 
34087026d2eSYevgeny Kliteynik 	rte_spinlock_lock(queue_lock);
34187026d2eSYevgeny Kliteynik 
34287026d2eSYevgeny Kliteynik 	ret = mlx5dr_bwc_rule_destroy_hws_sync(bwc_rule, &attr);
34387026d2eSYevgeny Kliteynik 	mlx5dr_bwc_rule_list_remove(bwc_rule);
34487026d2eSYevgeny Kliteynik 
34587026d2eSYevgeny Kliteynik 	rte_spinlock_unlock(queue_lock);
34687026d2eSYevgeny Kliteynik 
34787026d2eSYevgeny Kliteynik 	mlx5dr_bwc_rule_free(bwc_rule);
34887026d2eSYevgeny Kliteynik 
34987026d2eSYevgeny Kliteynik 	return ret;
35087026d2eSYevgeny Kliteynik }
35187026d2eSYevgeny Kliteynik 
35287026d2eSYevgeny Kliteynik static int mlx5dr_bwc_rule_destroy_root(struct mlx5dr_bwc_rule *bwc_rule)
35387026d2eSYevgeny Kliteynik {
35487026d2eSYevgeny Kliteynik 	int ret;
35587026d2eSYevgeny Kliteynik 
35687026d2eSYevgeny Kliteynik 	ret = mlx5dr_rule_destroy_root_no_comp(bwc_rule->rule);
35787026d2eSYevgeny Kliteynik 
35887026d2eSYevgeny Kliteynik 	mlx5dr_bwc_rule_free(bwc_rule);
35987026d2eSYevgeny Kliteynik 
36087026d2eSYevgeny Kliteynik 	return ret;
36187026d2eSYevgeny Kliteynik }
36287026d2eSYevgeny Kliteynik 
36387026d2eSYevgeny Kliteynik int mlx5dr_bwc_rule_destroy(struct mlx5dr_bwc_rule *bwc_rule)
36487026d2eSYevgeny Kliteynik {
36587026d2eSYevgeny Kliteynik 	if (unlikely(mlx5dr_table_is_root(bwc_rule->bwc_matcher->matcher->tbl)))
36687026d2eSYevgeny Kliteynik 		return mlx5dr_bwc_rule_destroy_root(bwc_rule);
36787026d2eSYevgeny Kliteynik 
36887026d2eSYevgeny Kliteynik 	return mlx5dr_bwc_rule_destroy_hws(bwc_rule);
36987026d2eSYevgeny Kliteynik }
37087026d2eSYevgeny Kliteynik 
37187026d2eSYevgeny Kliteynik static struct mlx5dr_bwc_rule *
37287026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_create_hws_async(struct mlx5dr_bwc_matcher *bwc_matcher,
37387026d2eSYevgeny Kliteynik 				 const struct rte_flow_item flow_items[],
37487026d2eSYevgeny Kliteynik 				 uint8_t at_idx,
37587026d2eSYevgeny Kliteynik 				 struct mlx5dr_rule_action rule_actions[],
37687026d2eSYevgeny Kliteynik 				 struct mlx5dr_rule_attr *rule_attr)
37787026d2eSYevgeny Kliteynik {
37887026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_rule *bwc_rule;
37987026d2eSYevgeny Kliteynik 	int ret;
38087026d2eSYevgeny Kliteynik 
38187026d2eSYevgeny Kliteynik 	bwc_rule = mlx5dr_bwc_rule_alloc();
38287026d2eSYevgeny Kliteynik 	if (unlikely(!bwc_rule))
38387026d2eSYevgeny Kliteynik 		return NULL;
38487026d2eSYevgeny Kliteynik 
38587026d2eSYevgeny Kliteynik 	bwc_rule->bwc_matcher = bwc_matcher;
38687026d2eSYevgeny Kliteynik 
38787026d2eSYevgeny Kliteynik 	ret = mlx5dr_rule_create(bwc_matcher->matcher,
38887026d2eSYevgeny Kliteynik 				 0, /* only one match template supported */
38987026d2eSYevgeny Kliteynik 				 flow_items,
39087026d2eSYevgeny Kliteynik 				 at_idx,
39187026d2eSYevgeny Kliteynik 				 rule_actions,
39287026d2eSYevgeny Kliteynik 				 rule_attr,
39387026d2eSYevgeny Kliteynik 				 bwc_rule->rule);
39487026d2eSYevgeny Kliteynik 
39587026d2eSYevgeny Kliteynik 	if (unlikely(ret)) {
39687026d2eSYevgeny Kliteynik 		mlx5dr_bwc_rule_free(bwc_rule);
39787026d2eSYevgeny Kliteynik 		rte_errno = EINVAL;
39887026d2eSYevgeny Kliteynik 		return NULL;
39987026d2eSYevgeny Kliteynik 	}
40087026d2eSYevgeny Kliteynik 
40187026d2eSYevgeny Kliteynik 	return bwc_rule;
40287026d2eSYevgeny Kliteynik }
40387026d2eSYevgeny Kliteynik 
40487026d2eSYevgeny Kliteynik static struct mlx5dr_bwc_rule *
40587026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_create_root_sync(struct mlx5dr_bwc_matcher *bwc_matcher,
40687026d2eSYevgeny Kliteynik 				 const struct rte_flow_item flow_items[],
40787026d2eSYevgeny Kliteynik 				 uint8_t num_actions,
40887026d2eSYevgeny Kliteynik 				 struct mlx5dr_rule_action rule_actions[])
40987026d2eSYevgeny Kliteynik {
41087026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_rule *bwc_rule;
41187026d2eSYevgeny Kliteynik 	int ret;
41287026d2eSYevgeny Kliteynik 
41387026d2eSYevgeny Kliteynik 	bwc_rule = mlx5dr_bwc_rule_alloc();
41487026d2eSYevgeny Kliteynik 	if (unlikely(!bwc_rule)) {
41587026d2eSYevgeny Kliteynik 		rte_errno = ENOMEM;
41687026d2eSYevgeny Kliteynik 		return NULL;
41787026d2eSYevgeny Kliteynik 	}
41887026d2eSYevgeny Kliteynik 
41987026d2eSYevgeny Kliteynik 	bwc_rule->bwc_matcher = bwc_matcher;
42087026d2eSYevgeny Kliteynik 	bwc_rule->rule->matcher = bwc_matcher->matcher;
42187026d2eSYevgeny Kliteynik 
42287026d2eSYevgeny Kliteynik 	ret = mlx5dr_rule_create_root_no_comp(bwc_rule->rule,
42387026d2eSYevgeny Kliteynik 					      flow_items,
42487026d2eSYevgeny Kliteynik 					      num_actions,
42587026d2eSYevgeny Kliteynik 					      rule_actions);
42687026d2eSYevgeny Kliteynik 	if (unlikely(ret)) {
42787026d2eSYevgeny Kliteynik 		mlx5dr_bwc_rule_free(bwc_rule);
42887026d2eSYevgeny Kliteynik 		rte_errno = EINVAL;
42987026d2eSYevgeny Kliteynik 		return NULL;
43087026d2eSYevgeny Kliteynik 	}
43187026d2eSYevgeny Kliteynik 
43287026d2eSYevgeny Kliteynik 	return bwc_rule;
43387026d2eSYevgeny Kliteynik }
43487026d2eSYevgeny Kliteynik 
43587026d2eSYevgeny Kliteynik static struct mlx5dr_bwc_rule *
43687026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_create_hws_sync(struct mlx5dr_bwc_matcher *bwc_matcher,
43787026d2eSYevgeny Kliteynik 				const struct rte_flow_item flow_items[],
43887026d2eSYevgeny Kliteynik 				uint8_t at_idx,
43987026d2eSYevgeny Kliteynik 				struct mlx5dr_rule_action rule_actions[],
44087026d2eSYevgeny Kliteynik 				struct mlx5dr_rule_attr *rule_attr)
44187026d2eSYevgeny Kliteynik 
44287026d2eSYevgeny Kliteynik {
44387026d2eSYevgeny Kliteynik 	struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
44487026d2eSYevgeny Kliteynik 	struct rte_flow_op_result completion;
44587026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_rule *bwc_rule;
44687026d2eSYevgeny Kliteynik 	int ret;
44787026d2eSYevgeny Kliteynik 
44887026d2eSYevgeny Kliteynik 	bwc_rule = mlx5dr_bwc_rule_create_hws_async(bwc_matcher, flow_items,
44987026d2eSYevgeny Kliteynik 						    at_idx, rule_actions,
45087026d2eSYevgeny Kliteynik 						    rule_attr);
45187026d2eSYevgeny Kliteynik 	if (unlikely(!bwc_rule))
45287026d2eSYevgeny Kliteynik 		return NULL;
45387026d2eSYevgeny Kliteynik 
45487026d2eSYevgeny Kliteynik 	do {
45587026d2eSYevgeny Kliteynik 		ret = mlx5dr_send_queue_poll(ctx, rule_attr->queue_id, &completion, 1);
45687026d2eSYevgeny Kliteynik 	} while (ret != 1);
45787026d2eSYevgeny Kliteynik 
45887026d2eSYevgeny Kliteynik 	if (unlikely(completion.status != RTE_FLOW_OP_SUCCESS ||
45987026d2eSYevgeny Kliteynik 		     (bwc_rule->rule->status != MLX5DR_RULE_STATUS_CREATED &&
46087026d2eSYevgeny Kliteynik 		      bwc_rule->rule->status != MLX5DR_RULE_STATUS_CREATING))) {
46187026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "Failed creating BWC rule: completion %d, rule status %d",
46287026d2eSYevgeny Kliteynik 		       completion.status, bwc_rule->rule->status);
46387026d2eSYevgeny Kliteynik 		mlx5dr_bwc_rule_free(bwc_rule);
46487026d2eSYevgeny Kliteynik 		return NULL;
46587026d2eSYevgeny Kliteynik 	}
46687026d2eSYevgeny Kliteynik 
46787026d2eSYevgeny Kliteynik 	return bwc_rule;
46887026d2eSYevgeny Kliteynik }
46987026d2eSYevgeny Kliteynik 
47087026d2eSYevgeny Kliteynik static bool
47187026d2eSYevgeny Kliteynik mlx5dr_bwc_matcher_size_maxed_out(struct mlx5dr_bwc_matcher *bwc_matcher)
47287026d2eSYevgeny Kliteynik {
47387026d2eSYevgeny Kliteynik 	struct mlx5dr_cmd_query_caps *caps = bwc_matcher->matcher->tbl->ctx->caps;
47487026d2eSYevgeny Kliteynik 
47587026d2eSYevgeny Kliteynik 	return bwc_matcher->size_log + MLX5DR_MATCHER_ASSURED_MAIN_TBL_DEPTH >=
47687026d2eSYevgeny Kliteynik 	       caps->ste_alloc_log_max - 1;
47787026d2eSYevgeny Kliteynik }
47887026d2eSYevgeny Kliteynik 
47987026d2eSYevgeny Kliteynik static bool
48087026d2eSYevgeny Kliteynik mlx5dr_bwc_matcher_rehash_size_needed(struct mlx5dr_bwc_matcher *bwc_matcher,
48187026d2eSYevgeny Kliteynik 				      uint32_t num_of_rules)
48287026d2eSYevgeny Kliteynik {
48387026d2eSYevgeny Kliteynik 	/* size-based rehash for root table is kernel's responsibility */
48487026d2eSYevgeny Kliteynik 	if (unlikely(mlx5dr_table_is_root(bwc_matcher->matcher->tbl)))
48587026d2eSYevgeny Kliteynik 		return false;
48687026d2eSYevgeny Kliteynik 
48787026d2eSYevgeny Kliteynik 	if (unlikely(mlx5dr_bwc_matcher_size_maxed_out(bwc_matcher)))
48887026d2eSYevgeny Kliteynik 		return false;
48987026d2eSYevgeny Kliteynik 
49087026d2eSYevgeny Kliteynik 	if (unlikely((num_of_rules * 100 / MLX5DR_BWC_MATCHER_REHASH_PERCENT_TH) >=
49187026d2eSYevgeny Kliteynik 		     (1UL << bwc_matcher->size_log)))
49287026d2eSYevgeny Kliteynik 		return true;
49387026d2eSYevgeny Kliteynik 
49487026d2eSYevgeny Kliteynik 	return false;
49587026d2eSYevgeny Kliteynik }
49687026d2eSYevgeny Kliteynik 
49787026d2eSYevgeny Kliteynik static void
49887026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_actions_to_action_types(struct mlx5dr_rule_action rule_actions[],
49987026d2eSYevgeny Kliteynik 					enum mlx5dr_action_type action_types[])
50087026d2eSYevgeny Kliteynik {
50187026d2eSYevgeny Kliteynik 	int i = 0;
50287026d2eSYevgeny Kliteynik 
50387026d2eSYevgeny Kliteynik 	for (i = 0;
50487026d2eSYevgeny Kliteynik 	     rule_actions[i].action && (rule_actions[i].action->type != MLX5DR_ACTION_TYP_LAST);
50587026d2eSYevgeny Kliteynik 	     i++) {
50687026d2eSYevgeny Kliteynik 		action_types[i] = (enum mlx5dr_action_type)rule_actions[i].action->type;
50787026d2eSYevgeny Kliteynik 	}
50887026d2eSYevgeny Kliteynik 
50987026d2eSYevgeny Kliteynik 	action_types[i] = MLX5DR_ACTION_TYP_LAST;
51087026d2eSYevgeny Kliteynik }
51187026d2eSYevgeny Kliteynik 
51287026d2eSYevgeny Kliteynik static int
51387026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_actions_num(struct mlx5dr_rule_action rule_actions[])
51487026d2eSYevgeny Kliteynik {
51587026d2eSYevgeny Kliteynik 	int i = 0;
51687026d2eSYevgeny Kliteynik 
51787026d2eSYevgeny Kliteynik 	while (rule_actions[i].action &&
51887026d2eSYevgeny Kliteynik 	       (rule_actions[i].action->type != MLX5DR_ACTION_TYP_LAST))
51987026d2eSYevgeny Kliteynik 		i++;
52087026d2eSYevgeny Kliteynik 
52187026d2eSYevgeny Kliteynik 	return i;
52287026d2eSYevgeny Kliteynik }
52387026d2eSYevgeny Kliteynik 
52487026d2eSYevgeny Kliteynik static int
52587026d2eSYevgeny Kliteynik mlx5dr_bwc_matcher_extend_at(struct mlx5dr_bwc_matcher *bwc_matcher,
52687026d2eSYevgeny Kliteynik 			     struct mlx5dr_rule_action rule_actions[])
52787026d2eSYevgeny Kliteynik {
52887026d2eSYevgeny Kliteynik 	enum mlx5dr_action_type action_types[MLX5_HW_MAX_ACTS];
52987026d2eSYevgeny Kliteynik 
53087026d2eSYevgeny Kliteynik 	mlx5dr_bwc_rule_actions_to_action_types(rule_actions, action_types);
53187026d2eSYevgeny Kliteynik 
53287026d2eSYevgeny Kliteynik 	bwc_matcher->at[bwc_matcher->num_of_at] =
53387026d2eSYevgeny Kliteynik 		mlx5dr_action_template_create(action_types, 0);
53487026d2eSYevgeny Kliteynik 
53587026d2eSYevgeny Kliteynik 	if (unlikely(!bwc_matcher->at[bwc_matcher->num_of_at])) {
53687026d2eSYevgeny Kliteynik 		rte_errno = ENOMEM;
53787026d2eSYevgeny Kliteynik 		return rte_errno;
53887026d2eSYevgeny Kliteynik 	}
53987026d2eSYevgeny Kliteynik 
54087026d2eSYevgeny Kliteynik 	bwc_matcher->num_of_at++;
54187026d2eSYevgeny Kliteynik 	return 0;
54287026d2eSYevgeny Kliteynik }
54387026d2eSYevgeny Kliteynik 
54487026d2eSYevgeny Kliteynik static int
54587026d2eSYevgeny Kliteynik mlx5dr_bwc_matcher_extend_size(struct mlx5dr_bwc_matcher *bwc_matcher)
54687026d2eSYevgeny Kliteynik {
54787026d2eSYevgeny Kliteynik 	struct mlx5dr_cmd_query_caps *caps = bwc_matcher->matcher->tbl->ctx->caps;
54887026d2eSYevgeny Kliteynik 
54987026d2eSYevgeny Kliteynik 	if (unlikely(mlx5dr_bwc_matcher_size_maxed_out(bwc_matcher))) {
55087026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "Can't resize matcher: depth exceeds limit %d",
55187026d2eSYevgeny Kliteynik 		       caps->rtc_log_depth_max);
55287026d2eSYevgeny Kliteynik 		return -ENOMEM;
55387026d2eSYevgeny Kliteynik 	}
55487026d2eSYevgeny Kliteynik 
55587026d2eSYevgeny Kliteynik 	bwc_matcher->size_log =
55687026d2eSYevgeny Kliteynik 		RTE_MIN(bwc_matcher->size_log + MLX5DR_BWC_MATCHER_SIZE_LOG_STEP,
55787026d2eSYevgeny Kliteynik 			caps->ste_alloc_log_max - MLX5DR_MATCHER_ASSURED_MAIN_TBL_DEPTH);
55887026d2eSYevgeny Kliteynik 
55987026d2eSYevgeny Kliteynik 	return 0;
56087026d2eSYevgeny Kliteynik }
56187026d2eSYevgeny Kliteynik 
56287026d2eSYevgeny Kliteynik static int
56387026d2eSYevgeny Kliteynik mlx5dr_bwc_matcher_find_at(struct mlx5dr_bwc_matcher *bwc_matcher,
56487026d2eSYevgeny Kliteynik 			   struct mlx5dr_rule_action rule_actions[])
56587026d2eSYevgeny Kliteynik {
56687026d2eSYevgeny Kliteynik 	enum mlx5dr_action_type *action_type_arr;
56787026d2eSYevgeny Kliteynik 	int i, j;
56887026d2eSYevgeny Kliteynik 
56987026d2eSYevgeny Kliteynik 	/* start from index 1 - first action template is a dummy */
57087026d2eSYevgeny Kliteynik 	for (i = 1; i < bwc_matcher->num_of_at; i++) {
57187026d2eSYevgeny Kliteynik 		j = 0;
57287026d2eSYevgeny Kliteynik 		action_type_arr = bwc_matcher->at[i]->action_type_arr;
57387026d2eSYevgeny Kliteynik 
57487026d2eSYevgeny Kliteynik 		while (rule_actions[j].action &&
57587026d2eSYevgeny Kliteynik 		       rule_actions[j].action->type != MLX5DR_ACTION_TYP_LAST) {
57687026d2eSYevgeny Kliteynik 			if (action_type_arr[j] != rule_actions[j].action->type)
57787026d2eSYevgeny Kliteynik 				break;
57887026d2eSYevgeny Kliteynik 			j++;
57987026d2eSYevgeny Kliteynik 		}
58087026d2eSYevgeny Kliteynik 
58187026d2eSYevgeny Kliteynik 		if (action_type_arr[j] == MLX5DR_ACTION_TYP_LAST &&
58287026d2eSYevgeny Kliteynik 		    (!rule_actions[j].action ||
58387026d2eSYevgeny Kliteynik 		     rule_actions[j].action->type == MLX5DR_ACTION_TYP_LAST))
58487026d2eSYevgeny Kliteynik 			return i;
58587026d2eSYevgeny Kliteynik 	}
58687026d2eSYevgeny Kliteynik 
58787026d2eSYevgeny Kliteynik 	return -1;
58887026d2eSYevgeny Kliteynik }
58987026d2eSYevgeny Kliteynik 
59087026d2eSYevgeny Kliteynik static int
59187026d2eSYevgeny Kliteynik mlx5dr_bwc_matcher_move_all(struct mlx5dr_bwc_matcher *bwc_matcher)
59287026d2eSYevgeny Kliteynik {
59387026d2eSYevgeny Kliteynik 	struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
59487026d2eSYevgeny Kliteynik 	uint16_t bwc_queues = mlx5dr_bwc_queues(ctx);
59587026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_rule **bwc_rules;
59687026d2eSYevgeny Kliteynik 	struct mlx5dr_rule_attr rule_attr;
59787026d2eSYevgeny Kliteynik 	uint32_t *pending_rules;
598f1788d7aSYevgeny Kliteynik 	uint16_t burst_th;
59987026d2eSYevgeny Kliteynik 	bool all_done;
60087026d2eSYevgeny Kliteynik 	int i, j, ret;
60187026d2eSYevgeny Kliteynik 
60287026d2eSYevgeny Kliteynik 	if (mlx5dr_table_is_root(bwc_matcher->matcher->tbl)) {
60387026d2eSYevgeny Kliteynik 		rte_errno = EINVAL;
60487026d2eSYevgeny Kliteynik 		return -rte_errno;
60587026d2eSYevgeny Kliteynik 	}
60687026d2eSYevgeny Kliteynik 
60787026d2eSYevgeny Kliteynik 	mlx5dr_bwc_rule_fill_attr(bwc_matcher, 0, &rule_attr);
60887026d2eSYevgeny Kliteynik 
60987026d2eSYevgeny Kliteynik 	pending_rules = simple_calloc(bwc_queues, sizeof(*pending_rules));
61087026d2eSYevgeny Kliteynik 	if (!pending_rules) {
61187026d2eSYevgeny Kliteynik 		rte_errno = ENOMEM;
61287026d2eSYevgeny Kliteynik 		return -rte_errno;
61387026d2eSYevgeny Kliteynik 	}
61487026d2eSYevgeny Kliteynik 
61587026d2eSYevgeny Kliteynik 	bwc_rules = simple_calloc(bwc_queues, sizeof(*bwc_rules));
61687026d2eSYevgeny Kliteynik 	if (!bwc_rules) {
61787026d2eSYevgeny Kliteynik 		rte_errno = ENOMEM;
61887026d2eSYevgeny Kliteynik 		goto free_pending_rules;
61987026d2eSYevgeny Kliteynik 	}
62087026d2eSYevgeny Kliteynik 
62187026d2eSYevgeny Kliteynik 	for (i = 0; i < bwc_queues; i++) {
62287026d2eSYevgeny Kliteynik 		if (LIST_EMPTY(&bwc_matcher->rules[i]))
62387026d2eSYevgeny Kliteynik 			bwc_rules[i] = NULL;
62487026d2eSYevgeny Kliteynik 		else
62587026d2eSYevgeny Kliteynik 			bwc_rules[i] = LIST_FIRST(&bwc_matcher->rules[i]);
62687026d2eSYevgeny Kliteynik 	}
62787026d2eSYevgeny Kliteynik 
62887026d2eSYevgeny Kliteynik 	do {
62987026d2eSYevgeny Kliteynik 		all_done = true;
63087026d2eSYevgeny Kliteynik 
63187026d2eSYevgeny Kliteynik 		for (i = 0; i < bwc_queues; i++) {
63287026d2eSYevgeny Kliteynik 			rule_attr.queue_id = mlx5dr_bwc_get_queue_id(ctx, i);
633f1788d7aSYevgeny Kliteynik 			burst_th = mlx5dr_bwc_get_burst_th(ctx, rule_attr.queue_id);
63487026d2eSYevgeny Kliteynik 
635f1788d7aSYevgeny Kliteynik 			for (j = 0; j < burst_th && bwc_rules[i]; j++) {
636f1788d7aSYevgeny Kliteynik 				rule_attr.burst = !!((j + 1) % burst_th);
63787026d2eSYevgeny Kliteynik 				ret = mlx5dr_matcher_resize_rule_move(bwc_matcher->matcher,
63887026d2eSYevgeny Kliteynik 								      bwc_rules[i]->rule,
63987026d2eSYevgeny Kliteynik 								      &rule_attr);
640d3bf0062SYevgeny Kliteynik 				if (unlikely(ret)) {
64187026d2eSYevgeny Kliteynik 					DR_LOG(ERR, "Moving BWC rule failed during rehash - %d",
64287026d2eSYevgeny Kliteynik 					       ret);
64387026d2eSYevgeny Kliteynik 					rte_errno = ENOMEM;
64487026d2eSYevgeny Kliteynik 					goto free_bwc_rules;
64587026d2eSYevgeny Kliteynik 				}
64687026d2eSYevgeny Kliteynik 
64787026d2eSYevgeny Kliteynik 				all_done = false;
64887026d2eSYevgeny Kliteynik 				pending_rules[i]++;
64987026d2eSYevgeny Kliteynik 				bwc_rules[i] = LIST_NEXT(bwc_rules[i], next);
65087026d2eSYevgeny Kliteynik 
651d3bf0062SYevgeny Kliteynik 				ret = mlx5dr_bwc_queue_poll(ctx, rule_attr.queue_id,
65287026d2eSYevgeny Kliteynik 							    &pending_rules[i], false);
653d3bf0062SYevgeny Kliteynik 				if (unlikely(ret)) {
654d3bf0062SYevgeny Kliteynik 					rte_errno = EINVAL;
655d3bf0062SYevgeny Kliteynik 					goto free_bwc_rules;
656d3bf0062SYevgeny Kliteynik 				}
65787026d2eSYevgeny Kliteynik 			}
65887026d2eSYevgeny Kliteynik 		}
65987026d2eSYevgeny Kliteynik 	} while (!all_done);
66087026d2eSYevgeny Kliteynik 
66187026d2eSYevgeny Kliteynik 	/* drain all the bwc queues */
66287026d2eSYevgeny Kliteynik 	for (i = 0; i < bwc_queues; i++) {
66387026d2eSYevgeny Kliteynik 		if (pending_rules[i]) {
66487026d2eSYevgeny Kliteynik 			uint16_t queue_id = mlx5dr_bwc_get_queue_id(ctx, i);
66587026d2eSYevgeny Kliteynik 			mlx5dr_send_engine_flush_queue(&ctx->send_queue[queue_id]);
666d3bf0062SYevgeny Kliteynik 			ret = mlx5dr_bwc_queue_poll(ctx, queue_id,
66787026d2eSYevgeny Kliteynik 						    &pending_rules[i], true);
668d3bf0062SYevgeny Kliteynik 			if (unlikely(ret)) {
669d3bf0062SYevgeny Kliteynik 				rte_errno = EINVAL;
670d3bf0062SYevgeny Kliteynik 				goto free_bwc_rules;
671d3bf0062SYevgeny Kliteynik 			}
67287026d2eSYevgeny Kliteynik 		}
67387026d2eSYevgeny Kliteynik 	}
67487026d2eSYevgeny Kliteynik 
67587026d2eSYevgeny Kliteynik 	rte_errno = 0;
67687026d2eSYevgeny Kliteynik 
67787026d2eSYevgeny Kliteynik free_bwc_rules:
67887026d2eSYevgeny Kliteynik 	simple_free(bwc_rules);
67987026d2eSYevgeny Kliteynik free_pending_rules:
68087026d2eSYevgeny Kliteynik 	simple_free(pending_rules);
68187026d2eSYevgeny Kliteynik 
68287026d2eSYevgeny Kliteynik 	return -rte_errno;
68387026d2eSYevgeny Kliteynik }
68487026d2eSYevgeny Kliteynik 
68587026d2eSYevgeny Kliteynik static int
68687026d2eSYevgeny Kliteynik mlx5dr_bwc_matcher_move(struct mlx5dr_bwc_matcher *bwc_matcher)
68787026d2eSYevgeny Kliteynik {
68887026d2eSYevgeny Kliteynik 	struct mlx5dr_matcher_attr matcher_attr = {0};
68987026d2eSYevgeny Kliteynik 	struct mlx5dr_matcher *old_matcher;
69087026d2eSYevgeny Kliteynik 	struct mlx5dr_matcher *new_matcher;
69187026d2eSYevgeny Kliteynik 	int ret;
69287026d2eSYevgeny Kliteynik 
69387026d2eSYevgeny Kliteynik 	mlx5dr_bwc_matcher_init_attr(&matcher_attr,
69487026d2eSYevgeny Kliteynik 				     bwc_matcher->priority,
69587026d2eSYevgeny Kliteynik 				     bwc_matcher->size_log,
69687026d2eSYevgeny Kliteynik 				     mlx5dr_table_is_root(bwc_matcher->matcher->tbl));
69787026d2eSYevgeny Kliteynik 
69887026d2eSYevgeny Kliteynik 	old_matcher = bwc_matcher->matcher;
69987026d2eSYevgeny Kliteynik 	new_matcher = mlx5dr_matcher_create(old_matcher->tbl,
70087026d2eSYevgeny Kliteynik 					    &bwc_matcher->mt, 1,
70187026d2eSYevgeny Kliteynik 					    bwc_matcher->at,
70287026d2eSYevgeny Kliteynik 					    bwc_matcher->num_of_at,
70387026d2eSYevgeny Kliteynik 					    &matcher_attr);
70487026d2eSYevgeny Kliteynik 	if (!new_matcher) {
70587026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "Rehash error: matcher creation failed");
70687026d2eSYevgeny Kliteynik 		return -ENOMEM;
70787026d2eSYevgeny Kliteynik 	}
70887026d2eSYevgeny Kliteynik 
70987026d2eSYevgeny Kliteynik 	ret = mlx5dr_matcher_resize_set_target(old_matcher, new_matcher);
71087026d2eSYevgeny Kliteynik 	if (ret) {
71187026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "Rehash error: failed setting resize target");
71287026d2eSYevgeny Kliteynik 		return ret;
71387026d2eSYevgeny Kliteynik 	}
71487026d2eSYevgeny Kliteynik 
71587026d2eSYevgeny Kliteynik 	ret = mlx5dr_bwc_matcher_move_all(bwc_matcher);
71687026d2eSYevgeny Kliteynik 	if (ret) {
71787026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "Rehash error: moving rules failed");
71887026d2eSYevgeny Kliteynik 		return -ENOMEM;
71987026d2eSYevgeny Kliteynik 	}
72087026d2eSYevgeny Kliteynik 
72187026d2eSYevgeny Kliteynik 	bwc_matcher->matcher = new_matcher;
72287026d2eSYevgeny Kliteynik 	mlx5dr_matcher_destroy(old_matcher);
72387026d2eSYevgeny Kliteynik 
72487026d2eSYevgeny Kliteynik 	return 0;
72587026d2eSYevgeny Kliteynik }
72687026d2eSYevgeny Kliteynik 
72787026d2eSYevgeny Kliteynik static int
72863911723SYevgeny Kliteynik mlx5dr_bwc_matcher_rehash_size(struct mlx5dr_bwc_matcher *bwc_matcher)
72987026d2eSYevgeny Kliteynik {
73087026d2eSYevgeny Kliteynik 	uint32_t num_of_rules;
73187026d2eSYevgeny Kliteynik 	int ret;
73287026d2eSYevgeny Kliteynik 
73387026d2eSYevgeny Kliteynik 	/* If the current matcher size is already at its max size, we can't
73487026d2eSYevgeny Kliteynik 	 * do the rehash. Skip it and try adding the rule again - perhaps
73587026d2eSYevgeny Kliteynik 	 * there was some change.
73687026d2eSYevgeny Kliteynik 	 */
73787026d2eSYevgeny Kliteynik 	if (mlx5dr_bwc_matcher_size_maxed_out(bwc_matcher))
73887026d2eSYevgeny Kliteynik 		return 0;
73987026d2eSYevgeny Kliteynik 
74087026d2eSYevgeny Kliteynik 	/* It is possible that other rule has already performed rehash.
74187026d2eSYevgeny Kliteynik 	 * Need to check again if we really need rehash.
74287026d2eSYevgeny Kliteynik 	 * If the reason for rehash was size, but not any more - skip rehash.
74387026d2eSYevgeny Kliteynik 	 */
74487026d2eSYevgeny Kliteynik 	num_of_rules = rte_atomic_load_explicit(&bwc_matcher->num_of_rules,
74587026d2eSYevgeny Kliteynik 						rte_memory_order_relaxed);
74663911723SYevgeny Kliteynik 	if (!mlx5dr_bwc_matcher_rehash_size_needed(bwc_matcher, num_of_rules))
74787026d2eSYevgeny Kliteynik 		return 0;
74887026d2eSYevgeny Kliteynik 
74987026d2eSYevgeny Kliteynik 	/* Now we're done all the checking - do the rehash:
75087026d2eSYevgeny Kliteynik 	 *  - extend match RTC size
75187026d2eSYevgeny Kliteynik 	 *  - create new matcher
75287026d2eSYevgeny Kliteynik 	 *  - move all the rules to the new matcher
75387026d2eSYevgeny Kliteynik 	 *  - destroy the old matcher
75487026d2eSYevgeny Kliteynik 	 */
75587026d2eSYevgeny Kliteynik 
75687026d2eSYevgeny Kliteynik 	ret = mlx5dr_bwc_matcher_extend_size(bwc_matcher);
75787026d2eSYevgeny Kliteynik 	if (ret)
75887026d2eSYevgeny Kliteynik 		return ret;
75987026d2eSYevgeny Kliteynik 
76087026d2eSYevgeny Kliteynik 	return mlx5dr_bwc_matcher_move(bwc_matcher);
76187026d2eSYevgeny Kliteynik }
76287026d2eSYevgeny Kliteynik 
76363911723SYevgeny Kliteynik static int
76463911723SYevgeny Kliteynik mlx5dr_bwc_matcher_rehash_at(struct mlx5dr_bwc_matcher *bwc_matcher)
76563911723SYevgeny Kliteynik {
76663911723SYevgeny Kliteynik 	/* Rehash by action template doesn't require any additional checking.
76763911723SYevgeny Kliteynik 	 * The bwc_matcher already contains the new action template.
76863911723SYevgeny Kliteynik 	 * Just do the usual rehash:
76963911723SYevgeny Kliteynik 	 *  - create new matcher
77063911723SYevgeny Kliteynik 	 *  - move all the rules to the new matcher
77163911723SYevgeny Kliteynik 	 *  - destroy the old matcher
77263911723SYevgeny Kliteynik 	 */
77363911723SYevgeny Kliteynik 	return mlx5dr_bwc_matcher_move(bwc_matcher);
77463911723SYevgeny Kliteynik }
77563911723SYevgeny Kliteynik 
77687026d2eSYevgeny Kliteynik static struct mlx5dr_bwc_rule *
77787026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_create_root(struct mlx5dr_bwc_matcher *bwc_matcher,
77887026d2eSYevgeny Kliteynik 			    const struct rte_flow_item flow_items[],
77987026d2eSYevgeny Kliteynik 			    struct mlx5dr_rule_action rule_actions[])
78087026d2eSYevgeny Kliteynik {
78187026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_rule *bwc_rule;
78287026d2eSYevgeny Kliteynik 
78387026d2eSYevgeny Kliteynik 	bwc_rule = mlx5dr_bwc_rule_create_root_sync(bwc_matcher,
78487026d2eSYevgeny Kliteynik 						    flow_items,
78587026d2eSYevgeny Kliteynik 						    mlx5dr_bwc_rule_actions_num(rule_actions),
78687026d2eSYevgeny Kliteynik 						    rule_actions);
78787026d2eSYevgeny Kliteynik 
78887026d2eSYevgeny Kliteynik 	if (unlikely(!bwc_rule))
78987026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "BWC rule: failed creating rule on root tbl");
79087026d2eSYevgeny Kliteynik 
79187026d2eSYevgeny Kliteynik 	return bwc_rule;
79287026d2eSYevgeny Kliteynik }
79387026d2eSYevgeny Kliteynik 
79487026d2eSYevgeny Kliteynik static struct mlx5dr_bwc_rule *
79587026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_create_hws(struct mlx5dr_bwc_matcher *bwc_matcher,
79687026d2eSYevgeny Kliteynik 			   const struct rte_flow_item flow_items[],
79787026d2eSYevgeny Kliteynik 			   struct mlx5dr_rule_action rule_actions[])
79887026d2eSYevgeny Kliteynik {
79987026d2eSYevgeny Kliteynik 	struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
80087026d2eSYevgeny Kliteynik 	struct mlx5dr_bwc_rule *bwc_rule = NULL;
80187026d2eSYevgeny Kliteynik 	struct mlx5dr_rule_attr rule_attr;
80287026d2eSYevgeny Kliteynik 	rte_spinlock_t *queue_lock;
80387026d2eSYevgeny Kliteynik 	uint32_t num_of_rules;
80487026d2eSYevgeny Kliteynik 	uint16_t idx;
80587026d2eSYevgeny Kliteynik 	int at_idx;
80687026d2eSYevgeny Kliteynik 	int ret;
80787026d2eSYevgeny Kliteynik 
80887026d2eSYevgeny Kliteynik 	idx = mlx5dr_bwc_gen_queue_idx(ctx);
80987026d2eSYevgeny Kliteynik 
81087026d2eSYevgeny Kliteynik 	mlx5dr_bwc_rule_fill_attr(bwc_matcher, idx, &rule_attr);
81187026d2eSYevgeny Kliteynik 
81287026d2eSYevgeny Kliteynik 	queue_lock = mlx5dr_bwc_get_queue_lock(ctx, idx);
81387026d2eSYevgeny Kliteynik 
81487026d2eSYevgeny Kliteynik 	rte_spinlock_lock(queue_lock);
81587026d2eSYevgeny Kliteynik 
81687026d2eSYevgeny Kliteynik 	/* check if rehash needed due to missing action template */
81787026d2eSYevgeny Kliteynik 	at_idx = mlx5dr_bwc_matcher_find_at(bwc_matcher, rule_actions);
81863911723SYevgeny Kliteynik 	if (unlikely(at_idx < 0)) {
81987026d2eSYevgeny Kliteynik 		/* we need to extend BWC matcher action templates array */
82087026d2eSYevgeny Kliteynik 		rte_spinlock_unlock(queue_lock);
82187026d2eSYevgeny Kliteynik 		mlx5dr_bwc_lock_all_queues(ctx);
82287026d2eSYevgeny Kliteynik 
82387026d2eSYevgeny Kliteynik 		ret = mlx5dr_bwc_matcher_extend_at(bwc_matcher, rule_actions);
82487026d2eSYevgeny Kliteynik 		if (unlikely(ret)) {
82587026d2eSYevgeny Kliteynik 			mlx5dr_bwc_unlock_all_queues(ctx);
82687026d2eSYevgeny Kliteynik 			rte_errno = EINVAL;
82787026d2eSYevgeny Kliteynik 			DR_LOG(ERR, "BWC rule: failed extending action template - %d", ret);
82887026d2eSYevgeny Kliteynik 			return NULL;
82987026d2eSYevgeny Kliteynik 		}
83087026d2eSYevgeny Kliteynik 
83187026d2eSYevgeny Kliteynik 		/* action templates array was extended, we need the last idx */
83287026d2eSYevgeny Kliteynik 		at_idx = bwc_matcher->num_of_at - 1;
83387026d2eSYevgeny Kliteynik 
83487026d2eSYevgeny Kliteynik 		ret = mlx5dr_matcher_attach_at(bwc_matcher->matcher,
83587026d2eSYevgeny Kliteynik 					       bwc_matcher->at[at_idx]);
83687026d2eSYevgeny Kliteynik 		if (unlikely(ret)) {
83763911723SYevgeny Kliteynik 			/* Action template attach failed, possibly due to
83863911723SYevgeny Kliteynik 			 * requiring more action STEs.
83963911723SYevgeny Kliteynik 			 * Need to attempt creating new matcher with all
84063911723SYevgeny Kliteynik 			 * the action templates, including the new one.
84163911723SYevgeny Kliteynik 			 */
84263911723SYevgeny Kliteynik 			ret = mlx5dr_bwc_matcher_rehash_at(bwc_matcher);
84363911723SYevgeny Kliteynik 			if (unlikely(ret)) {
84487026d2eSYevgeny Kliteynik 				mlx5dr_action_template_destroy(bwc_matcher->at[at_idx]);
84587026d2eSYevgeny Kliteynik 				bwc_matcher->at[at_idx] = NULL;
84687026d2eSYevgeny Kliteynik 				bwc_matcher->num_of_at--;
84787026d2eSYevgeny Kliteynik 
84887026d2eSYevgeny Kliteynik 				mlx5dr_bwc_unlock_all_queues(ctx);
84963911723SYevgeny Kliteynik 
85063911723SYevgeny Kliteynik 				DR_LOG(ERR, "BWC rule insertion: rehash AT failed - %d", ret);
85187026d2eSYevgeny Kliteynik 				return NULL;
85287026d2eSYevgeny Kliteynik 			}
85363911723SYevgeny Kliteynik 		}
85487026d2eSYevgeny Kliteynik 
85587026d2eSYevgeny Kliteynik 		mlx5dr_bwc_unlock_all_queues(ctx);
85687026d2eSYevgeny Kliteynik 		rte_spinlock_lock(queue_lock);
85787026d2eSYevgeny Kliteynik 	}
85887026d2eSYevgeny Kliteynik 
85987026d2eSYevgeny Kliteynik 	/* check if number of rules require rehash */
86087026d2eSYevgeny Kliteynik 	num_of_rules = rte_atomic_load_explicit(&bwc_matcher->num_of_rules,
86187026d2eSYevgeny Kliteynik 						rte_memory_order_relaxed);
86263911723SYevgeny Kliteynik 	if (unlikely(mlx5dr_bwc_matcher_rehash_size_needed(bwc_matcher, num_of_rules))) {
86363911723SYevgeny Kliteynik 		rte_spinlock_unlock(queue_lock);
86463911723SYevgeny Kliteynik 
86563911723SYevgeny Kliteynik 		mlx5dr_bwc_lock_all_queues(ctx);
86663911723SYevgeny Kliteynik 		ret = mlx5dr_bwc_matcher_rehash_size(bwc_matcher);
86763911723SYevgeny Kliteynik 		mlx5dr_bwc_unlock_all_queues(ctx);
86863911723SYevgeny Kliteynik 
86963911723SYevgeny Kliteynik 		if (ret) {
87063911723SYevgeny Kliteynik 			DR_LOG(ERR, "BWC rule insertion: rehash size [%d -> %d] failed - %d",
87163911723SYevgeny Kliteynik 			       bwc_matcher->size_log - MLX5DR_BWC_MATCHER_SIZE_LOG_STEP,
87263911723SYevgeny Kliteynik 			       bwc_matcher->size_log,
87363911723SYevgeny Kliteynik 			       ret);
87463911723SYevgeny Kliteynik 			return NULL;
87563911723SYevgeny Kliteynik 		}
87663911723SYevgeny Kliteynik 
87763911723SYevgeny Kliteynik 		rte_spinlock_lock(queue_lock);
87887026d2eSYevgeny Kliteynik 	}
87987026d2eSYevgeny Kliteynik 
88087026d2eSYevgeny Kliteynik 	bwc_rule = mlx5dr_bwc_rule_create_hws_sync(bwc_matcher,
88187026d2eSYevgeny Kliteynik 						   flow_items,
88287026d2eSYevgeny Kliteynik 						   at_idx,
88387026d2eSYevgeny Kliteynik 						   rule_actions,
88487026d2eSYevgeny Kliteynik 						   &rule_attr);
88587026d2eSYevgeny Kliteynik 
88687026d2eSYevgeny Kliteynik 	if (likely(bwc_rule)) {
88787026d2eSYevgeny Kliteynik 		mlx5dr_bwc_rule_list_add(bwc_rule, idx);
88887026d2eSYevgeny Kliteynik 		rte_spinlock_unlock(queue_lock);
88987026d2eSYevgeny Kliteynik 		return bwc_rule; /* rule inserted successfully */
89087026d2eSYevgeny Kliteynik 	}
89187026d2eSYevgeny Kliteynik 
89287026d2eSYevgeny Kliteynik 	/* At this point the rule wasn't added.
89387026d2eSYevgeny Kliteynik 	 * It could be because there was collision, or some other problem.
89487026d2eSYevgeny Kliteynik 	 * If we don't dive deeper than API, the only thing we know is that
89587026d2eSYevgeny Kliteynik 	 * the status of completion is RTE_FLOW_OP_ERROR.
89663911723SYevgeny Kliteynik 	 * Try rehash by size and insert rule again - last chance.
89787026d2eSYevgeny Kliteynik 	 */
89887026d2eSYevgeny Kliteynik 
89987026d2eSYevgeny Kliteynik 	rte_spinlock_unlock(queue_lock);
90087026d2eSYevgeny Kliteynik 
90187026d2eSYevgeny Kliteynik 	mlx5dr_bwc_lock_all_queues(ctx);
90263911723SYevgeny Kliteynik 	ret = mlx5dr_bwc_matcher_rehash_size(bwc_matcher);
90387026d2eSYevgeny Kliteynik 	mlx5dr_bwc_unlock_all_queues(ctx);
90487026d2eSYevgeny Kliteynik 
90587026d2eSYevgeny Kliteynik 	if (ret) {
90687026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "BWC rule insertion: rehash failed - %d", ret);
90787026d2eSYevgeny Kliteynik 		return NULL;
90887026d2eSYevgeny Kliteynik 	}
90987026d2eSYevgeny Kliteynik 
91087026d2eSYevgeny Kliteynik 	/* Rehash done, but we still have that pesky rule to add */
91187026d2eSYevgeny Kliteynik 	rte_spinlock_lock(queue_lock);
91287026d2eSYevgeny Kliteynik 
91387026d2eSYevgeny Kliteynik 	bwc_rule = mlx5dr_bwc_rule_create_hws_sync(bwc_matcher,
91487026d2eSYevgeny Kliteynik 						   flow_items,
91587026d2eSYevgeny Kliteynik 						   at_idx,
91687026d2eSYevgeny Kliteynik 						   rule_actions,
91787026d2eSYevgeny Kliteynik 						   &rule_attr);
91887026d2eSYevgeny Kliteynik 
91987026d2eSYevgeny Kliteynik 	if (unlikely(!bwc_rule)) {
92087026d2eSYevgeny Kliteynik 		rte_spinlock_unlock(queue_lock);
92187026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "BWC rule insertion failed");
92287026d2eSYevgeny Kliteynik 		return NULL;
92387026d2eSYevgeny Kliteynik 	}
92487026d2eSYevgeny Kliteynik 
92587026d2eSYevgeny Kliteynik 	mlx5dr_bwc_rule_list_add(bwc_rule, idx);
92687026d2eSYevgeny Kliteynik 	rte_spinlock_unlock(queue_lock);
92787026d2eSYevgeny Kliteynik 
92887026d2eSYevgeny Kliteynik 	return bwc_rule;
92987026d2eSYevgeny Kliteynik }
93087026d2eSYevgeny Kliteynik 
93187026d2eSYevgeny Kliteynik struct mlx5dr_bwc_rule *
93287026d2eSYevgeny Kliteynik mlx5dr_bwc_rule_create(struct mlx5dr_bwc_matcher *bwc_matcher,
93387026d2eSYevgeny Kliteynik 		       const struct rte_flow_item flow_items[],
93487026d2eSYevgeny Kliteynik 		       struct mlx5dr_rule_action rule_actions[])
93587026d2eSYevgeny Kliteynik {
93687026d2eSYevgeny Kliteynik 	struct mlx5dr_context *ctx = bwc_matcher->matcher->tbl->ctx;
93787026d2eSYevgeny Kliteynik 
93887026d2eSYevgeny Kliteynik 	if (unlikely(!mlx5dr_context_bwc_supported(ctx))) {
93987026d2eSYevgeny Kliteynik 		rte_errno = EINVAL;
94087026d2eSYevgeny Kliteynik 		DR_LOG(ERR, "BWC rule: Context created w/o BWC API compatibility");
94187026d2eSYevgeny Kliteynik 		return NULL;
94287026d2eSYevgeny Kliteynik 	}
94387026d2eSYevgeny Kliteynik 
94487026d2eSYevgeny Kliteynik 	if (unlikely(mlx5dr_table_is_root(bwc_matcher->matcher->tbl)))
94587026d2eSYevgeny Kliteynik 		return mlx5dr_bwc_rule_create_root(bwc_matcher,
94687026d2eSYevgeny Kliteynik 						   flow_items,
94787026d2eSYevgeny Kliteynik 						   rule_actions);
94887026d2eSYevgeny Kliteynik 
94987026d2eSYevgeny Kliteynik 	return mlx5dr_bwc_rule_create_hws(bwc_matcher,
95087026d2eSYevgeny Kliteynik 					  flow_items,
95187026d2eSYevgeny Kliteynik 					  rule_actions);
95287026d2eSYevgeny Kliteynik }
953