141d07074SAlex Vesker // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 241d07074SAlex Vesker /* Copyright (c) 2019 Mellanox Technologies. */ 341d07074SAlex Vesker 441d07074SAlex Vesker #include "dr_types.h" 541d07074SAlex Vesker 641d07074SAlex Vesker #define DR_RULE_MAX_STE_CHAIN (DR_RULE_MAX_STES + DR_ACTION_MAX_STES) 741d07074SAlex Vesker 841d07074SAlex Vesker struct mlx5dr_rule_action_member { 941d07074SAlex Vesker struct mlx5dr_action *action; 1041d07074SAlex Vesker struct list_head list; 1141d07074SAlex Vesker }; 1241d07074SAlex Vesker 1341d07074SAlex Vesker static int dr_rule_append_to_miss_list(struct mlx5dr_ste *new_last_ste, 1441d07074SAlex Vesker struct list_head *miss_list, 1541d07074SAlex Vesker struct list_head *send_list) 1641d07074SAlex Vesker { 1741d07074SAlex Vesker struct mlx5dr_ste_send_info *ste_info_last; 1841d07074SAlex Vesker struct mlx5dr_ste *last_ste; 1941d07074SAlex Vesker 2041d07074SAlex Vesker /* The new entry will be inserted after the last */ 2148cbde4bSAlex Vesker last_ste = list_last_entry(miss_list, struct mlx5dr_ste, miss_list_node); 2241d07074SAlex Vesker WARN_ON(!last_ste); 2341d07074SAlex Vesker 2441d07074SAlex Vesker ste_info_last = kzalloc(sizeof(*ste_info_last), GFP_KERNEL); 2541d07074SAlex Vesker if (!ste_info_last) 2641d07074SAlex Vesker return -ENOMEM; 2741d07074SAlex Vesker 2841d07074SAlex Vesker mlx5dr_ste_set_miss_addr(last_ste->hw_ste, 2941d07074SAlex Vesker mlx5dr_ste_get_icm_addr(new_last_ste)); 3041d07074SAlex Vesker list_add_tail(&new_last_ste->miss_list_node, miss_list); 3141d07074SAlex Vesker 3241d07074SAlex Vesker mlx5dr_send_fill_and_append_ste_send_info(last_ste, DR_STE_SIZE_REDUCED, 3341d07074SAlex Vesker 0, last_ste->hw_ste, 3441d07074SAlex Vesker ste_info_last, send_list, true); 3541d07074SAlex Vesker 3641d07074SAlex Vesker return 0; 3741d07074SAlex Vesker } 3841d07074SAlex Vesker 3941d07074SAlex Vesker static struct mlx5dr_ste * 4041d07074SAlex Vesker dr_rule_create_collision_htbl(struct mlx5dr_matcher *matcher, 4141d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher, 4241d07074SAlex Vesker u8 *hw_ste) 4341d07074SAlex Vesker { 4441d07074SAlex Vesker struct mlx5dr_domain *dmn = matcher->tbl->dmn; 4541d07074SAlex Vesker struct mlx5dr_ste_htbl *new_htbl; 4641d07074SAlex Vesker struct mlx5dr_ste *ste; 4741d07074SAlex Vesker 4841d07074SAlex Vesker /* Create new table for miss entry */ 4941d07074SAlex Vesker new_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, 5041d07074SAlex Vesker DR_CHUNK_SIZE_1, 5141d07074SAlex Vesker MLX5DR_STE_LU_TYPE_DONT_CARE, 5241d07074SAlex Vesker 0); 5341d07074SAlex Vesker if (!new_htbl) { 5441d07074SAlex Vesker mlx5dr_dbg(dmn, "Failed allocating collision table\n"); 5541d07074SAlex Vesker return NULL; 5641d07074SAlex Vesker } 5741d07074SAlex Vesker 5841d07074SAlex Vesker /* One and only entry, never grows */ 5941d07074SAlex Vesker ste = new_htbl->ste_arr; 6041d07074SAlex Vesker mlx5dr_ste_set_miss_addr(hw_ste, nic_matcher->e_anchor->chunk->icm_addr); 6141d07074SAlex Vesker mlx5dr_htbl_get(new_htbl); 6241d07074SAlex Vesker 6341d07074SAlex Vesker return ste; 6441d07074SAlex Vesker } 6541d07074SAlex Vesker 6641d07074SAlex Vesker static struct mlx5dr_ste * 6741d07074SAlex Vesker dr_rule_create_collision_entry(struct mlx5dr_matcher *matcher, 6841d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher, 6941d07074SAlex Vesker u8 *hw_ste, 7041d07074SAlex Vesker struct mlx5dr_ste *orig_ste) 7141d07074SAlex Vesker { 7241d07074SAlex Vesker struct mlx5dr_ste *ste; 7341d07074SAlex Vesker 7441d07074SAlex Vesker ste = dr_rule_create_collision_htbl(matcher, nic_matcher, hw_ste); 7541d07074SAlex Vesker if (!ste) { 7641d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Failed creating collision entry\n"); 7741d07074SAlex Vesker return NULL; 7841d07074SAlex Vesker } 7941d07074SAlex Vesker 8041d07074SAlex Vesker ste->ste_chain_location = orig_ste->ste_chain_location; 8141d07074SAlex Vesker 8241d07074SAlex Vesker /* In collision entry, all members share the same miss_list_head */ 8341d07074SAlex Vesker ste->htbl->miss_list = mlx5dr_ste_get_miss_list(orig_ste); 8441d07074SAlex Vesker 8541d07074SAlex Vesker /* Next table */ 8641d07074SAlex Vesker if (mlx5dr_ste_create_next_htbl(matcher, nic_matcher, ste, hw_ste, 8741d07074SAlex Vesker DR_CHUNK_SIZE_1)) { 8841d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Failed allocating table\n"); 8941d07074SAlex Vesker goto free_tbl; 9041d07074SAlex Vesker } 9141d07074SAlex Vesker 9241d07074SAlex Vesker return ste; 9341d07074SAlex Vesker 9441d07074SAlex Vesker free_tbl: 9541d07074SAlex Vesker mlx5dr_ste_free(ste, matcher, nic_matcher); 9641d07074SAlex Vesker return NULL; 9741d07074SAlex Vesker } 9841d07074SAlex Vesker 9941d07074SAlex Vesker static int 10041d07074SAlex Vesker dr_rule_handle_one_ste_in_update_list(struct mlx5dr_ste_send_info *ste_info, 10141d07074SAlex Vesker struct mlx5dr_domain *dmn) 10241d07074SAlex Vesker { 10341d07074SAlex Vesker int ret; 10441d07074SAlex Vesker 10541d07074SAlex Vesker list_del(&ste_info->send_list); 10641d07074SAlex Vesker ret = mlx5dr_send_postsend_ste(dmn, ste_info->ste, ste_info->data, 10741d07074SAlex Vesker ste_info->size, ste_info->offset); 10841d07074SAlex Vesker if (ret) 10941d07074SAlex Vesker goto out; 11041d07074SAlex Vesker /* Copy data to ste, only reduced size, the last 16B (mask) 11141d07074SAlex Vesker * is already written to the hw. 11241d07074SAlex Vesker */ 11341d07074SAlex Vesker memcpy(ste_info->ste->hw_ste, ste_info->data, DR_STE_SIZE_REDUCED); 11441d07074SAlex Vesker 11541d07074SAlex Vesker out: 11641d07074SAlex Vesker kfree(ste_info); 11741d07074SAlex Vesker return ret; 11841d07074SAlex Vesker } 11941d07074SAlex Vesker 12041d07074SAlex Vesker static int dr_rule_send_update_list(struct list_head *send_ste_list, 12141d07074SAlex Vesker struct mlx5dr_domain *dmn, 12241d07074SAlex Vesker bool is_reverse) 12341d07074SAlex Vesker { 12441d07074SAlex Vesker struct mlx5dr_ste_send_info *ste_info, *tmp_ste_info; 12541d07074SAlex Vesker int ret; 12641d07074SAlex Vesker 12741d07074SAlex Vesker if (is_reverse) { 12841d07074SAlex Vesker list_for_each_entry_safe_reverse(ste_info, tmp_ste_info, 12941d07074SAlex Vesker send_ste_list, send_list) { 13041d07074SAlex Vesker ret = dr_rule_handle_one_ste_in_update_list(ste_info, 13141d07074SAlex Vesker dmn); 13241d07074SAlex Vesker if (ret) 13341d07074SAlex Vesker return ret; 13441d07074SAlex Vesker } 13541d07074SAlex Vesker } else { 13641d07074SAlex Vesker list_for_each_entry_safe(ste_info, tmp_ste_info, 13741d07074SAlex Vesker send_ste_list, send_list) { 13841d07074SAlex Vesker ret = dr_rule_handle_one_ste_in_update_list(ste_info, 13941d07074SAlex Vesker dmn); 14041d07074SAlex Vesker if (ret) 14141d07074SAlex Vesker return ret; 14241d07074SAlex Vesker } 14341d07074SAlex Vesker } 14441d07074SAlex Vesker 14541d07074SAlex Vesker return 0; 14641d07074SAlex Vesker } 14741d07074SAlex Vesker 14841d07074SAlex Vesker static struct mlx5dr_ste * 14941d07074SAlex Vesker dr_rule_find_ste_in_miss_list(struct list_head *miss_list, u8 *hw_ste) 15041d07074SAlex Vesker { 15141d07074SAlex Vesker struct mlx5dr_ste *ste; 15241d07074SAlex Vesker 15341d07074SAlex Vesker if (list_empty(miss_list)) 15441d07074SAlex Vesker return NULL; 15541d07074SAlex Vesker 15641d07074SAlex Vesker /* Check if hw_ste is present in the list */ 15741d07074SAlex Vesker list_for_each_entry(ste, miss_list, miss_list_node) { 15841d07074SAlex Vesker if (mlx5dr_ste_equal_tag(ste->hw_ste, hw_ste)) 15941d07074SAlex Vesker return ste; 16041d07074SAlex Vesker } 16141d07074SAlex Vesker 16241d07074SAlex Vesker return NULL; 16341d07074SAlex Vesker } 16441d07074SAlex Vesker 16541d07074SAlex Vesker static struct mlx5dr_ste * 16641d07074SAlex Vesker dr_rule_rehash_handle_collision(struct mlx5dr_matcher *matcher, 16741d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher, 16841d07074SAlex Vesker struct list_head *update_list, 16941d07074SAlex Vesker struct mlx5dr_ste *col_ste, 17041d07074SAlex Vesker u8 *hw_ste) 17141d07074SAlex Vesker { 17241d07074SAlex Vesker struct mlx5dr_ste *new_ste; 17341d07074SAlex Vesker int ret; 17441d07074SAlex Vesker 17541d07074SAlex Vesker new_ste = dr_rule_create_collision_htbl(matcher, nic_matcher, hw_ste); 17641d07074SAlex Vesker if (!new_ste) 17741d07074SAlex Vesker return NULL; 17841d07074SAlex Vesker 17941d07074SAlex Vesker /* In collision entry, all members share the same miss_list_head */ 18041d07074SAlex Vesker new_ste->htbl->miss_list = mlx5dr_ste_get_miss_list(col_ste); 18141d07074SAlex Vesker 18241d07074SAlex Vesker /* Update the previous from the list */ 18341d07074SAlex Vesker ret = dr_rule_append_to_miss_list(new_ste, 18441d07074SAlex Vesker mlx5dr_ste_get_miss_list(col_ste), 18541d07074SAlex Vesker update_list); 18641d07074SAlex Vesker if (ret) { 18741d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Failed update dup entry\n"); 18841d07074SAlex Vesker goto err_exit; 18941d07074SAlex Vesker } 19041d07074SAlex Vesker 19141d07074SAlex Vesker return new_ste; 19241d07074SAlex Vesker 19341d07074SAlex Vesker err_exit: 19441d07074SAlex Vesker mlx5dr_ste_free(new_ste, matcher, nic_matcher); 19541d07074SAlex Vesker return NULL; 19641d07074SAlex Vesker } 19741d07074SAlex Vesker 19841d07074SAlex Vesker static void dr_rule_rehash_copy_ste_ctrl(struct mlx5dr_matcher *matcher, 19941d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher, 20041d07074SAlex Vesker struct mlx5dr_ste *cur_ste, 20141d07074SAlex Vesker struct mlx5dr_ste *new_ste) 20241d07074SAlex Vesker { 20341d07074SAlex Vesker new_ste->next_htbl = cur_ste->next_htbl; 20441d07074SAlex Vesker new_ste->ste_chain_location = cur_ste->ste_chain_location; 20541d07074SAlex Vesker 20641d07074SAlex Vesker if (!mlx5dr_ste_is_last_in_rule(nic_matcher, new_ste->ste_chain_location)) 20741d07074SAlex Vesker new_ste->next_htbl->pointing_ste = new_ste; 20841d07074SAlex Vesker 20941d07074SAlex Vesker /* We need to copy the refcount since this ste 21041d07074SAlex Vesker * may have been traversed several times 21141d07074SAlex Vesker */ 21241d07074SAlex Vesker refcount_set(&new_ste->refcount, refcount_read(&cur_ste->refcount)); 21341d07074SAlex Vesker 21441d07074SAlex Vesker /* Link old STEs rule_mem list to the new ste */ 21541d07074SAlex Vesker mlx5dr_rule_update_rule_member(cur_ste, new_ste); 21641d07074SAlex Vesker INIT_LIST_HEAD(&new_ste->rule_list); 21741d07074SAlex Vesker list_splice_tail_init(&cur_ste->rule_list, &new_ste->rule_list); 21841d07074SAlex Vesker } 21941d07074SAlex Vesker 22041d07074SAlex Vesker static struct mlx5dr_ste * 22141d07074SAlex Vesker dr_rule_rehash_copy_ste(struct mlx5dr_matcher *matcher, 22241d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher, 22341d07074SAlex Vesker struct mlx5dr_ste *cur_ste, 22441d07074SAlex Vesker struct mlx5dr_ste_htbl *new_htbl, 22541d07074SAlex Vesker struct list_head *update_list) 22641d07074SAlex Vesker { 22741d07074SAlex Vesker struct mlx5dr_ste_send_info *ste_info; 22841d07074SAlex Vesker bool use_update_list = false; 22941d07074SAlex Vesker u8 hw_ste[DR_STE_SIZE] = {}; 23041d07074SAlex Vesker struct mlx5dr_ste *new_ste; 23141d07074SAlex Vesker int new_idx; 23241d07074SAlex Vesker u8 sb_idx; 23341d07074SAlex Vesker 23441d07074SAlex Vesker /* Copy STE mask from the matcher */ 23541d07074SAlex Vesker sb_idx = cur_ste->ste_chain_location - 1; 23641d07074SAlex Vesker mlx5dr_ste_set_bit_mask(hw_ste, nic_matcher->ste_builder[sb_idx].bit_mask); 23741d07074SAlex Vesker 23841d07074SAlex Vesker /* Copy STE control and tag */ 23941d07074SAlex Vesker memcpy(hw_ste, cur_ste->hw_ste, DR_STE_SIZE_REDUCED); 24041d07074SAlex Vesker mlx5dr_ste_set_miss_addr(hw_ste, nic_matcher->e_anchor->chunk->icm_addr); 24141d07074SAlex Vesker 24241d07074SAlex Vesker new_idx = mlx5dr_ste_calc_hash_index(hw_ste, new_htbl); 24341d07074SAlex Vesker new_ste = &new_htbl->ste_arr[new_idx]; 24441d07074SAlex Vesker 24541d07074SAlex Vesker if (mlx5dr_ste_not_used_ste(new_ste)) { 24641d07074SAlex Vesker mlx5dr_htbl_get(new_htbl); 24741d07074SAlex Vesker list_add_tail(&new_ste->miss_list_node, 24841d07074SAlex Vesker mlx5dr_ste_get_miss_list(new_ste)); 24941d07074SAlex Vesker } else { 25041d07074SAlex Vesker new_ste = dr_rule_rehash_handle_collision(matcher, 25141d07074SAlex Vesker nic_matcher, 25241d07074SAlex Vesker update_list, 25341d07074SAlex Vesker new_ste, 25441d07074SAlex Vesker hw_ste); 25541d07074SAlex Vesker if (!new_ste) { 25641d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Failed adding collision entry, index: %d\n", 25741d07074SAlex Vesker new_idx); 25841d07074SAlex Vesker return NULL; 25941d07074SAlex Vesker } 26041d07074SAlex Vesker new_htbl->ctrl.num_of_collisions++; 26141d07074SAlex Vesker use_update_list = true; 26241d07074SAlex Vesker } 26341d07074SAlex Vesker 26441d07074SAlex Vesker memcpy(new_ste->hw_ste, hw_ste, DR_STE_SIZE_REDUCED); 26541d07074SAlex Vesker 26641d07074SAlex Vesker new_htbl->ctrl.num_of_valid_entries++; 26741d07074SAlex Vesker 26841d07074SAlex Vesker if (use_update_list) { 26941d07074SAlex Vesker ste_info = kzalloc(sizeof(*ste_info), GFP_KERNEL); 27041d07074SAlex Vesker if (!ste_info) 27141d07074SAlex Vesker goto err_exit; 27241d07074SAlex Vesker 27341d07074SAlex Vesker mlx5dr_send_fill_and_append_ste_send_info(new_ste, DR_STE_SIZE, 0, 27441d07074SAlex Vesker hw_ste, ste_info, 27541d07074SAlex Vesker update_list, true); 27641d07074SAlex Vesker } 27741d07074SAlex Vesker 27841d07074SAlex Vesker dr_rule_rehash_copy_ste_ctrl(matcher, nic_matcher, cur_ste, new_ste); 27941d07074SAlex Vesker 28041d07074SAlex Vesker return new_ste; 28141d07074SAlex Vesker 28241d07074SAlex Vesker err_exit: 28341d07074SAlex Vesker mlx5dr_ste_free(new_ste, matcher, nic_matcher); 28441d07074SAlex Vesker return NULL; 28541d07074SAlex Vesker } 28641d07074SAlex Vesker 28741d07074SAlex Vesker static int dr_rule_rehash_copy_miss_list(struct mlx5dr_matcher *matcher, 28841d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher, 28941d07074SAlex Vesker struct list_head *cur_miss_list, 29041d07074SAlex Vesker struct mlx5dr_ste_htbl *new_htbl, 29141d07074SAlex Vesker struct list_head *update_list) 29241d07074SAlex Vesker { 29341d07074SAlex Vesker struct mlx5dr_ste *tmp_ste, *cur_ste, *new_ste; 29441d07074SAlex Vesker 29541d07074SAlex Vesker if (list_empty(cur_miss_list)) 29641d07074SAlex Vesker return 0; 29741d07074SAlex Vesker 29841d07074SAlex Vesker list_for_each_entry_safe(cur_ste, tmp_ste, cur_miss_list, miss_list_node) { 29941d07074SAlex Vesker new_ste = dr_rule_rehash_copy_ste(matcher, 30041d07074SAlex Vesker nic_matcher, 30141d07074SAlex Vesker cur_ste, 30241d07074SAlex Vesker new_htbl, 30341d07074SAlex Vesker update_list); 30441d07074SAlex Vesker if (!new_ste) 30541d07074SAlex Vesker goto err_insert; 30641d07074SAlex Vesker 30741d07074SAlex Vesker list_del(&cur_ste->miss_list_node); 30841d07074SAlex Vesker mlx5dr_htbl_put(cur_ste->htbl); 30941d07074SAlex Vesker } 31041d07074SAlex Vesker return 0; 31141d07074SAlex Vesker 31241d07074SAlex Vesker err_insert: 31341d07074SAlex Vesker mlx5dr_err(matcher->tbl->dmn, "Fatal error during resize\n"); 31441d07074SAlex Vesker WARN_ON(true); 31541d07074SAlex Vesker return -EINVAL; 31641d07074SAlex Vesker } 31741d07074SAlex Vesker 31841d07074SAlex Vesker static int dr_rule_rehash_copy_htbl(struct mlx5dr_matcher *matcher, 31941d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher, 32041d07074SAlex Vesker struct mlx5dr_ste_htbl *cur_htbl, 32141d07074SAlex Vesker struct mlx5dr_ste_htbl *new_htbl, 32241d07074SAlex Vesker struct list_head *update_list) 32341d07074SAlex Vesker { 32441d07074SAlex Vesker struct mlx5dr_ste *cur_ste; 32541d07074SAlex Vesker int cur_entries; 32641d07074SAlex Vesker int err = 0; 32741d07074SAlex Vesker int i; 32841d07074SAlex Vesker 32941d07074SAlex Vesker cur_entries = mlx5dr_icm_pool_chunk_size_to_entries(cur_htbl->chunk_size); 33041d07074SAlex Vesker 33141d07074SAlex Vesker if (cur_entries < 1) { 33241d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Invalid number of entries\n"); 33341d07074SAlex Vesker return -EINVAL; 33441d07074SAlex Vesker } 33541d07074SAlex Vesker 33641d07074SAlex Vesker for (i = 0; i < cur_entries; i++) { 33741d07074SAlex Vesker cur_ste = &cur_htbl->ste_arr[i]; 33841d07074SAlex Vesker if (mlx5dr_ste_not_used_ste(cur_ste)) /* Empty, nothing to copy */ 33941d07074SAlex Vesker continue; 34041d07074SAlex Vesker 34141d07074SAlex Vesker err = dr_rule_rehash_copy_miss_list(matcher, 34241d07074SAlex Vesker nic_matcher, 34341d07074SAlex Vesker mlx5dr_ste_get_miss_list(cur_ste), 34441d07074SAlex Vesker new_htbl, 34541d07074SAlex Vesker update_list); 34641d07074SAlex Vesker if (err) 34741d07074SAlex Vesker goto clean_copy; 34841d07074SAlex Vesker } 34941d07074SAlex Vesker 35041d07074SAlex Vesker clean_copy: 35141d07074SAlex Vesker return err; 35241d07074SAlex Vesker } 35341d07074SAlex Vesker 35441d07074SAlex Vesker static struct mlx5dr_ste_htbl * 35541d07074SAlex Vesker dr_rule_rehash_htbl(struct mlx5dr_rule *rule, 35641d07074SAlex Vesker struct mlx5dr_rule_rx_tx *nic_rule, 35741d07074SAlex Vesker struct mlx5dr_ste_htbl *cur_htbl, 35841d07074SAlex Vesker u8 ste_location, 35941d07074SAlex Vesker struct list_head *update_list, 36041d07074SAlex Vesker enum mlx5dr_icm_chunk_size new_size) 36141d07074SAlex Vesker { 36241d07074SAlex Vesker struct mlx5dr_ste_send_info *del_ste_info, *tmp_ste_info; 36341d07074SAlex Vesker struct mlx5dr_matcher *matcher = rule->matcher; 36441d07074SAlex Vesker struct mlx5dr_domain *dmn = matcher->tbl->dmn; 36541d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher; 36641d07074SAlex Vesker struct mlx5dr_ste_send_info *ste_info; 36741d07074SAlex Vesker struct mlx5dr_htbl_connect_info info; 36841d07074SAlex Vesker struct mlx5dr_domain_rx_tx *nic_dmn; 36941d07074SAlex Vesker u8 formatted_ste[DR_STE_SIZE] = {}; 37041d07074SAlex Vesker LIST_HEAD(rehash_table_send_list); 37141d07074SAlex Vesker struct mlx5dr_ste *ste_to_update; 37241d07074SAlex Vesker struct mlx5dr_ste_htbl *new_htbl; 37341d07074SAlex Vesker int err; 37441d07074SAlex Vesker 37541d07074SAlex Vesker nic_matcher = nic_rule->nic_matcher; 37641d07074SAlex Vesker nic_dmn = nic_matcher->nic_tbl->nic_dmn; 37741d07074SAlex Vesker 37841d07074SAlex Vesker ste_info = kzalloc(sizeof(*ste_info), GFP_KERNEL); 37941d07074SAlex Vesker if (!ste_info) 38041d07074SAlex Vesker return NULL; 38141d07074SAlex Vesker 38241d07074SAlex Vesker new_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, 38341d07074SAlex Vesker new_size, 38441d07074SAlex Vesker cur_htbl->lu_type, 38541d07074SAlex Vesker cur_htbl->byte_mask); 38641d07074SAlex Vesker if (!new_htbl) { 38741d07074SAlex Vesker mlx5dr_err(dmn, "Failed to allocate new hash table\n"); 38841d07074SAlex Vesker goto free_ste_info; 38941d07074SAlex Vesker } 39041d07074SAlex Vesker 39141d07074SAlex Vesker /* Write new table to HW */ 39241d07074SAlex Vesker info.type = CONNECT_MISS; 39341d07074SAlex Vesker info.miss_icm_addr = nic_matcher->e_anchor->chunk->icm_addr; 39441d07074SAlex Vesker mlx5dr_ste_set_formatted_ste(dmn->info.caps.gvmi, 39541d07074SAlex Vesker nic_dmn, 39641d07074SAlex Vesker new_htbl, 39741d07074SAlex Vesker formatted_ste, 39841d07074SAlex Vesker &info); 39941d07074SAlex Vesker 40041d07074SAlex Vesker new_htbl->pointing_ste = cur_htbl->pointing_ste; 40141d07074SAlex Vesker new_htbl->pointing_ste->next_htbl = new_htbl; 40241d07074SAlex Vesker err = dr_rule_rehash_copy_htbl(matcher, 40341d07074SAlex Vesker nic_matcher, 40441d07074SAlex Vesker cur_htbl, 40541d07074SAlex Vesker new_htbl, 40641d07074SAlex Vesker &rehash_table_send_list); 40741d07074SAlex Vesker if (err) 40841d07074SAlex Vesker goto free_new_htbl; 40941d07074SAlex Vesker 41041d07074SAlex Vesker if (mlx5dr_send_postsend_htbl(dmn, new_htbl, formatted_ste, 41141d07074SAlex Vesker nic_matcher->ste_builder[ste_location - 1].bit_mask)) { 41241d07074SAlex Vesker mlx5dr_err(dmn, "Failed writing table to HW\n"); 41341d07074SAlex Vesker goto free_new_htbl; 41441d07074SAlex Vesker } 41541d07074SAlex Vesker 41641d07074SAlex Vesker /* Writing to the hw is done in regular order of rehash_table_send_list, 41741d07074SAlex Vesker * in order to have the origin data written before the miss address of 41841d07074SAlex Vesker * collision entries, if exists. 41941d07074SAlex Vesker */ 42041d07074SAlex Vesker if (dr_rule_send_update_list(&rehash_table_send_list, dmn, false)) { 42141d07074SAlex Vesker mlx5dr_err(dmn, "Failed updating table to HW\n"); 42241d07074SAlex Vesker goto free_ste_list; 42341d07074SAlex Vesker } 42441d07074SAlex Vesker 42541d07074SAlex Vesker /* Connect previous hash table to current */ 42641d07074SAlex Vesker if (ste_location == 1) { 42741d07074SAlex Vesker /* The previous table is an anchor, anchors size is always one STE */ 42841d07074SAlex Vesker struct mlx5dr_ste_htbl *prev_htbl = cur_htbl->pointing_ste->htbl; 42941d07074SAlex Vesker 43041d07074SAlex Vesker /* On matcher s_anchor we keep an extra refcount */ 43141d07074SAlex Vesker mlx5dr_htbl_get(new_htbl); 43241d07074SAlex Vesker mlx5dr_htbl_put(cur_htbl); 43341d07074SAlex Vesker 43441d07074SAlex Vesker nic_matcher->s_htbl = new_htbl; 43541d07074SAlex Vesker 43641d07074SAlex Vesker /* It is safe to operate dr_ste_set_hit_addr on the hw_ste here 43741d07074SAlex Vesker * (48B len) which works only on first 32B 43841d07074SAlex Vesker */ 43941d07074SAlex Vesker mlx5dr_ste_set_hit_addr(prev_htbl->ste_arr[0].hw_ste, 44041d07074SAlex Vesker new_htbl->chunk->icm_addr, 44141d07074SAlex Vesker new_htbl->chunk->num_of_entries); 44241d07074SAlex Vesker 44341d07074SAlex Vesker ste_to_update = &prev_htbl->ste_arr[0]; 44441d07074SAlex Vesker } else { 44541d07074SAlex Vesker mlx5dr_ste_set_hit_addr_by_next_htbl(cur_htbl->pointing_ste->hw_ste, 44641d07074SAlex Vesker new_htbl); 44741d07074SAlex Vesker ste_to_update = cur_htbl->pointing_ste; 44841d07074SAlex Vesker } 44941d07074SAlex Vesker 45041d07074SAlex Vesker mlx5dr_send_fill_and_append_ste_send_info(ste_to_update, DR_STE_SIZE_REDUCED, 45141d07074SAlex Vesker 0, ste_to_update->hw_ste, ste_info, 45241d07074SAlex Vesker update_list, false); 45341d07074SAlex Vesker 45441d07074SAlex Vesker return new_htbl; 45541d07074SAlex Vesker 45641d07074SAlex Vesker free_ste_list: 45741d07074SAlex Vesker /* Clean all ste_info's from the new table */ 45841d07074SAlex Vesker list_for_each_entry_safe(del_ste_info, tmp_ste_info, 45941d07074SAlex Vesker &rehash_table_send_list, send_list) { 46041d07074SAlex Vesker list_del(&del_ste_info->send_list); 46141d07074SAlex Vesker kfree(del_ste_info); 46241d07074SAlex Vesker } 46341d07074SAlex Vesker 46441d07074SAlex Vesker free_new_htbl: 46541d07074SAlex Vesker mlx5dr_ste_htbl_free(new_htbl); 46641d07074SAlex Vesker free_ste_info: 46741d07074SAlex Vesker kfree(ste_info); 46841d07074SAlex Vesker mlx5dr_info(dmn, "Failed creating rehash table\n"); 46941d07074SAlex Vesker return NULL; 47041d07074SAlex Vesker } 47141d07074SAlex Vesker 47241d07074SAlex Vesker static struct mlx5dr_ste_htbl *dr_rule_rehash(struct mlx5dr_rule *rule, 47341d07074SAlex Vesker struct mlx5dr_rule_rx_tx *nic_rule, 47441d07074SAlex Vesker struct mlx5dr_ste_htbl *cur_htbl, 47541d07074SAlex Vesker u8 ste_location, 47641d07074SAlex Vesker struct list_head *update_list) 47741d07074SAlex Vesker { 47841d07074SAlex Vesker struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; 47941d07074SAlex Vesker enum mlx5dr_icm_chunk_size new_size; 48041d07074SAlex Vesker 48141d07074SAlex Vesker new_size = mlx5dr_icm_next_higher_chunk(cur_htbl->chunk_size); 48241d07074SAlex Vesker new_size = min_t(u32, new_size, dmn->info.max_log_sw_icm_sz); 48341d07074SAlex Vesker 48441d07074SAlex Vesker if (new_size == cur_htbl->chunk_size) 48541d07074SAlex Vesker return NULL; /* Skip rehash, we already at the max size */ 48641d07074SAlex Vesker 48741d07074SAlex Vesker return dr_rule_rehash_htbl(rule, nic_rule, cur_htbl, ste_location, 48841d07074SAlex Vesker update_list, new_size); 48941d07074SAlex Vesker } 49041d07074SAlex Vesker 49141d07074SAlex Vesker static struct mlx5dr_ste * 49241d07074SAlex Vesker dr_rule_handle_collision(struct mlx5dr_matcher *matcher, 49341d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher, 49441d07074SAlex Vesker struct mlx5dr_ste *ste, 49541d07074SAlex Vesker u8 *hw_ste, 49641d07074SAlex Vesker struct list_head *miss_list, 49741d07074SAlex Vesker struct list_head *send_list) 49841d07074SAlex Vesker { 49941d07074SAlex Vesker struct mlx5dr_ste_send_info *ste_info; 50041d07074SAlex Vesker struct mlx5dr_ste *new_ste; 50141d07074SAlex Vesker 50241d07074SAlex Vesker ste_info = kzalloc(sizeof(*ste_info), GFP_KERNEL); 50341d07074SAlex Vesker if (!ste_info) 50441d07074SAlex Vesker return NULL; 50541d07074SAlex Vesker 50641d07074SAlex Vesker new_ste = dr_rule_create_collision_entry(matcher, nic_matcher, hw_ste, ste); 50741d07074SAlex Vesker if (!new_ste) 50841d07074SAlex Vesker goto free_send_info; 50941d07074SAlex Vesker 51041d07074SAlex Vesker if (dr_rule_append_to_miss_list(new_ste, miss_list, send_list)) { 51141d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Failed to update prev miss_list\n"); 51241d07074SAlex Vesker goto err_exit; 51341d07074SAlex Vesker } 51441d07074SAlex Vesker 51541d07074SAlex Vesker mlx5dr_send_fill_and_append_ste_send_info(new_ste, DR_STE_SIZE, 0, hw_ste, 51641d07074SAlex Vesker ste_info, send_list, false); 51741d07074SAlex Vesker 51841d07074SAlex Vesker ste->htbl->ctrl.num_of_collisions++; 51941d07074SAlex Vesker ste->htbl->ctrl.num_of_valid_entries++; 52041d07074SAlex Vesker 52141d07074SAlex Vesker return new_ste; 52241d07074SAlex Vesker 52341d07074SAlex Vesker err_exit: 52441d07074SAlex Vesker mlx5dr_ste_free(new_ste, matcher, nic_matcher); 52541d07074SAlex Vesker free_send_info: 52641d07074SAlex Vesker kfree(ste_info); 52741d07074SAlex Vesker return NULL; 52841d07074SAlex Vesker } 52941d07074SAlex Vesker 53041d07074SAlex Vesker static void dr_rule_remove_action_members(struct mlx5dr_rule *rule) 53141d07074SAlex Vesker { 53241d07074SAlex Vesker struct mlx5dr_rule_action_member *action_mem; 53341d07074SAlex Vesker struct mlx5dr_rule_action_member *tmp; 53441d07074SAlex Vesker 53541d07074SAlex Vesker list_for_each_entry_safe(action_mem, tmp, &rule->rule_actions_list, list) { 53641d07074SAlex Vesker list_del(&action_mem->list); 53741d07074SAlex Vesker refcount_dec(&action_mem->action->refcount); 53841d07074SAlex Vesker kvfree(action_mem); 53941d07074SAlex Vesker } 54041d07074SAlex Vesker } 54141d07074SAlex Vesker 54241d07074SAlex Vesker static int dr_rule_add_action_members(struct mlx5dr_rule *rule, 54341d07074SAlex Vesker size_t num_actions, 54441d07074SAlex Vesker struct mlx5dr_action *actions[]) 54541d07074SAlex Vesker { 54641d07074SAlex Vesker struct mlx5dr_rule_action_member *action_mem; 54741d07074SAlex Vesker int i; 54841d07074SAlex Vesker 54941d07074SAlex Vesker for (i = 0; i < num_actions; i++) { 55041d07074SAlex Vesker action_mem = kvzalloc(sizeof(*action_mem), GFP_KERNEL); 55141d07074SAlex Vesker if (!action_mem) 55241d07074SAlex Vesker goto free_action_members; 55341d07074SAlex Vesker 55441d07074SAlex Vesker action_mem->action = actions[i]; 55541d07074SAlex Vesker INIT_LIST_HEAD(&action_mem->list); 55641d07074SAlex Vesker list_add_tail(&action_mem->list, &rule->rule_actions_list); 55741d07074SAlex Vesker refcount_inc(&action_mem->action->refcount); 55841d07074SAlex Vesker } 55941d07074SAlex Vesker 56041d07074SAlex Vesker return 0; 56141d07074SAlex Vesker 56241d07074SAlex Vesker free_action_members: 56341d07074SAlex Vesker dr_rule_remove_action_members(rule); 56441d07074SAlex Vesker return -ENOMEM; 56541d07074SAlex Vesker } 56641d07074SAlex Vesker 56741d07074SAlex Vesker /* While the pointer of ste is no longer valid, like while moving ste to be 56841d07074SAlex Vesker * the first in the miss_list, and to be in the origin table, 56941d07074SAlex Vesker * all rule-members that are attached to this ste should update their ste member 57041d07074SAlex Vesker * to the new pointer 57141d07074SAlex Vesker */ 57241d07074SAlex Vesker void mlx5dr_rule_update_rule_member(struct mlx5dr_ste *ste, 57341d07074SAlex Vesker struct mlx5dr_ste *new_ste) 57441d07074SAlex Vesker { 57541d07074SAlex Vesker struct mlx5dr_rule_member *rule_mem; 57641d07074SAlex Vesker 57741d07074SAlex Vesker if (!list_empty(&ste->rule_list)) 57841d07074SAlex Vesker list_for_each_entry(rule_mem, &ste->rule_list, use_ste_list) 57941d07074SAlex Vesker rule_mem->ste = new_ste; 58041d07074SAlex Vesker } 58141d07074SAlex Vesker 58241d07074SAlex Vesker static void dr_rule_clean_rule_members(struct mlx5dr_rule *rule, 58341d07074SAlex Vesker struct mlx5dr_rule_rx_tx *nic_rule) 58441d07074SAlex Vesker { 58541d07074SAlex Vesker struct mlx5dr_rule_member *rule_mem; 58641d07074SAlex Vesker struct mlx5dr_rule_member *tmp_mem; 58741d07074SAlex Vesker 58841d07074SAlex Vesker if (list_empty(&nic_rule->rule_members_list)) 58941d07074SAlex Vesker return; 59041d07074SAlex Vesker list_for_each_entry_safe(rule_mem, tmp_mem, &nic_rule->rule_members_list, list) { 59141d07074SAlex Vesker list_del(&rule_mem->list); 59241d07074SAlex Vesker list_del(&rule_mem->use_ste_list); 59341d07074SAlex Vesker mlx5dr_ste_put(rule_mem->ste, rule->matcher, nic_rule->nic_matcher); 59441d07074SAlex Vesker kvfree(rule_mem); 59541d07074SAlex Vesker } 59641d07074SAlex Vesker } 59741d07074SAlex Vesker 59841d07074SAlex Vesker static bool dr_rule_need_enlarge_hash(struct mlx5dr_ste_htbl *htbl, 59941d07074SAlex Vesker struct mlx5dr_domain *dmn, 60041d07074SAlex Vesker struct mlx5dr_domain_rx_tx *nic_dmn) 60141d07074SAlex Vesker { 60241d07074SAlex Vesker struct mlx5dr_ste_htbl_ctrl *ctrl = &htbl->ctrl; 60341d07074SAlex Vesker 60441d07074SAlex Vesker if (dmn->info.max_log_sw_icm_sz <= htbl->chunk_size) 60541d07074SAlex Vesker return false; 60641d07074SAlex Vesker 60741d07074SAlex Vesker if (!ctrl->may_grow) 60841d07074SAlex Vesker return false; 60941d07074SAlex Vesker 61041d07074SAlex Vesker if (ctrl->num_of_collisions >= ctrl->increase_threshold && 61141d07074SAlex Vesker (ctrl->num_of_valid_entries - ctrl->num_of_collisions) >= ctrl->increase_threshold) 61241d07074SAlex Vesker return true; 61341d07074SAlex Vesker 61441d07074SAlex Vesker return false; 61541d07074SAlex Vesker } 61641d07074SAlex Vesker 61741d07074SAlex Vesker static int dr_rule_add_member(struct mlx5dr_rule_rx_tx *nic_rule, 61841d07074SAlex Vesker struct mlx5dr_ste *ste) 61941d07074SAlex Vesker { 62041d07074SAlex Vesker struct mlx5dr_rule_member *rule_mem; 62141d07074SAlex Vesker 62241d07074SAlex Vesker rule_mem = kvzalloc(sizeof(*rule_mem), GFP_KERNEL); 62341d07074SAlex Vesker if (!rule_mem) 62441d07074SAlex Vesker return -ENOMEM; 62541d07074SAlex Vesker 62641d07074SAlex Vesker rule_mem->ste = ste; 62741d07074SAlex Vesker list_add_tail(&rule_mem->list, &nic_rule->rule_members_list); 62841d07074SAlex Vesker 62941d07074SAlex Vesker list_add_tail(&rule_mem->use_ste_list, &ste->rule_list); 63041d07074SAlex Vesker 63141d07074SAlex Vesker return 0; 63241d07074SAlex Vesker } 63341d07074SAlex Vesker 63441d07074SAlex Vesker static int dr_rule_handle_action_stes(struct mlx5dr_rule *rule, 63541d07074SAlex Vesker struct mlx5dr_rule_rx_tx *nic_rule, 63641d07074SAlex Vesker struct list_head *send_ste_list, 63741d07074SAlex Vesker struct mlx5dr_ste *last_ste, 63841d07074SAlex Vesker u8 *hw_ste_arr, 63941d07074SAlex Vesker u32 new_hw_ste_arr_sz) 64041d07074SAlex Vesker { 64141d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher = nic_rule->nic_matcher; 64241d07074SAlex Vesker struct mlx5dr_ste_send_info *ste_info_arr[DR_ACTION_MAX_STES]; 64341d07074SAlex Vesker u8 num_of_builders = nic_matcher->num_of_builders; 64441d07074SAlex Vesker struct mlx5dr_matcher *matcher = rule->matcher; 64541d07074SAlex Vesker u8 *curr_hw_ste, *prev_hw_ste; 64641d07074SAlex Vesker struct mlx5dr_ste *action_ste; 64741d07074SAlex Vesker int i, k, ret; 64841d07074SAlex Vesker 64941d07074SAlex Vesker /* Two cases: 65041d07074SAlex Vesker * 1. num_of_builders is equal to new_hw_ste_arr_sz, the action in the ste 65141d07074SAlex Vesker * 2. num_of_builders is less then new_hw_ste_arr_sz, new ste was added 65241d07074SAlex Vesker * to support the action. 65341d07074SAlex Vesker */ 65441d07074SAlex Vesker if (num_of_builders == new_hw_ste_arr_sz) 65541d07074SAlex Vesker return 0; 65641d07074SAlex Vesker 65741d07074SAlex Vesker for (i = num_of_builders, k = 0; i < new_hw_ste_arr_sz; i++, k++) { 65841d07074SAlex Vesker curr_hw_ste = hw_ste_arr + i * DR_STE_SIZE; 65941d07074SAlex Vesker prev_hw_ste = (i == 0) ? curr_hw_ste : hw_ste_arr + ((i - 1) * DR_STE_SIZE); 66041d07074SAlex Vesker action_ste = dr_rule_create_collision_htbl(matcher, 66141d07074SAlex Vesker nic_matcher, 66241d07074SAlex Vesker curr_hw_ste); 66341d07074SAlex Vesker if (!action_ste) 66441d07074SAlex Vesker return -ENOMEM; 66541d07074SAlex Vesker 66641d07074SAlex Vesker mlx5dr_ste_get(action_ste); 66741d07074SAlex Vesker 66841d07074SAlex Vesker /* While free ste we go over the miss list, so add this ste to the list */ 66941d07074SAlex Vesker list_add_tail(&action_ste->miss_list_node, 67041d07074SAlex Vesker mlx5dr_ste_get_miss_list(action_ste)); 67141d07074SAlex Vesker 67241d07074SAlex Vesker ste_info_arr[k] = kzalloc(sizeof(*ste_info_arr[k]), 67341d07074SAlex Vesker GFP_KERNEL); 67441d07074SAlex Vesker if (!ste_info_arr[k]) 67541d07074SAlex Vesker goto err_exit; 67641d07074SAlex Vesker 67741d07074SAlex Vesker /* Point current ste to the new action */ 67841d07074SAlex Vesker mlx5dr_ste_set_hit_addr_by_next_htbl(prev_hw_ste, action_ste->htbl); 67941d07074SAlex Vesker ret = dr_rule_add_member(nic_rule, action_ste); 68041d07074SAlex Vesker if (ret) { 68141d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Failed adding rule member\n"); 68241d07074SAlex Vesker goto free_ste_info; 68341d07074SAlex Vesker } 68441d07074SAlex Vesker mlx5dr_send_fill_and_append_ste_send_info(action_ste, DR_STE_SIZE, 0, 68541d07074SAlex Vesker curr_hw_ste, 68641d07074SAlex Vesker ste_info_arr[k], 68741d07074SAlex Vesker send_ste_list, false); 68841d07074SAlex Vesker } 68941d07074SAlex Vesker 69041d07074SAlex Vesker return 0; 69141d07074SAlex Vesker 69241d07074SAlex Vesker free_ste_info: 69341d07074SAlex Vesker kfree(ste_info_arr[k]); 69441d07074SAlex Vesker err_exit: 69541d07074SAlex Vesker mlx5dr_ste_put(action_ste, matcher, nic_matcher); 69641d07074SAlex Vesker return -ENOMEM; 69741d07074SAlex Vesker } 69841d07074SAlex Vesker 69941d07074SAlex Vesker static int dr_rule_handle_empty_entry(struct mlx5dr_matcher *matcher, 70041d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher, 70141d07074SAlex Vesker struct mlx5dr_ste_htbl *cur_htbl, 70241d07074SAlex Vesker struct mlx5dr_ste *ste, 70341d07074SAlex Vesker u8 ste_location, 70441d07074SAlex Vesker u8 *hw_ste, 70541d07074SAlex Vesker struct list_head *miss_list, 70641d07074SAlex Vesker struct list_head *send_list) 70741d07074SAlex Vesker { 70841d07074SAlex Vesker struct mlx5dr_ste_send_info *ste_info; 70941d07074SAlex Vesker 71041d07074SAlex Vesker /* Take ref on table, only on first time this ste is used */ 71141d07074SAlex Vesker mlx5dr_htbl_get(cur_htbl); 71241d07074SAlex Vesker 71341d07074SAlex Vesker /* new entry -> new branch */ 71441d07074SAlex Vesker list_add_tail(&ste->miss_list_node, miss_list); 71541d07074SAlex Vesker 71641d07074SAlex Vesker mlx5dr_ste_set_miss_addr(hw_ste, nic_matcher->e_anchor->chunk->icm_addr); 71741d07074SAlex Vesker 71841d07074SAlex Vesker ste->ste_chain_location = ste_location; 71941d07074SAlex Vesker 72041d07074SAlex Vesker ste_info = kzalloc(sizeof(*ste_info), GFP_KERNEL); 72141d07074SAlex Vesker if (!ste_info) 72241d07074SAlex Vesker goto clean_ste_setting; 72341d07074SAlex Vesker 72441d07074SAlex Vesker if (mlx5dr_ste_create_next_htbl(matcher, 72541d07074SAlex Vesker nic_matcher, 72641d07074SAlex Vesker ste, 72741d07074SAlex Vesker hw_ste, 72841d07074SAlex Vesker DR_CHUNK_SIZE_1)) { 72941d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Failed allocating table\n"); 73041d07074SAlex Vesker goto clean_ste_info; 73141d07074SAlex Vesker } 73241d07074SAlex Vesker 73341d07074SAlex Vesker cur_htbl->ctrl.num_of_valid_entries++; 73441d07074SAlex Vesker 73541d07074SAlex Vesker mlx5dr_send_fill_and_append_ste_send_info(ste, DR_STE_SIZE, 0, hw_ste, 73641d07074SAlex Vesker ste_info, send_list, false); 73741d07074SAlex Vesker 73841d07074SAlex Vesker return 0; 73941d07074SAlex Vesker 74041d07074SAlex Vesker clean_ste_info: 74141d07074SAlex Vesker kfree(ste_info); 74241d07074SAlex Vesker clean_ste_setting: 74341d07074SAlex Vesker list_del_init(&ste->miss_list_node); 74441d07074SAlex Vesker mlx5dr_htbl_put(cur_htbl); 74541d07074SAlex Vesker 74641d07074SAlex Vesker return -ENOMEM; 74741d07074SAlex Vesker } 74841d07074SAlex Vesker 74941d07074SAlex Vesker static struct mlx5dr_ste * 75041d07074SAlex Vesker dr_rule_handle_ste_branch(struct mlx5dr_rule *rule, 75141d07074SAlex Vesker struct mlx5dr_rule_rx_tx *nic_rule, 75241d07074SAlex Vesker struct list_head *send_ste_list, 75341d07074SAlex Vesker struct mlx5dr_ste_htbl *cur_htbl, 75441d07074SAlex Vesker u8 *hw_ste, 75541d07074SAlex Vesker u8 ste_location, 75641d07074SAlex Vesker struct mlx5dr_ste_htbl **put_htbl) 75741d07074SAlex Vesker { 75841d07074SAlex Vesker struct mlx5dr_matcher *matcher = rule->matcher; 75941d07074SAlex Vesker struct mlx5dr_domain *dmn = matcher->tbl->dmn; 76041d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher; 76141d07074SAlex Vesker struct mlx5dr_domain_rx_tx *nic_dmn; 76241d07074SAlex Vesker struct mlx5dr_ste_htbl *new_htbl; 76341d07074SAlex Vesker struct mlx5dr_ste *matched_ste; 76441d07074SAlex Vesker struct list_head *miss_list; 76541d07074SAlex Vesker bool skip_rehash = false; 76641d07074SAlex Vesker struct mlx5dr_ste *ste; 76741d07074SAlex Vesker int index; 76841d07074SAlex Vesker 76941d07074SAlex Vesker nic_matcher = nic_rule->nic_matcher; 77041d07074SAlex Vesker nic_dmn = nic_matcher->nic_tbl->nic_dmn; 77141d07074SAlex Vesker 77241d07074SAlex Vesker again: 77341d07074SAlex Vesker index = mlx5dr_ste_calc_hash_index(hw_ste, cur_htbl); 77441d07074SAlex Vesker miss_list = &cur_htbl->chunk->miss_list[index]; 77541d07074SAlex Vesker ste = &cur_htbl->ste_arr[index]; 77641d07074SAlex Vesker 77741d07074SAlex Vesker if (mlx5dr_ste_not_used_ste(ste)) { 77841d07074SAlex Vesker if (dr_rule_handle_empty_entry(matcher, nic_matcher, cur_htbl, 77941d07074SAlex Vesker ste, ste_location, 78041d07074SAlex Vesker hw_ste, miss_list, 78141d07074SAlex Vesker send_ste_list)) 78241d07074SAlex Vesker return NULL; 78341d07074SAlex Vesker } else { 78441d07074SAlex Vesker /* Hash table index in use, check if this ste is in the miss list */ 78541d07074SAlex Vesker matched_ste = dr_rule_find_ste_in_miss_list(miss_list, hw_ste); 78641d07074SAlex Vesker if (matched_ste) { 78741d07074SAlex Vesker /* If it is last STE in the chain, and has the same tag 78841d07074SAlex Vesker * it means that all the previous stes are the same, 78941d07074SAlex Vesker * if so, this rule is duplicated. 79041d07074SAlex Vesker */ 79100414126SAlex Vesker if (!mlx5dr_ste_is_last_in_rule(nic_matcher, ste_location)) 79241d07074SAlex Vesker return matched_ste; 79300414126SAlex Vesker 79400414126SAlex Vesker mlx5dr_dbg(dmn, "Duplicate rule inserted\n"); 79541d07074SAlex Vesker } 79641d07074SAlex Vesker 79741d07074SAlex Vesker if (!skip_rehash && dr_rule_need_enlarge_hash(cur_htbl, dmn, nic_dmn)) { 79841d07074SAlex Vesker /* Hash table index in use, try to resize of the hash */ 79941d07074SAlex Vesker skip_rehash = true; 80041d07074SAlex Vesker 80141d07074SAlex Vesker /* Hold the table till we update. 80241d07074SAlex Vesker * Release in dr_rule_create_rule() 80341d07074SAlex Vesker */ 80441d07074SAlex Vesker *put_htbl = cur_htbl; 80541d07074SAlex Vesker mlx5dr_htbl_get(cur_htbl); 80641d07074SAlex Vesker 80741d07074SAlex Vesker new_htbl = dr_rule_rehash(rule, nic_rule, cur_htbl, 80841d07074SAlex Vesker ste_location, send_ste_list); 80941d07074SAlex Vesker if (!new_htbl) { 81041d07074SAlex Vesker mlx5dr_htbl_put(cur_htbl); 81141d07074SAlex Vesker mlx5dr_info(dmn, "failed creating rehash table, htbl-log_size: %d\n", 81241d07074SAlex Vesker cur_htbl->chunk_size); 81341d07074SAlex Vesker } else { 81441d07074SAlex Vesker cur_htbl = new_htbl; 81541d07074SAlex Vesker } 81641d07074SAlex Vesker goto again; 81741d07074SAlex Vesker } else { 81841d07074SAlex Vesker /* Hash table index in use, add another collision (miss) */ 81941d07074SAlex Vesker ste = dr_rule_handle_collision(matcher, 82041d07074SAlex Vesker nic_matcher, 82141d07074SAlex Vesker ste, 82241d07074SAlex Vesker hw_ste, 82341d07074SAlex Vesker miss_list, 82441d07074SAlex Vesker send_ste_list); 82541d07074SAlex Vesker if (!ste) { 82641d07074SAlex Vesker mlx5dr_dbg(dmn, "failed adding collision entry, index: %d\n", 82741d07074SAlex Vesker index); 82841d07074SAlex Vesker return NULL; 82941d07074SAlex Vesker } 83041d07074SAlex Vesker } 83141d07074SAlex Vesker } 83241d07074SAlex Vesker return ste; 83341d07074SAlex Vesker } 83441d07074SAlex Vesker 83541d07074SAlex Vesker static bool dr_rule_cmp_value_to_mask(u8 *mask, u8 *value, 83641d07074SAlex Vesker u32 s_idx, u32 e_idx) 83741d07074SAlex Vesker { 83841d07074SAlex Vesker u32 i; 83941d07074SAlex Vesker 84041d07074SAlex Vesker for (i = s_idx; i < e_idx; i++) { 84141d07074SAlex Vesker if (value[i] & ~mask[i]) { 84241d07074SAlex Vesker pr_info("Rule parameters contains a value not specified by mask\n"); 84341d07074SAlex Vesker return false; 84441d07074SAlex Vesker } 84541d07074SAlex Vesker } 84641d07074SAlex Vesker return true; 84741d07074SAlex Vesker } 84841d07074SAlex Vesker 84941d07074SAlex Vesker static bool dr_rule_verify(struct mlx5dr_matcher *matcher, 85041d07074SAlex Vesker struct mlx5dr_match_parameters *value, 85141d07074SAlex Vesker struct mlx5dr_match_param *param) 85241d07074SAlex Vesker { 85341d07074SAlex Vesker u8 match_criteria = matcher->match_criteria; 85441d07074SAlex Vesker size_t value_size = value->match_sz; 85541d07074SAlex Vesker u8 *mask_p = (u8 *)&matcher->mask; 85641d07074SAlex Vesker u8 *param_p = (u8 *)param; 85741d07074SAlex Vesker u32 s_idx, e_idx; 85841d07074SAlex Vesker 85941d07074SAlex Vesker if (!value_size || 86041d07074SAlex Vesker (value_size > sizeof(struct mlx5dr_match_param) || 86141d07074SAlex Vesker (value_size % sizeof(u32)))) { 86241d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Rule parameters length is incorrect\n"); 86341d07074SAlex Vesker return false; 86441d07074SAlex Vesker } 86541d07074SAlex Vesker 86641d07074SAlex Vesker mlx5dr_ste_copy_param(matcher->match_criteria, param, value); 86741d07074SAlex Vesker 86841d07074SAlex Vesker if (match_criteria & DR_MATCHER_CRITERIA_OUTER) { 86941d07074SAlex Vesker s_idx = offsetof(struct mlx5dr_match_param, outer); 87041d07074SAlex Vesker e_idx = min(s_idx + sizeof(param->outer), value_size); 87141d07074SAlex Vesker 87241d07074SAlex Vesker if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { 87341d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Rule outer parameters contains a value not specified by mask\n"); 87441d07074SAlex Vesker return false; 87541d07074SAlex Vesker } 87641d07074SAlex Vesker } 87741d07074SAlex Vesker 87841d07074SAlex Vesker if (match_criteria & DR_MATCHER_CRITERIA_MISC) { 87941d07074SAlex Vesker s_idx = offsetof(struct mlx5dr_match_param, misc); 88041d07074SAlex Vesker e_idx = min(s_idx + sizeof(param->misc), value_size); 88141d07074SAlex Vesker 88241d07074SAlex Vesker if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { 88341d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Rule misc parameters contains a value not specified by mask\n"); 88441d07074SAlex Vesker return false; 88541d07074SAlex Vesker } 88641d07074SAlex Vesker } 88741d07074SAlex Vesker 88841d07074SAlex Vesker if (match_criteria & DR_MATCHER_CRITERIA_INNER) { 88941d07074SAlex Vesker s_idx = offsetof(struct mlx5dr_match_param, inner); 89041d07074SAlex Vesker e_idx = min(s_idx + sizeof(param->inner), value_size); 89141d07074SAlex Vesker 89241d07074SAlex Vesker if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { 89341d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Rule inner parameters contains a value not specified by mask\n"); 89441d07074SAlex Vesker return false; 89541d07074SAlex Vesker } 89641d07074SAlex Vesker } 89741d07074SAlex Vesker 89841d07074SAlex Vesker if (match_criteria & DR_MATCHER_CRITERIA_MISC2) { 89941d07074SAlex Vesker s_idx = offsetof(struct mlx5dr_match_param, misc2); 90041d07074SAlex Vesker e_idx = min(s_idx + sizeof(param->misc2), value_size); 90141d07074SAlex Vesker 90241d07074SAlex Vesker if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { 90341d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Rule misc2 parameters contains a value not specified by mask\n"); 90441d07074SAlex Vesker return false; 90541d07074SAlex Vesker } 90641d07074SAlex Vesker } 90741d07074SAlex Vesker 90841d07074SAlex Vesker if (match_criteria & DR_MATCHER_CRITERIA_MISC3) { 90941d07074SAlex Vesker s_idx = offsetof(struct mlx5dr_match_param, misc3); 91041d07074SAlex Vesker e_idx = min(s_idx + sizeof(param->misc3), value_size); 91141d07074SAlex Vesker 91241d07074SAlex Vesker if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { 91341d07074SAlex Vesker mlx5dr_dbg(matcher->tbl->dmn, "Rule misc3 parameters contains a value not specified by mask\n"); 91441d07074SAlex Vesker return false; 91541d07074SAlex Vesker } 91641d07074SAlex Vesker } 91741d07074SAlex Vesker return true; 91841d07074SAlex Vesker } 91941d07074SAlex Vesker 92041d07074SAlex Vesker static int dr_rule_destroy_rule_nic(struct mlx5dr_rule *rule, 92141d07074SAlex Vesker struct mlx5dr_rule_rx_tx *nic_rule) 92241d07074SAlex Vesker { 92341d07074SAlex Vesker dr_rule_clean_rule_members(rule, nic_rule); 92441d07074SAlex Vesker return 0; 92541d07074SAlex Vesker } 92641d07074SAlex Vesker 92741d07074SAlex Vesker static int dr_rule_destroy_rule_fdb(struct mlx5dr_rule *rule) 92841d07074SAlex Vesker { 92941d07074SAlex Vesker dr_rule_destroy_rule_nic(rule, &rule->rx); 93041d07074SAlex Vesker dr_rule_destroy_rule_nic(rule, &rule->tx); 93141d07074SAlex Vesker return 0; 93241d07074SAlex Vesker } 93341d07074SAlex Vesker 93441d07074SAlex Vesker static int dr_rule_destroy_rule(struct mlx5dr_rule *rule) 93541d07074SAlex Vesker { 93641d07074SAlex Vesker struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; 93741d07074SAlex Vesker 93841d07074SAlex Vesker switch (dmn->type) { 93941d07074SAlex Vesker case MLX5DR_DOMAIN_TYPE_NIC_RX: 94041d07074SAlex Vesker dr_rule_destroy_rule_nic(rule, &rule->rx); 94141d07074SAlex Vesker break; 94241d07074SAlex Vesker case MLX5DR_DOMAIN_TYPE_NIC_TX: 94341d07074SAlex Vesker dr_rule_destroy_rule_nic(rule, &rule->tx); 94441d07074SAlex Vesker break; 94541d07074SAlex Vesker case MLX5DR_DOMAIN_TYPE_FDB: 94641d07074SAlex Vesker dr_rule_destroy_rule_fdb(rule); 94741d07074SAlex Vesker break; 94841d07074SAlex Vesker default: 94941d07074SAlex Vesker return -EINVAL; 95041d07074SAlex Vesker } 95141d07074SAlex Vesker 95241d07074SAlex Vesker dr_rule_remove_action_members(rule); 95341d07074SAlex Vesker kfree(rule); 95441d07074SAlex Vesker return 0; 95541d07074SAlex Vesker } 95641d07074SAlex Vesker 95741d07074SAlex Vesker static bool dr_rule_is_ipv6(struct mlx5dr_match_param *param) 95841d07074SAlex Vesker { 95941d07074SAlex Vesker return (param->outer.ip_version == 6 || 96041d07074SAlex Vesker param->inner.ip_version == 6 || 96141d07074SAlex Vesker param->outer.ethertype == ETH_P_IPV6 || 96241d07074SAlex Vesker param->inner.ethertype == ETH_P_IPV6); 96341d07074SAlex Vesker } 96441d07074SAlex Vesker 96541d07074SAlex Vesker static bool dr_rule_skip(enum mlx5dr_domain_type domain, 96641d07074SAlex Vesker enum mlx5dr_ste_entry_type ste_type, 96741d07074SAlex Vesker struct mlx5dr_match_param *mask, 96841d07074SAlex Vesker struct mlx5dr_match_param *value) 96941d07074SAlex Vesker { 97041d07074SAlex Vesker if (domain != MLX5DR_DOMAIN_TYPE_FDB) 97141d07074SAlex Vesker return false; 97241d07074SAlex Vesker 97341d07074SAlex Vesker if (mask->misc.source_port) { 97441d07074SAlex Vesker if (ste_type == MLX5DR_STE_TYPE_RX) 97541d07074SAlex Vesker if (value->misc.source_port != WIRE_PORT) 97641d07074SAlex Vesker return true; 97741d07074SAlex Vesker 97841d07074SAlex Vesker if (ste_type == MLX5DR_STE_TYPE_TX) 97941d07074SAlex Vesker if (value->misc.source_port == WIRE_PORT) 98041d07074SAlex Vesker return true; 98141d07074SAlex Vesker } 98241d07074SAlex Vesker 98341d07074SAlex Vesker /* Metadata C can be used to describe the source vport */ 98441d07074SAlex Vesker if (mask->misc2.metadata_reg_c_0) { 98541d07074SAlex Vesker if (ste_type == MLX5DR_STE_TYPE_RX) 98641d07074SAlex Vesker if ((value->misc2.metadata_reg_c_0 & WIRE_PORT) != WIRE_PORT) 98741d07074SAlex Vesker return true; 98841d07074SAlex Vesker 98941d07074SAlex Vesker if (ste_type == MLX5DR_STE_TYPE_TX) 99041d07074SAlex Vesker if ((value->misc2.metadata_reg_c_0 & WIRE_PORT) == WIRE_PORT) 99141d07074SAlex Vesker return true; 99241d07074SAlex Vesker } 99341d07074SAlex Vesker return false; 99441d07074SAlex Vesker } 99541d07074SAlex Vesker 99641d07074SAlex Vesker static int 99741d07074SAlex Vesker dr_rule_create_rule_nic(struct mlx5dr_rule *rule, 99841d07074SAlex Vesker struct mlx5dr_rule_rx_tx *nic_rule, 99941d07074SAlex Vesker struct mlx5dr_match_param *param, 100041d07074SAlex Vesker size_t num_actions, 100141d07074SAlex Vesker struct mlx5dr_action *actions[]) 100241d07074SAlex Vesker { 100341d07074SAlex Vesker struct mlx5dr_ste_send_info *ste_info, *tmp_ste_info; 100441d07074SAlex Vesker struct mlx5dr_matcher *matcher = rule->matcher; 100541d07074SAlex Vesker struct mlx5dr_domain *dmn = matcher->tbl->dmn; 100641d07074SAlex Vesker struct mlx5dr_matcher_rx_tx *nic_matcher; 100741d07074SAlex Vesker struct mlx5dr_domain_rx_tx *nic_dmn; 100841d07074SAlex Vesker struct mlx5dr_ste_htbl *htbl = NULL; 100941d07074SAlex Vesker struct mlx5dr_ste_htbl *cur_htbl; 101041d07074SAlex Vesker struct mlx5dr_ste *ste = NULL; 101141d07074SAlex Vesker LIST_HEAD(send_ste_list); 101241d07074SAlex Vesker u8 *hw_ste_arr = NULL; 101341d07074SAlex Vesker u32 new_hw_ste_arr_sz; 101441d07074SAlex Vesker int ret, i; 101541d07074SAlex Vesker 101641d07074SAlex Vesker nic_matcher = nic_rule->nic_matcher; 101741d07074SAlex Vesker nic_dmn = nic_matcher->nic_tbl->nic_dmn; 101841d07074SAlex Vesker 101941d07074SAlex Vesker INIT_LIST_HEAD(&nic_rule->rule_members_list); 102041d07074SAlex Vesker 102141d07074SAlex Vesker if (dr_rule_skip(dmn->type, nic_dmn->ste_type, &matcher->mask, param)) 102241d07074SAlex Vesker return 0; 102341d07074SAlex Vesker 102441d07074SAlex Vesker ret = mlx5dr_matcher_select_builders(matcher, 102541d07074SAlex Vesker nic_matcher, 102641d07074SAlex Vesker dr_rule_is_ipv6(param)); 102741d07074SAlex Vesker if (ret) 102841d07074SAlex Vesker goto out_err; 102941d07074SAlex Vesker 103041d07074SAlex Vesker hw_ste_arr = kzalloc(DR_RULE_MAX_STE_CHAIN * DR_STE_SIZE, GFP_KERNEL); 103141d07074SAlex Vesker if (!hw_ste_arr) { 103241d07074SAlex Vesker ret = -ENOMEM; 103341d07074SAlex Vesker goto out_err; 103441d07074SAlex Vesker } 103541d07074SAlex Vesker 103641d07074SAlex Vesker /* Set the tag values inside the ste array */ 103741d07074SAlex Vesker ret = mlx5dr_ste_build_ste_arr(matcher, nic_matcher, param, hw_ste_arr); 103841d07074SAlex Vesker if (ret) 103941d07074SAlex Vesker goto free_hw_ste; 104041d07074SAlex Vesker 104141d07074SAlex Vesker /* Set the actions values/addresses inside the ste array */ 104241d07074SAlex Vesker ret = mlx5dr_actions_build_ste_arr(matcher, nic_matcher, actions, 104341d07074SAlex Vesker num_actions, hw_ste_arr, 104441d07074SAlex Vesker &new_hw_ste_arr_sz); 104541d07074SAlex Vesker if (ret) 104641d07074SAlex Vesker goto free_hw_ste; 104741d07074SAlex Vesker 104841d07074SAlex Vesker cur_htbl = nic_matcher->s_htbl; 104941d07074SAlex Vesker 105041d07074SAlex Vesker /* Go over the array of STEs, and build dr_ste accordingly. 105141d07074SAlex Vesker * The loop is over only the builders which are equal or less to the 105241d07074SAlex Vesker * number of stes, in case we have actions that lives in other stes. 105341d07074SAlex Vesker */ 105441d07074SAlex Vesker for (i = 0; i < nic_matcher->num_of_builders; i++) { 105541d07074SAlex Vesker /* Calculate CRC and keep new ste entry */ 105641d07074SAlex Vesker u8 *cur_hw_ste_ent = hw_ste_arr + (i * DR_STE_SIZE); 105741d07074SAlex Vesker 105841d07074SAlex Vesker ste = dr_rule_handle_ste_branch(rule, 105941d07074SAlex Vesker nic_rule, 106041d07074SAlex Vesker &send_ste_list, 106141d07074SAlex Vesker cur_htbl, 106241d07074SAlex Vesker cur_hw_ste_ent, 106341d07074SAlex Vesker i + 1, 106441d07074SAlex Vesker &htbl); 106541d07074SAlex Vesker if (!ste) { 106641d07074SAlex Vesker mlx5dr_err(dmn, "Failed creating next branch\n"); 106741d07074SAlex Vesker ret = -ENOENT; 106841d07074SAlex Vesker goto free_rule; 106941d07074SAlex Vesker } 107041d07074SAlex Vesker 107141d07074SAlex Vesker cur_htbl = ste->next_htbl; 107241d07074SAlex Vesker 107341d07074SAlex Vesker /* Keep all STEs in the rule struct */ 107441d07074SAlex Vesker ret = dr_rule_add_member(nic_rule, ste); 107541d07074SAlex Vesker if (ret) { 107641d07074SAlex Vesker mlx5dr_dbg(dmn, "Failed adding rule member index %d\n", i); 107741d07074SAlex Vesker goto free_ste; 107841d07074SAlex Vesker } 107941d07074SAlex Vesker 108041d07074SAlex Vesker mlx5dr_ste_get(ste); 108141d07074SAlex Vesker } 108241d07074SAlex Vesker 108341d07074SAlex Vesker /* Connect actions */ 108441d07074SAlex Vesker ret = dr_rule_handle_action_stes(rule, nic_rule, &send_ste_list, 108541d07074SAlex Vesker ste, hw_ste_arr, new_hw_ste_arr_sz); 108641d07074SAlex Vesker if (ret) { 108741d07074SAlex Vesker mlx5dr_dbg(dmn, "Failed apply actions\n"); 108841d07074SAlex Vesker goto free_rule; 108941d07074SAlex Vesker } 109041d07074SAlex Vesker ret = dr_rule_send_update_list(&send_ste_list, dmn, true); 109141d07074SAlex Vesker if (ret) { 109241d07074SAlex Vesker mlx5dr_err(dmn, "Failed sending ste!\n"); 109341d07074SAlex Vesker goto free_rule; 109441d07074SAlex Vesker } 109541d07074SAlex Vesker 109641d07074SAlex Vesker if (htbl) 109741d07074SAlex Vesker mlx5dr_htbl_put(htbl); 109841d07074SAlex Vesker 1099260986fcSAlex Vesker kfree(hw_ste_arr); 1100260986fcSAlex Vesker 110141d07074SAlex Vesker return 0; 110241d07074SAlex Vesker 110341d07074SAlex Vesker free_ste: 110441d07074SAlex Vesker mlx5dr_ste_put(ste, matcher, nic_matcher); 110541d07074SAlex Vesker free_rule: 110641d07074SAlex Vesker dr_rule_clean_rule_members(rule, nic_rule); 110741d07074SAlex Vesker /* Clean all ste_info's */ 110841d07074SAlex Vesker list_for_each_entry_safe(ste_info, tmp_ste_info, &send_ste_list, send_list) { 110941d07074SAlex Vesker list_del(&ste_info->send_list); 111041d07074SAlex Vesker kfree(ste_info); 111141d07074SAlex Vesker } 111241d07074SAlex Vesker free_hw_ste: 111341d07074SAlex Vesker kfree(hw_ste_arr); 111441d07074SAlex Vesker out_err: 111541d07074SAlex Vesker return ret; 111641d07074SAlex Vesker } 111741d07074SAlex Vesker 111841d07074SAlex Vesker static int 111941d07074SAlex Vesker dr_rule_create_rule_fdb(struct mlx5dr_rule *rule, 112041d07074SAlex Vesker struct mlx5dr_match_param *param, 112141d07074SAlex Vesker size_t num_actions, 112241d07074SAlex Vesker struct mlx5dr_action *actions[]) 112341d07074SAlex Vesker { 112441d07074SAlex Vesker struct mlx5dr_match_param copy_param = {}; 112541d07074SAlex Vesker int ret; 112641d07074SAlex Vesker 112741d07074SAlex Vesker /* Copy match_param since they will be consumed during the first 112841d07074SAlex Vesker * nic_rule insertion. 112941d07074SAlex Vesker */ 113041d07074SAlex Vesker memcpy(©_param, param, sizeof(struct mlx5dr_match_param)); 113141d07074SAlex Vesker 113241d07074SAlex Vesker ret = dr_rule_create_rule_nic(rule, &rule->rx, param, 113341d07074SAlex Vesker num_actions, actions); 113441d07074SAlex Vesker if (ret) 113541d07074SAlex Vesker return ret; 113641d07074SAlex Vesker 113741d07074SAlex Vesker ret = dr_rule_create_rule_nic(rule, &rule->tx, ©_param, 113841d07074SAlex Vesker num_actions, actions); 113941d07074SAlex Vesker if (ret) 114041d07074SAlex Vesker goto destroy_rule_nic_rx; 114141d07074SAlex Vesker 114241d07074SAlex Vesker return 0; 114341d07074SAlex Vesker 114441d07074SAlex Vesker destroy_rule_nic_rx: 114541d07074SAlex Vesker dr_rule_destroy_rule_nic(rule, &rule->rx); 114641d07074SAlex Vesker return ret; 114741d07074SAlex Vesker } 114841d07074SAlex Vesker 114941d07074SAlex Vesker static struct mlx5dr_rule * 115041d07074SAlex Vesker dr_rule_create_rule(struct mlx5dr_matcher *matcher, 115141d07074SAlex Vesker struct mlx5dr_match_parameters *value, 115241d07074SAlex Vesker size_t num_actions, 115341d07074SAlex Vesker struct mlx5dr_action *actions[]) 115441d07074SAlex Vesker { 115541d07074SAlex Vesker struct mlx5dr_domain *dmn = matcher->tbl->dmn; 115641d07074SAlex Vesker struct mlx5dr_match_param param = {}; 115741d07074SAlex Vesker struct mlx5dr_rule *rule; 115841d07074SAlex Vesker int ret; 115941d07074SAlex Vesker 116041d07074SAlex Vesker if (!dr_rule_verify(matcher, value, ¶m)) 116141d07074SAlex Vesker return NULL; 116241d07074SAlex Vesker 116341d07074SAlex Vesker rule = kzalloc(sizeof(*rule), GFP_KERNEL); 116441d07074SAlex Vesker if (!rule) 116541d07074SAlex Vesker return NULL; 116641d07074SAlex Vesker 116741d07074SAlex Vesker rule->matcher = matcher; 116841d07074SAlex Vesker INIT_LIST_HEAD(&rule->rule_actions_list); 116941d07074SAlex Vesker 117041d07074SAlex Vesker ret = dr_rule_add_action_members(rule, num_actions, actions); 117141d07074SAlex Vesker if (ret) 117241d07074SAlex Vesker goto free_rule; 117341d07074SAlex Vesker 117441d07074SAlex Vesker switch (dmn->type) { 117541d07074SAlex Vesker case MLX5DR_DOMAIN_TYPE_NIC_RX: 117641d07074SAlex Vesker rule->rx.nic_matcher = &matcher->rx; 117741d07074SAlex Vesker ret = dr_rule_create_rule_nic(rule, &rule->rx, ¶m, 117841d07074SAlex Vesker num_actions, actions); 117941d07074SAlex Vesker break; 118041d07074SAlex Vesker case MLX5DR_DOMAIN_TYPE_NIC_TX: 118141d07074SAlex Vesker rule->tx.nic_matcher = &matcher->tx; 118241d07074SAlex Vesker ret = dr_rule_create_rule_nic(rule, &rule->tx, ¶m, 118341d07074SAlex Vesker num_actions, actions); 118441d07074SAlex Vesker break; 118541d07074SAlex Vesker case MLX5DR_DOMAIN_TYPE_FDB: 118641d07074SAlex Vesker rule->rx.nic_matcher = &matcher->rx; 118741d07074SAlex Vesker rule->tx.nic_matcher = &matcher->tx; 118841d07074SAlex Vesker ret = dr_rule_create_rule_fdb(rule, ¶m, 118941d07074SAlex Vesker num_actions, actions); 119041d07074SAlex Vesker break; 119141d07074SAlex Vesker default: 119241d07074SAlex Vesker ret = -EINVAL; 119341d07074SAlex Vesker break; 119441d07074SAlex Vesker } 119541d07074SAlex Vesker 119641d07074SAlex Vesker if (ret) 119741d07074SAlex Vesker goto remove_action_members; 119841d07074SAlex Vesker 119941d07074SAlex Vesker return rule; 120041d07074SAlex Vesker 120141d07074SAlex Vesker remove_action_members: 120241d07074SAlex Vesker dr_rule_remove_action_members(rule); 120341d07074SAlex Vesker free_rule: 120441d07074SAlex Vesker kfree(rule); 120541d07074SAlex Vesker mlx5dr_info(dmn, "Failed creating rule\n"); 120641d07074SAlex Vesker return NULL; 120741d07074SAlex Vesker } 120841d07074SAlex Vesker 120941d07074SAlex Vesker struct mlx5dr_rule *mlx5dr_rule_create(struct mlx5dr_matcher *matcher, 121041d07074SAlex Vesker struct mlx5dr_match_parameters *value, 121141d07074SAlex Vesker size_t num_actions, 121241d07074SAlex Vesker struct mlx5dr_action *actions[]) 121341d07074SAlex Vesker { 121441d07074SAlex Vesker struct mlx5dr_rule *rule; 121541d07074SAlex Vesker 121641d07074SAlex Vesker mutex_lock(&matcher->tbl->dmn->mutex); 121741d07074SAlex Vesker refcount_inc(&matcher->refcount); 121841d07074SAlex Vesker 121941d07074SAlex Vesker rule = dr_rule_create_rule(matcher, value, num_actions, actions); 122041d07074SAlex Vesker if (!rule) 122141d07074SAlex Vesker refcount_dec(&matcher->refcount); 122241d07074SAlex Vesker 122341d07074SAlex Vesker mutex_unlock(&matcher->tbl->dmn->mutex); 122441d07074SAlex Vesker 122541d07074SAlex Vesker return rule; 122641d07074SAlex Vesker } 122741d07074SAlex Vesker 122841d07074SAlex Vesker int mlx5dr_rule_destroy(struct mlx5dr_rule *rule) 122941d07074SAlex Vesker { 123041d07074SAlex Vesker struct mlx5dr_matcher *matcher = rule->matcher; 123141d07074SAlex Vesker struct mlx5dr_table *tbl = rule->matcher->tbl; 123241d07074SAlex Vesker int ret; 123341d07074SAlex Vesker 123441d07074SAlex Vesker mutex_lock(&tbl->dmn->mutex); 123541d07074SAlex Vesker 123641d07074SAlex Vesker ret = dr_rule_destroy_rule(rule); 123741d07074SAlex Vesker 123841d07074SAlex Vesker mutex_unlock(&tbl->dmn->mutex); 123941d07074SAlex Vesker 124041d07074SAlex Vesker if (!ret) 124141d07074SAlex Vesker refcount_dec(&matcher->refcount); 124241d07074SAlex Vesker return ret; 124341d07074SAlex Vesker } 1244