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 
617b3222eSYevgeny Kliteynik #if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN < 2048)
717b3222eSYevgeny Kliteynik /* don't try to optimize STE allocation if the stack is too constaraining */
817b3222eSYevgeny Kliteynik #define DR_RULE_MAX_STES_OPTIMIZED 0
917b3222eSYevgeny Kliteynik #else
10b9b81e1eSYevgeny Kliteynik #define DR_RULE_MAX_STES_OPTIMIZED 5
1117b3222eSYevgeny Kliteynik #endif
12b9b81e1eSYevgeny Kliteynik #define DR_RULE_MAX_STE_CHAIN_OPTIMIZED (DR_RULE_MAX_STES_OPTIMIZED + DR_ACTION_MAX_STES)
1341d07074SAlex Vesker 
dr_rule_append_to_miss_list(struct mlx5dr_domain * dmn,enum mlx5dr_domain_nic_type nic_type,struct mlx5dr_ste * new_last_ste,struct list_head * miss_list,struct list_head * send_list)1417b56073SYevgeny Kliteynik static int dr_rule_append_to_miss_list(struct mlx5dr_domain *dmn,
1517b56073SYevgeny Kliteynik 				       enum mlx5dr_domain_nic_type nic_type,
166b93b400SYevgeny Kliteynik 				       struct mlx5dr_ste *new_last_ste,
1741d07074SAlex Vesker 				       struct list_head *miss_list,
1841d07074SAlex Vesker 				       struct list_head *send_list)
1941d07074SAlex Vesker {
2017b56073SYevgeny Kliteynik 	struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx;
2141d07074SAlex Vesker 	struct mlx5dr_ste_send_info *ste_info_last;
2241d07074SAlex Vesker 	struct mlx5dr_ste *last_ste;
2341d07074SAlex Vesker 
2441d07074SAlex Vesker 	/* The new entry will be inserted after the last */
2548cbde4bSAlex Vesker 	last_ste = list_last_entry(miss_list, struct mlx5dr_ste, miss_list_node);
2641d07074SAlex Vesker 	WARN_ON(!last_ste);
2741d07074SAlex Vesker 
2817b56073SYevgeny Kliteynik 	ste_info_last = mlx5dr_send_info_alloc(dmn, nic_type);
2941d07074SAlex Vesker 	if (!ste_info_last)
3041d07074SAlex Vesker 		return -ENOMEM;
3141d07074SAlex Vesker 
320d7f1595SRongwei Liu 	mlx5dr_ste_set_miss_addr(ste_ctx, mlx5dr_ste_get_hw_ste(last_ste),
3341d07074SAlex Vesker 				 mlx5dr_ste_get_icm_addr(new_last_ste));
3441d07074SAlex Vesker 	list_add_tail(&new_last_ste->miss_list_node, miss_list);
3541d07074SAlex Vesker 
36f06d4969SYevgeny Kliteynik 	mlx5dr_send_fill_and_append_ste_send_info(last_ste, DR_STE_SIZE_CTRL,
370d7f1595SRongwei Liu 						  0, mlx5dr_ste_get_hw_ste(last_ste),
3841d07074SAlex Vesker 						  ste_info_last, send_list, true);
3941d07074SAlex Vesker 
4041d07074SAlex Vesker 	return 0;
4141d07074SAlex Vesker }
4241d07074SAlex Vesker 
dr_rule_set_last_ste_miss_addr(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,u8 * hw_ste)43f31bda78SYevgeny Kliteynik static void dr_rule_set_last_ste_miss_addr(struct mlx5dr_matcher *matcher,
44f31bda78SYevgeny Kliteynik 					   struct mlx5dr_matcher_rx_tx *nic_matcher,
45f31bda78SYevgeny Kliteynik 					   u8 *hw_ste)
46f31bda78SYevgeny Kliteynik {
47f31bda78SYevgeny Kliteynik 	struct mlx5dr_ste_ctx *ste_ctx = matcher->tbl->dmn->ste_ctx;
48f31bda78SYevgeny Kliteynik 	u64 icm_addr;
49f31bda78SYevgeny Kliteynik 
501207a772SYevgeny Kliteynik 	if (mlx5dr_ste_is_miss_addr_set(ste_ctx, hw_ste))
511207a772SYevgeny Kliteynik 		return;
521207a772SYevgeny Kliteynik 
53f31bda78SYevgeny Kliteynik 	icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk);
54f31bda78SYevgeny Kliteynik 	mlx5dr_ste_set_miss_addr(ste_ctx, hw_ste, icm_addr);
55f31bda78SYevgeny Kliteynik }
56f31bda78SYevgeny Kliteynik 
5741d07074SAlex Vesker static struct mlx5dr_ste *
dr_rule_create_collision_htbl(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,u8 * hw_ste)5841d07074SAlex Vesker dr_rule_create_collision_htbl(struct mlx5dr_matcher *matcher,
5941d07074SAlex Vesker 			      struct mlx5dr_matcher_rx_tx *nic_matcher,
6041d07074SAlex Vesker 			      u8 *hw_ste)
6141d07074SAlex Vesker {
6241d07074SAlex Vesker 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
6341d07074SAlex Vesker 	struct mlx5dr_ste_htbl *new_htbl;
6441d07074SAlex Vesker 	struct mlx5dr_ste *ste;
6541d07074SAlex Vesker 
6641d07074SAlex Vesker 	/* Create new table for miss entry */
6741d07074SAlex Vesker 	new_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
6841d07074SAlex Vesker 					 DR_CHUNK_SIZE_1,
6941d07074SAlex Vesker 					 MLX5DR_STE_LU_TYPE_DONT_CARE,
7041d07074SAlex Vesker 					 0);
7141d07074SAlex Vesker 	if (!new_htbl) {
7241d07074SAlex Vesker 		mlx5dr_dbg(dmn, "Failed allocating collision table\n");
7341d07074SAlex Vesker 		return NULL;
7441d07074SAlex Vesker 	}
7541d07074SAlex Vesker 
7641d07074SAlex Vesker 	/* One and only entry, never grows */
77597534bdSRongwei Liu 	ste = new_htbl->chunk->ste_arr;
78f31bda78SYevgeny Kliteynik 	dr_rule_set_last_ste_miss_addr(matcher, nic_matcher, hw_ste);
7941d07074SAlex Vesker 	mlx5dr_htbl_get(new_htbl);
8041d07074SAlex Vesker 
8141d07074SAlex Vesker 	return ste;
8241d07074SAlex Vesker }
8341d07074SAlex Vesker 
8441d07074SAlex Vesker static struct mlx5dr_ste *
dr_rule_create_collision_entry(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,u8 * hw_ste,struct mlx5dr_ste * orig_ste)8541d07074SAlex Vesker dr_rule_create_collision_entry(struct mlx5dr_matcher *matcher,
8641d07074SAlex Vesker 			       struct mlx5dr_matcher_rx_tx *nic_matcher,
8741d07074SAlex Vesker 			       u8 *hw_ste,
8841d07074SAlex Vesker 			       struct mlx5dr_ste *orig_ste)
8941d07074SAlex Vesker {
9041d07074SAlex Vesker 	struct mlx5dr_ste *ste;
9141d07074SAlex Vesker 
9241d07074SAlex Vesker 	ste = dr_rule_create_collision_htbl(matcher, nic_matcher, hw_ste);
9341d07074SAlex Vesker 	if (!ste) {
9441d07074SAlex Vesker 		mlx5dr_dbg(matcher->tbl->dmn, "Failed creating collision entry\n");
9541d07074SAlex Vesker 		return NULL;
9641d07074SAlex Vesker 	}
9741d07074SAlex Vesker 
9841d07074SAlex Vesker 	ste->ste_chain_location = orig_ste->ste_chain_location;
998a015baeSYevgeny Kliteynik 	ste->htbl->pointing_ste = orig_ste->htbl->pointing_ste;
10041d07074SAlex Vesker 
10141d07074SAlex Vesker 	/* In collision entry, all members share the same miss_list_head */
102597534bdSRongwei Liu 	ste->htbl->chunk->miss_list = mlx5dr_ste_get_miss_list(orig_ste);
10341d07074SAlex Vesker 
10441d07074SAlex Vesker 	/* Next table */
10541d07074SAlex Vesker 	if (mlx5dr_ste_create_next_htbl(matcher, nic_matcher, ste, hw_ste,
10641d07074SAlex Vesker 					DR_CHUNK_SIZE_1)) {
10741d07074SAlex Vesker 		mlx5dr_dbg(matcher->tbl->dmn, "Failed allocating table\n");
10841d07074SAlex Vesker 		goto free_tbl;
10941d07074SAlex Vesker 	}
11041d07074SAlex Vesker 
11141d07074SAlex Vesker 	return ste;
11241d07074SAlex Vesker 
11341d07074SAlex Vesker free_tbl:
11441d07074SAlex Vesker 	mlx5dr_ste_free(ste, matcher, nic_matcher);
11541d07074SAlex Vesker 	return NULL;
11641d07074SAlex Vesker }
11741d07074SAlex Vesker 
11841d07074SAlex Vesker static int
dr_rule_handle_one_ste_in_update_list(struct mlx5dr_ste_send_info * ste_info,struct mlx5dr_domain * dmn)11941d07074SAlex Vesker dr_rule_handle_one_ste_in_update_list(struct mlx5dr_ste_send_info *ste_info,
12041d07074SAlex Vesker 				      struct mlx5dr_domain *dmn)
12141d07074SAlex Vesker {
12241d07074SAlex Vesker 	int ret;
12341d07074SAlex Vesker 
12441d07074SAlex Vesker 	list_del(&ste_info->send_list);
125f06d4969SYevgeny Kliteynik 
126f06d4969SYevgeny Kliteynik 	/* Copy data to ste, only reduced size or control, the last 16B (mask)
12741d07074SAlex Vesker 	 * is already written to the hw.
12841d07074SAlex Vesker 	 */
129f06d4969SYevgeny Kliteynik 	if (ste_info->size == DR_STE_SIZE_CTRL)
1300d7f1595SRongwei Liu 		memcpy(mlx5dr_ste_get_hw_ste(ste_info->ste),
1310d7f1595SRongwei Liu 		       ste_info->data, DR_STE_SIZE_CTRL);
132f06d4969SYevgeny Kliteynik 	else
1330d7f1595SRongwei Liu 		memcpy(mlx5dr_ste_get_hw_ste(ste_info->ste),
1340d7f1595SRongwei Liu 		       ste_info->data, DR_STE_SIZE_REDUCED);
13541d07074SAlex Vesker 
1364fe45e1dSYevgeny Kliteynik 	ret = mlx5dr_send_postsend_ste(dmn, ste_info->ste, ste_info->data,
1374fe45e1dSYevgeny Kliteynik 				       ste_info->size, ste_info->offset);
1384fe45e1dSYevgeny Kliteynik 	if (ret)
1394fe45e1dSYevgeny Kliteynik 		goto out;
1404fe45e1dSYevgeny Kliteynik 
14141d07074SAlex Vesker out:
14217b56073SYevgeny Kliteynik 	mlx5dr_send_info_free(ste_info);
14341d07074SAlex Vesker 	return ret;
14441d07074SAlex Vesker }
14541d07074SAlex Vesker 
dr_rule_send_update_list(struct list_head * send_ste_list,struct mlx5dr_domain * dmn,bool is_reverse)14641d07074SAlex Vesker static int dr_rule_send_update_list(struct list_head *send_ste_list,
14741d07074SAlex Vesker 				    struct mlx5dr_domain *dmn,
14841d07074SAlex Vesker 				    bool is_reverse)
14941d07074SAlex Vesker {
15041d07074SAlex Vesker 	struct mlx5dr_ste_send_info *ste_info, *tmp_ste_info;
15141d07074SAlex Vesker 	int ret;
15241d07074SAlex Vesker 
15341d07074SAlex Vesker 	if (is_reverse) {
15441d07074SAlex Vesker 		list_for_each_entry_safe_reverse(ste_info, tmp_ste_info,
15541d07074SAlex Vesker 						 send_ste_list, send_list) {
15641d07074SAlex Vesker 			ret = dr_rule_handle_one_ste_in_update_list(ste_info,
15741d07074SAlex Vesker 								    dmn);
15841d07074SAlex Vesker 			if (ret)
15941d07074SAlex Vesker 				return ret;
16041d07074SAlex Vesker 		}
16141d07074SAlex Vesker 	} else {
16241d07074SAlex Vesker 		list_for_each_entry_safe(ste_info, tmp_ste_info,
16341d07074SAlex Vesker 					 send_ste_list, send_list) {
16441d07074SAlex Vesker 			ret = dr_rule_handle_one_ste_in_update_list(ste_info,
16541d07074SAlex Vesker 								    dmn);
16641d07074SAlex Vesker 			if (ret)
16741d07074SAlex Vesker 				return ret;
16841d07074SAlex Vesker 		}
16941d07074SAlex Vesker 	}
17041d07074SAlex Vesker 
17141d07074SAlex Vesker 	return 0;
17241d07074SAlex Vesker }
17341d07074SAlex Vesker 
17441d07074SAlex Vesker static struct mlx5dr_ste *
dr_rule_find_ste_in_miss_list(struct list_head * miss_list,u8 * hw_ste)17541d07074SAlex Vesker dr_rule_find_ste_in_miss_list(struct list_head *miss_list, u8 *hw_ste)
17641d07074SAlex Vesker {
17741d07074SAlex Vesker 	struct mlx5dr_ste *ste;
17841d07074SAlex Vesker 
17941d07074SAlex Vesker 	if (list_empty(miss_list))
18041d07074SAlex Vesker 		return NULL;
18141d07074SAlex Vesker 
18241d07074SAlex Vesker 	/* Check if hw_ste is present in the list */
18341d07074SAlex Vesker 	list_for_each_entry(ste, miss_list, miss_list_node) {
1840d7f1595SRongwei Liu 		if (mlx5dr_ste_equal_tag(mlx5dr_ste_get_hw_ste(ste), hw_ste))
18541d07074SAlex Vesker 			return ste;
18641d07074SAlex Vesker 	}
18741d07074SAlex Vesker 
18841d07074SAlex Vesker 	return NULL;
18941d07074SAlex Vesker }
19041d07074SAlex Vesker 
19141d07074SAlex Vesker static struct mlx5dr_ste *
dr_rule_rehash_handle_collision(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,struct list_head * update_list,struct mlx5dr_ste * col_ste,u8 * hw_ste)19241d07074SAlex Vesker dr_rule_rehash_handle_collision(struct mlx5dr_matcher *matcher,
19341d07074SAlex Vesker 				struct mlx5dr_matcher_rx_tx *nic_matcher,
19441d07074SAlex Vesker 				struct list_head *update_list,
19541d07074SAlex Vesker 				struct mlx5dr_ste *col_ste,
19641d07074SAlex Vesker 				u8 *hw_ste)
19741d07074SAlex Vesker {
1986b93b400SYevgeny Kliteynik 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
19941d07074SAlex Vesker 	struct mlx5dr_ste *new_ste;
20041d07074SAlex Vesker 	int ret;
20141d07074SAlex Vesker 
20241d07074SAlex Vesker 	new_ste = dr_rule_create_collision_htbl(matcher, nic_matcher, hw_ste);
20341d07074SAlex Vesker 	if (!new_ste)
20441d07074SAlex Vesker 		return NULL;
20541d07074SAlex Vesker 
2068a015baeSYevgeny Kliteynik 	/* Update collision pointing STE */
2078a015baeSYevgeny Kliteynik 	new_ste->htbl->pointing_ste = col_ste->htbl->pointing_ste;
2088a015baeSYevgeny Kliteynik 
20941d07074SAlex Vesker 	/* In collision entry, all members share the same miss_list_head */
210597534bdSRongwei Liu 	new_ste->htbl->chunk->miss_list = mlx5dr_ste_get_miss_list(col_ste);
21141d07074SAlex Vesker 
21241d07074SAlex Vesker 	/* Update the previous from the list */
21317b56073SYevgeny Kliteynik 	ret = dr_rule_append_to_miss_list(dmn, nic_matcher->nic_tbl->nic_dmn->type,
21417b56073SYevgeny Kliteynik 					  new_ste, mlx5dr_ste_get_miss_list(col_ste),
21541d07074SAlex Vesker 					  update_list);
21641d07074SAlex Vesker 	if (ret) {
2176b93b400SYevgeny Kliteynik 		mlx5dr_dbg(dmn, "Failed update dup entry\n");
21841d07074SAlex Vesker 		goto err_exit;
21941d07074SAlex Vesker 	}
22041d07074SAlex Vesker 
22141d07074SAlex Vesker 	return new_ste;
22241d07074SAlex Vesker 
22341d07074SAlex Vesker err_exit:
22441d07074SAlex Vesker 	mlx5dr_ste_free(new_ste, matcher, nic_matcher);
22541d07074SAlex Vesker 	return NULL;
22641d07074SAlex Vesker }
22741d07074SAlex Vesker 
dr_rule_rehash_copy_ste_ctrl(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,struct mlx5dr_ste * cur_ste,struct mlx5dr_ste * new_ste)22841d07074SAlex Vesker static void dr_rule_rehash_copy_ste_ctrl(struct mlx5dr_matcher *matcher,
22941d07074SAlex Vesker 					 struct mlx5dr_matcher_rx_tx *nic_matcher,
23041d07074SAlex Vesker 					 struct mlx5dr_ste *cur_ste,
23141d07074SAlex Vesker 					 struct mlx5dr_ste *new_ste)
23241d07074SAlex Vesker {
23341d07074SAlex Vesker 	new_ste->next_htbl = cur_ste->next_htbl;
23441d07074SAlex Vesker 	new_ste->ste_chain_location = cur_ste->ste_chain_location;
23541d07074SAlex Vesker 
2368a015baeSYevgeny Kliteynik 	if (new_ste->next_htbl)
23741d07074SAlex Vesker 		new_ste->next_htbl->pointing_ste = new_ste;
23841d07074SAlex Vesker 
23941d07074SAlex Vesker 	/* We need to copy the refcount since this ste
24041d07074SAlex Vesker 	 * may have been traversed several times
24141d07074SAlex Vesker 	 */
2424ce380caSYevgeny Kliteynik 	new_ste->refcount = cur_ste->refcount;
24341d07074SAlex Vesker 
2448a015baeSYevgeny Kliteynik 	/* Link old STEs rule to the new ste */
2458a015baeSYevgeny Kliteynik 	mlx5dr_rule_set_last_member(cur_ste->rule_rx_tx, new_ste, false);
24641d07074SAlex Vesker }
24741d07074SAlex Vesker 
24841d07074SAlex Vesker static struct mlx5dr_ste *
dr_rule_rehash_copy_ste(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,struct mlx5dr_ste * cur_ste,struct mlx5dr_ste_htbl * new_htbl,struct list_head * update_list)24941d07074SAlex Vesker dr_rule_rehash_copy_ste(struct mlx5dr_matcher *matcher,
25041d07074SAlex Vesker 			struct mlx5dr_matcher_rx_tx *nic_matcher,
25141d07074SAlex Vesker 			struct mlx5dr_ste *cur_ste,
25241d07074SAlex Vesker 			struct mlx5dr_ste_htbl *new_htbl,
25341d07074SAlex Vesker 			struct list_head *update_list)
25441d07074SAlex Vesker {
2556b93b400SYevgeny Kliteynik 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
25641d07074SAlex Vesker 	struct mlx5dr_ste_send_info *ste_info;
25741d07074SAlex Vesker 	bool use_update_list = false;
25841d07074SAlex Vesker 	u8 hw_ste[DR_STE_SIZE] = {};
25941d07074SAlex Vesker 	struct mlx5dr_ste *new_ste;
26041d07074SAlex Vesker 	int new_idx;
26141d07074SAlex Vesker 	u8 sb_idx;
26241d07074SAlex Vesker 
26341d07074SAlex Vesker 	/* Copy STE mask from the matcher */
26441d07074SAlex Vesker 	sb_idx = cur_ste->ste_chain_location - 1;
26541d07074SAlex Vesker 	mlx5dr_ste_set_bit_mask(hw_ste, nic_matcher->ste_builder[sb_idx].bit_mask);
26641d07074SAlex Vesker 
26741d07074SAlex Vesker 	/* Copy STE control and tag */
2680d7f1595SRongwei Liu 	memcpy(hw_ste, mlx5dr_ste_get_hw_ste(cur_ste), DR_STE_SIZE_REDUCED);
269f31bda78SYevgeny Kliteynik 	dr_rule_set_last_ste_miss_addr(matcher, nic_matcher, hw_ste);
27041d07074SAlex Vesker 
27141d07074SAlex Vesker 	new_idx = mlx5dr_ste_calc_hash_index(hw_ste, new_htbl);
272597534bdSRongwei Liu 	new_ste = &new_htbl->chunk->ste_arr[new_idx];
27341d07074SAlex Vesker 
27497ffd895SYevgeny Kliteynik 	if (mlx5dr_ste_is_not_used(new_ste)) {
27541d07074SAlex Vesker 		mlx5dr_htbl_get(new_htbl);
27641d07074SAlex Vesker 		list_add_tail(&new_ste->miss_list_node,
27741d07074SAlex Vesker 			      mlx5dr_ste_get_miss_list(new_ste));
27841d07074SAlex Vesker 	} else {
27941d07074SAlex Vesker 		new_ste = dr_rule_rehash_handle_collision(matcher,
28041d07074SAlex Vesker 							  nic_matcher,
28141d07074SAlex Vesker 							  update_list,
28241d07074SAlex Vesker 							  new_ste,
28341d07074SAlex Vesker 							  hw_ste);
28441d07074SAlex Vesker 		if (!new_ste) {
2856b93b400SYevgeny Kliteynik 			mlx5dr_dbg(dmn, "Failed adding collision entry, index: %d\n",
28641d07074SAlex Vesker 				   new_idx);
28741d07074SAlex Vesker 			return NULL;
28841d07074SAlex Vesker 		}
28941d07074SAlex Vesker 		new_htbl->ctrl.num_of_collisions++;
29041d07074SAlex Vesker 		use_update_list = true;
29141d07074SAlex Vesker 	}
29241d07074SAlex Vesker 
2930d7f1595SRongwei Liu 	memcpy(mlx5dr_ste_get_hw_ste(new_ste), hw_ste, DR_STE_SIZE_REDUCED);
29441d07074SAlex Vesker 
29541d07074SAlex Vesker 	new_htbl->ctrl.num_of_valid_entries++;
29641d07074SAlex Vesker 
29741d07074SAlex Vesker 	if (use_update_list) {
29817b56073SYevgeny Kliteynik 		ste_info = mlx5dr_send_info_alloc(dmn,
29917b56073SYevgeny Kliteynik 						  nic_matcher->nic_tbl->nic_dmn->type);
30041d07074SAlex Vesker 		if (!ste_info)
30141d07074SAlex Vesker 			goto err_exit;
30241d07074SAlex Vesker 
30341d07074SAlex Vesker 		mlx5dr_send_fill_and_append_ste_send_info(new_ste, DR_STE_SIZE, 0,
30441d07074SAlex Vesker 							  hw_ste, ste_info,
30541d07074SAlex Vesker 							  update_list, true);
30641d07074SAlex Vesker 	}
30741d07074SAlex Vesker 
30841d07074SAlex Vesker 	dr_rule_rehash_copy_ste_ctrl(matcher, nic_matcher, cur_ste, new_ste);
30941d07074SAlex Vesker 
31041d07074SAlex Vesker 	return new_ste;
31141d07074SAlex Vesker 
31241d07074SAlex Vesker err_exit:
31341d07074SAlex Vesker 	mlx5dr_ste_free(new_ste, matcher, nic_matcher);
31441d07074SAlex Vesker 	return NULL;
31541d07074SAlex Vesker }
31641d07074SAlex Vesker 
dr_rule_rehash_copy_miss_list(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,struct list_head * cur_miss_list,struct mlx5dr_ste_htbl * new_htbl,struct list_head * update_list)31741d07074SAlex Vesker static int dr_rule_rehash_copy_miss_list(struct mlx5dr_matcher *matcher,
31841d07074SAlex Vesker 					 struct mlx5dr_matcher_rx_tx *nic_matcher,
31941d07074SAlex Vesker 					 struct list_head *cur_miss_list,
32041d07074SAlex Vesker 					 struct mlx5dr_ste_htbl *new_htbl,
32141d07074SAlex Vesker 					 struct list_head *update_list)
32241d07074SAlex Vesker {
32341d07074SAlex Vesker 	struct mlx5dr_ste *tmp_ste, *cur_ste, *new_ste;
32441d07074SAlex Vesker 
32541d07074SAlex Vesker 	if (list_empty(cur_miss_list))
32641d07074SAlex Vesker 		return 0;
32741d07074SAlex Vesker 
32841d07074SAlex Vesker 	list_for_each_entry_safe(cur_ste, tmp_ste, cur_miss_list, miss_list_node) {
32941d07074SAlex Vesker 		new_ste = dr_rule_rehash_copy_ste(matcher,
33041d07074SAlex Vesker 						  nic_matcher,
33141d07074SAlex Vesker 						  cur_ste,
33241d07074SAlex Vesker 						  new_htbl,
33341d07074SAlex Vesker 						  update_list);
33441d07074SAlex Vesker 		if (!new_ste)
33541d07074SAlex Vesker 			goto err_insert;
33641d07074SAlex Vesker 
33741d07074SAlex Vesker 		list_del(&cur_ste->miss_list_node);
33841d07074SAlex Vesker 		mlx5dr_htbl_put(cur_ste->htbl);
33941d07074SAlex Vesker 	}
34041d07074SAlex Vesker 	return 0;
34141d07074SAlex Vesker 
34241d07074SAlex Vesker err_insert:
34341d07074SAlex Vesker 	mlx5dr_err(matcher->tbl->dmn, "Fatal error during resize\n");
34441d07074SAlex Vesker 	WARN_ON(true);
34541d07074SAlex Vesker 	return -EINVAL;
34641d07074SAlex Vesker }
34741d07074SAlex Vesker 
dr_rule_rehash_copy_htbl(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,struct mlx5dr_ste_htbl * cur_htbl,struct mlx5dr_ste_htbl * new_htbl,struct list_head * update_list)34841d07074SAlex Vesker static int dr_rule_rehash_copy_htbl(struct mlx5dr_matcher *matcher,
34941d07074SAlex Vesker 				    struct mlx5dr_matcher_rx_tx *nic_matcher,
35041d07074SAlex Vesker 				    struct mlx5dr_ste_htbl *cur_htbl,
35141d07074SAlex Vesker 				    struct mlx5dr_ste_htbl *new_htbl,
35241d07074SAlex Vesker 				    struct list_head *update_list)
35341d07074SAlex Vesker {
35441d07074SAlex Vesker 	struct mlx5dr_ste *cur_ste;
35541d07074SAlex Vesker 	int cur_entries;
35641d07074SAlex Vesker 	int err = 0;
35741d07074SAlex Vesker 	int i;
35841d07074SAlex Vesker 
359597534bdSRongwei Liu 	cur_entries = mlx5dr_icm_pool_chunk_size_to_entries(cur_htbl->chunk->size);
36041d07074SAlex Vesker 
36141d07074SAlex Vesker 	if (cur_entries < 1) {
36241d07074SAlex Vesker 		mlx5dr_dbg(matcher->tbl->dmn, "Invalid number of entries\n");
36341d07074SAlex Vesker 		return -EINVAL;
36441d07074SAlex Vesker 	}
36541d07074SAlex Vesker 
36641d07074SAlex Vesker 	for (i = 0; i < cur_entries; i++) {
367597534bdSRongwei Liu 		cur_ste = &cur_htbl->chunk->ste_arr[i];
36897ffd895SYevgeny Kliteynik 		if (mlx5dr_ste_is_not_used(cur_ste)) /* Empty, nothing to copy */
36941d07074SAlex Vesker 			continue;
37041d07074SAlex Vesker 
37141d07074SAlex Vesker 		err = dr_rule_rehash_copy_miss_list(matcher,
37241d07074SAlex Vesker 						    nic_matcher,
37341d07074SAlex Vesker 						    mlx5dr_ste_get_miss_list(cur_ste),
37441d07074SAlex Vesker 						    new_htbl,
37541d07074SAlex Vesker 						    update_list);
37641d07074SAlex Vesker 		if (err)
37741d07074SAlex Vesker 			goto clean_copy;
3781bea2dc7SYevgeny Kliteynik 
3791bea2dc7SYevgeny Kliteynik 		/* In order to decrease the number of allocated ste_send_info
3801bea2dc7SYevgeny Kliteynik 		 * structs, send the current table row now.
3811bea2dc7SYevgeny Kliteynik 		 */
3821bea2dc7SYevgeny Kliteynik 		err = dr_rule_send_update_list(update_list, matcher->tbl->dmn, false);
3831bea2dc7SYevgeny Kliteynik 		if (err) {
3841bea2dc7SYevgeny Kliteynik 			mlx5dr_dbg(matcher->tbl->dmn, "Failed updating table to HW\n");
3851bea2dc7SYevgeny Kliteynik 			goto clean_copy;
3861bea2dc7SYevgeny Kliteynik 		}
38741d07074SAlex Vesker 	}
38841d07074SAlex Vesker 
38941d07074SAlex Vesker clean_copy:
39041d07074SAlex Vesker 	return err;
39141d07074SAlex Vesker }
39241d07074SAlex Vesker 
39341d07074SAlex Vesker static struct mlx5dr_ste_htbl *
dr_rule_rehash_htbl(struct mlx5dr_rule * rule,struct mlx5dr_rule_rx_tx * nic_rule,struct mlx5dr_ste_htbl * cur_htbl,u8 ste_location,struct list_head * update_list,enum mlx5dr_icm_chunk_size new_size)39441d07074SAlex Vesker dr_rule_rehash_htbl(struct mlx5dr_rule *rule,
39541d07074SAlex Vesker 		    struct mlx5dr_rule_rx_tx *nic_rule,
39641d07074SAlex Vesker 		    struct mlx5dr_ste_htbl *cur_htbl,
39741d07074SAlex Vesker 		    u8 ste_location,
39841d07074SAlex Vesker 		    struct list_head *update_list,
39941d07074SAlex Vesker 		    enum mlx5dr_icm_chunk_size new_size)
40041d07074SAlex Vesker {
40141d07074SAlex Vesker 	struct mlx5dr_ste_send_info *del_ste_info, *tmp_ste_info;
40241d07074SAlex Vesker 	struct mlx5dr_matcher *matcher = rule->matcher;
40341d07074SAlex Vesker 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
40441d07074SAlex Vesker 	struct mlx5dr_matcher_rx_tx *nic_matcher;
40541d07074SAlex Vesker 	struct mlx5dr_ste_send_info *ste_info;
40641d07074SAlex Vesker 	struct mlx5dr_htbl_connect_info info;
40741d07074SAlex Vesker 	struct mlx5dr_domain_rx_tx *nic_dmn;
40841d07074SAlex Vesker 	u8 formatted_ste[DR_STE_SIZE] = {};
40941d07074SAlex Vesker 	LIST_HEAD(rehash_table_send_list);
41041d07074SAlex Vesker 	struct mlx5dr_ste *ste_to_update;
41141d07074SAlex Vesker 	struct mlx5dr_ste_htbl *new_htbl;
41241d07074SAlex Vesker 	int err;
41341d07074SAlex Vesker 
41441d07074SAlex Vesker 	nic_matcher = nic_rule->nic_matcher;
41541d07074SAlex Vesker 	nic_dmn = nic_matcher->nic_tbl->nic_dmn;
41641d07074SAlex Vesker 
41717b56073SYevgeny Kliteynik 	ste_info = mlx5dr_send_info_alloc(dmn,
41817b56073SYevgeny Kliteynik 					  nic_matcher->nic_tbl->nic_dmn->type);
41941d07074SAlex Vesker 	if (!ste_info)
42041d07074SAlex Vesker 		return NULL;
42141d07074SAlex Vesker 
42241d07074SAlex Vesker 	new_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
42341d07074SAlex Vesker 					 new_size,
42441d07074SAlex Vesker 					 cur_htbl->lu_type,
42541d07074SAlex Vesker 					 cur_htbl->byte_mask);
42641d07074SAlex Vesker 	if (!new_htbl) {
42741d07074SAlex Vesker 		mlx5dr_err(dmn, "Failed to allocate new hash table\n");
42841d07074SAlex Vesker 		goto free_ste_info;
42941d07074SAlex Vesker 	}
43041d07074SAlex Vesker 
43141d07074SAlex Vesker 	/* Write new table to HW */
43241d07074SAlex Vesker 	info.type = CONNECT_MISS;
4335c4f9b6eSRongwei Liu 	info.miss_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk);
4346b93b400SYevgeny Kliteynik 	mlx5dr_ste_set_formatted_ste(dmn->ste_ctx,
4356b93b400SYevgeny Kliteynik 				     dmn->info.caps.gvmi,
43646f2a8aeSYevgeny Kliteynik 				     nic_dmn->type,
43741d07074SAlex Vesker 				     new_htbl,
43841d07074SAlex Vesker 				     formatted_ste,
43941d07074SAlex Vesker 				     &info);
44041d07074SAlex Vesker 
44141d07074SAlex Vesker 	new_htbl->pointing_ste = cur_htbl->pointing_ste;
44241d07074SAlex Vesker 	new_htbl->pointing_ste->next_htbl = new_htbl;
44341d07074SAlex Vesker 	err = dr_rule_rehash_copy_htbl(matcher,
44441d07074SAlex Vesker 				       nic_matcher,
44541d07074SAlex Vesker 				       cur_htbl,
44641d07074SAlex Vesker 				       new_htbl,
44741d07074SAlex Vesker 				       &rehash_table_send_list);
44841d07074SAlex Vesker 	if (err)
44941d07074SAlex Vesker 		goto free_new_htbl;
45041d07074SAlex Vesker 
45141d07074SAlex Vesker 	if (mlx5dr_send_postsend_htbl(dmn, new_htbl, formatted_ste,
45241d07074SAlex Vesker 				      nic_matcher->ste_builder[ste_location - 1].bit_mask)) {
45341d07074SAlex Vesker 		mlx5dr_err(dmn, "Failed writing table to HW\n");
45441d07074SAlex Vesker 		goto free_new_htbl;
45541d07074SAlex Vesker 	}
45641d07074SAlex Vesker 
45741d07074SAlex Vesker 	/* Writing to the hw is done in regular order of rehash_table_send_list,
45841d07074SAlex Vesker 	 * in order to have the origin data written before the miss address of
45941d07074SAlex Vesker 	 * collision entries, if exists.
46041d07074SAlex Vesker 	 */
46141d07074SAlex Vesker 	if (dr_rule_send_update_list(&rehash_table_send_list, dmn, false)) {
46241d07074SAlex Vesker 		mlx5dr_err(dmn, "Failed updating table to HW\n");
46341d07074SAlex Vesker 		goto free_ste_list;
46441d07074SAlex Vesker 	}
46541d07074SAlex Vesker 
46641d07074SAlex Vesker 	/* Connect previous hash table to current */
46741d07074SAlex Vesker 	if (ste_location == 1) {
46841d07074SAlex Vesker 		/* The previous table is an anchor, anchors size is always one STE */
46941d07074SAlex Vesker 		struct mlx5dr_ste_htbl *prev_htbl = cur_htbl->pointing_ste->htbl;
47041d07074SAlex Vesker 
47141d07074SAlex Vesker 		/* On matcher s_anchor we keep an extra refcount */
47241d07074SAlex Vesker 		mlx5dr_htbl_get(new_htbl);
47341d07074SAlex Vesker 		mlx5dr_htbl_put(cur_htbl);
47441d07074SAlex Vesker 
47541d07074SAlex Vesker 		nic_matcher->s_htbl = new_htbl;
47641d07074SAlex Vesker 
47741d07074SAlex Vesker 		/* It is safe to operate dr_ste_set_hit_addr on the hw_ste here
47841d07074SAlex Vesker 		 * (48B len) which works only on first 32B
47941d07074SAlex Vesker 		 */
4806b93b400SYevgeny Kliteynik 		mlx5dr_ste_set_hit_addr(dmn->ste_ctx,
4810d7f1595SRongwei Liu 					prev_htbl->chunk->hw_ste_arr,
4825c4f9b6eSRongwei Liu 					mlx5dr_icm_pool_get_chunk_icm_addr(new_htbl->chunk),
483f51bb517SRongwei Liu 					mlx5dr_icm_pool_get_chunk_num_of_entries(new_htbl->chunk));
48441d07074SAlex Vesker 
485597534bdSRongwei Liu 		ste_to_update = &prev_htbl->chunk->ste_arr[0];
48641d07074SAlex Vesker 	} else {
4876b93b400SYevgeny Kliteynik 		mlx5dr_ste_set_hit_addr_by_next_htbl(dmn->ste_ctx,
4880d7f1595SRongwei Liu 						     mlx5dr_ste_get_hw_ste(cur_htbl->pointing_ste),
48941d07074SAlex Vesker 						     new_htbl);
49041d07074SAlex Vesker 		ste_to_update = cur_htbl->pointing_ste;
49141d07074SAlex Vesker 	}
49241d07074SAlex Vesker 
493f06d4969SYevgeny Kliteynik 	mlx5dr_send_fill_and_append_ste_send_info(ste_to_update, DR_STE_SIZE_CTRL,
4940d7f1595SRongwei Liu 						  0, mlx5dr_ste_get_hw_ste(ste_to_update),
4950d7f1595SRongwei Liu 						  ste_info, update_list, false);
49641d07074SAlex Vesker 
49741d07074SAlex Vesker 	return new_htbl;
49841d07074SAlex Vesker 
49941d07074SAlex Vesker free_ste_list:
50041d07074SAlex Vesker 	/* Clean all ste_info's from the new table */
50141d07074SAlex Vesker 	list_for_each_entry_safe(del_ste_info, tmp_ste_info,
50241d07074SAlex Vesker 				 &rehash_table_send_list, send_list) {
50341d07074SAlex Vesker 		list_del(&del_ste_info->send_list);
50417b56073SYevgeny Kliteynik 		mlx5dr_send_info_free(del_ste_info);
50541d07074SAlex Vesker 	}
50641d07074SAlex Vesker 
50741d07074SAlex Vesker free_new_htbl:
50841d07074SAlex Vesker 	mlx5dr_ste_htbl_free(new_htbl);
50941d07074SAlex Vesker free_ste_info:
51017b56073SYevgeny Kliteynik 	mlx5dr_send_info_free(ste_info);
51141d07074SAlex Vesker 	mlx5dr_info(dmn, "Failed creating rehash table\n");
51241d07074SAlex Vesker 	return NULL;
51341d07074SAlex Vesker }
51441d07074SAlex Vesker 
dr_rule_rehash(struct mlx5dr_rule * rule,struct mlx5dr_rule_rx_tx * nic_rule,struct mlx5dr_ste_htbl * cur_htbl,u8 ste_location,struct list_head * update_list)51541d07074SAlex Vesker static struct mlx5dr_ste_htbl *dr_rule_rehash(struct mlx5dr_rule *rule,
51641d07074SAlex Vesker 					      struct mlx5dr_rule_rx_tx *nic_rule,
51741d07074SAlex Vesker 					      struct mlx5dr_ste_htbl *cur_htbl,
51841d07074SAlex Vesker 					      u8 ste_location,
51941d07074SAlex Vesker 					      struct list_head *update_list)
52041d07074SAlex Vesker {
52141d07074SAlex Vesker 	struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn;
52241d07074SAlex Vesker 	enum mlx5dr_icm_chunk_size new_size;
52341d07074SAlex Vesker 
524597534bdSRongwei Liu 	new_size = mlx5dr_icm_next_higher_chunk(cur_htbl->chunk->size);
52541d07074SAlex Vesker 	new_size = min_t(u32, new_size, dmn->info.max_log_sw_icm_sz);
52641d07074SAlex Vesker 
527597534bdSRongwei Liu 	if (new_size == cur_htbl->chunk->size)
52841d07074SAlex Vesker 		return NULL; /* Skip rehash, we already at the max size */
52941d07074SAlex Vesker 
53041d07074SAlex Vesker 	return dr_rule_rehash_htbl(rule, nic_rule, cur_htbl, ste_location,
53141d07074SAlex Vesker 				   update_list, new_size);
53241d07074SAlex Vesker }
53341d07074SAlex Vesker 
53441d07074SAlex Vesker static struct mlx5dr_ste *
dr_rule_handle_collision(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,struct mlx5dr_ste * ste,u8 * hw_ste,struct list_head * miss_list,struct list_head * send_list)53541d07074SAlex Vesker dr_rule_handle_collision(struct mlx5dr_matcher *matcher,
53641d07074SAlex Vesker 			 struct mlx5dr_matcher_rx_tx *nic_matcher,
53741d07074SAlex Vesker 			 struct mlx5dr_ste *ste,
53841d07074SAlex Vesker 			 u8 *hw_ste,
53941d07074SAlex Vesker 			 struct list_head *miss_list,
54041d07074SAlex Vesker 			 struct list_head *send_list)
54141d07074SAlex Vesker {
5426b93b400SYevgeny Kliteynik 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
54341d07074SAlex Vesker 	struct mlx5dr_ste_send_info *ste_info;
54441d07074SAlex Vesker 	struct mlx5dr_ste *new_ste;
54541d07074SAlex Vesker 
54617b56073SYevgeny Kliteynik 	ste_info = mlx5dr_send_info_alloc(dmn,
54717b56073SYevgeny Kliteynik 					  nic_matcher->nic_tbl->nic_dmn->type);
54841d07074SAlex Vesker 	if (!ste_info)
54941d07074SAlex Vesker 		return NULL;
55041d07074SAlex Vesker 
55141d07074SAlex Vesker 	new_ste = dr_rule_create_collision_entry(matcher, nic_matcher, hw_ste, ste);
55241d07074SAlex Vesker 	if (!new_ste)
55341d07074SAlex Vesker 		goto free_send_info;
55441d07074SAlex Vesker 
55517b56073SYevgeny Kliteynik 	if (dr_rule_append_to_miss_list(dmn, nic_matcher->nic_tbl->nic_dmn->type,
55617b56073SYevgeny Kliteynik 					new_ste, miss_list, send_list)) {
5576b93b400SYevgeny Kliteynik 		mlx5dr_dbg(dmn, "Failed to update prev miss_list\n");
55841d07074SAlex Vesker 		goto err_exit;
55941d07074SAlex Vesker 	}
56041d07074SAlex Vesker 
56141d07074SAlex Vesker 	mlx5dr_send_fill_and_append_ste_send_info(new_ste, DR_STE_SIZE, 0, hw_ste,
56241d07074SAlex Vesker 						  ste_info, send_list, false);
56341d07074SAlex Vesker 
56441d07074SAlex Vesker 	ste->htbl->ctrl.num_of_collisions++;
56541d07074SAlex Vesker 	ste->htbl->ctrl.num_of_valid_entries++;
56641d07074SAlex Vesker 
56741d07074SAlex Vesker 	return new_ste;
56841d07074SAlex Vesker 
56941d07074SAlex Vesker err_exit:
57041d07074SAlex Vesker 	mlx5dr_ste_free(new_ste, matcher, nic_matcher);
57141d07074SAlex Vesker free_send_info:
57217b56073SYevgeny Kliteynik 	mlx5dr_send_info_free(ste_info);
57341d07074SAlex Vesker 	return NULL;
57441d07074SAlex Vesker }
57541d07074SAlex Vesker 
dr_rule_remove_action_members(struct mlx5dr_rule * rule)57641d07074SAlex Vesker static void dr_rule_remove_action_members(struct mlx5dr_rule *rule)
57741d07074SAlex Vesker {
57841d07074SAlex Vesker 	struct mlx5dr_rule_action_member *action_mem;
57941d07074SAlex Vesker 	struct mlx5dr_rule_action_member *tmp;
58041d07074SAlex Vesker 
58141d07074SAlex Vesker 	list_for_each_entry_safe(action_mem, tmp, &rule->rule_actions_list, list) {
58241d07074SAlex Vesker 		list_del(&action_mem->list);
58341d07074SAlex Vesker 		refcount_dec(&action_mem->action->refcount);
58441d07074SAlex Vesker 		kvfree(action_mem);
58541d07074SAlex Vesker 	}
58641d07074SAlex Vesker }
58741d07074SAlex Vesker 
dr_rule_add_action_members(struct mlx5dr_rule * rule,size_t num_actions,struct mlx5dr_action * actions[])58841d07074SAlex Vesker static int dr_rule_add_action_members(struct mlx5dr_rule *rule,
58941d07074SAlex Vesker 				      size_t num_actions,
59041d07074SAlex Vesker 				      struct mlx5dr_action *actions[])
59141d07074SAlex Vesker {
59241d07074SAlex Vesker 	struct mlx5dr_rule_action_member *action_mem;
59341d07074SAlex Vesker 	int i;
59441d07074SAlex Vesker 
59541d07074SAlex Vesker 	for (i = 0; i < num_actions; i++) {
59641d07074SAlex Vesker 		action_mem = kvzalloc(sizeof(*action_mem), GFP_KERNEL);
59741d07074SAlex Vesker 		if (!action_mem)
59841d07074SAlex Vesker 			goto free_action_members;
59941d07074SAlex Vesker 
60041d07074SAlex Vesker 		action_mem->action = actions[i];
60141d07074SAlex Vesker 		INIT_LIST_HEAD(&action_mem->list);
60241d07074SAlex Vesker 		list_add_tail(&action_mem->list, &rule->rule_actions_list);
60341d07074SAlex Vesker 		refcount_inc(&action_mem->action->refcount);
60441d07074SAlex Vesker 	}
60541d07074SAlex Vesker 
60641d07074SAlex Vesker 	return 0;
60741d07074SAlex Vesker 
60841d07074SAlex Vesker free_action_members:
60941d07074SAlex Vesker 	dr_rule_remove_action_members(rule);
61041d07074SAlex Vesker 	return -ENOMEM;
61141d07074SAlex Vesker }
61241d07074SAlex Vesker 
mlx5dr_rule_set_last_member(struct mlx5dr_rule_rx_tx * nic_rule,struct mlx5dr_ste * ste,bool force)6138a015baeSYevgeny Kliteynik void mlx5dr_rule_set_last_member(struct mlx5dr_rule_rx_tx *nic_rule,
6148a015baeSYevgeny Kliteynik 				 struct mlx5dr_ste *ste,
6158a015baeSYevgeny Kliteynik 				 bool force)
61641d07074SAlex Vesker {
6178a015baeSYevgeny Kliteynik 	/* Update rule member is usually done for the last STE or during rule
6188a015baeSYevgeny Kliteynik 	 * creation to recover from mid-creation failure (for this peruse the
6198a015baeSYevgeny Kliteynik 	 * force flag is used)
6208a015baeSYevgeny Kliteynik 	 */
6218a015baeSYevgeny Kliteynik 	if (ste->next_htbl && !force)
6228a015baeSYevgeny Kliteynik 		return;
62341d07074SAlex Vesker 
6248a015baeSYevgeny Kliteynik 	/* Update is required since each rule keeps track of its last STE */
6258a015baeSYevgeny Kliteynik 	ste->rule_rx_tx = nic_rule;
6268a015baeSYevgeny Kliteynik 	nic_rule->last_rule_ste = ste;
6278a015baeSYevgeny Kliteynik }
6288a015baeSYevgeny Kliteynik 
dr_rule_get_pointed_ste(struct mlx5dr_ste * curr_ste)6298a015baeSYevgeny Kliteynik static struct mlx5dr_ste *dr_rule_get_pointed_ste(struct mlx5dr_ste *curr_ste)
6308a015baeSYevgeny Kliteynik {
6318a015baeSYevgeny Kliteynik 	struct mlx5dr_ste *first_ste;
6328a015baeSYevgeny Kliteynik 
6338a015baeSYevgeny Kliteynik 	first_ste = list_first_entry(mlx5dr_ste_get_miss_list(curr_ste),
6348a015baeSYevgeny Kliteynik 				     struct mlx5dr_ste, miss_list_node);
6358a015baeSYevgeny Kliteynik 
6368a015baeSYevgeny Kliteynik 	return first_ste->htbl->pointing_ste;
6378a015baeSYevgeny Kliteynik }
6388a015baeSYevgeny Kliteynik 
mlx5dr_rule_get_reverse_rule_members(struct mlx5dr_ste ** ste_arr,struct mlx5dr_ste * curr_ste,int * num_of_stes)6398a015baeSYevgeny Kliteynik int mlx5dr_rule_get_reverse_rule_members(struct mlx5dr_ste **ste_arr,
6408a015baeSYevgeny Kliteynik 					 struct mlx5dr_ste *curr_ste,
6418a015baeSYevgeny Kliteynik 					 int *num_of_stes)
6428a015baeSYevgeny Kliteynik {
6438a015baeSYevgeny Kliteynik 	bool first = false;
6448a015baeSYevgeny Kliteynik 
6458a015baeSYevgeny Kliteynik 	*num_of_stes = 0;
6468a015baeSYevgeny Kliteynik 
6478a015baeSYevgeny Kliteynik 	if (!curr_ste)
6488a015baeSYevgeny Kliteynik 		return -ENOENT;
6498a015baeSYevgeny Kliteynik 
6508a015baeSYevgeny Kliteynik 	/* Iterate from last to first */
6518a015baeSYevgeny Kliteynik 	while (!first) {
6528a015baeSYevgeny Kliteynik 		first = curr_ste->ste_chain_location == 1;
6538a015baeSYevgeny Kliteynik 		ste_arr[*num_of_stes] = curr_ste;
6548a015baeSYevgeny Kliteynik 		*num_of_stes += 1;
6558a015baeSYevgeny Kliteynik 		curr_ste = dr_rule_get_pointed_ste(curr_ste);
6568a015baeSYevgeny Kliteynik 	}
6578a015baeSYevgeny Kliteynik 
6588a015baeSYevgeny Kliteynik 	return 0;
65941d07074SAlex Vesker }
66041d07074SAlex Vesker 
dr_rule_clean_rule_members(struct mlx5dr_rule * rule,struct mlx5dr_rule_rx_tx * nic_rule)66141d07074SAlex Vesker static void dr_rule_clean_rule_members(struct mlx5dr_rule *rule,
66241d07074SAlex Vesker 				       struct mlx5dr_rule_rx_tx *nic_rule)
66341d07074SAlex Vesker {
6648a015baeSYevgeny Kliteynik 	struct mlx5dr_ste *ste_arr[DR_RULE_MAX_STES + DR_ACTION_MAX_STES];
6658a015baeSYevgeny Kliteynik 	struct mlx5dr_ste *curr_ste = nic_rule->last_rule_ste;
6668a015baeSYevgeny Kliteynik 	int i;
66741d07074SAlex Vesker 
6688a015baeSYevgeny Kliteynik 	if (mlx5dr_rule_get_reverse_rule_members(ste_arr, curr_ste, &i))
66941d07074SAlex Vesker 		return;
6708a015baeSYevgeny Kliteynik 
6718a015baeSYevgeny Kliteynik 	while (i--)
6728a015baeSYevgeny Kliteynik 		mlx5dr_ste_put(ste_arr[i], rule->matcher, nic_rule->nic_matcher);
67341d07074SAlex Vesker }
67441d07074SAlex Vesker 
dr_get_bits_per_mask(u16 byte_mask)67521586a0fSAlex Vesker static u16 dr_get_bits_per_mask(u16 byte_mask)
67621586a0fSAlex Vesker {
67721586a0fSAlex Vesker 	u16 bits = 0;
67821586a0fSAlex Vesker 
67921586a0fSAlex Vesker 	while (byte_mask) {
68021586a0fSAlex Vesker 		byte_mask = byte_mask & (byte_mask - 1);
68121586a0fSAlex Vesker 		bits++;
68221586a0fSAlex Vesker 	}
68321586a0fSAlex Vesker 
68421586a0fSAlex Vesker 	return bits;
68521586a0fSAlex Vesker }
68621586a0fSAlex Vesker 
dr_rule_need_enlarge_hash(struct mlx5dr_ste_htbl * htbl,struct mlx5dr_domain * dmn,struct mlx5dr_domain_rx_tx * nic_dmn)68741d07074SAlex Vesker static bool dr_rule_need_enlarge_hash(struct mlx5dr_ste_htbl *htbl,
68841d07074SAlex Vesker 				      struct mlx5dr_domain *dmn,
68941d07074SAlex Vesker 				      struct mlx5dr_domain_rx_tx *nic_dmn)
69041d07074SAlex Vesker {
69141d07074SAlex Vesker 	struct mlx5dr_ste_htbl_ctrl *ctrl = &htbl->ctrl;
69232c8e3b2SYevgeny Kliteynik 	int threshold;
69341d07074SAlex Vesker 
694597534bdSRongwei Liu 	if (dmn->info.max_log_sw_icm_sz <= htbl->chunk->size)
69541d07074SAlex Vesker 		return false;
69641d07074SAlex Vesker 
69732c8e3b2SYevgeny Kliteynik 	if (!mlx5dr_ste_htbl_may_grow(htbl))
69841d07074SAlex Vesker 		return false;
69941d07074SAlex Vesker 
700597534bdSRongwei Liu 	if (dr_get_bits_per_mask(htbl->byte_mask) * BITS_PER_BYTE <= htbl->chunk->size)
70121586a0fSAlex Vesker 		return false;
70221586a0fSAlex Vesker 
70332c8e3b2SYevgeny Kliteynik 	threshold = mlx5dr_ste_htbl_increase_threshold(htbl);
70432c8e3b2SYevgeny Kliteynik 	if (ctrl->num_of_collisions >= threshold &&
70532c8e3b2SYevgeny Kliteynik 	    (ctrl->num_of_valid_entries - ctrl->num_of_collisions) >= threshold)
70641d07074SAlex Vesker 		return true;
70741d07074SAlex Vesker 
70841d07074SAlex Vesker 	return false;
70941d07074SAlex Vesker }
71041d07074SAlex Vesker 
dr_rule_handle_action_stes(struct mlx5dr_rule * rule,struct mlx5dr_rule_rx_tx * nic_rule,struct list_head * send_ste_list,struct mlx5dr_ste * last_ste,u8 * hw_ste_arr,u32 new_hw_ste_arr_sz)71141d07074SAlex Vesker static int dr_rule_handle_action_stes(struct mlx5dr_rule *rule,
71241d07074SAlex Vesker 				      struct mlx5dr_rule_rx_tx *nic_rule,
71341d07074SAlex Vesker 				      struct list_head *send_ste_list,
71441d07074SAlex Vesker 				      struct mlx5dr_ste *last_ste,
71541d07074SAlex Vesker 				      u8 *hw_ste_arr,
71641d07074SAlex Vesker 				      u32 new_hw_ste_arr_sz)
71741d07074SAlex Vesker {
71841d07074SAlex Vesker 	struct mlx5dr_matcher_rx_tx *nic_matcher = nic_rule->nic_matcher;
71941d07074SAlex Vesker 	struct mlx5dr_ste_send_info *ste_info_arr[DR_ACTION_MAX_STES];
72041d07074SAlex Vesker 	u8 num_of_builders = nic_matcher->num_of_builders;
72141d07074SAlex Vesker 	struct mlx5dr_matcher *matcher = rule->matcher;
7226b93b400SYevgeny Kliteynik 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
72341d07074SAlex Vesker 	u8 *curr_hw_ste, *prev_hw_ste;
72441d07074SAlex Vesker 	struct mlx5dr_ste *action_ste;
7258a015baeSYevgeny Kliteynik 	int i, k;
72641d07074SAlex Vesker 
72741d07074SAlex Vesker 	/* Two cases:
72841d07074SAlex Vesker 	 * 1. num_of_builders is equal to new_hw_ste_arr_sz, the action in the ste
72941d07074SAlex Vesker 	 * 2. num_of_builders is less then new_hw_ste_arr_sz, new ste was added
73041d07074SAlex Vesker 	 *    to support the action.
73141d07074SAlex Vesker 	 */
73241d07074SAlex Vesker 
73341d07074SAlex Vesker 	for (i = num_of_builders, k = 0; i < new_hw_ste_arr_sz; i++, k++) {
73441d07074SAlex Vesker 		curr_hw_ste = hw_ste_arr + i * DR_STE_SIZE;
73541d07074SAlex Vesker 		prev_hw_ste = (i == 0) ? curr_hw_ste : hw_ste_arr + ((i - 1) * DR_STE_SIZE);
73641d07074SAlex Vesker 		action_ste = dr_rule_create_collision_htbl(matcher,
73741d07074SAlex Vesker 							   nic_matcher,
73841d07074SAlex Vesker 							   curr_hw_ste);
73941d07074SAlex Vesker 		if (!action_ste)
74041d07074SAlex Vesker 			return -ENOMEM;
74141d07074SAlex Vesker 
74241d07074SAlex Vesker 		mlx5dr_ste_get(action_ste);
74341d07074SAlex Vesker 
7448a015baeSYevgeny Kliteynik 		action_ste->htbl->pointing_ste = last_ste;
7458a015baeSYevgeny Kliteynik 		last_ste->next_htbl = action_ste->htbl;
7468a015baeSYevgeny Kliteynik 		last_ste = action_ste;
7478a015baeSYevgeny Kliteynik 
74841d07074SAlex Vesker 		/* While free ste we go over the miss list, so add this ste to the list */
74941d07074SAlex Vesker 		list_add_tail(&action_ste->miss_list_node,
75041d07074SAlex Vesker 			      mlx5dr_ste_get_miss_list(action_ste));
75141d07074SAlex Vesker 
75217b56073SYevgeny Kliteynik 		ste_info_arr[k] = mlx5dr_send_info_alloc(dmn,
75317b56073SYevgeny Kliteynik 							 nic_matcher->nic_tbl->nic_dmn->type);
75441d07074SAlex Vesker 		if (!ste_info_arr[k])
75541d07074SAlex Vesker 			goto err_exit;
75641d07074SAlex Vesker 
75741d07074SAlex Vesker 		/* Point current ste to the new action */
7586b93b400SYevgeny Kliteynik 		mlx5dr_ste_set_hit_addr_by_next_htbl(dmn->ste_ctx,
7596b93b400SYevgeny Kliteynik 						     prev_hw_ste,
7606b93b400SYevgeny Kliteynik 						     action_ste->htbl);
7618a015baeSYevgeny Kliteynik 
7628a015baeSYevgeny Kliteynik 		mlx5dr_rule_set_last_member(nic_rule, action_ste, true);
7638a015baeSYevgeny Kliteynik 
76441d07074SAlex Vesker 		mlx5dr_send_fill_and_append_ste_send_info(action_ste, DR_STE_SIZE, 0,
76541d07074SAlex Vesker 							  curr_hw_ste,
76641d07074SAlex Vesker 							  ste_info_arr[k],
76741d07074SAlex Vesker 							  send_ste_list, false);
76841d07074SAlex Vesker 	}
76941d07074SAlex Vesker 
7708a015baeSYevgeny Kliteynik 	last_ste->next_htbl = NULL;
7718a015baeSYevgeny Kliteynik 
77241d07074SAlex Vesker 	return 0;
77341d07074SAlex Vesker 
77441d07074SAlex Vesker err_exit:
77541d07074SAlex Vesker 	mlx5dr_ste_put(action_ste, matcher, nic_matcher);
77641d07074SAlex Vesker 	return -ENOMEM;
77741d07074SAlex Vesker }
77841d07074SAlex Vesker 
dr_rule_handle_empty_entry(struct mlx5dr_matcher * matcher,struct mlx5dr_matcher_rx_tx * nic_matcher,struct mlx5dr_ste_htbl * cur_htbl,struct mlx5dr_ste * ste,u8 ste_location,u8 * hw_ste,struct list_head * miss_list,struct list_head * send_list)77941d07074SAlex Vesker static int dr_rule_handle_empty_entry(struct mlx5dr_matcher *matcher,
78041d07074SAlex Vesker 				      struct mlx5dr_matcher_rx_tx *nic_matcher,
78141d07074SAlex Vesker 				      struct mlx5dr_ste_htbl *cur_htbl,
78241d07074SAlex Vesker 				      struct mlx5dr_ste *ste,
78341d07074SAlex Vesker 				      u8 ste_location,
78441d07074SAlex Vesker 				      u8 *hw_ste,
78541d07074SAlex Vesker 				      struct list_head *miss_list,
78641d07074SAlex Vesker 				      struct list_head *send_list)
78741d07074SAlex Vesker {
7886b93b400SYevgeny Kliteynik 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
78941d07074SAlex Vesker 	struct mlx5dr_ste_send_info *ste_info;
79041d07074SAlex Vesker 
79141d07074SAlex Vesker 	/* Take ref on table, only on first time this ste is used */
79241d07074SAlex Vesker 	mlx5dr_htbl_get(cur_htbl);
79341d07074SAlex Vesker 
79441d07074SAlex Vesker 	/* new entry -> new branch */
79541d07074SAlex Vesker 	list_add_tail(&ste->miss_list_node, miss_list);
79641d07074SAlex Vesker 
797f31bda78SYevgeny Kliteynik 	dr_rule_set_last_ste_miss_addr(matcher, nic_matcher, hw_ste);
79841d07074SAlex Vesker 
79941d07074SAlex Vesker 	ste->ste_chain_location = ste_location;
80041d07074SAlex Vesker 
80117b56073SYevgeny Kliteynik 	ste_info = mlx5dr_send_info_alloc(dmn,
80217b56073SYevgeny Kliteynik 					  nic_matcher->nic_tbl->nic_dmn->type);
80341d07074SAlex Vesker 	if (!ste_info)
80441d07074SAlex Vesker 		goto clean_ste_setting;
80541d07074SAlex Vesker 
80641d07074SAlex Vesker 	if (mlx5dr_ste_create_next_htbl(matcher,
80741d07074SAlex Vesker 					nic_matcher,
80841d07074SAlex Vesker 					ste,
80941d07074SAlex Vesker 					hw_ste,
81041d07074SAlex Vesker 					DR_CHUNK_SIZE_1)) {
8116b93b400SYevgeny Kliteynik 		mlx5dr_dbg(dmn, "Failed allocating table\n");
81241d07074SAlex Vesker 		goto clean_ste_info;
81341d07074SAlex Vesker 	}
81441d07074SAlex Vesker 
81541d07074SAlex Vesker 	cur_htbl->ctrl.num_of_valid_entries++;
81641d07074SAlex Vesker 
81741d07074SAlex Vesker 	mlx5dr_send_fill_and_append_ste_send_info(ste, DR_STE_SIZE, 0, hw_ste,
81841d07074SAlex Vesker 						  ste_info, send_list, false);
81941d07074SAlex Vesker 
82041d07074SAlex Vesker 	return 0;
82141d07074SAlex Vesker 
82241d07074SAlex Vesker clean_ste_info:
82317b56073SYevgeny Kliteynik 	mlx5dr_send_info_free(ste_info);
82441d07074SAlex Vesker clean_ste_setting:
82541d07074SAlex Vesker 	list_del_init(&ste->miss_list_node);
82641d07074SAlex Vesker 	mlx5dr_htbl_put(cur_htbl);
82741d07074SAlex Vesker 
82841d07074SAlex Vesker 	return -ENOMEM;
82941d07074SAlex Vesker }
83041d07074SAlex Vesker 
83141d07074SAlex Vesker static struct mlx5dr_ste *
dr_rule_handle_ste_branch(struct mlx5dr_rule * rule,struct mlx5dr_rule_rx_tx * nic_rule,struct list_head * send_ste_list,struct mlx5dr_ste_htbl * cur_htbl,u8 * hw_ste,u8 ste_location,struct mlx5dr_ste_htbl ** put_htbl)83241d07074SAlex Vesker dr_rule_handle_ste_branch(struct mlx5dr_rule *rule,
83341d07074SAlex Vesker 			  struct mlx5dr_rule_rx_tx *nic_rule,
83441d07074SAlex Vesker 			  struct list_head *send_ste_list,
83541d07074SAlex Vesker 			  struct mlx5dr_ste_htbl *cur_htbl,
83641d07074SAlex Vesker 			  u8 *hw_ste,
83741d07074SAlex Vesker 			  u8 ste_location,
83841d07074SAlex Vesker 			  struct mlx5dr_ste_htbl **put_htbl)
83941d07074SAlex Vesker {
84041d07074SAlex Vesker 	struct mlx5dr_matcher *matcher = rule->matcher;
84141d07074SAlex Vesker 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
84241d07074SAlex Vesker 	struct mlx5dr_matcher_rx_tx *nic_matcher;
84341d07074SAlex Vesker 	struct mlx5dr_domain_rx_tx *nic_dmn;
84441d07074SAlex Vesker 	struct mlx5dr_ste_htbl *new_htbl;
84541d07074SAlex Vesker 	struct mlx5dr_ste *matched_ste;
84641d07074SAlex Vesker 	struct list_head *miss_list;
84741d07074SAlex Vesker 	bool skip_rehash = false;
84841d07074SAlex Vesker 	struct mlx5dr_ste *ste;
84941d07074SAlex Vesker 	int index;
85041d07074SAlex Vesker 
85141d07074SAlex Vesker 	nic_matcher = nic_rule->nic_matcher;
85241d07074SAlex Vesker 	nic_dmn = nic_matcher->nic_tbl->nic_dmn;
85341d07074SAlex Vesker 
85441d07074SAlex Vesker again:
85541d07074SAlex Vesker 	index = mlx5dr_ste_calc_hash_index(hw_ste, cur_htbl);
85641d07074SAlex Vesker 	miss_list = &cur_htbl->chunk->miss_list[index];
857597534bdSRongwei Liu 	ste = &cur_htbl->chunk->ste_arr[index];
85841d07074SAlex Vesker 
85997ffd895SYevgeny Kliteynik 	if (mlx5dr_ste_is_not_used(ste)) {
86041d07074SAlex Vesker 		if (dr_rule_handle_empty_entry(matcher, nic_matcher, cur_htbl,
86141d07074SAlex Vesker 					       ste, ste_location,
86241d07074SAlex Vesker 					       hw_ste, miss_list,
86341d07074SAlex Vesker 					       send_ste_list))
86441d07074SAlex Vesker 			return NULL;
86541d07074SAlex Vesker 	} else {
86641d07074SAlex Vesker 		/* Hash table index in use, check if this ste is in the miss list */
86741d07074SAlex Vesker 		matched_ste = dr_rule_find_ste_in_miss_list(miss_list, hw_ste);
86841d07074SAlex Vesker 		if (matched_ste) {
86941d07074SAlex Vesker 			/* If it is last STE in the chain, and has the same tag
87041d07074SAlex Vesker 			 * it means that all the previous stes are the same,
87141d07074SAlex Vesker 			 * if so, this rule is duplicated.
87241d07074SAlex Vesker 			 */
87300414126SAlex Vesker 			if (!mlx5dr_ste_is_last_in_rule(nic_matcher, ste_location))
87441d07074SAlex Vesker 				return matched_ste;
87500414126SAlex Vesker 
87600414126SAlex Vesker 			mlx5dr_dbg(dmn, "Duplicate rule inserted\n");
87741d07074SAlex Vesker 		}
87841d07074SAlex Vesker 
87941d07074SAlex Vesker 		if (!skip_rehash && dr_rule_need_enlarge_hash(cur_htbl, dmn, nic_dmn)) {
88041d07074SAlex Vesker 			/* Hash table index in use, try to resize of the hash */
88141d07074SAlex Vesker 			skip_rehash = true;
88241d07074SAlex Vesker 
88341d07074SAlex Vesker 			/* Hold the table till we update.
88441d07074SAlex Vesker 			 * Release in dr_rule_create_rule()
88541d07074SAlex Vesker 			 */
88641d07074SAlex Vesker 			*put_htbl = cur_htbl;
88741d07074SAlex Vesker 			mlx5dr_htbl_get(cur_htbl);
88841d07074SAlex Vesker 
88941d07074SAlex Vesker 			new_htbl = dr_rule_rehash(rule, nic_rule, cur_htbl,
89041d07074SAlex Vesker 						  ste_location, send_ste_list);
89141d07074SAlex Vesker 			if (!new_htbl) {
892b7d0db55SErez Shitrit 				mlx5dr_err(dmn, "Failed creating rehash table, htbl-log_size: %d\n",
893597534bdSRongwei Liu 					   cur_htbl->chunk->size);
8946cc64770SWentao_Liang 				mlx5dr_htbl_put(cur_htbl);
89541d07074SAlex Vesker 			} else {
89641d07074SAlex Vesker 				cur_htbl = new_htbl;
89741d07074SAlex Vesker 			}
89841d07074SAlex Vesker 			goto again;
89941d07074SAlex Vesker 		} else {
90041d07074SAlex Vesker 			/* Hash table index in use, add another collision (miss) */
90141d07074SAlex Vesker 			ste = dr_rule_handle_collision(matcher,
90241d07074SAlex Vesker 						       nic_matcher,
90341d07074SAlex Vesker 						       ste,
90441d07074SAlex Vesker 						       hw_ste,
90541d07074SAlex Vesker 						       miss_list,
90641d07074SAlex Vesker 						       send_ste_list);
90741d07074SAlex Vesker 			if (!ste) {
90841d07074SAlex Vesker 				mlx5dr_dbg(dmn, "failed adding collision entry, index: %d\n",
90941d07074SAlex Vesker 					   index);
91041d07074SAlex Vesker 				return NULL;
91141d07074SAlex Vesker 			}
91241d07074SAlex Vesker 		}
91341d07074SAlex Vesker 	}
91441d07074SAlex Vesker 	return ste;
91541d07074SAlex Vesker }
91641d07074SAlex Vesker 
dr_rule_cmp_value_to_mask(u8 * mask,u8 * value,u32 s_idx,u32 e_idx)91741d07074SAlex Vesker static bool dr_rule_cmp_value_to_mask(u8 *mask, u8 *value,
91841d07074SAlex Vesker 				      u32 s_idx, u32 e_idx)
91941d07074SAlex Vesker {
92041d07074SAlex Vesker 	u32 i;
92141d07074SAlex Vesker 
92241d07074SAlex Vesker 	for (i = s_idx; i < e_idx; i++) {
92341d07074SAlex Vesker 		if (value[i] & ~mask[i]) {
92441d07074SAlex Vesker 			pr_info("Rule parameters contains a value not specified by mask\n");
92541d07074SAlex Vesker 			return false;
92641d07074SAlex Vesker 		}
92741d07074SAlex Vesker 	}
92841d07074SAlex Vesker 	return true;
92941d07074SAlex Vesker }
93041d07074SAlex Vesker 
dr_rule_verify(struct mlx5dr_matcher * matcher,struct mlx5dr_match_parameters * value,struct mlx5dr_match_param * param)93141d07074SAlex Vesker static bool dr_rule_verify(struct mlx5dr_matcher *matcher,
93241d07074SAlex Vesker 			   struct mlx5dr_match_parameters *value,
93341d07074SAlex Vesker 			   struct mlx5dr_match_param *param)
93441d07074SAlex Vesker {
93541d07074SAlex Vesker 	u8 match_criteria = matcher->match_criteria;
93641d07074SAlex Vesker 	size_t value_size = value->match_sz;
93741d07074SAlex Vesker 	u8 *mask_p = (u8 *)&matcher->mask;
93841d07074SAlex Vesker 	u8 *param_p = (u8 *)param;
93941d07074SAlex Vesker 	u32 s_idx, e_idx;
94041d07074SAlex Vesker 
94141d07074SAlex Vesker 	if (!value_size ||
942699d531fSMuhammad Sammar 	    (value_size > DR_SZ_MATCH_PARAM || (value_size % sizeof(u32)))) {
943b7d0db55SErez Shitrit 		mlx5dr_err(matcher->tbl->dmn, "Rule parameters length is incorrect\n");
94441d07074SAlex Vesker 		return false;
94541d07074SAlex Vesker 	}
94641d07074SAlex Vesker 
947941f1979SMuhammad Sammar 	mlx5dr_ste_copy_param(matcher->match_criteria, param, value, false);
94841d07074SAlex Vesker 
94941d07074SAlex Vesker 	if (match_criteria & DR_MATCHER_CRITERIA_OUTER) {
95041d07074SAlex Vesker 		s_idx = offsetof(struct mlx5dr_match_param, outer);
95141d07074SAlex Vesker 		e_idx = min(s_idx + sizeof(param->outer), value_size);
95241d07074SAlex Vesker 
95341d07074SAlex Vesker 		if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) {
954b7d0db55SErez Shitrit 			mlx5dr_err(matcher->tbl->dmn, "Rule outer parameters contains a value not specified by mask\n");
95541d07074SAlex Vesker 			return false;
95641d07074SAlex Vesker 		}
95741d07074SAlex Vesker 	}
95841d07074SAlex Vesker 
95941d07074SAlex Vesker 	if (match_criteria & DR_MATCHER_CRITERIA_MISC) {
96041d07074SAlex Vesker 		s_idx = offsetof(struct mlx5dr_match_param, misc);
96141d07074SAlex Vesker 		e_idx = min(s_idx + sizeof(param->misc), value_size);
96241d07074SAlex Vesker 
96341d07074SAlex Vesker 		if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) {
964b7d0db55SErez Shitrit 			mlx5dr_err(matcher->tbl->dmn, "Rule misc parameters contains a value not specified by mask\n");
96541d07074SAlex Vesker 			return false;
96641d07074SAlex Vesker 		}
96741d07074SAlex Vesker 	}
96841d07074SAlex Vesker 
96941d07074SAlex Vesker 	if (match_criteria & DR_MATCHER_CRITERIA_INNER) {
97041d07074SAlex Vesker 		s_idx = offsetof(struct mlx5dr_match_param, inner);
97141d07074SAlex Vesker 		e_idx = min(s_idx + sizeof(param->inner), value_size);
97241d07074SAlex Vesker 
97341d07074SAlex Vesker 		if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) {
974b7d0db55SErez Shitrit 			mlx5dr_err(matcher->tbl->dmn, "Rule inner parameters contains a value not specified by mask\n");
97541d07074SAlex Vesker 			return false;
97641d07074SAlex Vesker 		}
97741d07074SAlex Vesker 	}
97841d07074SAlex Vesker 
97941d07074SAlex Vesker 	if (match_criteria & DR_MATCHER_CRITERIA_MISC2) {
98041d07074SAlex Vesker 		s_idx = offsetof(struct mlx5dr_match_param, misc2);
98141d07074SAlex Vesker 		e_idx = min(s_idx + sizeof(param->misc2), value_size);
98241d07074SAlex Vesker 
98341d07074SAlex Vesker 		if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) {
984b7d0db55SErez Shitrit 			mlx5dr_err(matcher->tbl->dmn, "Rule misc2 parameters contains a value not specified by mask\n");
98541d07074SAlex Vesker 			return false;
98641d07074SAlex Vesker 		}
98741d07074SAlex Vesker 	}
98841d07074SAlex Vesker 
98941d07074SAlex Vesker 	if (match_criteria & DR_MATCHER_CRITERIA_MISC3) {
99041d07074SAlex Vesker 		s_idx = offsetof(struct mlx5dr_match_param, misc3);
99141d07074SAlex Vesker 		e_idx = min(s_idx + sizeof(param->misc3), value_size);
99241d07074SAlex Vesker 
99341d07074SAlex Vesker 		if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) {
994b7d0db55SErez Shitrit 			mlx5dr_err(matcher->tbl->dmn, "Rule misc3 parameters contains a value not specified by mask\n");
99541d07074SAlex Vesker 			return false;
99641d07074SAlex Vesker 		}
99741d07074SAlex Vesker 	}
998160e9cb3SYevgeny Kliteynik 
999160e9cb3SYevgeny Kliteynik 	if (match_criteria & DR_MATCHER_CRITERIA_MISC4) {
1000160e9cb3SYevgeny Kliteynik 		s_idx = offsetof(struct mlx5dr_match_param, misc4);
1001160e9cb3SYevgeny Kliteynik 		e_idx = min(s_idx + sizeof(param->misc4), value_size);
1002160e9cb3SYevgeny Kliteynik 
1003160e9cb3SYevgeny Kliteynik 		if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) {
1004160e9cb3SYevgeny Kliteynik 			mlx5dr_err(matcher->tbl->dmn,
1005160e9cb3SYevgeny Kliteynik 				   "Rule misc4 parameters contains a value not specified by mask\n");
1006160e9cb3SYevgeny Kliteynik 			return false;
1007160e9cb3SYevgeny Kliteynik 		}
1008160e9cb3SYevgeny Kliteynik 	}
10098c2b4feeSMuhammad Sammar 
10108c2b4feeSMuhammad Sammar 	if (match_criteria & DR_MATCHER_CRITERIA_MISC5) {
10118c2b4feeSMuhammad Sammar 		s_idx = offsetof(struct mlx5dr_match_param, misc5);
10128c2b4feeSMuhammad Sammar 		e_idx = min(s_idx + sizeof(param->misc5), value_size);
10138c2b4feeSMuhammad Sammar 
10148c2b4feeSMuhammad Sammar 		if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) {
10158c2b4feeSMuhammad Sammar 			mlx5dr_err(matcher->tbl->dmn, "Rule misc5 parameters contains a value not specified by mask\n");
10168c2b4feeSMuhammad Sammar 			return false;
10178c2b4feeSMuhammad Sammar 		}
10188c2b4feeSMuhammad Sammar 	}
101941d07074SAlex Vesker 	return true;
102041d07074SAlex Vesker }
102141d07074SAlex Vesker 
dr_rule_destroy_rule_nic(struct mlx5dr_rule * rule,struct mlx5dr_rule_rx_tx * nic_rule)102241d07074SAlex Vesker static int dr_rule_destroy_rule_nic(struct mlx5dr_rule *rule,
102341d07074SAlex Vesker 				    struct mlx5dr_rule_rx_tx *nic_rule)
102441d07074SAlex Vesker {
1025cc2295cdSYevgeny Kliteynik 	/* Check if this nic rule was actually created, or was it skipped
1026cc2295cdSYevgeny Kliteynik 	 * and only the other type of the RX/TX nic rule was created.
1027cc2295cdSYevgeny Kliteynik 	 */
1028cc2295cdSYevgeny Kliteynik 	if (!nic_rule->last_rule_ste)
1029cc2295cdSYevgeny Kliteynik 		return 0;
1030cc2295cdSYevgeny Kliteynik 
1031ed03a418SAlex Vesker 	mlx5dr_domain_nic_lock(nic_rule->nic_matcher->nic_tbl->nic_dmn);
103241d07074SAlex Vesker 	dr_rule_clean_rule_members(rule, nic_rule);
1033cc2295cdSYevgeny Kliteynik 
1034cc2295cdSYevgeny Kliteynik 	nic_rule->nic_matcher->rules--;
1035cc2295cdSYevgeny Kliteynik 	if (!nic_rule->nic_matcher->rules)
1036cc2295cdSYevgeny Kliteynik 		mlx5dr_matcher_remove_from_tbl_nic(rule->matcher->tbl->dmn,
1037cc2295cdSYevgeny Kliteynik 						   nic_rule->nic_matcher);
1038cc2295cdSYevgeny Kliteynik 
1039ed03a418SAlex Vesker 	mlx5dr_domain_nic_unlock(nic_rule->nic_matcher->nic_tbl->nic_dmn);
1040ed03a418SAlex Vesker 
104141d07074SAlex Vesker 	return 0;
104241d07074SAlex Vesker }
104341d07074SAlex Vesker 
dr_rule_destroy_rule_fdb(struct mlx5dr_rule * rule)104441d07074SAlex Vesker static int dr_rule_destroy_rule_fdb(struct mlx5dr_rule *rule)
104541d07074SAlex Vesker {
104641d07074SAlex Vesker 	dr_rule_destroy_rule_nic(rule, &rule->rx);
104741d07074SAlex Vesker 	dr_rule_destroy_rule_nic(rule, &rule->tx);
104841d07074SAlex Vesker 	return 0;
104941d07074SAlex Vesker }
105041d07074SAlex Vesker 
dr_rule_destroy_rule(struct mlx5dr_rule * rule)105141d07074SAlex Vesker static int dr_rule_destroy_rule(struct mlx5dr_rule *rule)
105241d07074SAlex Vesker {
105341d07074SAlex Vesker 	struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn;
105441d07074SAlex Vesker 
10559222f0b2SMuhammad Sammar 	mlx5dr_dbg_rule_del(rule);
10569222f0b2SMuhammad Sammar 
105741d07074SAlex Vesker 	switch (dmn->type) {
105841d07074SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_RX:
105941d07074SAlex Vesker 		dr_rule_destroy_rule_nic(rule, &rule->rx);
106041d07074SAlex Vesker 		break;
106141d07074SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_TX:
106241d07074SAlex Vesker 		dr_rule_destroy_rule_nic(rule, &rule->tx);
106341d07074SAlex Vesker 		break;
106441d07074SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_FDB:
106541d07074SAlex Vesker 		dr_rule_destroy_rule_fdb(rule);
106641d07074SAlex Vesker 		break;
106741d07074SAlex Vesker 	default:
106841d07074SAlex Vesker 		return -EINVAL;
106941d07074SAlex Vesker 	}
107041d07074SAlex Vesker 
107141d07074SAlex Vesker 	dr_rule_remove_action_members(rule);
107241d07074SAlex Vesker 	kfree(rule);
107341d07074SAlex Vesker 	return 0;
107441d07074SAlex Vesker }
107541d07074SAlex Vesker 
dr_rule_get_ipv(struct mlx5dr_match_spec * spec)1076667f2646SAlex Vesker static enum mlx5dr_ipv dr_rule_get_ipv(struct mlx5dr_match_spec *spec)
107741d07074SAlex Vesker {
1078667f2646SAlex Vesker 	if (spec->ip_version == 6 || spec->ethertype == ETH_P_IPV6)
1079667f2646SAlex Vesker 		return DR_RULE_IPV6;
1080667f2646SAlex Vesker 
1081667f2646SAlex Vesker 	return DR_RULE_IPV4;
108241d07074SAlex Vesker }
108341d07074SAlex Vesker 
dr_rule_skip(enum mlx5dr_domain_type domain,enum mlx5dr_domain_nic_type nic_type,struct mlx5dr_match_param * mask,struct mlx5dr_match_param * value,u32 flow_source)108441d07074SAlex Vesker static bool dr_rule_skip(enum mlx5dr_domain_type domain,
108546f2a8aeSYevgeny Kliteynik 			 enum mlx5dr_domain_nic_type nic_type,
108641d07074SAlex Vesker 			 struct mlx5dr_match_param *mask,
108701723919SHamdan Igbaria 			 struct mlx5dr_match_param *value,
108801723919SHamdan Igbaria 			 u32 flow_source)
108941d07074SAlex Vesker {
109046f2a8aeSYevgeny Kliteynik 	bool rx = nic_type == DR_DOMAIN_NIC_TYPE_RX;
109101723919SHamdan Igbaria 
109241d07074SAlex Vesker 	if (domain != MLX5DR_DOMAIN_TYPE_FDB)
109341d07074SAlex Vesker 		return false;
109441d07074SAlex Vesker 
109541d07074SAlex Vesker 	if (mask->misc.source_port) {
10967ae8ac9aSYevgeny Kliteynik 		if (rx && value->misc.source_port != MLX5_VPORT_UPLINK)
109741d07074SAlex Vesker 			return true;
109841d07074SAlex Vesker 
10997ae8ac9aSYevgeny Kliteynik 		if (!rx && value->misc.source_port == MLX5_VPORT_UPLINK)
110041d07074SAlex Vesker 			return true;
110141d07074SAlex Vesker 	}
110241d07074SAlex Vesker 
110301723919SHamdan Igbaria 	if (rx && flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT)
110441d07074SAlex Vesker 		return true;
110541d07074SAlex Vesker 
110601723919SHamdan Igbaria 	if (!rx && flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK)
110741d07074SAlex Vesker 		return true;
110801723919SHamdan Igbaria 
110941d07074SAlex Vesker 	return false;
111041d07074SAlex Vesker }
111141d07074SAlex Vesker 
111241d07074SAlex Vesker static int
dr_rule_create_rule_nic(struct mlx5dr_rule * rule,struct mlx5dr_rule_rx_tx * nic_rule,struct mlx5dr_match_param * param,size_t num_actions,struct mlx5dr_action * actions[])111341d07074SAlex Vesker dr_rule_create_rule_nic(struct mlx5dr_rule *rule,
111441d07074SAlex Vesker 			struct mlx5dr_rule_rx_tx *nic_rule,
111541d07074SAlex Vesker 			struct mlx5dr_match_param *param,
111641d07074SAlex Vesker 			size_t num_actions,
111741d07074SAlex Vesker 			struct mlx5dr_action *actions[])
111841d07074SAlex Vesker {
1119b9b81e1eSYevgeny Kliteynik 	u8 hw_ste_arr_optimized[DR_RULE_MAX_STE_CHAIN_OPTIMIZED * DR_STE_SIZE] = {};
112041d07074SAlex Vesker 	struct mlx5dr_ste_send_info *ste_info, *tmp_ste_info;
112141d07074SAlex Vesker 	struct mlx5dr_matcher *matcher = rule->matcher;
112241d07074SAlex Vesker 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
112341d07074SAlex Vesker 	struct mlx5dr_matcher_rx_tx *nic_matcher;
112441d07074SAlex Vesker 	struct mlx5dr_domain_rx_tx *nic_dmn;
112541d07074SAlex Vesker 	struct mlx5dr_ste_htbl *htbl = NULL;
112641d07074SAlex Vesker 	struct mlx5dr_ste_htbl *cur_htbl;
112741d07074SAlex Vesker 	struct mlx5dr_ste *ste = NULL;
112841d07074SAlex Vesker 	LIST_HEAD(send_ste_list);
1129b9b81e1eSYevgeny Kliteynik 	bool hw_ste_arr_is_opt;
113041d07074SAlex Vesker 	u8 *hw_ste_arr = NULL;
113141d07074SAlex Vesker 	u32 new_hw_ste_arr_sz;
113241d07074SAlex Vesker 	int ret, i;
113341d07074SAlex Vesker 
113441d07074SAlex Vesker 	nic_matcher = nic_rule->nic_matcher;
113541d07074SAlex Vesker 	nic_dmn = nic_matcher->nic_tbl->nic_dmn;
113641d07074SAlex Vesker 
113746f2a8aeSYevgeny Kliteynik 	if (dr_rule_skip(dmn->type, nic_dmn->type, &matcher->mask, param,
113801723919SHamdan Igbaria 			 rule->flow_source))
113941d07074SAlex Vesker 		return 0;
114041d07074SAlex Vesker 
1141*288d85e0SYevgeny Kliteynik 	mlx5dr_domain_nic_lock(nic_dmn);
1142*288d85e0SYevgeny Kliteynik 
1143b9b81e1eSYevgeny Kliteynik 	ret = mlx5dr_matcher_select_builders(matcher,
1144b9b81e1eSYevgeny Kliteynik 					     nic_matcher,
1145b9b81e1eSYevgeny Kliteynik 					     dr_rule_get_ipv(&param->outer),
1146b9b81e1eSYevgeny Kliteynik 					     dr_rule_get_ipv(&param->inner));
1147b9b81e1eSYevgeny Kliteynik 	if (ret)
1148*288d85e0SYevgeny Kliteynik 		goto err_unlock;
1149b9b81e1eSYevgeny Kliteynik 
1150b9b81e1eSYevgeny Kliteynik 	hw_ste_arr_is_opt = nic_matcher->num_of_builders <= DR_RULE_MAX_STES_OPTIMIZED;
1151b9b81e1eSYevgeny Kliteynik 	if (likely(hw_ste_arr_is_opt)) {
1152b9b81e1eSYevgeny Kliteynik 		hw_ste_arr = hw_ste_arr_optimized;
1153b9b81e1eSYevgeny Kliteynik 	} else {
1154b9b81e1eSYevgeny Kliteynik 		hw_ste_arr = kzalloc((nic_matcher->num_of_builders + DR_ACTION_MAX_STES) *
1155b9b81e1eSYevgeny Kliteynik 				     DR_STE_SIZE, GFP_KERNEL);
1156b9b81e1eSYevgeny Kliteynik 
1157*288d85e0SYevgeny Kliteynik 		if (!hw_ste_arr) {
1158*288d85e0SYevgeny Kliteynik 			ret = -ENOMEM;
1159*288d85e0SYevgeny Kliteynik 			goto err_unlock;
1160b9b81e1eSYevgeny Kliteynik 		}
1161*288d85e0SYevgeny Kliteynik 	}
1162ed03a418SAlex Vesker 
1163cc2295cdSYevgeny Kliteynik 	ret = mlx5dr_matcher_add_to_tbl_nic(dmn, nic_matcher);
1164cc2295cdSYevgeny Kliteynik 	if (ret)
1165cc2295cdSYevgeny Kliteynik 		goto free_hw_ste;
1166cc2295cdSYevgeny Kliteynik 
116741d07074SAlex Vesker 	/* Set the tag values inside the ste array */
116841d07074SAlex Vesker 	ret = mlx5dr_ste_build_ste_arr(matcher, nic_matcher, param, hw_ste_arr);
116941d07074SAlex Vesker 	if (ret)
1170cc2295cdSYevgeny Kliteynik 		goto remove_from_nic_tbl;
117141d07074SAlex Vesker 
117241d07074SAlex Vesker 	/* Set the actions values/addresses inside the ste array */
117341d07074SAlex Vesker 	ret = mlx5dr_actions_build_ste_arr(matcher, nic_matcher, actions,
117441d07074SAlex Vesker 					   num_actions, hw_ste_arr,
117541d07074SAlex Vesker 					   &new_hw_ste_arr_sz);
117641d07074SAlex Vesker 	if (ret)
1177cc2295cdSYevgeny Kliteynik 		goto remove_from_nic_tbl;
117841d07074SAlex Vesker 
117941d07074SAlex Vesker 	cur_htbl = nic_matcher->s_htbl;
118041d07074SAlex Vesker 
118141d07074SAlex Vesker 	/* Go over the array of STEs, and build dr_ste accordingly.
118241d07074SAlex Vesker 	 * The loop is over only the builders which are equal or less to the
118341d07074SAlex Vesker 	 * number of stes, in case we have actions that lives in other stes.
118441d07074SAlex Vesker 	 */
118541d07074SAlex Vesker 	for (i = 0; i < nic_matcher->num_of_builders; i++) {
118641d07074SAlex Vesker 		/* Calculate CRC and keep new ste entry */
118741d07074SAlex Vesker 		u8 *cur_hw_ste_ent = hw_ste_arr + (i * DR_STE_SIZE);
118841d07074SAlex Vesker 
118941d07074SAlex Vesker 		ste = dr_rule_handle_ste_branch(rule,
119041d07074SAlex Vesker 						nic_rule,
119141d07074SAlex Vesker 						&send_ste_list,
119241d07074SAlex Vesker 						cur_htbl,
119341d07074SAlex Vesker 						cur_hw_ste_ent,
119441d07074SAlex Vesker 						i + 1,
119541d07074SAlex Vesker 						&htbl);
119641d07074SAlex Vesker 		if (!ste) {
119741d07074SAlex Vesker 			mlx5dr_err(dmn, "Failed creating next branch\n");
119841d07074SAlex Vesker 			ret = -ENOENT;
119941d07074SAlex Vesker 			goto free_rule;
120041d07074SAlex Vesker 		}
120141d07074SAlex Vesker 
120241d07074SAlex Vesker 		cur_htbl = ste->next_htbl;
120341d07074SAlex Vesker 
120441d07074SAlex Vesker 		mlx5dr_ste_get(ste);
12058a015baeSYevgeny Kliteynik 		mlx5dr_rule_set_last_member(nic_rule, ste, true);
120641d07074SAlex Vesker 	}
120741d07074SAlex Vesker 
120841d07074SAlex Vesker 	/* Connect actions */
120941d07074SAlex Vesker 	ret = dr_rule_handle_action_stes(rule, nic_rule, &send_ste_list,
121041d07074SAlex Vesker 					 ste, hw_ste_arr, new_hw_ste_arr_sz);
121141d07074SAlex Vesker 	if (ret) {
121241d07074SAlex Vesker 		mlx5dr_dbg(dmn, "Failed apply actions\n");
121341d07074SAlex Vesker 		goto free_rule;
121441d07074SAlex Vesker 	}
121541d07074SAlex Vesker 	ret = dr_rule_send_update_list(&send_ste_list, dmn, true);
121641d07074SAlex Vesker 	if (ret) {
121741d07074SAlex Vesker 		mlx5dr_err(dmn, "Failed sending ste!\n");
121841d07074SAlex Vesker 		goto free_rule;
121941d07074SAlex Vesker 	}
122041d07074SAlex Vesker 
122141d07074SAlex Vesker 	if (htbl)
122241d07074SAlex Vesker 		mlx5dr_htbl_put(htbl);
122341d07074SAlex Vesker 
1224cc2295cdSYevgeny Kliteynik 	nic_matcher->rules++;
1225cc2295cdSYevgeny Kliteynik 
1226ed03a418SAlex Vesker 	mlx5dr_domain_nic_unlock(nic_dmn);
1227ed03a418SAlex Vesker 
1228*288d85e0SYevgeny Kliteynik 	if (unlikely(!hw_ste_arr_is_opt))
1229*288d85e0SYevgeny Kliteynik 		kfree(hw_ste_arr);
1230*288d85e0SYevgeny Kliteynik 
1231*288d85e0SYevgeny Kliteynik 	return 0;
123241d07074SAlex Vesker 
123341d07074SAlex Vesker free_rule:
123441d07074SAlex Vesker 	dr_rule_clean_rule_members(rule, nic_rule);
123541d07074SAlex Vesker 	/* Clean all ste_info's */
123641d07074SAlex Vesker 	list_for_each_entry_safe(ste_info, tmp_ste_info, &send_ste_list, send_list) {
123741d07074SAlex Vesker 		list_del(&ste_info->send_list);
123817b56073SYevgeny Kliteynik 		mlx5dr_send_info_free(ste_info);
123941d07074SAlex Vesker 	}
1240cc2295cdSYevgeny Kliteynik 
1241cc2295cdSYevgeny Kliteynik remove_from_nic_tbl:
12424ea9891dSRongwei Liu 	if (!nic_matcher->rules)
1243cc2295cdSYevgeny Kliteynik 		mlx5dr_matcher_remove_from_tbl_nic(dmn, nic_matcher);
1244cc2295cdSYevgeny Kliteynik 
124541d07074SAlex Vesker free_hw_ste:
1246*288d85e0SYevgeny Kliteynik 	if (!hw_ste_arr_is_opt)
124741d07074SAlex Vesker 		kfree(hw_ste_arr);
1248b9b81e1eSYevgeny Kliteynik 
1249*288d85e0SYevgeny Kliteynik err_unlock:
1250*288d85e0SYevgeny Kliteynik 	mlx5dr_domain_nic_unlock(nic_dmn);
1251*288d85e0SYevgeny Kliteynik 
125241d07074SAlex Vesker 	return ret;
125341d07074SAlex Vesker }
125441d07074SAlex Vesker 
125541d07074SAlex Vesker static int
dr_rule_create_rule_fdb(struct mlx5dr_rule * rule,struct mlx5dr_match_param * param,size_t num_actions,struct mlx5dr_action * actions[])125641d07074SAlex Vesker dr_rule_create_rule_fdb(struct mlx5dr_rule *rule,
125741d07074SAlex Vesker 			struct mlx5dr_match_param *param,
125841d07074SAlex Vesker 			size_t num_actions,
125941d07074SAlex Vesker 			struct mlx5dr_action *actions[])
126041d07074SAlex Vesker {
126141d07074SAlex Vesker 	struct mlx5dr_match_param copy_param = {};
126241d07074SAlex Vesker 	int ret;
126341d07074SAlex Vesker 
126441d07074SAlex Vesker 	/* Copy match_param since they will be consumed during the first
126541d07074SAlex Vesker 	 * nic_rule insertion.
126641d07074SAlex Vesker 	 */
126741d07074SAlex Vesker 	memcpy(&copy_param, param, sizeof(struct mlx5dr_match_param));
126841d07074SAlex Vesker 
126941d07074SAlex Vesker 	ret = dr_rule_create_rule_nic(rule, &rule->rx, param,
127041d07074SAlex Vesker 				      num_actions, actions);
127141d07074SAlex Vesker 	if (ret)
127241d07074SAlex Vesker 		return ret;
127341d07074SAlex Vesker 
127441d07074SAlex Vesker 	ret = dr_rule_create_rule_nic(rule, &rule->tx, &copy_param,
127541d07074SAlex Vesker 				      num_actions, actions);
127641d07074SAlex Vesker 	if (ret)
127741d07074SAlex Vesker 		goto destroy_rule_nic_rx;
127841d07074SAlex Vesker 
127941d07074SAlex Vesker 	return 0;
128041d07074SAlex Vesker 
128141d07074SAlex Vesker destroy_rule_nic_rx:
128241d07074SAlex Vesker 	dr_rule_destroy_rule_nic(rule, &rule->rx);
128341d07074SAlex Vesker 	return ret;
128441d07074SAlex Vesker }
128541d07074SAlex Vesker 
128641d07074SAlex Vesker static struct mlx5dr_rule *
dr_rule_create_rule(struct mlx5dr_matcher * matcher,struct mlx5dr_match_parameters * value,size_t num_actions,struct mlx5dr_action * actions[],u32 flow_source)128741d07074SAlex Vesker dr_rule_create_rule(struct mlx5dr_matcher *matcher,
128841d07074SAlex Vesker 		    struct mlx5dr_match_parameters *value,
128941d07074SAlex Vesker 		    size_t num_actions,
129001723919SHamdan Igbaria 		    struct mlx5dr_action *actions[],
129101723919SHamdan Igbaria 		    u32 flow_source)
129241d07074SAlex Vesker {
129341d07074SAlex Vesker 	struct mlx5dr_domain *dmn = matcher->tbl->dmn;
129441d07074SAlex Vesker 	struct mlx5dr_match_param param = {};
129541d07074SAlex Vesker 	struct mlx5dr_rule *rule;
129641d07074SAlex Vesker 	int ret;
129741d07074SAlex Vesker 
129841d07074SAlex Vesker 	if (!dr_rule_verify(matcher, value, &param))
129941d07074SAlex Vesker 		return NULL;
130041d07074SAlex Vesker 
130141d07074SAlex Vesker 	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
130241d07074SAlex Vesker 	if (!rule)
130341d07074SAlex Vesker 		return NULL;
130441d07074SAlex Vesker 
130541d07074SAlex Vesker 	rule->matcher = matcher;
130601723919SHamdan Igbaria 	rule->flow_source = flow_source;
130741d07074SAlex Vesker 	INIT_LIST_HEAD(&rule->rule_actions_list);
130841d07074SAlex Vesker 
130941d07074SAlex Vesker 	ret = dr_rule_add_action_members(rule, num_actions, actions);
131041d07074SAlex Vesker 	if (ret)
131141d07074SAlex Vesker 		goto free_rule;
131241d07074SAlex Vesker 
131341d07074SAlex Vesker 	switch (dmn->type) {
131441d07074SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_RX:
131541d07074SAlex Vesker 		rule->rx.nic_matcher = &matcher->rx;
131641d07074SAlex Vesker 		ret = dr_rule_create_rule_nic(rule, &rule->rx, &param,
131741d07074SAlex Vesker 					      num_actions, actions);
131841d07074SAlex Vesker 		break;
131941d07074SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_NIC_TX:
132041d07074SAlex Vesker 		rule->tx.nic_matcher = &matcher->tx;
132141d07074SAlex Vesker 		ret = dr_rule_create_rule_nic(rule, &rule->tx, &param,
132241d07074SAlex Vesker 					      num_actions, actions);
132341d07074SAlex Vesker 		break;
132441d07074SAlex Vesker 	case MLX5DR_DOMAIN_TYPE_FDB:
132541d07074SAlex Vesker 		rule->rx.nic_matcher = &matcher->rx;
132641d07074SAlex Vesker 		rule->tx.nic_matcher = &matcher->tx;
132741d07074SAlex Vesker 		ret = dr_rule_create_rule_fdb(rule, &param,
132841d07074SAlex Vesker 					      num_actions, actions);
132941d07074SAlex Vesker 		break;
133041d07074SAlex Vesker 	default:
133141d07074SAlex Vesker 		ret = -EINVAL;
133241d07074SAlex Vesker 		break;
133341d07074SAlex Vesker 	}
133441d07074SAlex Vesker 
133541d07074SAlex Vesker 	if (ret)
133641d07074SAlex Vesker 		goto remove_action_members;
133741d07074SAlex Vesker 
13389222f0b2SMuhammad Sammar 	INIT_LIST_HEAD(&rule->dbg_node);
13399222f0b2SMuhammad Sammar 	mlx5dr_dbg_rule_add(rule);
134041d07074SAlex Vesker 	return rule;
134141d07074SAlex Vesker 
134241d07074SAlex Vesker remove_action_members:
134341d07074SAlex Vesker 	dr_rule_remove_action_members(rule);
134441d07074SAlex Vesker free_rule:
134541d07074SAlex Vesker 	kfree(rule);
1346b7d0db55SErez Shitrit 	mlx5dr_err(dmn, "Failed creating rule\n");
134741d07074SAlex Vesker 	return NULL;
134841d07074SAlex Vesker }
134941d07074SAlex Vesker 
mlx5dr_rule_create(struct mlx5dr_matcher * matcher,struct mlx5dr_match_parameters * value,size_t num_actions,struct mlx5dr_action * actions[],u32 flow_source)135041d07074SAlex Vesker struct mlx5dr_rule *mlx5dr_rule_create(struct mlx5dr_matcher *matcher,
135141d07074SAlex Vesker 				       struct mlx5dr_match_parameters *value,
135241d07074SAlex Vesker 				       size_t num_actions,
135301723919SHamdan Igbaria 				       struct mlx5dr_action *actions[],
135401723919SHamdan Igbaria 				       u32 flow_source)
135541d07074SAlex Vesker {
135641d07074SAlex Vesker 	struct mlx5dr_rule *rule;
135741d07074SAlex Vesker 
135841d07074SAlex Vesker 	refcount_inc(&matcher->refcount);
135941d07074SAlex Vesker 
136001723919SHamdan Igbaria 	rule = dr_rule_create_rule(matcher, value, num_actions, actions, flow_source);
136141d07074SAlex Vesker 	if (!rule)
136241d07074SAlex Vesker 		refcount_dec(&matcher->refcount);
136341d07074SAlex Vesker 
136441d07074SAlex Vesker 	return rule;
136541d07074SAlex Vesker }
136641d07074SAlex Vesker 
mlx5dr_rule_destroy(struct mlx5dr_rule * rule)136741d07074SAlex Vesker int mlx5dr_rule_destroy(struct mlx5dr_rule *rule)
136841d07074SAlex Vesker {
136941d07074SAlex Vesker 	struct mlx5dr_matcher *matcher = rule->matcher;
137041d07074SAlex Vesker 	int ret;
137141d07074SAlex Vesker 
137241d07074SAlex Vesker 	ret = dr_rule_destroy_rule(rule);
137341d07074SAlex Vesker 	if (!ret)
137441d07074SAlex Vesker 		refcount_dec(&matcher->refcount);
1375ed03a418SAlex Vesker 
137641d07074SAlex Vesker 	return ret;
137741d07074SAlex Vesker }
1378