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