Skip to contentSkip to conversation

net/mlx5: Add HW steering low level support

PATCH Superseded Alex Vesker 3 participants 134 messages Sep 22, 2022 – Oct 24, 2022 Page 5 of 5

Subsystems (2)
lore
Share & tools
lore
#112 lore raw

PATCH v6 8/18 net/mlx5/hws: Add HWS command layer

In reply to Alex Vesker

From: Erez Shitrit <[email protected]>

The command layer is used to communicate with the FW, query capabilities and allocate FW resources needed for HWS.

---
 drivers/common/mlx5/mlx5_prm.h    | 607 ++++++++++++++++++-
 drivers/net/mlx5/hws/mlx5dr_cmd.c | 948 ++++++++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_cmd.h | 230 ++++++++
 3 files changed, 1775 insertions(+), 10 deletions(-)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_cmd.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_cmd.h
drivers/common/mlx5/mlx5_prm.h +597 -10
index ca4763f53d..371942ae50 100644
@@ -289,6 +289,8 @@
 /* The alignment needed for CQ buffer. */
 #define MLX5_CQE_BUF_ALIGNMENT rte_mem_page_size()
 
+#define MAX_ACTIONS_DATA_IN_HEADER_MODIFY 512
+
 /* Completion mode. */
 enum mlx5_completion_mode {
 	MLX5_COMP_ONLY_ERR = 0x0,
@@ -677,6 +679,10 @@ enum {
 	MLX5_MODIFICATION_TYPE_SET = 0x1,
 	MLX5_MODIFICATION_TYPE_ADD = 0x2,
 	MLX5_MODIFICATION_TYPE_COPY = 0x3,
+	MLX5_MODIFICATION_TYPE_INSERT = 0x4,
+	MLX5_MODIFICATION_TYPE_REMOVE = 0x5,
+	MLX5_MODIFICATION_TYPE_NOP = 0x6,
+	MLX5_MODIFICATION_TYPE_REMOVE_WORDS = 0x7,
 };
 
 /* The field of packet to be modified. */
@@ -1111,6 +1117,10 @@ enum {
 	MLX5_CMD_OP_QUERY_TIS = 0x915,
 	MLX5_CMD_OP_CREATE_RQT = 0x916,
 	MLX5_CMD_OP_MODIFY_RQT = 0x917,
+	MLX5_CMD_OP_CREATE_FLOW_TABLE = 0x930,
+	MLX5_CMD_OP_CREATE_FLOW_GROUP = 0x933,
+	MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY = 0x936,
+	MLX5_CMD_OP_MODIFY_FLOW_TABLE = 0x93c,
 	MLX5_CMD_OP_ALLOC_FLOW_COUNTER = 0x939,
 	MLX5_CMD_OP_QUERY_FLOW_COUNTER = 0x93b,
 	MLX5_CMD_OP_CREATE_GENERAL_OBJECT = 0xa00,
@@ -1299,6 +1309,7 @@ enum {
 	MLX5_SET_HCA_CAP_OP_MOD_ESW = 0x9 << 1,
 	MLX5_GET_HCA_CAP_OP_MOD_VDPA_EMULATION = 0x13 << 1,
 	MLX5_GET_HCA_CAP_OP_MOD_CRYPTO = 0x1A << 1,
+	MLX5_GET_HCA_CAP_OP_MOD_WQE_BASED_FLOW_TABLE = 0x1B << 1,
 	MLX5_GET_HCA_CAP_OP_MOD_PARSE_GRAPH_NODE_CAP = 0x1C << 1,
 	MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE_2 = 0x20 << 1,
 };
@@ -1317,6 +1328,14 @@ enum {
 			(1ULL << MLX5_GENERAL_OBJ_TYPE_GENEVE_TLV_OPT)
 #define MLX5_GENERAL_OBJ_TYPES_CAP_CONN_TRACK_OFFLOAD \
 			(1ULL << MLX5_GENERAL_OBJ_TYPE_CONN_TRACK_OFFLOAD)
+#define MLX5_GENERAL_OBJ_TYPES_CAP_RTC \
+			(1ULL << MLX5_GENERAL_OBJ_TYPE_RTC)
+#define MLX5_GENERAL_OBJ_TYPES_CAP_STC \
+			(1ULL << MLX5_GENERAL_OBJ_TYPE_STC)
+#define MLX5_GENERAL_OBJ_TYPES_CAP_STE \
+			(1ULL << MLX5_GENERAL_OBJ_TYPE_STE)
+#define MLX5_GENERAL_OBJ_TYPES_CAP_DEFINER \
+			(1ULL << MLX5_GENERAL_OBJ_TYPE_DEFINER)
 #define MLX5_GENERAL_OBJ_TYPES_CAP_DEK \
 			(1ULL << MLX5_GENERAL_OBJ_TYPE_DEK)
 #define MLX5_GENERAL_OBJ_TYPES_CAP_IMPORT_KEK \
@@ -1373,6 +1392,11 @@ enum {
 #define MLX5_HCA_FLEX_VXLAN_GPE_ENABLED (1UL << 7)
 #define MLX5_HCA_FLEX_ICMP_ENABLED (1UL << 8)
 #define MLX5_HCA_FLEX_ICMPV6_ENABLED (1UL << 9)
+#define MLX5_HCA_FLEX_GTPU_ENABLED (1UL << 11)
+#define MLX5_HCA_FLEX_GTPU_DW_2_ENABLED (1UL << 16)
+#define MLX5_HCA_FLEX_GTPU_FIRST_EXT_DW_0_ENABLED (1UL << 17)
+#define MLX5_HCA_FLEX_GTPU_DW_0_ENABLED (1UL << 18)
+#define MLX5_HCA_FLEX_GTPU_TEID_ENABLED (1UL << 19)
 
 /* The device steering logic format. */
 #define MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 0x0
@@ -1505,7 +1529,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
 	u8 wol_u[0x1];
 	u8 wol_p[0x1];
 	u8 stat_rate_support[0x10];
-	u8 reserved_at_1f0[0xc];
+	u8 reserved_at_1ef[0xb];
+	u8 wqe_based_flow_table_update_cap[0x1];
 	u8 cqe_version[0x4];
 	u8 compact_address_vector[0x1];
 	u8 striding_rq[0x1];
@@ -1681,7 +1706,9 @@ struct mlx5_ifc_cmd_hca_cap_bits {
 	u8 cqe_compression[0x1];
 	u8 cqe_compression_timeout[0x10];
 	u8 cqe_compression_max_num[0x10];
-	u8 reserved_at_5e0[0x10];
+	u8 reserved_at_5e0[0x8];
+	u8 flex_parser_id_gtpu_dw_0[0x4];
+	u8 reserved_at_5ec[0x4];
 	u8 tag_matching[0x1];
 	u8 rndv_offload_rc[0x1];
 	u8 rndv_offload_dc[0x1];
@@ -1691,17 +1718,38 @@ struct mlx5_ifc_cmd_hca_cap_bits {
 	u8 affiliate_nic_vport_criteria[0x8];
 	u8 native_port_num[0x8];
 	u8 num_vhca_ports[0x8];
-	u8 reserved_at_618[0x6];
+	u8 flex_parser_id_gtpu_teid[0x4];
+	u8 reserved_at_61c[0x2];
 	u8 sw_owner_id[0x1];
 	u8 reserved_at_61f[0x6C];
 	u8 wait_on_data[0x1];
 	u8 wait_on_time[0x1];
-	u8 reserved_at_68d[0xBB];
+	u8 reserved_at_68d[0x37];
+	u8 flex_parser_id_geneve_opt_0[0x4];
+	u8 flex_parser_id_icmp_dw1[0x4];
+	u8 flex_parser_id_icmp_dw0[0x4];
+	u8 flex_parser_id_icmpv6_dw1[0x4];
+	u8 flex_parser_id_icmpv6_dw0[0x4];
+	u8 flex_parser_id_outer_first_mpls_over_gre[0x4];
+	u8 flex_parser_id_outer_first_mpls_over_udp_label[0x4];
+	u8 reserved_at_6e0[0x20];
+	u8 flex_parser_id_gtpu_dw_2[0x4];
+	u8 flex_parser_id_gtpu_first_ext_dw_0[0x4];
+	u8 reserved_at_708[0x40];
 	u8 dma_mmo_qp[0x1];
 	u8 regexp_mmo_qp[0x1];
 	u8 compress_mmo_qp[0x1];
 	u8 decompress_mmo_qp[0x1];
-	u8 reserved_at_624[0xd4];
+	u8 reserved_at_74c[0x14];
+	u8 reserved_at_760[0x3];
+	u8 log_max_num_header_modify_argument[0x5];
+	u8 log_header_modify_argument_granularity_offset[0x4];
+	u8 log_header_modify_argument_granularity[0x4];
+	u8 reserved_at_770[0x3];
+	u8 log_header_modify_argument_max_alloc[0x5];
+	u8 reserved_at_778[0x8];
+	u8 reserved_at_780[0x40];
+	u8 match_definer_format_supported[0x40];
 };
 
 struct mlx5_ifc_qos_cap_bits {
@@ -1876,7 +1924,9 @@ struct mlx5_ifc_flow_table_prop_layout_bits {
 	u8 log_max_ft_sampler_num[8];
 	u8 metadata_reg_b_width[0x8];
 	u8 metadata_reg_a_width[0x8];
-	u8 reserved_at_60[0x18];
+	u8 reserved_at_60[0xa];
+	u8 reparse[0x1];
+	u8 reserved_at_6b[0xd];
 	u8 log_max_ft_num[0x8];
 	u8 reserved_at_80[0x10];
 	u8 log_max_flow_counter[0x8];
@@ -2061,7 +2111,17 @@ struct mlx5_ifc_cmd_hca_cap_2_bits {
 	u8 hairpin_sq_wqe_bb_size[0x5];
 	u8 hairpin_sq_wq_in_host_mem[0x1];
 	u8 hairpin_data_buffer_locked[0x1];
-	u8 reserved_at_16a[0x696];
+	u8 reserved_at_16a[0x36];
+	u8 reserved_at_1a0[0xb];
+	u8 format_select_dw_8_6_ext[0x1];
+	u8 reserved_at_1ac[0x14];
+	u8 general_obj_types_127_64[0x40];
+	u8 reserved_at_200[0x80];
+	u8 format_select_dw_gtpu_dw_0[0x8];
+	u8 format_select_dw_gtpu_dw_1[0x8];
+	u8 format_select_dw_gtpu_dw_2[0x8];
+	u8 format_select_dw_gtpu_first_ext_dw_0[0x8];
+	u8 reserved_at_2a0[0x560];
 };
 
 struct mlx5_ifc_esw_cap_bits {
@@ -2074,6 +2134,37 @@ struct mlx5_ifc_esw_cap_bits {
 	u8 reserved_at_80[0x780];
 };
 
+struct mlx5_ifc_wqe_based_flow_table_cap_bits {
+	u8 reserved_at_0[0x3];
+	u8 log_max_num_ste[0x5];
+	u8 reserved_at_8[0x3];
+	u8 log_max_num_stc[0x5];
+	u8 reserved_at_10[0x3];
+	u8 log_max_num_rtc[0x5];
+	u8 reserved_at_18[0x3];
+	u8 log_max_num_header_modify_pattern[0x5];
+	u8 reserved_at_20[0x3];
+	u8 stc_alloc_log_granularity[0x5];
+	u8 reserved_at_28[0x3];
+	u8 stc_alloc_log_max[0x5];
+	u8 reserved_at_30[0x3];
+	u8 ste_alloc_log_granularity[0x5];
+	u8 reserved_at_38[0x3];
+	u8 ste_alloc_log_max[0x5];
+	u8 reserved_at_40[0xb];
+	u8 rtc_reparse_mode[0x5];
+	u8 reserved_at_50[0x3];
+	u8 rtc_index_mode[0x5];
+	u8 reserved_at_58[0x3];
+	u8 rtc_log_depth_max[0x5];
+	u8 reserved_at_60[0x10];
+	u8 ste_format[0x10];
+	u8 stc_action_type[0x80];
+	u8 header_insert_type[0x10];
+	u8 header_remove_type[0x10];
+	u8 trivial_match_definer[0x20];
+};
+
 union mlx5_ifc_hca_cap_union_bits {
 	struct mlx5_ifc_cmd_hca_cap_bits cmd_hca_cap;
 	struct mlx5_ifc_cmd_hca_cap_2_bits cmd_hca_cap_2;
@@ -2085,6 +2176,7 @@ union mlx5_ifc_hca_cap_union_bits {
 	struct mlx5_ifc_flow_table_esw_cap_bits flow_table_esw_cap;
 	struct mlx5_ifc_esw_cap_bits esw_cap;
 	struct mlx5_ifc_roce_caps_bits roce_caps;
+	struct mlx5_ifc_wqe_based_flow_table_cap_bits wqe_based_flow_table_cap;
 	u8 reserved_at_0[0x8000];
 };
 
@@ -2098,6 +2190,20 @@ struct mlx5_ifc_set_action_in_bits {
 	u8 data[0x20];
 };
 
+struct mlx5_ifc_copy_action_in_bits {
+	u8 action_type[0x4];
+	u8 src_field[0xc];
+	u8 reserved_at_10[0x3];
+	u8 src_offset[0x5];
+	u8 reserved_at_18[0x3];
+	u8 length[0x5];
+	u8 reserved_at_20[0x4];
+	u8 dst_field[0xc];
+	u8 reserved_at_30[0x3];
+	u8 dst_offset[0x5];
+	u8 reserved_at_38[0x8];
+};
+
 struct mlx5_ifc_query_hca_cap_out_bits {
 	u8 status[0x8];
 	u8 reserved_at_8[0x18];
@@ -2978,6 +3084,7 @@ enum {
 	MLX5_GENERAL_OBJ_TYPE_GENEVE_TLV_OPT = 0x000b,
 	MLX5_GENERAL_OBJ_TYPE_DEK = 0x000c,
 	MLX5_GENERAL_OBJ_TYPE_VIRTQ = 0x000d,
+	MLX5_GENERAL_OBJ_TYPE_DEFINER = 0x0018,
 	MLX5_GENERAL_OBJ_TYPE_VIRTIO_Q_COUNTERS = 0x001c,
 	MLX5_GENERAL_OBJ_TYPE_IMPORT_KEK = 0x001d,
 	MLX5_GENERAL_OBJ_TYPE_CREDENTIAL = 0x001e,
@@ -2986,6 +3093,11 @@ enum {
 	MLX5_GENERAL_OBJ_TYPE_FLOW_METER_ASO = 0x0024,
 	MLX5_GENERAL_OBJ_TYPE_FLOW_HIT_ASO = 0x0025,
 	MLX5_GENERAL_OBJ_TYPE_CONN_TRACK_OFFLOAD = 0x0031,
+	MLX5_GENERAL_OBJ_TYPE_ARG = 0x0023,
+	MLX5_GENERAL_OBJ_TYPE_STC = 0x0040,
+	MLX5_GENERAL_OBJ_TYPE_RTC = 0x0041,
+	MLX5_GENERAL_OBJ_TYPE_STE = 0x0042,
+	MLX5_GENERAL_OBJ_TYPE_MODIFY_HEADER_PATTERN = 0x0043,
 };
 
 struct mlx5_ifc_general_obj_in_cmd_hdr_bits {
@@ -2993,9 +3105,14 @@ struct mlx5_ifc_general_obj_in_cmd_hdr_bits {
 	u8 reserved_at_10[0x20];
 	u8 obj_type[0x10];
 	u8 obj_id[0x20];
-	u8 reserved_at_60[0x3];
-	u8 log_obj_range[0x5];
-	u8 reserved_at_58[0x18];
+	union {
+		struct {
+			u8 reserved_at_60[0x3];
+			u8 log_obj_range[0x5];
+			u8 reserved_at_58[0x18];
+		};
+		u8 obj_offset[0x20];
+	};
 };
 
 struct mlx5_ifc_general_obj_out_cmd_hdr_bits {
@@ -3029,6 +3146,243 @@ struct mlx5_ifc_geneve_tlv_option_bits {
 	u8 reserved_at_80[0x180];
 };
 
+
+enum mlx5_ifc_rtc_update_mode {
+	MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH = 0x0,
+	MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET = 0x1,
+};
+
+enum mlx5_ifc_rtc_ste_format {
+	MLX5_IFC_RTC_STE_FORMAT_8DW = 0x4,
+	MLX5_IFC_RTC_STE_FORMAT_11DW = 0x5,
+};
+
+enum mlx5_ifc_rtc_reparse_mode {
+	MLX5_IFC_RTC_REPARSE_NEVER = 0x0,
+	MLX5_IFC_RTC_REPARSE_ALWAYS = 0x1,
+};
+
+struct mlx5_ifc_rtc_bits {
+	u8 modify_field_select[0x40];
+	u8 reserved_at_40[0x40];
+	u8 update_index_mode[0x2];
+	u8 reparse_mode[0x2];
+	u8 reserved_at_84[0x4];
+	u8 pd[0x18];
+	u8 reserved_at_a0[0x13];
+	u8 log_depth[0x5];
+	u8 log_hash_size[0x8];
+	u8 ste_format[0x8];
+	u8 table_type[0x8];
+	u8 reserved_at_d0[0x10];
+	u8 match_definer_id[0x20];
+	u8 stc_id[0x20];
+	u8 ste_table_base_id[0x20];
+	u8 ste_table_offset[0x20];
+	u8 reserved_at_160[0x8];
+	u8 miss_flow_table_id[0x18];
+	u8 reserved_at_180[0x280];
+};
+
+enum mlx5_ifc_stc_action_type {
+	MLX5_IFC_STC_ACTION_TYPE_NOP = 0x00,
+	MLX5_IFC_STC_ACTION_TYPE_COPY = 0x05,
+	MLX5_IFC_STC_ACTION_TYPE_SET = 0x06,
+	MLX5_IFC_STC_ACTION_TYPE_ADD = 0x07,
+	MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS = 0x08,
+	MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE = 0x09,
+	MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT = 0x0b,
+	MLX5_IFC_STC_ACTION_TYPE_TAG = 0x0c,
+	MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST = 0x0e,
+	MLX5_IFC_STC_ACTION_TYPE_ASO = 0x12,
+	MLX5_IFC_STC_ACTION_TYPE_COUNTER = 0x14,
+	MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE = 0x80,
+	MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR = 0x81,
+	MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT = 0x82,
+	MLX5_IFC_STC_ACTION_TYPE_DROP = 0x83,
+	MLX5_IFC_STC_ACTION_TYPE_ALLOW = 0x84,
+	MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT = 0x85,
+	MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK = 0x86,
+};
+
+struct mlx5_ifc_stc_ste_param_ste_table_bits {
+	u8 ste_obj_id[0x20];
+	u8 match_definer_id[0x20];
+	u8 reserved_at_40[0x3];
+	u8 log_hash_size[0x5];
+	u8 reserved_at_48[0x38];
+};
+
+struct mlx5_ifc_stc_ste_param_tir_bits {
+	u8 reserved_at_0[0x8];
+	u8 tirn[0x18];
+	u8 reserved_at_20[0x60];
+};
+
+struct mlx5_ifc_stc_ste_param_table_bits {
+	u8 reserved_at_0[0x8];
+	u8 table_id[0x18];
+	u8 reserved_at_20[0x60];
+};
+
+struct mlx5_ifc_stc_ste_param_flow_counter_bits {
+	u8 flow_counter_id[0x20];
+};
+
+enum {
+	MLX5_ASO_CT_NUM_PER_OBJ = 1,
+	MLX5_ASO_METER_NUM_PER_OBJ = 2,
+};
+
+struct mlx5_ifc_stc_ste_param_execute_aso_bits {
+	u8 aso_object_id[0x20];
+	u8 return_reg_id[0x4];
+	u8 aso_type[0x4];
+	u8 reserved_at_28[0x18];
+};
+
+struct mlx5_ifc_stc_ste_param_header_modify_list_bits {
+	u8 header_modify_pattern_id[0x20];
+	u8 header_modify_argument_id[0x20];
+};
+
+enum mlx5_ifc_header_anchors {
+	MLX5_HEADER_ANCHOR_PACKET_START = 0x0,
+	MLX5_HEADER_ANCHOR_FIRST_VLAN_START = 0x2,
+	MLX5_HEADER_ANCHOR_IPV6_IPV4 = 0x07,
+	MLX5_HEADER_ANCHOR_INNER_MAC = 0x13,
+	MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4 = 0x19,
+};
+
+struct mlx5_ifc_stc_ste_param_remove_bits {
+	u8 action_type[0x4];
+	u8 decap[0x1];
+	u8 reserved_at_5[0x5];
+	u8 remove_start_anchor[0x6];
+	u8 reserved_at_10[0x2];
+	u8 remove_end_anchor[0x6];
+	u8 reserved_at_18[0x8];
+};
+
+struct mlx5_ifc_stc_ste_param_remove_words_bits {
+	u8 action_type[0x4];
+	u8 reserved_at_4[0x6];
+	u8 remove_start_anchor[0x6];
+	u8 reserved_at_10[0x1];
+	u8 remove_offset[0x7];
+	u8 reserved_at_18[0x2];
+	u8 remove_size[0x6];
+};
+
+struct mlx5_ifc_stc_ste_param_insert_bits {
+	u8 action_type[0x4];
+	u8 encap[0x1];
+	u8 inline_data[0x1];
+	u8 reserved_at_6[0x4];
+	u8 insert_anchor[0x6];
+	u8 reserved_at_10[0x1];
+	u8 insert_offset[0x7];
+	u8 reserved_at_18[0x1];
+	u8 insert_size[0x7];
+	u8 insert_argument[0x20];
+};
+
+struct mlx5_ifc_stc_ste_param_vport_bits {
+	u8 eswitch_owner_vhca_id[0x10];
+	u8 vport_number[0x10];
+	u8 eswitch_owner_vhca_id_valid[0x1];
+	u8 reserved_at_21[0x59];
+};
+
+union mlx5_ifc_stc_param_bits {
+	struct mlx5_ifc_stc_ste_param_ste_table_bits ste_table;
+	struct mlx5_ifc_stc_ste_param_tir_bits tir;
+	struct mlx5_ifc_stc_ste_param_table_bits table;
+	struct mlx5_ifc_stc_ste_param_flow_counter_bits counter;
+	struct mlx5_ifc_stc_ste_param_header_modify_list_bits modify_header;
+	struct mlx5_ifc_stc_ste_param_execute_aso_bits aso;
+	struct mlx5_ifc_stc_ste_param_remove_bits remove_header;
+	struct mlx5_ifc_stc_ste_param_insert_bits insert_header;
+	struct mlx5_ifc_set_action_in_bits add;
+	struct mlx5_ifc_set_action_in_bits set;
+	struct mlx5_ifc_copy_action_in_bits copy;
+	struct mlx5_ifc_stc_ste_param_vport_bits vport;
+	u8 reserved_at_0[0x80];
+};
+
+enum {
+	MLX5_IFC_MODIFY_STC_FIELD_SELECT_NEW_STC = 1 << 0,
+};
+
+struct mlx5_ifc_stc_bits {
+	u8 modify_field_select[0x40];
+	u8 reserved_at_40[0x48];
+	u8 table_type[0x8];
+	u8 ste_action_offset[0x8];
+	u8 action_type[0x8];
+	u8 reserved_at_a0[0x60];
+	union mlx5_ifc_stc_param_bits stc_param;
+	u8 reserved_at_180[0x280];
+};
+
+struct mlx5_ifc_ste_bits {
+	u8 modify_field_select[0x40];
+	u8 reserved_at_40[0x48];
+	u8 table_type[0x8];
+	u8 reserved_at_90[0x370];
+};
+
+enum {
+	MLX5_IFC_DEFINER_FORMAT_ID_SELECT = 61,
+};
+
+struct mlx5_ifc_definer_bits {
+	u8 modify_field_select[0x40];
+	u8 reserved_at_40[0x50];
+	u8 format_id[0x10];
+	u8 reserved_at_60[0x60];
+	u8 format_select_dw3[0x8];
+	u8 format_select_dw2[0x8];
+	u8 format_select_dw1[0x8];
+	u8 format_select_dw0[0x8];
+	u8 format_select_dw7[0x8];
+	u8 format_select_dw6[0x8];
+	u8 format_select_dw5[0x8];
+	u8 format_select_dw4[0x8];
+	u8 reserved_at_100[0x18];
+	u8 format_select_dw8[0x8];
+	u8 reserved_at_120[0x20];
+	u8 format_select_byte3[0x8];
+	u8 format_select_byte2[0x8];
+	u8 format_select_byte1[0x8];
+	u8 format_select_byte0[0x8];
+	u8 format_select_byte7[0x8];
+	u8 format_select_byte6[0x8];
+	u8 format_select_byte5[0x8];
+	u8 format_select_byte4[0x8];
+	u8 reserved_at_180[0x40];
+	u8 ctrl[0xa0];
+	u8 match_mask[0x160];
+};
+
+struct mlx5_ifc_arg_bits {
+	u8 rsvd0[0x88];
+	u8 access_pd[0x18];
+};
+
+struct mlx5_ifc_header_modify_pattern_in_bits {
+	u8 modify_field_select[0x40];
+
+	u8 reserved_at_40[0x40];
+
+	u8 pattern_length[0x8];
+	u8 reserved_at_88[0x18];
+
+	u8 reserved_at_a0[0x60];
+
+	u8 pattern_data[MAX_ACTIONS_DATA_IN_HEADER_MODIFY * 8];
+};
+
 struct mlx5_ifc_create_virtio_q_counters_in_bits {
 	struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr;
 	struct mlx5_ifc_virtio_q_counters_bits virtio_q_counters;
@@ -3044,6 +3398,36 @@ struct mlx5_ifc_create_geneve_tlv_option_in_bits {
 	struct mlx5_ifc_geneve_tlv_option_bits geneve_tlv_opt;
 };
 
+struct mlx5_ifc_create_rtc_in_bits {
+	struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr;
+	struct mlx5_ifc_rtc_bits rtc;
+};
+
+struct mlx5_ifc_create_stc_in_bits {
+	struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr;
+	struct mlx5_ifc_stc_bits stc;
+};
+
+struct mlx5_ifc_create_ste_in_bits {
+	struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr;
+	struct mlx5_ifc_ste_bits ste;
+};
+
+struct mlx5_ifc_create_definer_in_bits {
+	struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr;
+	struct mlx5_ifc_definer_bits definer;
+};
+
+struct mlx5_ifc_create_arg_in_bits {
+	struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr;
+	struct mlx5_ifc_arg_bits arg;
+};
+
+struct mlx5_ifc_create_header_modify_pattern_in_bits {
+	struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr;
+	struct mlx5_ifc_header_modify_pattern_in_bits pattern;
+};
+
 enum {
 	MLX5_CRYPTO_KEY_SIZE_128b = 0x0,
 	MLX5_CRYPTO_KEY_SIZE_256b = 0x1,
@@ -4253,6 +4637,209 @@ struct mlx5_ifc_query_q_counter_in_bits {
 	u8 counter_set_id[0x8];
 };
 
+enum {
+	FS_FT_NIC_RX = 0x0,
+	FS_FT_NIC_TX = 0x1,
+	FS_FT_FDB = 0x4,
+	FS_FT_FDB_RX = 0xa,
+	FS_FT_FDB_TX = 0xb,
+};
+
+struct mlx5_ifc_flow_table_context_bits {
+	u8 reformat_en[0x1];
+	u8 decap_en[0x1];
+	u8 sw_owner[0x1];
+	u8 termination_table[0x1];
+	u8 table_miss_action[0x4];
+	u8 level[0x8];
+	u8 rtc_valid[0x1];
+	u8 reserved_at_11[0x7];
+	u8 log_size[0x8];
+
+	u8 reserved_at_20[0x8];
+	u8 table_miss_id[0x18];
+
+	u8 reserved_at_40[0x8];
+	u8 lag_master_next_table_id[0x18];
+
+	u8 reserved_at_60[0x60];
+
+	u8 rtc_id_0[0x20];
+
+	u8 rtc_id_1[0x20];
+
+	u8 reserved_at_100[0x40];
+};
+
+struct mlx5_ifc_create_flow_table_in_bits {
+	u8 opcode[0x10];
+	u8 uid[0x10];
+
+	u8 reserved_at_20[0x10];
+	u8 op_mod[0x10];
+
+	u8 other_vport[0x1];
+	u8 reserved_at_41[0xf];
+	u8 vport_number[0x10];
+
+	u8 reserved_at_60[0x20];
+
+	u8 table_type[0x8];
+	u8 reserved_at_88[0x18];
+
+	u8 reserved_at_a0[0x20];
+
+	struct mlx5_ifc_flow_table_context_bits flow_table_context;
+};
+
+struct mlx5_ifc_create_flow_table_out_bits {
+	u8 status[0x8];
+	u8 icm_address_63_40[0x18];
+	u8 syndrome[0x20];
+	u8 icm_address_39_32[0x8];
+	u8 table_id[0x18];
+	u8 icm_address_31_0[0x20];
+};
+
+enum mlx5_flow_destination_type {
+	MLX5_FLOW_DESTINATION_TYPE_VPORT = 0x0,
+};
+
+enum {
+	MLX5_FLOW_CONTEXT_ACTION_FWD_DEST  = 0x4,
+};
+
+struct mlx5_ifc_set_fte_out_bits {
+	u8 status[0x8];
+	u8 reserved_at_8[0x18];
+	u8 syndrome[0x20];
+	u8 reserved_at_40[0x40];
+};
+
+struct mlx5_ifc_dest_format_bits {
+	u8 destination_type[0x8];
+	u8 destination_id[0x18];
+	u8 destination_eswitch_owner_vhca_id_valid[0x1];
+	u8 packet_reformat[0x1];
+	u8 reserved_at_22[0xe];
+	u8 destination_eswitch_owner_vhca_id[0x10];
+};
+
+struct mlx5_ifc_flow_counter_list_bits {
+	u8 flow_counter_id[0x20];
+	u8 reserved_at_20[0x20];
+};
+
+union mlx5_ifc_dest_format_flow_counter_list_auto_bits {
+	struct mlx5_ifc_dest_format_bits dest_format;
+	struct mlx5_ifc_flow_counter_list_bits flow_counter_list;
+	u8 reserved_at_0[0x40];
+};
+
+struct mlx5_ifc_flow_context_bits {
+	u8 reserved_at_00[0x20];
+	u8 group_id[0x20];
+	u8 reserved_at_40[0x8];
+	u8 flow_tag[0x18];
+	u8 reserved_at_60[0x10];
+	u8 action[0x10];
+	u8 extended_destination[0x1];
+	u8 reserved_at_81[0x7];
+	u8 destination_list_size[0x18];
+	u8 reserved_at_a0[0x8];
+	u8 flow_counter_list_size[0x18];
+	u8 reserved_at_c0[0x1740];
+	/* Currently only one destnation */
+	union mlx5_ifc_dest_format_flow_counter_list_auto_bits destination[1];
+};
+
+struct mlx5_ifc_set_fte_in_bits {
+	u8 opcode[0x10];
+	u8 reserved_at_10[0x10];
+	u8 reserved_at_20[0x10];
+	u8 op_mod[0x10];
+	u8 other_vport[0x1];
+	u8 reserved_at_41[0xf];
+	u8 vport_number[0x10];
+	u8 reserved_at_60[0x20];
+	u8 table_type[0x8];
+	u8 reserved_at_88[0x18];
+	u8 reserved_at_a0[0x8];
+	u8 table_id[0x18];
+	u8 ignore_flow_level[0x1];
+	u8 reserved_at_c1[0x17];
+	u8 modify_enable_mask[0x8];
+	u8 reserved_at_e0[0x20];
+	u8 flow_index[0x20];
+	u8 reserved_at_120[0xe0];
+	struct mlx5_ifc_flow_context_bits flow_context;
+};
+
+struct mlx5_ifc_create_flow_group_in_bits {
+	u8 opcode[0x10];
+	u8 reserved_at_10[0x10];
+	u8 reserved_at_20[0x20];
+	u8 other_vport[0x1];
+	u8 reserved_at_41[0xf];
+	u8 vport_number[0x10];
+	u8 reserved_at_60[0x20];
+	u8 table_type[0x8];
+	u8 reserved_at_88[0x18];
+	u8 reserved_at_a0[0x8];
+	u8 table_id[0x18];
+	u8 reserved_at_c0[0x1f40];
+};
+
+struct mlx5_ifc_create_flow_group_out_bits {
+	u8 status[0x8];
+	u8 reserved_at_8[0x18];
+	u8 syndrome[0x20];
+	u8 reserved_at_40[0x8];
+	u8 group_id[0x18];
+	u8 reserved_at_60[0x20];
+};
+
+enum {
+	MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION = 1 << 0,
+	MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID = 1 << 1,
+};
+
+enum {
+	MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_DEFAULT = 0,
+	MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL = 1,
+};
+
+struct mlx5_ifc_modify_flow_table_in_bits {
+	u8 opcode[0x10];
+	u8 uid[0x10];
+
+	u8 reserved_at_20[0x10];
+	u8 op_mod[0x10];
+
+	u8 reserved_at_40[0x10];
+	u8 vport_number[0x10];
+
+	u8 reserved_at_60[0x10];
+	u8 modify_field_select[0x10];
+
+	u8 table_type[0x8];
+	u8 reserved_at_88[0x18];
+
+	u8 reserved_at_a0[0x8];
+	u8 table_id[0x18];
+
+	struct mlx5_ifc_flow_table_context_bits flow_table_context;
+};
+
+struct mlx5_ifc_modify_flow_table_out_bits {
+	u8 status[0x8];
+	u8 reserved_at_8[0x18];
+
+	u8 syndrome[0x20];
+
+	u8 reserved_at_40[0x60];
+};
+
 /* CQE format mask. */
 #define MLX5E_CQE_FORMAT_MASK 0xc
 
drivers/net/mlx5/hws/mlx5dr_cmd.c new file +948 -0

948 lines not on this page · raw message

drivers/net/mlx5/hws/mlx5dr_cmd.h new file +230 -0

230 lines not on this page · raw message

Signature · 1 line
2.18.1
Acked-by on v6 8/18
#113 lore raw

RE: [v6 08/18] net/mlx5/hws: Add HWS command layer

Quoted 11 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>; Erez Shitrit <[email protected]>
Subject: [v6 08/18] net/mlx5/hws: Add HWS command layer

Quoted 7 lines

From: Erez Shitrit <[email protected]>

The command layer is used to communicate with the FW, query capabilities and allocate FW resources needed for HWS.

#114 lore raw

PATCH v6 9/18 net/mlx5/hws: Add HWS pool and buddy

In reply to Alex Vesker

From: Erez Shitrit <[email protected]>

HWS needs to manage different types of device memory in an efficient and quick way. For this, memory pools are being used.

---
 drivers/net/mlx5/hws/mlx5dr_buddy.c | 200 +++++++++
 drivers/net/mlx5/hws/mlx5dr_buddy.h |  22 +
 drivers/net/mlx5/hws/mlx5dr_pool.c  | 672 ++++++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_pool.h  | 152 +++++++
 4 files changed, 1046 insertions(+)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_buddy.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_buddy.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_pool.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_pool.h
drivers/net/mlx5/hws/mlx5dr_buddy.c new file +200 -0
new file mode 100644
index 0000000000..cde4f54f66
@@ -0,0 +1,200 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#include <rte_bitmap.h>
+#include <rte_malloc.h>
+#include "mlx5dr_internal.h"
+#include "mlx5dr_buddy.h"
+
+static struct rte_bitmap *bitmap_alloc0(int s)
+{
+	struct rte_bitmap *bitmap;
+	uint32_t bmp_size;
+	void *mem;
+
+	bmp_size = rte_bitmap_get_memory_footprint(s);
+	mem = rte_zmalloc("create_bmap", bmp_size, RTE_CACHE_LINE_SIZE);
+	if (!mem) {
+		DR_LOG(ERR, "No mem for bitmap");
+		rte_errno = ENOMEM;
+		return NULL;
+	}
+
+	bitmap = rte_bitmap_init(s, mem, bmp_size);
+	if (!bitmap) {
+		DR_LOG(ERR, "%s Failed to initialize bitmap", __func__);
+		rte_errno = EINVAL;
+		goto err_mem_alloc;
+	}
+
+	return bitmap;
+
+err_mem_alloc:
+	rte_free(mem);
+	return NULL;
+}
+
+static void bitmap_set_bit(struct rte_bitmap *bmp, uint32_t pos)
+{
+	rte_bitmap_set(bmp, pos);
+}
+
+static void bitmap_clear_bit(struct rte_bitmap *bmp, uint32_t pos)
+{
+	rte_bitmap_clear(bmp, pos);
+}
+
+static bool bitmap_test_bit(struct rte_bitmap *bmp, unsigned long n)
+{
+	return !!rte_bitmap_get(bmp, n);
+}
+
+static unsigned long bitmap_ffs(struct rte_bitmap *bmap,
+				uint64_t n, unsigned long m)
+{
+	uint64_t out_slab = 0;
+	uint32_t pos = 0; /* Compilation warn */
+
+	__rte_bitmap_scan_init(bmap);
+	if (!rte_bitmap_scan(bmap, &pos, &out_slab)) {
+		DR_LOG(ERR, "Failed to get slab from bitmap.");
+		return m;
+	}
+	pos = pos + __builtin_ctzll(out_slab);
+
+	if (pos < n) {
+		DR_LOG(ERR, "Unexpected bit (%d < %"PRIx64") from bitmap", pos, n);
+		return m;
+	}
+	return pos;
+}
+
+static unsigned long mlx5dr_buddy_find_first_bit(struct rte_bitmap *addr,
+						 uint32_t size)
+{
+	return bitmap_ffs(addr, 0, size);
+}
+
+static int mlx5dr_buddy_init(struct mlx5dr_buddy_mem *buddy, uint32_t max_order)
+{
+	int i, s;
+
+	buddy->max_order = max_order;
+
+	buddy->bits = simple_calloc(buddy->max_order + 1, sizeof(long *));
+	if (!buddy->bits) {
+		rte_errno = ENOMEM;
+		return -1;
+	}
+
+	buddy->num_free = simple_calloc(buddy->max_order + 1, sizeof(*buddy->num_free));
+	if (!buddy->num_free) {
+		rte_errno = ENOMEM;
+		goto err_out_free_bits;
+	}
+
+	for (i = 0; i <= (int)buddy->max_order; ++i) {
+		s = 1 << (buddy->max_order - i);
+		buddy->bits[i] = bitmap_alloc0(s);
+		if (!buddy->bits[i])
+			goto err_out_free_num_free;
+	}
+
+	bitmap_set_bit(buddy->bits[buddy->max_order], 0);
+
+	buddy->num_free[buddy->max_order] = 1;
+
+	return 0;
+
+err_out_free_num_free:
+	for (i = 0; i <= (int)buddy->max_order; ++i)
+		rte_free(buddy->bits[i]);
+
+	simple_free(buddy->num_free);
+
+err_out_free_bits:
+	simple_free(buddy->bits);
+	return -1;
+}
+
+struct mlx5dr_buddy_mem *mlx5dr_buddy_create(uint32_t max_order)
+{
+	struct mlx5dr_buddy_mem *buddy;
+
+	buddy = simple_calloc(1, sizeof(*buddy));
+	if (!buddy) {
+		rte_errno = ENOMEM;
+		return NULL;
+	}
+
+	if (mlx5dr_buddy_init(buddy, max_order))
+		goto free_buddy;
+
+	return buddy;
+
+free_buddy:
+	simple_free(buddy);
+	return NULL;
+}
+
+void mlx5dr_buddy_cleanup(struct mlx5dr_buddy_mem *buddy)
+{
+	int i;
+
+	for (i = 0; i <= (int)buddy->max_order; ++i)
+		rte_free(buddy->bits[i]);
+
+	simple_free(buddy->num_free);
+	simple_free(buddy->bits);
+}
+
+int mlx5dr_buddy_alloc_mem(struct mlx5dr_buddy_mem *buddy, int order)
+{
+	int seg;
+	int o, m;
+
+	for (o = order; o <= (int)buddy->max_order; ++o)
+		if (buddy->num_free[o]) {
+			m = 1 << (buddy->max_order - o);
+			seg = mlx5dr_buddy_find_first_bit(buddy->bits[o], m);
+			if (m <= seg)
+				return -1;
+
+			goto found;
+		}
+
+	return -1;
+
+found:
+	bitmap_clear_bit(buddy->bits[o], seg);
+	--buddy->num_free[o];
+
+	while (o > order) {
+		--o;
+		seg <<= 1;
+		bitmap_set_bit(buddy->bits[o], seg ^ 1);
+		++buddy->num_free[o];
+	}
+
+	seg <<= order;
+
+	return seg;
+}
+
+void mlx5dr_buddy_free_mem(struct mlx5dr_buddy_mem *buddy, uint32_t seg, int order)
+{
+	seg >>= order;
+
+	while (bitmap_test_bit(buddy->bits[order], seg ^ 1)) {
+		bitmap_clear_bit(buddy->bits[order], seg ^ 1);
+		--buddy->num_free[order];
+		seg >>= 1;
+		++order;
+	}
+
+	bitmap_set_bit(buddy->bits[order], seg);
+
+	++buddy->num_free[order];
+}
+
drivers/net/mlx5/hws/mlx5dr_buddy.h new file +22 -0
new file mode 100644
index 0000000000..b9ec446b99
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#ifndef MLX5DR_BUDDY_H_
+#define MLX5DR_BUDDY_H_
+
+struct mlx5dr_buddy_mem {
+	struct rte_bitmap **bits;
+	unsigned int *num_free;
+	uint32_t max_order;
+};
+
+struct mlx5dr_buddy_mem *mlx5dr_buddy_create(uint32_t max_order);
+
+void mlx5dr_buddy_cleanup(struct mlx5dr_buddy_mem *buddy);
+
+int mlx5dr_buddy_alloc_mem(struct mlx5dr_buddy_mem *buddy, int order);
+
+void mlx5dr_buddy_free_mem(struct mlx5dr_buddy_mem *buddy, uint32_t seg, int order);
+
+#endif /* MLX5DR_BUDDY_H_ */
drivers/net/mlx5/hws/mlx5dr_pool.c new file +672 -0

672 lines not on this page · raw message

drivers/net/mlx5/hws/mlx5dr_pool.h new file +152 -0

152 lines not on this page · raw message

Signature · 1 line
2.18.1
Acked-by on v6 9/18
#115 lore raw

RE: [v6 09/18] net/mlx5/hws: Add HWS pool and buddy

Quoted 11 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>; Erez Shitrit <[email protected]>
Subject: [v6 09/18] net/mlx5/hws: Add HWS pool and buddy

Quoted 7 lines

From: Erez Shitrit <[email protected]>

HWS needs to manage different types of device memory in an efficient and quick way. For this, memory pools are being used.

#116 lore raw

PATCH v6 10/18 net/mlx5/hws: Add HWS send layer

In reply to Alex Vesker

HWS configures flows to the HW using a QP, each WQE has the details of the flow we want to offload. The send layer allocates the resources needed to send the request to the HW as well as managing the queues, getting completions and handling failures.

---
 drivers/net/mlx5/hws/mlx5dr_send.c | 844 +++++++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_send.h | 275 ++++++++++
 2 files changed, 1119 insertions(+)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_send.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_send.h
drivers/net/mlx5/hws/mlx5dr_send.c new file +844 -0
new file mode 100644
index 0000000000..26904a9040
@@ -0,0 +1,844 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#include "mlx5dr_internal.h"
+
+struct mlx5dr_send_ring_dep_wqe *
+mlx5dr_send_add_new_dep_wqe(struct mlx5dr_send_engine *queue)
+{
+	struct mlx5dr_send_ring_sq *send_sq = &queue->send_ring->send_sq;
+	unsigned int idx = send_sq->head_dep_idx++ & (queue->num_entries - 1);
+
+	memset(&send_sq->dep_wqe[idx].wqe_data.tag, 0, MLX5DR_MATCH_TAG_SZ);
+
+	return &send_sq->dep_wqe[idx];
+}
+
+void mlx5dr_send_abort_new_dep_wqe(struct mlx5dr_send_engine *queue)
+{
+	queue->send_ring->send_sq.head_dep_idx--;
+}
+
+void mlx5dr_send_all_dep_wqe(struct mlx5dr_send_engine *queue)
+{
+	struct mlx5dr_send_ring_sq *send_sq = &queue->send_ring->send_sq;
+	struct mlx5dr_send_ste_attr ste_attr = {0};
+	struct mlx5dr_send_ring_dep_wqe *dep_wqe;
+
+	ste_attr.send_attr.opmod = MLX5DR_WQE_GTA_OPMOD_STE;
+	ste_attr.send_attr.opcode = MLX5DR_WQE_OPCODE_TBL_ACCESS;
+	ste_attr.send_attr.len = MLX5DR_WQE_SZ_GTA_CTRL + MLX5DR_WQE_SZ_GTA_DATA;
+	ste_attr.gta_opcode = MLX5DR_WQE_GTA_OP_ACTIVATE;
+
+	/* Fence first from previous depend WQEs  */
+	ste_attr.send_attr.fence = 1;
+
+	while (send_sq->head_dep_idx != send_sq->tail_dep_idx) {
+		dep_wqe = &send_sq->dep_wqe[send_sq->tail_dep_idx++ & (queue->num_entries - 1)];
+
+		/* Notify HW on the last WQE */
+		ste_attr.send_attr.notify_hw = (send_sq->tail_dep_idx == send_sq->head_dep_idx);
+		ste_attr.send_attr.user_data = dep_wqe->user_data;
+		ste_attr.send_attr.rule = dep_wqe->rule;
+
+		ste_attr.rtc_0 = dep_wqe->rtc_0;
+		ste_attr.rtc_1 = dep_wqe->rtc_1;
+		ste_attr.retry_rtc_0 = dep_wqe->retry_rtc_0;
+		ste_attr.retry_rtc_1 = dep_wqe->retry_rtc_1;
+		ste_attr.used_id_rtc_0 = &dep_wqe->rule->rtc_0;
+		ste_attr.used_id_rtc_1 = &dep_wqe->rule->rtc_1;
+		ste_attr.wqe_ctrl = &dep_wqe->wqe_ctrl;
+		ste_attr.wqe_data = &dep_wqe->wqe_data;
+
+		mlx5dr_send_ste(queue, &ste_attr);
+
+		/* Fencing is done only on the first WQE */
+		ste_attr.send_attr.fence = 0;
+	}
+}
+
+struct mlx5dr_send_engine_post_ctrl
+mlx5dr_send_engine_post_start(struct mlx5dr_send_engine *queue)
+{
+	struct mlx5dr_send_engine_post_ctrl ctrl;
+
+	ctrl.queue = queue;
+	/* Currently only one send ring is supported */
+	ctrl.send_ring = &queue->send_ring[0];
+	ctrl.num_wqebbs = 0;
+
+	return ctrl;
+}
+
+void mlx5dr_send_engine_post_req_wqe(struct mlx5dr_send_engine_post_ctrl *ctrl,
+				     char **buf, size_t *len)
+{
+	struct mlx5dr_send_ring_sq *send_sq = &ctrl->send_ring->send_sq;
+	unsigned int idx;
+
+	idx = (send_sq->cur_post + ctrl->num_wqebbs) & send_sq->buf_mask;
+
+	*buf = send_sq->buf + (idx << MLX5_SEND_WQE_SHIFT);
+	*len = MLX5_SEND_WQE_BB;
+
+	if (!ctrl->num_wqebbs) {
+		*buf += sizeof(struct mlx5dr_wqe_ctrl_seg);
+		*len -= sizeof(struct mlx5dr_wqe_ctrl_seg);
+	}
+
+	ctrl->num_wqebbs++;
+}
+
+static void mlx5dr_send_engine_post_ring(struct mlx5dr_send_ring_sq *sq,
+					 struct mlx5dv_devx_uar *uar,
+					 struct mlx5dr_wqe_ctrl_seg *wqe_ctrl)
+{
+	rte_compiler_barrier();
+	sq->db[MLX5_SND_DBR] = rte_cpu_to_be_32(sq->cur_post);
+
+	rte_wmb();
+	mlx5dr_uar_write64_relaxed(*((uint64_t *)wqe_ctrl), uar->reg_addr);
+	rte_wmb();
+}
+
+static void
+mlx5dr_send_wqe_set_tag(struct mlx5dr_wqe_gta_data_seg_ste *wqe_data,
+			struct mlx5dr_rule_match_tag *tag,
+			bool is_jumbo)
+{
+	if (is_jumbo) {
+		/* Clear previous possibly dirty control */
+		memset(wqe_data, 0, MLX5DR_STE_CTRL_SZ);
+		memcpy(wqe_data->action, tag->jumbo, MLX5DR_JUMBO_TAG_SZ);
+	} else {
+		/* Clear previous possibly dirty control and actions */
+		memset(wqe_data, 0, MLX5DR_STE_CTRL_SZ + MLX5DR_ACTIONS_SZ);
+		memcpy(wqe_data->tag, tag->match, MLX5DR_MATCH_TAG_SZ);
+	}
+}
+
+void mlx5dr_send_engine_post_end(struct mlx5dr_send_engine_post_ctrl *ctrl,
+				 struct mlx5dr_send_engine_post_attr *attr)
+{
+	struct mlx5dr_wqe_ctrl_seg *wqe_ctrl;
+	struct mlx5dr_send_ring_sq *sq;
+	uint32_t flags = 0;
+	unsigned int idx;
+
+	sq = &ctrl->send_ring->send_sq;
+	idx = sq->cur_post & sq->buf_mask;
+	sq->last_idx = idx;
+
+	wqe_ctrl = (void *)(sq->buf + (idx << MLX5_SEND_WQE_SHIFT));
+
+	wqe_ctrl->opmod_idx_opcode =
+		rte_cpu_to_be_32((attr->opmod << 24) |
+				 ((sq->cur_post & 0xffff) << 8) |
+				 attr->opcode);
+	wqe_ctrl->qpn_ds =
+		rte_cpu_to_be_32((attr->len + sizeof(struct mlx5dr_wqe_ctrl_seg)) / 16 |
+				 sq->sqn << 8);
+
+	wqe_ctrl->imm = rte_cpu_to_be_32(attr->id);
+
+	flags |= attr->notify_hw ? MLX5_WQE_CTRL_CQ_UPDATE : 0;
+	flags |= attr->fence ? MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE : 0;
+	wqe_ctrl->flags = rte_cpu_to_be_32(flags);
+
+	sq->wr_priv[idx].id = attr->id;
+	sq->wr_priv[idx].retry_id = attr->retry_id;
+
+	sq->wr_priv[idx].rule = attr->rule;
+	sq->wr_priv[idx].user_data = attr->user_data;
+	sq->wr_priv[idx].num_wqebbs = ctrl->num_wqebbs;
+
+	if (attr->rule) {
+		sq->wr_priv[idx].rule->pending_wqes++;
+		sq->wr_priv[idx].used_id = attr->used_id;
+	}
+
+	sq->cur_post += ctrl->num_wqebbs;
+
+	if (attr->notify_hw)
+		mlx5dr_send_engine_post_ring(sq, ctrl->queue->uar, wqe_ctrl);
+}
+
+static void mlx5dr_send_wqe(struct mlx5dr_send_engine *queue,
+			    struct mlx5dr_send_engine_post_attr *send_attr,
+			    struct mlx5dr_wqe_gta_ctrl_seg *send_wqe_ctrl,
+			    void *send_wqe_data,
+			    void *send_wqe_tag,
+			    bool is_jumbo,
+			    uint8_t gta_opcode,
+			    uint32_t direct_index)
+{
+	struct mlx5dr_wqe_gta_data_seg_ste *wqe_data;
+	struct mlx5dr_wqe_gta_ctrl_seg *wqe_ctrl;
+	struct mlx5dr_send_engine_post_ctrl ctrl;
+	size_t wqe_len;
+
+	ctrl = mlx5dr_send_engine_post_start(queue);
+	mlx5dr_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len);
+	mlx5dr_send_engine_post_req_wqe(&ctrl, (void *)&wqe_data, &wqe_len);
+
+	wqe_ctrl->op_dirix = htobe32(gta_opcode << 28 | direct_index);
+	memcpy(wqe_ctrl->stc_ix, send_wqe_ctrl->stc_ix, sizeof(send_wqe_ctrl->stc_ix));
+
+	if (send_wqe_data)
+		memcpy(wqe_data, send_wqe_data, sizeof(*wqe_data));
+	else
+		mlx5dr_send_wqe_set_tag(wqe_data, send_wqe_tag, is_jumbo);
+
+	mlx5dr_send_engine_post_end(&ctrl, send_attr);
+}
+
+void mlx5dr_send_ste(struct mlx5dr_send_engine *queue,
+		     struct mlx5dr_send_ste_attr *ste_attr)
+{
+	struct mlx5dr_send_engine_post_attr *send_attr = &ste_attr->send_attr;
+	uint8_t notify_hw = send_attr->notify_hw;
+	uint8_t fence = send_attr->fence;
+
+	if (ste_attr->rtc_1) {
+		send_attr->id = ste_attr->rtc_1;
+		send_attr->used_id = ste_attr->used_id_rtc_1;
+		send_attr->retry_id = ste_attr->retry_rtc_1;
+		send_attr->fence = fence;
+		send_attr->notify_hw = notify_hw && !ste_attr->rtc_0;
+		mlx5dr_send_wqe(queue, send_attr,
+				ste_attr->wqe_ctrl,
+				ste_attr->wqe_data,
+				ste_attr->wqe_tag,
+				ste_attr->wqe_tag_is_jumbo,
+				ste_attr->gta_opcode,
+				ste_attr->direct_index);
+	}
+
+	if (ste_attr->rtc_0) {
+		send_attr->id = ste_attr->rtc_0;
+		send_attr->used_id = ste_attr->used_id_rtc_0;
+		send_attr->retry_id = ste_attr->retry_rtc_0;
+		send_attr->fence = fence && !ste_attr->rtc_1;
+		send_attr->notify_hw = notify_hw;
+		mlx5dr_send_wqe(queue, send_attr,
+				ste_attr->wqe_ctrl,
+				ste_attr->wqe_data,
+				ste_attr->wqe_tag,
+				ste_attr->wqe_tag_is_jumbo,
+				ste_attr->gta_opcode,
+				ste_attr->direct_index);
+	}
+
+	/* Restore to ortginal requested values */
+	send_attr->notify_hw = notify_hw;
+	send_attr->fence = fence;
+}
+
+static void mlx5dr_send_engine_retry_post_send(struct mlx5dr_send_engine *queue,
+					       struct mlx5dr_send_ring_priv *priv,
+					       uint16_t wqe_cnt)
+{
+	struct mlx5dr_send_engine_post_attr send_attr = {0};
+	struct mlx5dr_wqe_gta_data_seg_ste *wqe_data;
+	struct mlx5dr_wqe_gta_ctrl_seg *wqe_ctrl;
+	struct mlx5dr_send_engine_post_ctrl ctrl;
+	struct mlx5dr_send_ring_sq *send_sq;
+	unsigned int idx;
+	size_t wqe_len;
+	char *p;
+
+	send_attr.rule = priv->rule;
+	send_attr.opcode = MLX5DR_WQE_OPCODE_TBL_ACCESS;
+	send_attr.opmod = MLX5DR_WQE_GTA_OPMOD_STE;
+	send_attr.len = MLX5_SEND_WQE_BB * 2 - sizeof(struct mlx5dr_wqe_ctrl_seg);
+	send_attr.notify_hw = 1;
+	send_attr.fence = 0;
+	send_attr.user_data = priv->user_data;
+	send_attr.id = priv->retry_id;
+	send_attr.used_id = priv->used_id;
+
+	ctrl = mlx5dr_send_engine_post_start(queue);
+	mlx5dr_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len);
+	mlx5dr_send_engine_post_req_wqe(&ctrl, (void *)&wqe_data, &wqe_len);
+
+	send_sq = &ctrl.send_ring->send_sq;
+	idx = wqe_cnt & send_sq->buf_mask;
+	p = send_sq->buf + (idx << MLX5_SEND_WQE_SHIFT);
+
+	/* Copy old gta ctrl */
+	memcpy(wqe_ctrl, p + sizeof(struct mlx5dr_wqe_ctrl_seg),
+	       MLX5_SEND_WQE_BB - sizeof(struct mlx5dr_wqe_ctrl_seg));
+
+	idx = (wqe_cnt + 1) & send_sq->buf_mask;
+	p = send_sq->buf + (idx << MLX5_SEND_WQE_SHIFT);
+
+	/* Copy old gta data */
+	memcpy(wqe_data, p, MLX5_SEND_WQE_BB);
+
+	mlx5dr_send_engine_post_end(&ctrl, &send_attr);
+}
+
+void mlx5dr_send_engine_flush_queue(struct mlx5dr_send_engine *queue)
+{
+	struct mlx5dr_send_ring_sq *sq = &queue->send_ring[0].send_sq;
+	struct mlx5dr_wqe_ctrl_seg *wqe_ctrl;
+
+	wqe_ctrl = (void *)(sq->buf + (sq->last_idx << MLX5_SEND_WQE_SHIFT));
+
+	wqe_ctrl->flags |= rte_cpu_to_be_32(MLX5_WQE_CTRL_CQ_UPDATE);
+
+	mlx5dr_send_engine_post_ring(sq, queue->uar, wqe_ctrl);
+}
+
+static void mlx5dr_send_engine_update_rule(struct mlx5dr_send_engine *queue,
+					   struct mlx5dr_send_ring_priv *priv,
+					   uint16_t wqe_cnt,
+					   enum rte_flow_op_status *status)
+{
+	priv->rule->pending_wqes--;
+
+	if (*status == RTE_FLOW_OP_ERROR) {
+		if (priv->retry_id) {
+			mlx5dr_send_engine_retry_post_send(queue, priv, wqe_cnt);
+			return;
+		}
+		/* Some part of the rule failed */
+		priv->rule->status = MLX5DR_RULE_STATUS_FAILING;
+		*priv->used_id = 0;
+	} else {
+		*priv->used_id = priv->id;
+	}
+
+	/* Update rule status for the last completion */
+	if (!priv->rule->pending_wqes) {
+		if (unlikely(priv->rule->status == MLX5DR_RULE_STATUS_FAILING)) {
+			/* Rule completely failed and doesn't require cleanup */
+			if (!priv->rule->rtc_0 && !priv->rule->rtc_1)
+				priv->rule->status = MLX5DR_RULE_STATUS_FAILED;
+
+			*status = RTE_FLOW_OP_ERROR;
+		} else {
+			/* Increase the status, this only works on good flow as the enum
+			 * is arrange it away creating -> created -> deleting -> deleted
+			 */
+			priv->rule->status++;
+			*status = RTE_FLOW_OP_SUCCESS;
+			/* Rule was deleted now we can safely release action STEs */
+			if (priv->rule->status == MLX5DR_RULE_STATUS_DELETED)
+				mlx5dr_rule_free_action_ste_idx(priv->rule);
+		}
+	}
+}
+
+static void mlx5dr_send_engine_update(struct mlx5dr_send_engine *queue,
+				      struct mlx5_cqe64 *cqe,
+				      struct mlx5dr_send_ring_priv *priv,
+				      struct rte_flow_op_result res[],
+				      int64_t *i,
+				      uint32_t res_nb,
+				      uint16_t wqe_cnt)
+{
+	enum rte_flow_op_status status;
+
+	if (!cqe || (likely(rte_be_to_cpu_32(cqe->byte_cnt) >> 31 == 0) &&
+	    likely(mlx5dv_get_cqe_opcode(cqe) == MLX5_CQE_REQ))) {
+		status = RTE_FLOW_OP_SUCCESS;
+	} else {
+		status = RTE_FLOW_OP_ERROR;
+	}
+
+	if (priv->user_data) {
+		if (priv->rule) {
+			mlx5dr_send_engine_update_rule(queue, priv, wqe_cnt, &status);
+			/* Completion is provided on the last rule WQE */
+			if (priv->rule->pending_wqes)
+				return;
+		}
+
+		if (*i < res_nb) {
+			res[*i].user_data = priv->user_data;
+			res[*i].status = status;
+			(*i)++;
+			mlx5dr_send_engine_dec_rule(queue);
+		} else {
+			mlx5dr_send_engine_gen_comp(queue, priv->user_data, status);
+		}
+	}
+}
+
+static void mlx5dr_send_engine_poll_cq(struct mlx5dr_send_engine *queue,
+				       struct mlx5dr_send_ring *send_ring,
+				       struct rte_flow_op_result res[],
+				       int64_t *i,
+				       uint32_t res_nb)
+{
+	struct mlx5dr_send_ring_cq *cq = &send_ring->send_cq;
+	struct mlx5dr_send_ring_sq *sq = &send_ring->send_sq;
+	uint32_t cq_idx = cq->cons_index & cq->ncqe_mask;
+	struct mlx5dr_send_ring_priv *priv;
+	struct mlx5_cqe64 *cqe;
+	uint32_t offset_cqe64;
+	uint8_t cqe_opcode;
+	uint8_t cqe_owner;
+	uint16_t wqe_cnt;
+	uint8_t sw_own;
+
+	offset_cqe64 = RTE_CACHE_LINE_SIZE - sizeof(struct mlx5_cqe64);
+	cqe = (void *)(cq->buf + (cq_idx << cq->cqe_log_sz) + offset_cqe64);
+
+	sw_own = (cq->cons_index & cq->ncqe) ? 1 : 0;
+	cqe_opcode = mlx5dv_get_cqe_opcode(cqe);
+	cqe_owner = mlx5dv_get_cqe_owner(cqe);
+
+	if (cqe_opcode == MLX5_CQE_INVALID ||
+	    cqe_owner != sw_own)
+		return;
+
+	if (unlikely(mlx5dv_get_cqe_opcode(cqe) != MLX5_CQE_REQ))
+		queue->err = true;
+
+	rte_io_rmb();
+
+	wqe_cnt = be16toh(cqe->wqe_counter) & sq->buf_mask;
+
+	while (cq->poll_wqe != wqe_cnt) {
+		priv = &sq->wr_priv[cq->poll_wqe];
+		mlx5dr_send_engine_update(queue, NULL, priv, res, i, res_nb, 0);
+		cq->poll_wqe = (cq->poll_wqe + priv->num_wqebbs) & sq->buf_mask;
+	}
+
+	priv = &sq->wr_priv[wqe_cnt];
+	cq->poll_wqe = (wqe_cnt + priv->num_wqebbs) & sq->buf_mask;
+	mlx5dr_send_engine_update(queue, cqe, priv, res, i, res_nb, wqe_cnt);
+	cq->cons_index++;
+}
+
+static void mlx5dr_send_engine_poll_cqs(struct mlx5dr_send_engine *queue,
+					struct rte_flow_op_result res[],
+					int64_t *polled,
+					uint32_t res_nb)
+{
+	int j;
+
+	for (j = 0; j < MLX5DR_NUM_SEND_RINGS; j++) {
+		mlx5dr_send_engine_poll_cq(queue, &queue->send_ring[j],
+					   res, polled, res_nb);
+
+		*queue->send_ring[j].send_cq.db =
+			htobe32(queue->send_ring[j].send_cq.cons_index & 0xffffff);
+	}
+}
+
+static void mlx5dr_send_engine_poll_list(struct mlx5dr_send_engine *queue,
+					 struct rte_flow_op_result res[],
+					 int64_t *polled,
+					 uint32_t res_nb)
+{
+	struct mlx5dr_completed_poll *comp = &queue->completed;
+
+	while (comp->ci != comp->pi) {
+		if (*polled < res_nb) {
+			res[*polled].status =
+				comp->entries[comp->ci].status;
+			res[*polled].user_data =
+				comp->entries[comp->ci].user_data;
+			(*polled)++;
+			comp->ci = (comp->ci + 1) & comp->mask;
+			mlx5dr_send_engine_dec_rule(queue);
+		} else {
+			return;
+		}
+	}
+}
+
+static int mlx5dr_send_engine_poll(struct mlx5dr_send_engine *queue,
+				   struct rte_flow_op_result res[],
+				   uint32_t res_nb)
+{
+	int64_t polled = 0;
+
+	mlx5dr_send_engine_poll_list(queue, res, &polled, res_nb);
+
+	if (polled >= res_nb)
+		return polled;
+
+	mlx5dr_send_engine_poll_cqs(queue, res, &polled, res_nb);
+
+	return polled;
+}
+
+int mlx5dr_send_queue_poll(struct mlx5dr_context *ctx,
+			   uint16_t queue_id,
+			   struct rte_flow_op_result res[],
+			   uint32_t res_nb)
+{
+	return mlx5dr_send_engine_poll(&ctx->send_queue[queue_id],
+				       res, res_nb);
+}
+
+static int mlx5dr_send_ring_create_sq_obj(struct mlx5dr_context *ctx,
+					  struct mlx5dr_send_engine *queue,
+					  struct mlx5dr_send_ring_sq *sq,
+					  struct mlx5dr_send_ring_cq *cq,
+					  size_t log_wq_sz)
+{
+	struct mlx5dr_cmd_sq_create_attr attr = {0};
+	int err;
+
+	attr.cqn = cq->cqn;
+	attr.pdn = ctx->pd_num;
+	attr.page_id = queue->uar->page_id;
+	attr.dbr_id = sq->db_umem->umem_id;
+	attr.wq_id = sq->buf_umem->umem_id;
+	attr.log_wq_sz = log_wq_sz;
+
+	sq->obj = mlx5dr_cmd_sq_create(ctx->ibv_ctx, &attr);
+	if (!sq->obj)
+		return rte_errno;
+
+	sq->sqn = sq->obj->id;
+
+	err = mlx5dr_cmd_sq_modify_rdy(sq->obj);
+	if (err)
+		goto free_sq;
+
+	return 0;
+
+free_sq:
+	mlx5dr_cmd_destroy_obj(sq->obj);
+
+	return err;
+}
+
+static inline unsigned long align(unsigned long val, unsigned long align)
+{
+	return (val + align - 1) & ~(align - 1);
+}
+
+static int mlx5dr_send_ring_open_sq(struct mlx5dr_context *ctx,
+				    struct mlx5dr_send_engine *queue,
+				    struct mlx5dr_send_ring_sq *sq,
+				    struct mlx5dr_send_ring_cq *cq)
+{
+	size_t sq_log_buf_sz;
+	size_t buf_aligned;
+	size_t sq_buf_sz;
+	size_t buf_sz;
+	int err;
+
+	buf_sz = queue->num_entries * MAX_WQES_PER_RULE;
+	sq_log_buf_sz = log2above(buf_sz);
+	sq_buf_sz = 1 << (sq_log_buf_sz + log2above(MLX5_SEND_WQE_BB));
+	sq->reg_addr = queue->uar->reg_addr;
+
+	buf_aligned = align(sq_buf_sz, sysconf(_SC_PAGESIZE));
+	err = posix_memalign((void **)&sq->buf, sysconf(_SC_PAGESIZE), buf_aligned);
+	if (err) {
+		rte_errno = ENOMEM;
+		return err;
+	}
+	memset(sq->buf, 0, buf_aligned);
+
+	err = posix_memalign((void **)&sq->db, 8, 8);
+	if (err)
+		goto free_buf;
+
+	sq->buf_umem = mlx5_glue->devx_umem_reg(ctx->ibv_ctx, sq->buf, sq_buf_sz, 0);
+
+	if (!sq->buf_umem) {
+		err = errno;
+		goto free_db;
+	}
+
+	sq->db_umem = mlx5_glue->devx_umem_reg(ctx->ibv_ctx, sq->db, 8, 0);
+	if (!sq->db_umem) {
+		err = errno;
+		goto free_buf_umem;
+	}
+
+	err = mlx5dr_send_ring_create_sq_obj(ctx, queue, sq, cq, sq_log_buf_sz);
+
+	if (err)
+		goto free_db_umem;
+
+	sq->wr_priv = simple_malloc(sizeof(*sq->wr_priv) * buf_sz);
+	if (!sq->wr_priv) {
+		err = ENOMEM;
+		goto destroy_sq_obj;
+	}
+
+	sq->dep_wqe = simple_calloc(queue->num_entries, sizeof(*sq->dep_wqe));
+	if (!sq->dep_wqe) {
+		err = ENOMEM;
+		goto destroy_wr_priv;
+	}
+
+	sq->buf_mask = buf_sz - 1;
+
+	return 0;
+
+destroy_wr_priv:
+	simple_free(sq->wr_priv);
+destroy_sq_obj:
+	mlx5dr_cmd_destroy_obj(sq->obj);
+free_db_umem:
+	mlx5_glue->devx_umem_dereg(sq->db_umem);
+free_buf_umem:
+	mlx5_glue->devx_umem_dereg(sq->buf_umem);
+free_db:
+	free(sq->db);
+free_buf:
+	free(sq->buf);
+	rte_errno = err;
+	return err;
+}
+
+static void mlx5dr_send_ring_close_sq(struct mlx5dr_send_ring_sq *sq)
+{
+	simple_free(sq->dep_wqe);
+	mlx5dr_cmd_destroy_obj(sq->obj);
+	mlx5_glue->devx_umem_dereg(sq->db_umem);
+	mlx5_glue->devx_umem_dereg(sq->buf_umem);
+	simple_free(sq->wr_priv);
+	free(sq->db);
+	free(sq->buf);
+}
+
+static int mlx5dr_send_ring_open_cq(struct mlx5dr_context *ctx,
+				    struct mlx5dr_send_engine *queue,
+				    struct mlx5dr_send_ring_cq *cq)
+{
+	struct mlx5dv_cq mlx5_cq = {0};
+	struct mlx5dv_obj obj;
+	struct ibv_cq *ibv_cq;
+	size_t cq_size;
+	int err;
+
+	cq_size = queue->num_entries;
+	ibv_cq = mlx5_glue->create_cq(ctx->ibv_ctx, cq_size, NULL, NULL, 0);
+	if (!ibv_cq) {
+		DR_LOG(ERR, "Failed to create CQ");
+		rte_errno = errno;
+		return rte_errno;
+	}
+
+	obj.cq.in = ibv_cq;
+	obj.cq.out = &mlx5_cq;
+	err = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ);
+	if (err) {
+		err = errno;
+		goto close_cq;
+	}
+
+	cq->buf = mlx5_cq.buf;
+	cq->db = mlx5_cq.dbrec;
+	cq->ncqe = mlx5_cq.cqe_cnt;
+	cq->cqe_sz = mlx5_cq.cqe_size;
+	cq->cqe_log_sz = log2above(cq->cqe_sz);
+	cq->ncqe_mask = cq->ncqe - 1;
+	cq->buf_sz = cq->cqe_sz * cq->ncqe;
+	cq->cqn = mlx5_cq.cqn;
+	cq->ibv_cq = ibv_cq;
+
+	return 0;
+
+close_cq:
+	mlx5_glue->destroy_cq(ibv_cq);
+	rte_errno = err;
+	return err;
+}
+
+static void mlx5dr_send_ring_close_cq(struct mlx5dr_send_ring_cq *cq)
+{
+	mlx5_glue->destroy_cq(cq->ibv_cq);
+}
+
+static void mlx5dr_send_ring_close(struct mlx5dr_send_ring *ring)
+{
+	mlx5dr_send_ring_close_sq(&ring->send_sq);
+	mlx5dr_send_ring_close_cq(&ring->send_cq);
+}
+
+static int mlx5dr_send_ring_open(struct mlx5dr_context *ctx,
+				 struct mlx5dr_send_engine *queue,
+				 struct mlx5dr_send_ring *ring)
+{
+	int err;
+
+	err = mlx5dr_send_ring_open_cq(ctx, queue, &ring->send_cq);
+	if (err)
+		return err;
+
+	err = mlx5dr_send_ring_open_sq(ctx, queue, &ring->send_sq, &ring->send_cq);
+	if (err)
+		goto close_cq;
+
+	return err;
+
+close_cq:
+	mlx5dr_send_ring_close_cq(&ring->send_cq);
+
+	return err;
+}
+
+static void __mlx5dr_send_rings_close(struct mlx5dr_send_engine *queue,
+				      uint16_t i)
+{
+	while (i--)
+		mlx5dr_send_ring_close(&queue->send_ring[i]);
+}
+
+static void mlx5dr_send_rings_close(struct mlx5dr_send_engine *queue)
+{
+	__mlx5dr_send_rings_close(queue, queue->rings);
+}
+
+static int mlx5dr_send_rings_open(struct mlx5dr_context *ctx,
+				  struct mlx5dr_send_engine *queue)
+{
+	uint16_t i;
+	int err;
+
+	for (i = 0; i < queue->rings; i++) {
+		err = mlx5dr_send_ring_open(ctx, queue, &queue->send_ring[i]);
+		if (err)
+			goto free_rings;
+	}
+
+	return 0;
+
+free_rings:
+	__mlx5dr_send_rings_close(queue, i);
+
+	return err;
+}
+
+void mlx5dr_send_queue_close(struct mlx5dr_send_engine *queue)
+{
+	mlx5dr_send_rings_close(queue);
+	simple_free(queue->completed.entries);
+	mlx5_glue->devx_free_uar(queue->uar);
+}
+
+int mlx5dr_send_queue_open(struct mlx5dr_context *ctx,
+			   struct mlx5dr_send_engine *queue,
+			   uint16_t queue_size)
+{
+	struct mlx5dv_devx_uar *uar;
+	int err;
+
+#ifdef MLX5DV_UAR_ALLOC_TYPE_NC
+	uar = mlx5_glue->devx_alloc_uar(ctx->ibv_ctx, MLX5_IB_UAPI_UAR_ALLOC_TYPE_NC);
+	if (!uar) {
+		rte_errno = errno;
+		return rte_errno;
+	}
+#else
+	uar = NULL;
+	rte_errno = ENOTSUP;
+	return rte_errno;
+#endif
+
+	queue->uar = uar;
+	queue->rings = MLX5DR_NUM_SEND_RINGS;
+	queue->num_entries = roundup_pow_of_two(queue_size);
+	queue->used_entries = 0;
+	queue->th_entries = queue->num_entries;
+
+	queue->completed.entries = simple_calloc(queue->num_entries,
+						 sizeof(queue->completed.entries[0]));
+	if (!queue->completed.entries) {
+		rte_errno = ENOMEM;
+		goto free_uar;
+	}
+	queue->completed.pi = 0;
+	queue->completed.ci = 0;
+	queue->completed.mask = queue->num_entries - 1;
+
+	err = mlx5dr_send_rings_open(ctx, queue);
+	if (err)
+		goto free_completed_entries;
+
+	return 0;
+
+free_completed_entries:
+	simple_free(queue->completed.entries);
+free_uar:
+	mlx5_glue->devx_free_uar(uar);
+	return rte_errno;
+}
+
+static void __mlx5dr_send_queues_close(struct mlx5dr_context *ctx, uint16_t queues)
+{
+	struct mlx5dr_send_engine *queue;
+
+	while (queues--) {
+		queue = &ctx->send_queue[queues];
+
+		mlx5dr_send_queue_close(queue);
+	}
+}
+
+void mlx5dr_send_queues_close(struct mlx5dr_context *ctx)
+{
+	__mlx5dr_send_queues_close(ctx, ctx->queues);
+	simple_free(ctx->send_queue);
+}
+
+int mlx5dr_send_queues_open(struct mlx5dr_context *ctx,
+			    uint16_t queues,
+			    uint16_t queue_size)
+{
+	int err = 0;
+	uint32_t i;
+
+	/* Open one extra queue for control path */
+	ctx->queues = queues + 1;
+
+	ctx->send_queue = simple_calloc(ctx->queues, sizeof(*ctx->send_queue));
+	if (!ctx->send_queue) {
+		rte_errno = ENOMEM;
+		return rte_errno;
+	}
+
+	for (i = 0; i < ctx->queues; i++) {
+		err = mlx5dr_send_queue_open(ctx, &ctx->send_queue[i], queue_size);
+		if (err)
+			goto close_send_queues;
+	}
+
+	return 0;
+
+close_send_queues:
+	 __mlx5dr_send_queues_close(ctx, i);
+
+	simple_free(ctx->send_queue);
+
+	return err;
+}
+
+int mlx5dr_send_queue_action(struct mlx5dr_context *ctx,
+			     uint16_t queue_id,
+			     uint32_t actions)
+{
+	struct mlx5dr_send_ring_sq *send_sq;
+	struct mlx5dr_send_engine *queue;
+
+	queue = &ctx->send_queue[queue_id];
+	send_sq = &queue->send_ring->send_sq;
+
+	if (actions == MLX5DR_SEND_QUEUE_ACTION_DRAIN) {
+		if (send_sq->head_dep_idx != send_sq->tail_dep_idx)
+			/* Send dependent WQEs to drain the queue */
+			mlx5dr_send_all_dep_wqe(queue);
+		else
+			/* Signal on the last posted WQE */
+			mlx5dr_send_engine_flush_queue(queue);
+	} else {
+		rte_errno = -EINVAL;
+		return rte_errno;
+	}
+
+	return 0;
+}
drivers/net/mlx5/hws/mlx5dr_send.h new file +275 -0

275 lines not on this page · raw message

Signature · 1 line
2.18.1
Acked-by on v6 10/18
#117 lore raw

RE: [v6 10/18] net/mlx5/hws: Add HWS send layer

Quoted 10 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>; Mark Bloch <[email protected]>
Subject: [v6 10/18] net/mlx5/hws: Add HWS send layer

Quoted 7 lines

HWS configures flows to the HW using a QP, each WQE has the details of the flow we want to offload. The send layer allocates the resources needed to send the request to the HW as well as managing the queues, getting completions and handling failures.

#118 lore raw

PATCH v6 11/18 net/mlx5/hws: Add HWS definer layer

In reply to Alex Vesker

Definers are HW objects that are used for matching, rte items are translated to definers, each definer holds the fields and bit-masks used for HW flow matching. The definer layer is used for finding the most efficient definer for each set of items. In addition to definer creation we also calculate the field copy (fc) array used for efficient items to WQE conversion.

---
 doc/guides/nics/features/default.ini  |    1 +
 doc/guides/nics/features/mlx5.ini     |    1 +
 drivers/net/mlx5/hws/mlx5dr_definer.c | 1968 +++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_definer.h |  585 ++++++++
 4 files changed, 2555 insertions(+)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_definer.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_definer.h
doc/guides/nics/features/default.ini +1 -0
index 27f1a70a87..67ba3567c2 100644
@@ -140,6 +140,7 @@ udp                  =
 vlan                 =
 vxlan                =
 vxlan_gpe            =
+meter_color          =
 
 [rte_flow actions]
 age                  =
doc/guides/nics/features/mlx5.ini +1 -0
index 8697515385..b129f5787d 100644
@@ -84,6 +84,7 @@ vlan                 = Y
 vxlan                = Y
 vxlan_gpe            = Y
 represented_port     = Y
+meter_color          = Y
 
 [rte_flow actions]
 age                  = I
drivers/net/mlx5/hws/mlx5dr_definer.c new file +1968 -0

1,968 lines not on this page · raw message

drivers/net/mlx5/hws/mlx5dr_definer.h new file +585 -0

585 lines not on this page · raw message

Signature · 1 line
2.18.1
Acked-by on v6 11/18
#119 lore raw

RE: [v6 11/18] net/mlx5/hws: Add HWS definer layer

Quoted 17 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Ferruh Yigit <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>; Mark Bloch <[email protected]>
Subject: [v6 11/18] net/mlx5/hws: Add HWS definer layer

Definers are HW objects that are used for matching, rte items are translated to definers, each definer holds the fields and bit-masks used for HW flow matching. The definer layer is used for finding the most efficient definer for each set of items. In addition to definer creation we also calculate the field copy (fc) array used for efficient items to WQE conversion.

Quoted 2 lines
#120 lore raw

PATCH v6 12/18 net/mlx5/hws: Add HWS context object

In reply to Alex Vesker

Context is the first mlx5dr object created, all sub object:
table, matcher, rule, action are created using the context. The context holds the capabilities and send queues used for configuring the offloads to the HW.

---
 drivers/net/mlx5/hws/mlx5dr_context.c | 223 ++++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_context.h |  40 +++++
 2 files changed, 263 insertions(+)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_context.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_context.h
drivers/net/mlx5/hws/mlx5dr_context.c new file +223 -0
new file mode 100644
index 0000000000..ae86694a51
@@ -0,0 +1,223 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#include "mlx5dr_internal.h"
+
+static int mlx5dr_context_pools_init(struct mlx5dr_context *ctx)
+{
+	struct mlx5dr_pool_attr pool_attr = {0};
+	uint8_t max_log_sz;
+	int i;
+
+	if (mlx5dr_pat_init_pattern_cache(&ctx->pattern_cache))
+		return rte_errno;
+
+	/* Create an STC pool per FT type */
+	pool_attr.pool_type = MLX5DR_POOL_TYPE_STC;
+	pool_attr.flags = MLX5DR_POOL_FLAGS_FOR_STC_POOL;
+	max_log_sz = RTE_MIN(MLX5DR_POOL_STC_LOG_SZ, ctx->caps->stc_alloc_log_max);
+	pool_attr.alloc_log_sz = RTE_MAX(max_log_sz, ctx->caps->stc_alloc_log_gran);
+
+	for (i = 0; i < MLX5DR_TABLE_TYPE_MAX; i++) {
+		pool_attr.table_type = i;
+		ctx->stc_pool[i] = mlx5dr_pool_create(ctx, &pool_attr);
+		if (!ctx->stc_pool[i]) {
+			DR_LOG(ERR, "Failed to allocate STC pool [%d]", i);
+			goto free_stc_pools;
+		}
+	}
+
+	return 0;
+
+free_stc_pools:
+	for (i = 0; i < MLX5DR_TABLE_TYPE_MAX; i++)
+		if (ctx->stc_pool[i])
+			mlx5dr_pool_destroy(ctx->stc_pool[i]);
+
+	mlx5dr_pat_uninit_pattern_cache(ctx->pattern_cache);
+
+	return rte_errno;
+}
+
+static void mlx5dr_context_pools_uninit(struct mlx5dr_context *ctx)
+{
+	int i;
+
+	mlx5dr_pat_uninit_pattern_cache(ctx->pattern_cache);
+
+	for (i = 0; i < MLX5DR_TABLE_TYPE_MAX; i++) {
+		if (ctx->stc_pool[i])
+			mlx5dr_pool_destroy(ctx->stc_pool[i]);
+	}
+}
+
+static int mlx5dr_context_init_pd(struct mlx5dr_context *ctx,
+				  struct ibv_pd *pd)
+{
+	struct mlx5dv_pd mlx5_pd = {0};
+	struct mlx5dv_obj obj;
+	int ret;
+
+	if (pd) {
+		ctx->pd = pd;
+	} else {
+		ctx->pd = mlx5_glue->alloc_pd(ctx->ibv_ctx);
+		if (!ctx->pd) {
+			DR_LOG(ERR, "Failed to allocate PD");
+			rte_errno = errno;
+			return rte_errno;
+		}
+		ctx->flags |= MLX5DR_CONTEXT_FLAG_PRIVATE_PD;
+	}
+
+	obj.pd.in = ctx->pd;
+	obj.pd.out = &mlx5_pd;
+
+	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_PD);
+	if (ret)
+		goto free_private_pd;
+
+	ctx->pd_num = mlx5_pd.pdn;
+
+	return 0;
+
+free_private_pd:
+	if (ctx->flags & MLX5DR_CONTEXT_FLAG_PRIVATE_PD)
+		mlx5_glue->dealloc_pd(ctx->pd);
+
+	return ret;
+}
+
+static int mlx5dr_context_uninit_pd(struct mlx5dr_context *ctx)
+{
+	if (ctx->flags & MLX5DR_CONTEXT_FLAG_PRIVATE_PD)
+		return mlx5_glue->dealloc_pd(ctx->pd);
+
+	return 0;
+}
+
+static void mlx5dr_context_check_hws_supp(struct mlx5dr_context *ctx)
+{
+	struct mlx5dr_cmd_query_caps *caps = ctx->caps;
+
+	/* HWS not supported on device / FW */
+	if (!caps->wqe_based_update) {
+		DR_LOG(INFO, "Required HWS WQE based insertion cap not supported");
+		return;
+	}
+
+	/* Current solution requires all rules to set reparse bit */
+	if ((!caps->nic_ft.reparse || !caps->fdb_ft.reparse) ||
+	    !IS_BIT_SET(caps->rtc_reparse_mode, MLX5_IFC_RTC_REPARSE_ALWAYS)) {
+		DR_LOG(INFO, "Required HWS reparse cap not supported");
+		return;
+	}
+
+	/* FW/HW must support 8DW STE */
+	if (!IS_BIT_SET(caps->ste_format, MLX5_IFC_RTC_STE_FORMAT_8DW)) {
+		DR_LOG(INFO, "Required HWS STE format not supported");
+		return;
+	}
+
+	/* Adding rules by hash and by offset are requirements */
+	if (!IS_BIT_SET(caps->rtc_index_mode, MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH) ||
+	    !IS_BIT_SET(caps->rtc_index_mode, MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET)) {
+		DR_LOG(INFO, "Required HWS RTC update mode not supported");
+		return;
+	}
+
+	/* Support for SELECT definer ID is required */
+	if (!IS_BIT_SET(caps->definer_format_sup, MLX5_IFC_DEFINER_FORMAT_ID_SELECT)) {
+		DR_LOG(INFO, "Required HWS Dynamic definer not supported");
+		return;
+	}
+
+	ctx->flags |= MLX5DR_CONTEXT_FLAG_HWS_SUPPORT;
+}
+
+static int mlx5dr_context_init_hws(struct mlx5dr_context *ctx,
+				   struct mlx5dr_context_attr *attr)
+{
+	int ret;
+
+	mlx5dr_context_check_hws_supp(ctx);
+
+	if (!(ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT))
+		return 0;
+
+	ret = mlx5dr_context_init_pd(ctx, attr->pd);
+	if (ret)
+		return ret;
+
+	ret = mlx5dr_context_pools_init(ctx);
+	if (ret)
+		goto uninit_pd;
+
+	ret = mlx5dr_send_queues_open(ctx, attr->queues, attr->queue_size);
+	if (ret)
+		goto pools_uninit;
+
+	return 0;
+
+pools_uninit:
+	mlx5dr_context_pools_uninit(ctx);
+uninit_pd:
+	mlx5dr_context_uninit_pd(ctx);
+	return ret;
+}
+
+static void mlx5dr_context_uninit_hws(struct mlx5dr_context *ctx)
+{
+	if (!(ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT))
+		return;
+
+	mlx5dr_send_queues_close(ctx);
+	mlx5dr_context_pools_uninit(ctx);
+	mlx5dr_context_uninit_pd(ctx);
+}
+
+struct mlx5dr_context *mlx5dr_context_open(struct ibv_context *ibv_ctx,
+					   struct mlx5dr_context_attr *attr)
+{
+	struct mlx5dr_context *ctx;
+	int ret;
+
+	ctx = simple_calloc(1, sizeof(*ctx));
+	if (!ctx) {
+		rte_errno = ENOMEM;
+		return NULL;
+	}
+
+	ctx->ibv_ctx = ibv_ctx;
+	pthread_spin_init(&ctx->ctrl_lock, PTHREAD_PROCESS_PRIVATE);
+
+	ctx->caps = simple_calloc(1, sizeof(*ctx->caps));
+	if (!ctx->caps)
+		goto free_ctx;
+
+	ret = mlx5dr_cmd_query_caps(ibv_ctx, ctx->caps);
+	if (ret)
+		goto free_caps;
+
+	ret = mlx5dr_context_init_hws(ctx, attr);
+	if (ret)
+		goto free_caps;
+
+	return ctx;
+
+free_caps:
+	simple_free(ctx->caps);
+free_ctx:
+	simple_free(ctx);
+	return NULL;
+}
+
+int mlx5dr_context_close(struct mlx5dr_context *ctx)
+{
+	mlx5dr_context_uninit_hws(ctx);
+	simple_free(ctx->caps);
+	pthread_spin_destroy(&ctx->ctrl_lock);
+	simple_free(ctx);
+	return 0;
+}
drivers/net/mlx5/hws/mlx5dr_context.h new file +40 -0
new file mode 100644
index 0000000000..b0c7802daf
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#ifndef MLX5DR_CONTEXT_H_
+#define MLX5DR_CONTEXT_H_
+
+enum mlx5dr_context_flags {
+	MLX5DR_CONTEXT_FLAG_HWS_SUPPORT = 1 << 0,
+	MLX5DR_CONTEXT_FLAG_PRIVATE_PD = 1 << 1,
+};
+
+enum mlx5dr_context_shared_stc_type {
+	MLX5DR_CONTEXT_SHARED_STC_DECAP = 0,
+	MLX5DR_CONTEXT_SHARED_STC_POP = 1,
+	MLX5DR_CONTEXT_SHARED_STC_MAX = 2,
+};
+
+struct mlx5dr_context_common_res {
+	struct mlx5dr_action_default_stc *default_stc;
+	struct mlx5dr_action_shared_stc *shared_stc[MLX5DR_CONTEXT_SHARED_STC_MAX];
+	struct mlx5dr_cmd_forward_tbl *default_miss;
+};
+
+struct mlx5dr_context {
+	struct ibv_context *ibv_ctx;
+	struct mlx5dr_cmd_query_caps *caps;
+	struct ibv_pd *pd;
+	uint32_t pd_num;
+	struct mlx5dr_pool *stc_pool[MLX5DR_TABLE_TYPE_MAX];
+	struct mlx5dr_context_common_res common_res[MLX5DR_TABLE_TYPE_MAX];
+	struct mlx5dr_pattern_cache *pattern_cache;
+	pthread_spinlock_t ctrl_lock;
+	enum mlx5dr_context_flags flags;
+	struct mlx5dr_send_engine *send_queue;
+	size_t queues;
+	LIST_HEAD(table_head, mlx5dr_table) head;
+};
+
+#endif /* MLX5DR_CONTEXT_H_ */
Signature · 1 line
2.18.1
Acked-by on v6 12/18
#121 lore raw

RE: [v6 12/18] net/mlx5/hws: Add HWS context object

Quoted 10 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>
Subject: [v6 12/18] net/mlx5/hws: Add HWS context object

Quoted 6 lines

Context is the first mlx5dr object created, all sub object:
table, matcher, rule, action are created using the context.
The context holds the capabilities and send queues used for configuring the offloads to the HW.

#122 lore raw

PATCH v6 13/18 net/mlx5/hws: Add HWS table object

In reply to Alex Vesker

HWS table resides under the context object, each context can have multiple tables with different steering types RX/TX/FDB. The table is not only a logical object but it is also represented in the HW, packets can be steered to the table and from there to other tables.

---
 drivers/net/mlx5/hws/mlx5dr_table.c | 248 ++++++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_table.h |  44 +++++
 2 files changed, 292 insertions(+)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_table.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_table.h
drivers/net/mlx5/hws/mlx5dr_table.c new file +248 -0
new file mode 100644
index 0000000000..d3f77e4780
@@ -0,0 +1,248 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#include "mlx5dr_internal.h"
+
+static void mlx5dr_table_init_next_ft_attr(struct mlx5dr_table *tbl,
+					   struct mlx5dr_cmd_ft_create_attr *ft_attr)
+{
+	ft_attr->type = tbl->fw_ft_type;
+	if (tbl->type == MLX5DR_TABLE_TYPE_FDB)
+		ft_attr->level = tbl->ctx->caps->fdb_ft.max_level - 1;
+	else
+		ft_attr->level = tbl->ctx->caps->nic_ft.max_level - 1;
+	ft_attr->rtc_valid = true;
+}
+
+/* Call this under ctx->ctrl_lock */
+static int
+mlx5dr_table_up_default_fdb_miss_tbl(struct mlx5dr_table *tbl)
+{
+	struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
+	struct mlx5dr_cmd_forward_tbl *default_miss;
+	struct mlx5dr_context *ctx = tbl->ctx;
+	uint8_t tbl_type = tbl->type;
+	uint32_t vport;
+
+	if (tbl->type != MLX5DR_TABLE_TYPE_FDB)
+		return 0;
+
+	if (ctx->common_res[tbl_type].default_miss) {
+		ctx->common_res[tbl_type].default_miss->refcount++;
+		return 0;
+	}
+
+	ft_attr.type = tbl->fw_ft_type;
+	ft_attr.level = tbl->ctx->caps->fdb_ft.max_level; /* The last level */
+	ft_attr.rtc_valid = false;
+
+	assert(ctx->caps->eswitch_manager);
+	vport = ctx->caps->eswitch_manager_vport_number;
+
+	default_miss = mlx5dr_cmd_miss_ft_create(ctx->ibv_ctx, &ft_attr, vport);
+	if (!default_miss) {
+		DR_LOG(ERR, "Failed to default miss table type: 0x%x", tbl_type);
+		return rte_errno;
+	}
+
+	ctx->common_res[tbl_type].default_miss = default_miss;
+	ctx->common_res[tbl_type].default_miss->refcount++;
+	return 0;
+}
+
+/* Called under pthread_spin_lock(&ctx->ctrl_lock) */
+static void mlx5dr_table_down_default_fdb_miss_tbl(struct mlx5dr_table *tbl)
+{
+	struct mlx5dr_cmd_forward_tbl *default_miss;
+	struct mlx5dr_context *ctx = tbl->ctx;
+	uint8_t tbl_type = tbl->type;
+
+	if (tbl->type != MLX5DR_TABLE_TYPE_FDB)
+		return;
+
+	default_miss = ctx->common_res[tbl_type].default_miss;
+	if (--default_miss->refcount)
+		return;
+
+	mlx5dr_cmd_miss_ft_destroy(default_miss);
+
+	simple_free(default_miss);
+	ctx->common_res[tbl_type].default_miss = NULL;
+}
+
+static int
+mlx5dr_table_connect_to_default_miss_tbl(struct mlx5dr_table *tbl,
+					 struct mlx5dr_devx_obj *ft)
+{
+	struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
+	int ret;
+
+	assert(tbl->type == MLX5DR_TABLE_TYPE_FDB);
+
+	mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx,
+					     tbl->fw_ft_type,
+					     tbl->type,
+					     &ft_attr);
+
+	/* Connect to next */
+	ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
+	if (ret) {
+		DR_LOG(ERR, "Failed to connect FT to default FDB FT");
+		return errno;
+	}
+
+	return 0;
+}
+
+struct mlx5dr_devx_obj *
+mlx5dr_table_create_default_ft(struct mlx5dr_table *tbl)
+{
+	struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
+	struct mlx5dr_devx_obj *ft_obj;
+	int ret;
+
+	mlx5dr_table_init_next_ft_attr(tbl, &ft_attr);
+
+	ft_obj = mlx5dr_cmd_flow_table_create(tbl->ctx->ibv_ctx, &ft_attr);
+	if (ft_obj && tbl->type == MLX5DR_TABLE_TYPE_FDB) {
+		/* Take/create ref over the default miss */
+		ret = mlx5dr_table_up_default_fdb_miss_tbl(tbl);
+		if (ret) {
+			DR_LOG(ERR, "Failed to get default fdb miss");
+			goto free_ft_obj;
+		}
+		ret = mlx5dr_table_connect_to_default_miss_tbl(tbl, ft_obj);
+		if (ret) {
+			DR_LOG(ERR, "Failed connecting to default miss tbl");
+			goto down_miss_tbl;
+		}
+	}
+
+	return ft_obj;
+
+down_miss_tbl:
+	mlx5dr_table_down_default_fdb_miss_tbl(tbl);
+free_ft_obj:
+	mlx5dr_cmd_destroy_obj(ft_obj);
+	return NULL;
+}
+
+void mlx5dr_table_destroy_default_ft(struct mlx5dr_table *tbl,
+				     struct mlx5dr_devx_obj *ft_obj)
+{
+	mlx5dr_table_down_default_fdb_miss_tbl(tbl);
+	mlx5dr_cmd_destroy_obj(ft_obj);
+}
+
+static int mlx5dr_table_init(struct mlx5dr_table *tbl)
+{
+	struct mlx5dr_context *ctx = tbl->ctx;
+	int ret;
+
+	if (mlx5dr_table_is_root(tbl))
+		return 0;
+
+	if (!(tbl->ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT)) {
+		DR_LOG(ERR, "HWS not supported, cannot create mlx5dr_table");
+		rte_errno = EOPNOTSUPP;
+		return rte_errno;
+	}
+
+	switch (tbl->type) {
+	case MLX5DR_TABLE_TYPE_NIC_RX:
+		tbl->fw_ft_type = FS_FT_NIC_RX;
+		break;
+	case MLX5DR_TABLE_TYPE_NIC_TX:
+		tbl->fw_ft_type = FS_FT_NIC_TX;
+		break;
+	case MLX5DR_TABLE_TYPE_FDB:
+		tbl->fw_ft_type = FS_FT_FDB;
+		break;
+	default:
+		assert(0);
+		break;
+	}
+
+	pthread_spin_lock(&ctx->ctrl_lock);
+	tbl->ft = mlx5dr_table_create_default_ft(tbl);
+	if (!tbl->ft) {
+		DR_LOG(ERR, "Failed to create flow table devx object");
+		pthread_spin_unlock(&ctx->ctrl_lock);
+		return rte_errno;
+	}
+
+	ret = mlx5dr_action_get_default_stc(ctx, tbl->type);
+	if (ret)
+		goto tbl_destroy;
+	pthread_spin_unlock(&ctx->ctrl_lock);
+
+	return 0;
+
+tbl_destroy:
+	mlx5dr_table_destroy_default_ft(tbl, tbl->ft);
+	pthread_spin_unlock(&ctx->ctrl_lock);
+	return rte_errno;
+}
+
+static void mlx5dr_table_uninit(struct mlx5dr_table *tbl)
+{
+	if (mlx5dr_table_is_root(tbl))
+		return;
+	pthread_spin_lock(&tbl->ctx->ctrl_lock);
+	mlx5dr_action_put_default_stc(tbl->ctx, tbl->type);
+	mlx5dr_table_destroy_default_ft(tbl, tbl->ft);
+	pthread_spin_unlock(&tbl->ctx->ctrl_lock);
+}
+
+struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_context *ctx,
+					 struct mlx5dr_table_attr *attr)
+{
+	struct mlx5dr_table *tbl;
+	int ret;
+
+	if (attr->type > MLX5DR_TABLE_TYPE_FDB) {
+		DR_LOG(ERR, "Invalid table type %d", attr->type);
+		return NULL;
+	}
+
+	tbl = simple_malloc(sizeof(*tbl));
+	if (!tbl) {
+		rte_errno = ENOMEM;
+		return NULL;
+	}
+
+	tbl->ctx = ctx;
+	tbl->type = attr->type;
+	tbl->level = attr->level;
+	LIST_INIT(&tbl->head);
+
+	ret = mlx5dr_table_init(tbl);
+	if (ret) {
+		DR_LOG(ERR, "Failed to initialise table");
+		goto free_tbl;
+	}
+
+	pthread_spin_lock(&ctx->ctrl_lock);
+	LIST_INSERT_HEAD(&ctx->head, tbl, next);
+	pthread_spin_unlock(&ctx->ctrl_lock);
+
+	return tbl;
+
+free_tbl:
+	simple_free(tbl);
+	return NULL;
+}
+
+int mlx5dr_table_destroy(struct mlx5dr_table *tbl)
+{
+	struct mlx5dr_context *ctx = tbl->ctx;
+
+	pthread_spin_lock(&ctx->ctrl_lock);
+	LIST_REMOVE(tbl, next);
+	pthread_spin_unlock(&ctx->ctrl_lock);
+	mlx5dr_table_uninit(tbl);
+	simple_free(tbl);
+
+	return 0;
+}
drivers/net/mlx5/hws/mlx5dr_table.h new file +44 -0

44 lines not on this page · raw message

Signature · 1 line
2.18.1
Acked-by on v6 13/18
#123 lore raw

RE: [v6 13/18] net/mlx5/hws: Add HWS table object

Quoted 11 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>; Erez Shitrit <[email protected]>
Subject: [v6 13/18] net/mlx5/hws: Add HWS table object

Quoted 7 lines

HWS table resides under the context object, each context can have multiple tables with different steering types RX/TX/FDB.
The table is not only a logical object but it is also represented in the HW, packets can be steered to the table and from there to other tables.

#124 lore raw

PATCH v6 14/18 net/mlx5/hws: Add HWS matcher object

In reply to Alex Vesker

HWS matcher resides under the table object, each table can have multiple chained matcher with different attributes. Each matcher represents a combination of match and action templates. Each matcher can contain multiple configurations based on the templates. Packets are steered from the table to the matcher and from there to other objects. The matcher allows efficent HW packet field matching and action execution based on the configuration done to it.

---
 drivers/common/mlx5/linux/meson.build |   2 +
 drivers/net/mlx5/hws/mlx5dr_matcher.c | 919 ++++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_matcher.h |  76 +++
 3 files changed, 997 insertions(+)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_matcher.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_matcher.h
drivers/common/mlx5/linux/meson.build +2 -0
index b044f95700..e6b32eb84d 100644
@@ -74,6 +74,8 @@ has_member_args = [
             'struct ibv_counters_init_attr', 'comp_mask' ],
         [ 'HAVE_MLX5DV_DEVX_UAR_OFFSET', 'infiniband/mlx5dv.h',
             'struct mlx5dv_devx_uar', 'mmap_off' ],
+        [ 'HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE', 'infiniband/mlx5dv.h',
+            'struct mlx5dv_flow_matcher_attr', 'ft_type' ],
 ]
 # input array for meson symbol search:
 # [ "MACRO to define if found", "header for the search",
drivers/net/mlx5/hws/mlx5dr_matcher.c new file +919 -0

919 lines not on this page · raw message

drivers/net/mlx5/hws/mlx5dr_matcher.h new file +76 -0

76 lines not on this page · raw message

Signature · 1 line
2.18.1
Acked-by on v6 14/18
#125 lore raw

RE: [v6 14/18] net/mlx5/hws: Add HWS matcher object

Quoted 19 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>; Erez Shitrit <[email protected]>
Subject: [v6 14/18] net/mlx5/hws: Add HWS matcher object

HWS matcher resides under the table object, each table can have multiple chained matcher with different attributes. Each matcher represents a combination of match and action templates.
Each matcher can contain multiple configurations based on the templates. Packets are steered from the table to the matcher and from there to other objects. The matcher allows efficent HW packet field matching and action execution based on the configuration done to it.

Quoted 2 lines
#126 lore raw

PATCH v6 15/18 net/mlx5/hws: Add HWS rule object

In reply to Alex Vesker

HWS rule objects reside under the matcher, each rule holds the configuration for the packet fields to match on and the set of actions to execute over the packet that has the requested fields. Rules can be created asynchronously in parallel over multiple queues to different matchers. Each rule is configured to the HW.

---
 drivers/net/mlx5/hws/mlx5dr_rule.c | 528 +++++++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_rule.h |  50 +++
 2 files changed, 578 insertions(+)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_rule.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_rule.h
drivers/net/mlx5/hws/mlx5dr_rule.c new file +528 -0
new file mode 100644
index 0000000000..b27318e6d4
@@ -0,0 +1,528 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#include "mlx5dr_internal.h"
+
+static void mlx5dr_rule_skip(struct mlx5dr_matcher *matcher,
+			     const struct rte_flow_item *items,
+			     bool *skip_rx, bool *skip_tx)
+{
+	struct mlx5dr_match_template *mt = matcher->mt[0];
+	const struct flow_hw_port_info *vport;
+	const struct rte_flow_item_ethdev *v;
+
+	/* Flow_src is the 1st priority */
+	if (matcher->attr.optimize_flow_src) {
+		*skip_tx = matcher->attr.optimize_flow_src == MLX5DR_MATCHER_FLOW_SRC_WIRE;
+		*skip_rx = matcher->attr.optimize_flow_src == MLX5DR_MATCHER_FLOW_SRC_VPORT;
+		return;
+	}
+
+	/* By default FDB rules are added to both RX and TX */
+	*skip_rx = false;
+	*skip_tx = false;
+
+	if (mt->item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) {
+		v = items[mt->vport_item_id].spec;
+		vport = flow_hw_conv_port_id(v->port_id);
+		if (unlikely(!vport)) {
+			DR_LOG(ERR, "Fail to map port ID %d, ignoring", v->port_id);
+			return;
+		}
+
+		if (!vport->is_wire)
+			/* Match vport ID is not WIRE -> Skip RX */
+			*skip_rx = true;
+		else
+			/* Match vport ID is WIRE -> Skip TX */
+			*skip_tx = true;
+	}
+}
+
+static void mlx5dr_rule_init_dep_wqe(struct mlx5dr_send_ring_dep_wqe *dep_wqe,
+				     struct mlx5dr_rule *rule,
+				     const struct rte_flow_item *items,
+				     void *user_data)
+{
+	struct mlx5dr_matcher *matcher = rule->matcher;
+	struct mlx5dr_table *tbl = matcher->tbl;
+	bool skip_rx, skip_tx;
+
+	dep_wqe->rule = rule;
+	dep_wqe->user_data = user_data;
+
+	switch (tbl->type) {
+	case MLX5DR_TABLE_TYPE_NIC_RX:
+	case MLX5DR_TABLE_TYPE_NIC_TX:
+		dep_wqe->rtc_0 = matcher->match_ste.rtc_0->id;
+		dep_wqe->retry_rtc_0 = matcher->col_matcher ?
+				       matcher->col_matcher->match_ste.rtc_0->id : 0;
+		dep_wqe->rtc_1 = 0;
+		dep_wqe->retry_rtc_1 = 0;
+		break;
+
+	case MLX5DR_TABLE_TYPE_FDB:
+		mlx5dr_rule_skip(matcher, items, &skip_rx, &skip_tx);
+
+		if (!skip_rx) {
+			dep_wqe->rtc_0 = matcher->match_ste.rtc_0->id;
+			dep_wqe->retry_rtc_0 = matcher->col_matcher ?
+					       matcher->col_matcher->match_ste.rtc_0->id : 0;
+		} else {
+			dep_wqe->rtc_0 = 0;
+			dep_wqe->retry_rtc_0 = 0;
+		}
+
+		if (!skip_tx) {
+			dep_wqe->rtc_1 = matcher->match_ste.rtc_1->id;
+			dep_wqe->retry_rtc_1 = matcher->col_matcher ?
+					       matcher->col_matcher->match_ste.rtc_1->id : 0;
+		} else {
+			dep_wqe->rtc_1 = 0;
+			dep_wqe->retry_rtc_1 = 0;
+		}
+
+		break;
+
+	default:
+		assert(false);
+		break;
+	}
+}
+
+static void mlx5dr_rule_gen_comp(struct mlx5dr_send_engine *queue,
+				 struct mlx5dr_rule *rule,
+				 bool err,
+				 void *user_data,
+				 enum mlx5dr_rule_status rule_status_on_succ)
+{
+	enum rte_flow_op_status comp_status;
+
+	if (!err) {
+		comp_status = RTE_FLOW_OP_SUCCESS;
+		rule->status = rule_status_on_succ;
+	} else {
+		comp_status = RTE_FLOW_OP_ERROR;
+		rule->status = MLX5DR_RULE_STATUS_FAILED;
+	}
+
+	mlx5dr_send_engine_inc_rule(queue);
+	mlx5dr_send_engine_gen_comp(queue, user_data, comp_status);
+}
+
+static int mlx5dr_rule_alloc_action_ste(struct mlx5dr_rule *rule,
+					struct mlx5dr_rule_attr *attr)
+{
+	struct mlx5dr_matcher *matcher = rule->matcher;
+	int ret;
+
+	/* Use rule_idx for locking optimzation, otherwise allocate from pool */
+	if (matcher->attr.optimize_using_rule_idx) {
+		rule->action_ste_idx = attr->rule_idx * matcher->action_ste.max_stes;
+	} else {
+		struct mlx5dr_pool_chunk ste = {0};
+
+		ste.order = rte_log2_u32(matcher->action_ste.max_stes);
+		ret = mlx5dr_pool_chunk_alloc(matcher->action_ste.pool, &ste);
+		if (ret) {
+			DR_LOG(ERR, "Failed to allocate STE for rule actions");
+			return ret;
+		}
+		rule->action_ste_idx = ste.offset;
+	}
+	return 0;
+}
+
+void mlx5dr_rule_free_action_ste_idx(struct mlx5dr_rule *rule)
+{
+	struct mlx5dr_matcher *matcher = rule->matcher;
+
+	if (rule->action_ste_idx > -1 && !matcher->attr.optimize_using_rule_idx) {
+		struct mlx5dr_pool_chunk ste = {0};
+
+		/* This release is safe only when the rule match part was deleted */
+		ste.order = rte_log2_u32(matcher->action_ste.max_stes);
+		ste.offset = rule->action_ste_idx;
+		mlx5dr_pool_chunk_free(matcher->action_ste.pool, &ste);
+	}
+}
+
+static void mlx5dr_rule_create_init(struct mlx5dr_rule *rule,
+				    struct mlx5dr_send_ste_attr *ste_attr,
+				    struct mlx5dr_actions_apply_data *apply)
+{
+	struct mlx5dr_matcher *matcher = rule->matcher;
+	struct mlx5dr_table *tbl = matcher->tbl;
+	struct mlx5dr_context *ctx = tbl->ctx;
+
+	/* Init rule before reuse */
+	rule->rtc_0 = 0;
+	rule->rtc_1 = 0;
+	rule->pending_wqes = 0;
+	rule->action_ste_idx = -1;
+	rule->status = MLX5DR_RULE_STATUS_CREATING;
+
+	/* Init default send STE attributes */
+	ste_attr->gta_opcode = MLX5DR_WQE_GTA_OP_ACTIVATE;
+	ste_attr->send_attr.opmod = MLX5DR_WQE_GTA_OPMOD_STE;
+	ste_attr->send_attr.opcode = MLX5DR_WQE_OPCODE_TBL_ACCESS;
+	ste_attr->send_attr.len = MLX5DR_WQE_SZ_GTA_CTRL + MLX5DR_WQE_SZ_GTA_DATA;
+
+	/* Init default action apply */
+	apply->tbl_type = tbl->type;
+	apply->common_res = &ctx->common_res[tbl->type];
+	apply->jump_to_action_stc = matcher->action_ste.stc.offset;
+	apply->require_dep = 0;
+}
+
+static int mlx5dr_rule_create_hws(struct mlx5dr_rule *rule,
+				  struct mlx5dr_rule_attr *attr,
+				  uint8_t mt_idx,
+				  const struct rte_flow_item items[],
+				  uint8_t at_idx,
+				  struct mlx5dr_rule_action rule_actions[])
+{
+	struct mlx5dr_action_template *at = rule->matcher->at[at_idx];
+	struct mlx5dr_match_template *mt = rule->matcher->mt[mt_idx];
+	bool is_jumbo = mlx5dr_definer_is_jumbo(mt->definer);
+	struct mlx5dr_matcher *matcher = rule->matcher;
+	struct mlx5dr_context *ctx = matcher->tbl->ctx;
+	struct mlx5dr_send_ste_attr ste_attr = {0};
+	struct mlx5dr_send_ring_dep_wqe *dep_wqe;
+	struct mlx5dr_actions_wqe_setter *setter;
+	struct mlx5dr_actions_apply_data apply;
+	struct mlx5dr_send_engine *queue;
+	uint8_t total_stes, action_stes;
+	int i, ret;
+
+	queue = &ctx->send_queue[attr->queue_id];
+	if (unlikely(mlx5dr_send_engine_err(queue))) {
+		rte_errno = EIO;
+		return rte_errno;
+	}
+
+	mlx5dr_rule_create_init(rule, &ste_attr, &apply);
+
+	/* Allocate dependent match WQE since rule might have dependent writes.
+	 * The queued dependent WQE can be later aborted or kept as a dependency.
+	 * dep_wqe buffers (ctrl, data) are also reused for all STE writes.
+	 */
+	dep_wqe = mlx5dr_send_add_new_dep_wqe(queue);
+	mlx5dr_rule_init_dep_wqe(dep_wqe, rule, items, attr->user_data);
+
+	ste_attr.wqe_ctrl = &dep_wqe->wqe_ctrl;
+	ste_attr.wqe_data = &dep_wqe->wqe_data;
+	apply.wqe_ctrl = &dep_wqe->wqe_ctrl;
+	apply.wqe_data = (uint32_t *)&dep_wqe->wqe_data;
+	apply.rule_action = rule_actions;
+	apply.queue = queue;
+
+	setter = &at->setters[at->num_of_action_stes];
+	total_stes = at->num_of_action_stes + (is_jumbo && !at->only_term);
+	action_stes = total_stes - 1;
+
+	if (action_stes) {
+		/* Allocate action STEs for complex rules */
+		ret = mlx5dr_rule_alloc_action_ste(rule, attr);
+		if (ret) {
+			DR_LOG(ERR, "Failed to allocate action memory %d", ret);
+			mlx5dr_send_abort_new_dep_wqe(queue);
+			return ret;
+		}
+		/* Skip RX/TX based on the dep_wqe init */
+		ste_attr.rtc_0 = dep_wqe->rtc_0 ? matcher->action_ste.rtc_0->id : 0;
+		ste_attr.rtc_1 = dep_wqe->rtc_1 ? matcher->action_ste.rtc_1->id : 0;
+		/* Action STEs are written to a specific index last to first */
+		ste_attr.direct_index = rule->action_ste_idx + action_stes;
+		apply.next_direct_idx = ste_attr.direct_index;
+	} else {
+		apply.next_direct_idx = 0;
+	}
+
+	for (i = total_stes; i-- > 0;) {
+		mlx5dr_action_apply_setter(&apply, setter--, !i && is_jumbo);
+
+		if (i == 0) {
+			/* Handle last match STE */
+			mlx5dr_definer_create_tag(items, mt->fc, mt->fc_sz,
+						  (uint8_t *)dep_wqe->wqe_data.action);
+
+			/* Rule has dependent WQEs, match dep_wqe is queued */
+			if (action_stes || apply.require_dep)
+				break;
+
+			/* Rule has no dependencies, abort dep_wqe and send WQE now */
+			mlx5dr_send_abort_new_dep_wqe(queue);
+			ste_attr.wqe_tag_is_jumbo = is_jumbo;
+			ste_attr.send_attr.notify_hw = !attr->burst;
+			ste_attr.send_attr.user_data = dep_wqe->user_data;
+			ste_attr.send_attr.rule = dep_wqe->rule;
+			ste_attr.direct_index = 0;
+			ste_attr.rtc_0 = dep_wqe->rtc_0;
+			ste_attr.rtc_1 = dep_wqe->rtc_1;
+			ste_attr.used_id_rtc_0 = &rule->rtc_0;
+			ste_attr.used_id_rtc_1 = &rule->rtc_1;
+			ste_attr.retry_rtc_0 = dep_wqe->retry_rtc_0;
+			ste_attr.retry_rtc_1 = dep_wqe->retry_rtc_1;
+		} else {
+			apply.next_direct_idx = --ste_attr.direct_index;
+		}
+
+		mlx5dr_send_ste(queue, &ste_attr);
+	}
+
+	/* Backup TAG on the rule for deletion */
+	if (is_jumbo)
+		memcpy(rule->tag.jumbo, dep_wqe->wqe_data.action, MLX5DR_JUMBO_TAG_SZ);
+	else
+		memcpy(rule->tag.match, dep_wqe->wqe_data.tag, MLX5DR_MATCH_TAG_SZ);
+
+	mlx5dr_send_engine_inc_rule(queue);
+
+	/* Send dependent WQEs */
+	if (!attr->burst)
+		mlx5dr_send_all_dep_wqe(queue);
+
+	return 0;
+}
+
+static void mlx5dr_rule_destroy_failed_hws(struct mlx5dr_rule *rule,
+					   struct mlx5dr_rule_attr *attr)
+{
+	struct mlx5dr_context *ctx = rule->matcher->tbl->ctx;
+	struct mlx5dr_send_engine *queue;
+
+	queue = &ctx->send_queue[attr->queue_id];
+
+	mlx5dr_rule_gen_comp(queue, rule, false,
+			     attr->user_data, MLX5DR_RULE_STATUS_DELETED);
+
+	/* Rule failed now we can safely release action STEs */
+	mlx5dr_rule_free_action_ste_idx(rule);
+
+	/* If a rule that was indicated as burst (need to trigger HW) has failed
+	 * insertion we won't ring the HW as nothing is being written to the WQ.
+	 * In such case update the last WQE and ring the HW with that work
+	 */
+	if (attr->burst)
+		return;
+
+	mlx5dr_send_all_dep_wqe(queue);
+	mlx5dr_send_engine_flush_queue(queue);
+}
+
+static int mlx5dr_rule_destroy_hws(struct mlx5dr_rule *rule,
+				   struct mlx5dr_rule_attr *attr)
+{
+	struct mlx5dr_context *ctx = rule->matcher->tbl->ctx;
+	struct mlx5dr_matcher *matcher = rule->matcher;
+	struct mlx5dr_wqe_gta_ctrl_seg wqe_ctrl = {0};
+	struct mlx5dr_send_ste_attr ste_attr = {0};
+	struct mlx5dr_send_engine *queue;
+
+	queue = &ctx->send_queue[attr->queue_id];
+
+	/* Rule is not completed yet */
+	if (rule->status == MLX5DR_RULE_STATUS_CREATING) {
+		rte_errno = EBUSY;
+		return rte_errno;
+	}
+
+	/* Rule failed and doesn't require cleanup */
+	if (rule->status == MLX5DR_RULE_STATUS_FAILED) {
+		mlx5dr_rule_destroy_failed_hws(rule, attr);
+		return 0;
+	}
+
+	if (unlikely(mlx5dr_send_engine_err(queue))) {
+		mlx5dr_rule_destroy_failed_hws(rule, attr);
+		return 0;
+	}
+
+	mlx5dr_send_engine_inc_rule(queue);
+
+	/* Send dependent WQE */
+	if (!attr->burst)
+		mlx5dr_send_all_dep_wqe(queue);
+
+	rule->status = MLX5DR_RULE_STATUS_DELETING;
+
+	ste_attr.send_attr.opmod = MLX5DR_WQE_GTA_OPMOD_STE;
+	ste_attr.send_attr.opcode = MLX5DR_WQE_OPCODE_TBL_ACCESS;
+	ste_attr.send_attr.len = MLX5DR_WQE_SZ_GTA_CTRL + MLX5DR_WQE_SZ_GTA_DATA;
+
+	ste_attr.send_attr.rule = rule;
+	ste_attr.send_attr.notify_hw = !attr->burst;
+	ste_attr.send_attr.user_data = attr->user_data;
+
+	ste_attr.rtc_0 = rule->rtc_0;
+	ste_attr.rtc_1 = rule->rtc_1;
+	ste_attr.used_id_rtc_0 = &rule->rtc_0;
+	ste_attr.used_id_rtc_1 = &rule->rtc_1;
+	ste_attr.wqe_ctrl = &wqe_ctrl;
+	ste_attr.wqe_tag = &rule->tag;
+	ste_attr.wqe_tag_is_jumbo = mlx5dr_definer_is_jumbo(matcher->mt[0]->definer);
+	ste_attr.gta_opcode = MLX5DR_WQE_GTA_OP_DEACTIVATE;
+
+	mlx5dr_send_ste(queue, &ste_attr);
+
+	return 0;
+}
+
+static int mlx5dr_rule_create_root(struct mlx5dr_rule *rule,
+				   struct mlx5dr_rule_attr *rule_attr,
+				   const struct rte_flow_item items[],
+				   uint8_t at_idx,
+				   struct mlx5dr_rule_action rule_actions[])
+{
+	struct mlx5dv_flow_matcher *dv_matcher = rule->matcher->dv_matcher;
+	uint8_t num_actions = rule->matcher->at[at_idx]->num_actions;
+	struct mlx5dr_context *ctx = rule->matcher->tbl->ctx;
+	struct mlx5dv_flow_match_parameters *value;
+	struct mlx5_flow_attr flow_attr = {0};
+	struct mlx5dv_flow_action_attr *attr;
+	struct rte_flow_error error;
+	uint8_t match_criteria;
+	int ret;
+
+	attr = simple_calloc(num_actions, sizeof(*attr));
+	if (!attr) {
+		rte_errno = ENOMEM;
+		return rte_errno;
+	}
+
+	value = simple_calloc(1, MLX5_ST_SZ_BYTES(fte_match_param) +
+			      offsetof(struct mlx5dv_flow_match_parameters, match_buf));
+	if (!value) {
+		rte_errno = ENOMEM;
+		goto free_attr;
+	}
+
+	flow_attr.tbl_type = rule->matcher->tbl->type;
+
+	ret = flow_dv_translate_items_hws(items, &flow_attr, value->match_buf,
+					  MLX5_SET_MATCHER_HS_V, NULL,
+					  &match_criteria,
+					  &error);
+	if (ret) {
+		DR_LOG(ERR, "Failed to convert items to PRM [%s]", error.message);
+		goto free_value;
+	}
+
+	/* Convert actions to verb action attr */
+	ret = mlx5dr_action_root_build_attr(rule_actions, num_actions, attr);
+	if (ret)
+		goto free_value;
+
+	/* Create verb flow */
+	value->match_sz = MLX5_ST_SZ_BYTES(fte_match_param);
+	rule->flow = mlx5_glue->dv_create_flow_root(dv_matcher,
+						    value,
+						    num_actions,
+						    attr);
+
+	mlx5dr_rule_gen_comp(&ctx->send_queue[rule_attr->queue_id], rule, !rule->flow,
+			     rule_attr->user_data, MLX5DR_RULE_STATUS_CREATED);
+
+	simple_free(value);
+	simple_free(attr);
+
+	return 0;
+
+free_value:
+	simple_free(value);
+free_attr:
+	simple_free(attr);
+
+	return -rte_errno;
+}
+
+static int mlx5dr_rule_destroy_root(struct mlx5dr_rule *rule,
+				    struct mlx5dr_rule_attr *attr)
+{
+	struct mlx5dr_context *ctx = rule->matcher->tbl->ctx;
+	int err = 0;
+
+	if (rule->flow)
+		err = ibv_destroy_flow(rule->flow);
+
+	mlx5dr_rule_gen_comp(&ctx->send_queue[attr->queue_id], rule, err,
+			     attr->user_data, MLX5DR_RULE_STATUS_DELETED);
+
+	return 0;
+}
+
+int mlx5dr_rule_create(struct mlx5dr_matcher *matcher,
+		       uint8_t mt_idx,
+		       const struct rte_flow_item items[],
+		       uint8_t at_idx,
+		       struct mlx5dr_rule_action rule_actions[],
+		       struct mlx5dr_rule_attr *attr,
+		       struct mlx5dr_rule *rule_handle)
+{
+	struct mlx5dr_context *ctx;
+	int ret;
+
+	rule_handle->matcher = matcher;
+	ctx = matcher->tbl->ctx;
+
+	if (unlikely(!attr->user_data)) {
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+
+	/* Check if there is room in queue */
+	if (unlikely(mlx5dr_send_engine_full(&ctx->send_queue[attr->queue_id]))) {
+		rte_errno = EBUSY;
+		return -rte_errno;
+	}
+
+	assert(matcher->num_of_mt >= mt_idx);
+	assert(matcher->num_of_at >= at_idx);
+
+	if (unlikely(mlx5dr_table_is_root(matcher->tbl)))
+		ret = mlx5dr_rule_create_root(rule_handle,
+					      attr,
+					      items,
+					      at_idx,
+					      rule_actions);
+	else
+		ret = mlx5dr_rule_create_hws(rule_handle,
+					     attr,
+					     mt_idx,
+					     items,
+					     at_idx,
+					     rule_actions);
+	return -ret;
+}
+
+int mlx5dr_rule_destroy(struct mlx5dr_rule *rule,
+			struct mlx5dr_rule_attr *attr)
+{
+	struct mlx5dr_context *ctx = rule->matcher->tbl->ctx;
+	int ret;
+
+	if (unlikely(!attr->user_data)) {
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+
+	/* Check if there is room in queue */
+	if (unlikely(mlx5dr_send_engine_full(&ctx->send_queue[attr->queue_id]))) {
+		rte_errno = EBUSY;
+		return -rte_errno;
+	}
+
+	if (unlikely(mlx5dr_table_is_root(rule->matcher->tbl)))
+		ret = mlx5dr_rule_destroy_root(rule, attr);
+	else
+		ret = mlx5dr_rule_destroy_hws(rule, attr);
+
+	return -ret;
+}
+
+size_t mlx5dr_rule_get_handle_size(void)
+{
+	return sizeof(struct mlx5dr_rule);
+}
drivers/net/mlx5/hws/mlx5dr_rule.h new file +50 -0

50 lines not on this page · raw message

Signature · 1 line
2.18.1
Acked-by on v6 15/18
#127 lore raw

RE: [v6 15/18] net/mlx5/hws: Add HWS rule object

Quoted 11 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>; Erez Shitrit <[email protected]>
Subject: [v6 15/18] net/mlx5/hws: Add HWS rule object

Quoted 8 lines

HWS rule objects reside under the matcher, each rule holds the configuration for the packet fields to match on and the set of actions to execute over the packet that has the requested fields. Rules can be created asynchronously in parallel over multiple queues to different matchers. Each rule is configured to the HW.

#128 lore raw

PATCH v6 16/18 net/mlx5/hws: Add HWS action object

In reply to Alex Vesker

From: Erez Shitrit <[email protected]>

Action objects are used for executing different HW actions over packets. Each action contains the HW resources and parameters needed for action use over the HW when creating a rule.

---
 drivers/net/mlx5/hws/mlx5dr_action.c  | 2237 +++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_action.h  |  253 +++
 drivers/net/mlx5/hws/mlx5dr_pat_arg.c |  511 ++++++
 drivers/net/mlx5/hws/mlx5dr_pat_arg.h |   83 +
 4 files changed, 3084 insertions(+)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_action.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_action.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_pat_arg.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_pat_arg.h
drivers/net/mlx5/hws/mlx5dr_action.c new file +2237 -0
new file mode 100644
index 0000000000..755d5d09cf
@@ -0,0 +1,2237 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#include "mlx5dr_internal.h"
+
+#define WIRE_PORT 0xFFFF
+
+#define MLX5DR_ACTION_METER_INIT_COLOR_OFFSET 1
+
+/* This is the maximum allowed action order for each table type:
+ *	 TX: POP_VLAN, CTR, ASO_METER, AS_CT, PUSH_VLAN, MODIFY, ENCAP, Term
+ *	 RX: TAG, DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY,
+ *	     ENCAP, Term
+ *	FDB: DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY,
+ *	     ENCAP, Term
+ */
+static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_MAX] = {
+	[MLX5DR_TABLE_TYPE_NIC_RX] = {
+		BIT(MLX5DR_ACTION_TYP_TAG),
+		BIT(MLX5DR_ACTION_TYP_TNL_L2_TO_L2) |
+		BIT(MLX5DR_ACTION_TYP_TNL_L3_TO_L2),
+		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
+		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
+		BIT(MLX5DR_ACTION_TYP_CTR),
+		BIT(MLX5DR_ACTION_TYP_ASO_METER),
+		BIT(MLX5DR_ACTION_TYP_ASO_CT),
+		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
+		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
+		BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
+		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) |
+		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3),
+		BIT(MLX5DR_ACTION_TYP_FT) |
+		BIT(MLX5DR_ACTION_TYP_MISS) |
+		BIT(MLX5DR_ACTION_TYP_TIR) |
+		BIT(MLX5DR_ACTION_TYP_DROP),
+		BIT(MLX5DR_ACTION_TYP_LAST),
+	},
+	[MLX5DR_TABLE_TYPE_NIC_TX] = {
+		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
+		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
+		BIT(MLX5DR_ACTION_TYP_CTR),
+		BIT(MLX5DR_ACTION_TYP_ASO_METER),
+		BIT(MLX5DR_ACTION_TYP_ASO_CT),
+		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
+		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
+		BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
+		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) |
+		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3),
+		BIT(MLX5DR_ACTION_TYP_FT) |
+		BIT(MLX5DR_ACTION_TYP_MISS) |
+		BIT(MLX5DR_ACTION_TYP_DROP),
+		BIT(MLX5DR_ACTION_TYP_LAST),
+	},
+	[MLX5DR_TABLE_TYPE_FDB] = {
+		BIT(MLX5DR_ACTION_TYP_TNL_L2_TO_L2) |
+		BIT(MLX5DR_ACTION_TYP_TNL_L3_TO_L2),
+		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
+		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
+		BIT(MLX5DR_ACTION_TYP_CTR),
+		BIT(MLX5DR_ACTION_TYP_ASO_METER),
+		BIT(MLX5DR_ACTION_TYP_ASO_CT),
+		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
+		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
+		BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
+		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) |
+		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3),
+		BIT(MLX5DR_ACTION_TYP_FT) |
+		BIT(MLX5DR_ACTION_TYP_MISS) |
+		BIT(MLX5DR_ACTION_TYP_VPORT) |
+		BIT(MLX5DR_ACTION_TYP_DROP),
+		BIT(MLX5DR_ACTION_TYP_LAST),
+	},
+};
+
+static int mlx5dr_action_get_shared_stc_nic(struct mlx5dr_context *ctx,
+					    enum mlx5dr_context_shared_stc_type stc_type,
+					    uint8_t tbl_type)
+{
+	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
+	struct mlx5dr_action_shared_stc *shared_stc;
+	int ret;
+
+	pthread_spin_lock(&ctx->ctrl_lock);
+	if (ctx->common_res[tbl_type].shared_stc[stc_type]) {
+		rte_atomic32_add(&ctx->common_res[tbl_type].shared_stc[stc_type]->refcount, 1);
+		pthread_spin_unlock(&ctx->ctrl_lock);
+		return 0;
+	}
+
+	shared_stc = simple_calloc(1, sizeof(*shared_stc));
+	if (!shared_stc) {
+		DR_LOG(ERR, "Failed to allocate memory for shared STCs");
+		rte_errno = ENOMEM;
+		goto unlock_and_out;
+	}
+	switch (stc_type) {
+	case MLX5DR_CONTEXT_SHARED_STC_DECAP:
+		stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE;
+		stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5;
+		stc_attr.remove_header.decap = 0;
+		stc_attr.remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
+		stc_attr.remove_header.end_anchor = MLX5_HEADER_ANCHOR_IPV6_IPV4;
+		break;
+	case MLX5DR_CONTEXT_SHARED_STC_POP:
+		stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS;
+		stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5;
+		stc_attr.remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START;
+		stc_attr.remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN;
+		break;
+	default:
+		DR_LOG(ERR, "No such type : stc_type\n");
+		assert(false);
+		rte_errno = EINVAL;
+		goto unlock_and_out;
+	}
+
+	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
+					     &shared_stc->remove_header);
+	if (ret) {
+		DR_LOG(ERR, "Failed to allocate shared decap l2 STC");
+		goto free_shared_stc;
+	}
+
+	ctx->common_res[tbl_type].shared_stc[stc_type] = shared_stc;
+
+	rte_atomic32_init(&ctx->common_res[tbl_type].shared_stc[stc_type]->refcount);
+	rte_atomic32_set(&ctx->common_res[tbl_type].shared_stc[stc_type]->refcount, 1);
+
+	pthread_spin_unlock(&ctx->ctrl_lock);
+
+	return 0;
+
+free_shared_stc:
+	simple_free(shared_stc);
+unlock_and_out:
+	pthread_spin_unlock(&ctx->ctrl_lock);
+	return rte_errno;
+}
+
+static void mlx5dr_action_put_shared_stc_nic(struct mlx5dr_context *ctx,
+					     enum mlx5dr_context_shared_stc_type stc_type,
+					     uint8_t tbl_type)
+{
+	struct mlx5dr_action_shared_stc *shared_stc;
+
+	pthread_spin_lock(&ctx->ctrl_lock);
+	if (!rte_atomic32_dec_and_test(&ctx->common_res[tbl_type].shared_stc[stc_type]->refcount)) {
+		pthread_spin_unlock(&ctx->ctrl_lock);
+		return;
+	}
+
+	shared_stc = ctx->common_res[tbl_type].shared_stc[stc_type];
+
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &shared_stc->remove_header);
+	simple_free(shared_stc);
+	ctx->common_res[tbl_type].shared_stc[stc_type] = NULL;
+	pthread_spin_unlock(&ctx->ctrl_lock);
+}
+
+static int mlx5dr_action_get_shared_stc(struct mlx5dr_action *action,
+					enum mlx5dr_context_shared_stc_type stc_type)
+{
+	struct mlx5dr_context *ctx = action->ctx;
+	int ret;
+
+	if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) {
+		assert(false);
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) {
+		ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX);
+		if (ret) {
+			DR_LOG(ERR, "Failed to allocate memory for RX shared STCs (type: %d)",
+			       stc_type);
+			return ret;
+		}
+	}
+
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) {
+		ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX);
+		if (ret) {
+			DR_LOG(ERR, "Failed to allocate memory for TX shared STCs(type: %d)",
+			       stc_type);
+			goto clean_nic_rx_stc;
+		}
+	}
+
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) {
+		ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB);
+		if (ret) {
+			DR_LOG(ERR, "Failed to allocate memory for FDB shared STCs (type: %d)",
+			       stc_type);
+			goto clean_nic_tx_stc;
+		}
+	}
+
+	return 0;
+
+clean_nic_tx_stc:
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
+		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX);
+clean_nic_rx_stc:
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
+		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX);
+
+	return ret;
+}
+
+static void mlx5dr_action_put_shared_stc(struct mlx5dr_action *action,
+					 enum mlx5dr_context_shared_stc_type stc_type)
+{
+	struct mlx5dr_context *ctx = action->ctx;
+
+	if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) {
+		assert(false);
+		return;
+	}
+
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
+		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX);
+
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
+		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX);
+
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB)
+		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB);
+}
+
+static void mlx5dr_action_print_combo(enum mlx5dr_action_type *user_actions)
+{
+	DR_LOG(ERR, "Invalid action_type sequence");
+	while (*user_actions != MLX5DR_ACTION_TYP_LAST) {
+		DR_LOG(ERR, "%s", mlx5dr_debug_action_type_to_str(*user_actions));
+		user_actions++;
+	}
+}
+
+bool mlx5dr_action_check_combo(enum mlx5dr_action_type *user_actions,
+			       enum mlx5dr_table_type table_type)
+{
+	const uint32_t *order_arr = action_order_arr[table_type];
+	uint8_t order_idx = 0;
+	uint8_t user_idx = 0;
+	bool valid_combo;
+
+	while (order_arr[order_idx] != BIT(MLX5DR_ACTION_TYP_LAST)) {
+		/* User action order validated move to next user action */
+		if (BIT(user_actions[user_idx]) & order_arr[order_idx])
+			user_idx++;
+
+		/* Iterate to the next supported action in the order */
+		order_idx++;
+	}
+
+	/* Combination is valid if all user action were processed */
+	valid_combo = user_actions[user_idx] == MLX5DR_ACTION_TYP_LAST;
+	if (!valid_combo)
+		mlx5dr_action_print_combo(user_actions);
+
+	return valid_combo;
+}
+
+int mlx5dr_action_root_build_attr(struct mlx5dr_rule_action rule_actions[],
+				  uint32_t num_actions,
+				  struct mlx5dv_flow_action_attr *attr)
+{
+	struct mlx5dr_action *action;
+	uint32_t i;
+
+	for (i = 0; i < num_actions; i++) {
+		action = rule_actions[i].action;
+
+		switch (action->type) {
+		case MLX5DR_ACTION_TYP_FT:
+		case MLX5DR_ACTION_TYP_TIR:
+			attr[i].type = MLX5DV_FLOW_ACTION_DEST_DEVX;
+			attr[i].obj = action->devx_obj;
+			break;
+		case MLX5DR_ACTION_TYP_TAG:
+			attr[i].type = MLX5DV_FLOW_ACTION_TAG;
+			attr[i].tag_value = rule_actions[i].tag.value;
+			break;
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_DEFAULT_MISS
+		case MLX5DR_ACTION_TYP_MISS:
+			attr[i].type = MLX5DV_FLOW_ACTION_DEFAULT_MISS;
+			break;
+#endif
+		case MLX5DR_ACTION_TYP_DROP:
+			attr[i].type = MLX5DV_FLOW_ACTION_DROP;
+			break;
+		case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
+		case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
+		case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
+		case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
+		case MLX5DR_ACTION_TYP_MODIFY_HDR:
+			attr[i].type = MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION;
+			attr[i].action = action->flow_action;
+			break;
+#ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
+		case MLX5DR_ACTION_TYP_CTR:
+			attr[i].type = MLX5DV_FLOW_ACTION_COUNTERS_DEVX;
+			attr[i].obj = action->devx_obj;
+
+			if (rule_actions[i].counter.offset) {
+				DR_LOG(ERR, "Counter offset not supported over root");
+				rte_errno = ENOTSUP;
+				return rte_errno;
+			}
+			break;
+#endif
+		default:
+			DR_LOG(ERR, "Found unsupported action type: %d", action->type);
+			rte_errno = ENOTSUP;
+			return rte_errno;
+		}
+	}
+
+	return 0;
+}
+
+static bool mlx5dr_action_fixup_stc_attr(struct mlx5dr_cmd_stc_modify_attr *stc_attr,
+					 struct mlx5dr_cmd_stc_modify_attr *fixup_stc_attr,
+					 enum mlx5dr_table_type table_type,
+					 bool is_mirror)
+{
+	struct mlx5dr_devx_obj *devx_obj;
+	bool use_fixup = false;
+	uint32_t fw_tbl_type;
+
+	fw_tbl_type = mlx5dr_table_get_res_fw_ft_type(table_type, is_mirror);
+
+	switch (stc_attr->action_type) {
+	case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE:
+		if (!is_mirror)
+			devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_attr->ste_table.ste_pool,
+								       &stc_attr->ste_table.ste);
+		else
+			devx_obj =
+			mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_attr->ste_table.ste_pool,
+								   &stc_attr->ste_table.ste);
+
+		*fixup_stc_attr = *stc_attr;
+		fixup_stc_attr->ste_table.ste_obj_id = devx_obj->id;
+		use_fixup = true;
+		break;
+
+	case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT:
+		if (stc_attr->vport.vport_num != WIRE_PORT)
+			break;
+
+		if (fw_tbl_type == FS_FT_FDB_RX) {
+			/* The FW doesn't allow to go back to wire in RX, so change it to DROP */
+			fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
+			fixup_stc_attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
+			fixup_stc_attr->stc_offset = stc_attr->stc_offset;
+		} else if (fw_tbl_type == FS_FT_FDB_TX) {
+			/*The FW doesn't allow to go to wire in the TX by JUMP_TO_VPORT*/
+			fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK;
+			fixup_stc_attr->action_offset = stc_attr->action_offset;
+			fixup_stc_attr->stc_offset = stc_attr->stc_offset;
+			fixup_stc_attr->vport.vport_num = 0;
+			fixup_stc_attr->vport.esw_owner_vhca_id = stc_attr->vport.esw_owner_vhca_id;
+		}
+		use_fixup = true;
+		break;
+
+	default:
+		break;
+	}
+
+	return use_fixup;
+}
+
+int mlx5dr_action_alloc_single_stc(struct mlx5dr_context *ctx,
+				   struct mlx5dr_cmd_stc_modify_attr *stc_attr,
+				   uint32_t table_type,
+				   struct mlx5dr_pool_chunk *stc)
+{
+	struct mlx5dr_cmd_stc_modify_attr cleanup_stc_attr = {0};
+	struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type];
+	struct mlx5dr_cmd_stc_modify_attr fixup_stc_attr = {0};
+	struct mlx5dr_devx_obj *devx_obj_0;
+	bool use_fixup;
+	int ret;
+
+	ret = mlx5dr_pool_chunk_alloc(stc_pool, stc);
+	if (ret) {
+		DR_LOG(ERR, "Failed to allocate single action STC");
+		return ret;
+	}
+
+	stc_attr->stc_offset = stc->offset;
+	devx_obj_0 = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc);
+
+	/* According to table/action limitation change the stc_attr */
+	use_fixup = mlx5dr_action_fixup_stc_attr(stc_attr, &fixup_stc_attr, table_type, false);
+	ret = mlx5dr_cmd_stc_modify(devx_obj_0, use_fixup ? &fixup_stc_attr : stc_attr);
+	if (ret) {
+		DR_LOG(ERR, "Failed to modify STC action_type %d tbl_type %d",
+		       stc_attr->action_type, table_type);
+		goto free_chunk;
+	}
+
+	/* Modify the FDB peer */
+	if (table_type == MLX5DR_TABLE_TYPE_FDB) {
+		struct mlx5dr_devx_obj *devx_obj_1;
+
+		devx_obj_1 = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc);
+
+		use_fixup = mlx5dr_action_fixup_stc_attr(stc_attr, &fixup_stc_attr,
+							 table_type, true);
+		ret = mlx5dr_cmd_stc_modify(devx_obj_1, use_fixup ? &fixup_stc_attr : stc_attr);
+		if (ret) {
+			DR_LOG(ERR, "Failed to modify peer STC action_type %d tbl_type %d",
+			       stc_attr->action_type, table_type);
+			goto clean_devx_obj_0;
+		}
+	}
+
+	return 0;
+
+clean_devx_obj_0:
+	cleanup_stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
+	cleanup_stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
+	cleanup_stc_attr.stc_offset = stc->offset;
+	mlx5dr_cmd_stc_modify(devx_obj_0, &cleanup_stc_attr);
+free_chunk:
+	mlx5dr_pool_chunk_free(stc_pool, stc);
+	return rte_errno;
+}
+
+void mlx5dr_action_free_single_stc(struct mlx5dr_context *ctx,
+				   uint32_t table_type,
+				   struct mlx5dr_pool_chunk *stc)
+{
+	struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type];
+	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
+	struct mlx5dr_devx_obj *devx_obj;
+
+	/* Modify the STC not to point to an object */
+	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
+	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
+	stc_attr.stc_offset = stc->offset;
+	devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc);
+	mlx5dr_cmd_stc_modify(devx_obj, &stc_attr);
+
+	if (table_type == MLX5DR_TABLE_TYPE_FDB) {
+		devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc);
+		mlx5dr_cmd_stc_modify(devx_obj, &stc_attr);
+	}
+
+	mlx5dr_pool_chunk_free(stc_pool, stc);
+}
+
+static uint32_t mlx5dr_action_get_mh_stc_type(__be64 pattern)
+{
+	uint8_t action_type = MLX5_GET(set_action_in, &pattern, action_type);
+
+	switch (action_type) {
+	case MLX5_MODIFICATION_TYPE_SET:
+		return MLX5_IFC_STC_ACTION_TYPE_SET;
+	case MLX5_MODIFICATION_TYPE_ADD:
+		return MLX5_IFC_STC_ACTION_TYPE_ADD;
+	case MLX5_MODIFICATION_TYPE_COPY:
+		return MLX5_IFC_STC_ACTION_TYPE_COPY;
+	default:
+		assert(false);
+		DR_LOG(ERR, "Unsupported action type: 0x%x\n", action_type);
+		rte_errno = ENOTSUP;
+		return MLX5_IFC_STC_ACTION_TYPE_NOP;
+	}
+}
+
+static void mlx5dr_action_fill_stc_attr(struct mlx5dr_action *action,
+					struct mlx5dr_devx_obj *obj,
+					struct mlx5dr_cmd_stc_modify_attr *attr)
+{
+	switch (action->type) {
+	case MLX5DR_ACTION_TYP_TAG:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_TAG;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
+		break;
+	case MLX5DR_ACTION_TYP_DROP:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
+		break;
+	case MLX5DR_ACTION_TYP_MISS:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
+		/* TODO Need to support default miss for FDB */
+		break;
+	case MLX5DR_ACTION_TYP_CTR:
+		attr->id = obj->id;
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_COUNTER;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW0;
+		break;
+	case MLX5DR_ACTION_TYP_TIR:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
+		attr->dest_tir_num = obj->id;
+		break;
+	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
+	case MLX5DR_ACTION_TYP_MODIFY_HDR:
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
+		if (action->modify_header.num_of_actions == 1) {
+			attr->modify_action.data = action->modify_header.single_action;
+			attr->action_type = mlx5dr_action_get_mh_stc_type(attr->modify_action.data);
+
+			if (attr->action_type == MLX5_IFC_STC_ACTION_TYPE_ADD ||
+			    attr->action_type == MLX5_IFC_STC_ACTION_TYPE_SET)
+				MLX5_SET(set_action_in, &attr->modify_action.data, data, 0);
+		} else {
+			attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST;
+			attr->modify_header.arg_id = action->modify_header.arg_obj->id;
+			attr->modify_header.pattern_id = action->modify_header.pattern_obj->id;
+		}
+		break;
+	case MLX5DR_ACTION_TYP_FT:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
+		attr->dest_table_id = obj->id;
+		break;
+	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
+		attr->remove_header.decap = 1;
+		attr->remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
+		attr->remove_header.end_anchor = MLX5_HEADER_ANCHOR_INNER_MAC;
+		break;
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
+		attr->insert_header.encap = 1;
+		attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
+		attr->insert_header.arg_id = action->reformat.arg_obj->id;
+		attr->insert_header.header_size = action->reformat.header_size;
+		break;
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
+		attr->insert_header.encap = 1;
+		attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
+		attr->insert_header.arg_id = action->reformat.arg_obj->id;
+		attr->insert_header.header_size = action->reformat.header_size;
+		break;
+	case MLX5DR_ACTION_TYP_ASO_METER:
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO;
+		attr->aso.aso_type = ASO_OPC_MOD_POLICER;
+		attr->aso.devx_obj_id = obj->id;
+		attr->aso.return_reg_id = action->aso.return_reg_id;
+		break;
+	case MLX5DR_ACTION_TYP_ASO_CT:
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO;
+		attr->aso.aso_type = ASO_OPC_MOD_CONNECTION_TRACKING;
+		attr->aso.devx_obj_id = obj->id;
+		attr->aso.return_reg_id = action->aso.return_reg_id;
+		break;
+	case MLX5DR_ACTION_TYP_VPORT:
+		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT;
+		attr->vport.vport_num = action->vport.vport_num;
+		attr->vport.esw_owner_vhca_id =	action->vport.esw_owner_vhca_id;
+		break;
+	case MLX5DR_ACTION_TYP_POP_VLAN:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
+		attr->remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START;
+		attr->remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN / 2;
+		break;
+	case MLX5DR_ACTION_TYP_PUSH_VLAN:
+		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT;
+		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
+		attr->insert_header.encap = 0;
+		attr->insert_header.is_inline = 1;
+		attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
+		attr->insert_header.insert_offset = MLX5DR_ACTION_HDR_LEN_L2_MACS;
+		attr->insert_header.header_size = MLX5DR_ACTION_HDR_LEN_L2_VLAN;
+		break;
+	default:
+		DR_LOG(ERR, "Invalid action type %d", action->type);
+		assert(false);
+	}
+}
+
+static int
+mlx5dr_action_create_stcs(struct mlx5dr_action *action,
+			  struct mlx5dr_devx_obj *obj)
+{
+	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
+	struct mlx5dr_context *ctx = action->ctx;
+	int ret;
+
+	mlx5dr_action_fill_stc_attr(action, obj, &stc_attr);
+
+	/* Block unsupported parallel devx obj modify over the same base */
+	pthread_spin_lock(&ctx->ctrl_lock);
+
+	/* Allocate STC for RX */
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) {
+		ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr,
+						     MLX5DR_TABLE_TYPE_NIC_RX,
+						     &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]);
+		if (ret)
+			goto out_err;
+	}
+
+	/* Allocate STC for TX */
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) {
+		ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr,
+						     MLX5DR_TABLE_TYPE_NIC_TX,
+						     &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]);
+		if (ret)
+			goto free_nic_rx_stc;
+	}
+
+	/* Allocate STC for FDB */
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) {
+		ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr,
+						     MLX5DR_TABLE_TYPE_FDB,
+						     &action->stc[MLX5DR_TABLE_TYPE_FDB]);
+		if (ret)
+			goto free_nic_tx_stc;
+	}
+
+	pthread_spin_unlock(&ctx->ctrl_lock);
+
+	return 0;
+
+free_nic_tx_stc:
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
+		mlx5dr_action_free_single_stc(ctx,
+					      MLX5DR_TABLE_TYPE_NIC_TX,
+					      &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]);
+free_nic_rx_stc:
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
+		mlx5dr_action_free_single_stc(ctx,
+					      MLX5DR_TABLE_TYPE_NIC_RX,
+					      &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]);
+out_err:
+	pthread_spin_unlock(&ctx->ctrl_lock);
+	return rte_errno;
+}
+
+static void
+mlx5dr_action_destroy_stcs(struct mlx5dr_action *action)
+{
+	struct mlx5dr_context *ctx = action->ctx;
+
+	/* Block unsupported parallel devx obj modify over the same base */
+	pthread_spin_lock(&ctx->ctrl_lock);
+
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
+		mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_RX,
+					      &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]);
+
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
+		mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_TX,
+					      &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]);
+
+	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB)
+		mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_FDB,
+					      &action->stc[MLX5DR_TABLE_TYPE_FDB]);
+
+	pthread_spin_unlock(&ctx->ctrl_lock);
+}
+
+static bool
+mlx5dr_action_is_root_flags(uint32_t flags)
+{
+	return flags & (MLX5DR_ACTION_FLAG_ROOT_RX |
+			MLX5DR_ACTION_FLAG_ROOT_TX |
+			MLX5DR_ACTION_FLAG_ROOT_FDB);
+}
+
+static bool
+mlx5dr_action_is_hws_flags(uint32_t flags)
+{
+	return flags & (MLX5DR_ACTION_FLAG_HWS_RX |
+			MLX5DR_ACTION_FLAG_HWS_TX |
+			MLX5DR_ACTION_FLAG_HWS_FDB);
+}
+
+static struct mlx5dr_action *
+mlx5dr_action_create_generic(struct mlx5dr_context *ctx,
+			     uint32_t flags,
+			     enum mlx5dr_action_type action_type)
+{
+	struct mlx5dr_action *action;
+
+	if (!mlx5dr_action_is_root_flags(flags) &&
+	    !mlx5dr_action_is_hws_flags(flags)) {
+		DR_LOG(ERR, "Action flags must specify root or non root (HWS)");
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+
+	action = simple_calloc(1, sizeof(*action));
+	if (!action) {
+		DR_LOG(ERR, "Failed to allocate memory for action [%d]", action_type);
+		rte_errno = ENOMEM;
+		return NULL;
+	}
+
+	action->ctx = ctx;
+	action->flags = flags;
+	action->type = action_type;
+
+	return action;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_dest_table(struct mlx5dr_context *ctx,
+				struct mlx5dr_table *tbl,
+				uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	if (mlx5dr_table_is_root(tbl)) {
+		DR_LOG(ERR, "Root table cannot be set as destination");
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+
+	if (mlx5dr_action_is_hws_flags(flags) &&
+	    mlx5dr_action_is_root_flags(flags)) {
+		DR_LOG(ERR, "Same action cannot be used for root and non root");
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_FT);
+	if (!action)
+		return NULL;
+
+	if (mlx5dr_action_is_root_flags(flags)) {
+		action->devx_obj = tbl->ft->obj;
+	} else {
+		ret = mlx5dr_action_create_stcs(action, tbl->ft);
+		if (ret)
+			goto free_action;
+	}
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_dest_tir(struct mlx5dr_context *ctx,
+			      struct mlx5dr_devx_obj *obj,
+			      uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	if (mlx5dr_action_is_hws_flags(flags) &&
+	    mlx5dr_action_is_root_flags(flags)) {
+		DR_LOG(ERR, "Same action cannot be used for root and non root");
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TIR);
+	if (!action)
+		return NULL;
+
+	if (mlx5dr_action_is_root_flags(flags)) {
+		action->devx_obj = obj->obj;
+	} else {
+		ret = mlx5dr_action_create_stcs(action, obj);
+		if (ret)
+			goto free_action;
+	}
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_dest_drop(struct mlx5dr_context *ctx,
+			       uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_DROP);
+	if (!action)
+		return NULL;
+
+	if (mlx5dr_action_is_hws_flags(flags)) {
+		ret = mlx5dr_action_create_stcs(action, NULL);
+		if (ret)
+			goto free_action;
+	}
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_default_miss(struct mlx5dr_context *ctx,
+				  uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_MISS);
+	if (!action)
+		return NULL;
+
+	if (mlx5dr_action_is_hws_flags(flags)) {
+		ret = mlx5dr_action_create_stcs(action, NULL);
+		if (ret)
+			goto free_action;
+	}
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_tag(struct mlx5dr_context *ctx,
+			 uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TAG);
+	if (!action)
+		return NULL;
+
+	if (mlx5dr_action_is_hws_flags(flags)) {
+		ret = mlx5dr_action_create_stcs(action, NULL);
+		if (ret)
+			goto free_action;
+	}
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+static struct mlx5dr_action *
+mlx5dr_action_create_aso(struct mlx5dr_context *ctx,
+			 enum mlx5dr_action_type action_type,
+			 struct mlx5dr_devx_obj *devx_obj,
+			 uint8_t return_reg_id,
+			 uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	if (mlx5dr_action_is_root_flags(flags)) {
+		DR_LOG(ERR, "ASO action cannot be used over root table");
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+
+	action = mlx5dr_action_create_generic(ctx, flags, action_type);
+	if (!action)
+		return NULL;
+
+	action->aso.devx_obj = devx_obj;
+	action->aso.return_reg_id = return_reg_id;
+
+	ret = mlx5dr_action_create_stcs(action, devx_obj);
+	if (ret)
+		goto free_action;
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_aso_meter(struct mlx5dr_context *ctx,
+			       struct mlx5dr_devx_obj *devx_obj,
+			       uint8_t return_reg_id,
+			       uint32_t flags)
+{
+	return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_METER,
+					devx_obj, return_reg_id, flags);
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_aso_ct(struct mlx5dr_context *ctx,
+			    struct mlx5dr_devx_obj *devx_obj,
+			    uint8_t return_reg_id,
+			    uint32_t flags)
+{
+	return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_CT,
+					devx_obj, return_reg_id, flags);
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_counter(struct mlx5dr_context *ctx,
+			     struct mlx5dr_devx_obj *obj,
+			     uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	if (mlx5dr_action_is_hws_flags(flags) &&
+	    mlx5dr_action_is_root_flags(flags)) {
+		DR_LOG(ERR, "Same action cannot be used for root and non root");
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_CTR);
+	if (!action)
+		return NULL;
+
+	if (mlx5dr_action_is_root_flags(flags)) {
+		action->devx_obj = obj->obj;
+	} else {
+		ret = mlx5dr_action_create_stcs(action, obj);
+		if (ret)
+			goto free_action;
+	}
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+static int mlx5dr_action_create_dest_vport_hws(struct mlx5dr_context *ctx,
+					       struct mlx5dr_action *action,
+					       uint32_t ib_port_num)
+{
+	struct mlx5dr_cmd_query_vport_caps vport_caps = {0};
+	int ret;
+
+	ret = mlx5dr_cmd_query_ib_port(ctx->ibv_ctx, &vport_caps, ib_port_num);
+	if (ret) {
+		DR_LOG(ERR, "Failed querying port %d\n", ib_port_num);
+		return ret;
+	}
+	action->vport.vport_num = vport_caps.vport_num;
+	action->vport.esw_owner_vhca_id = vport_caps.esw_owner_vhca_id;
+
+	ret = mlx5dr_action_create_stcs(action, NULL);
+	if (ret) {
+		DR_LOG(ERR, "Failed creating stc for port %d\n", ib_port_num);
+		return ret;
+	}
+
+	return 0;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_dest_vport(struct mlx5dr_context *ctx,
+				uint32_t ib_port_num,
+				uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	if (!(flags & MLX5DR_ACTION_FLAG_HWS_FDB)) {
+		DR_LOG(ERR, "Vport action is supported for FDB only\n");
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_VPORT);
+	if (!action)
+		return NULL;
+
+	ret = mlx5dr_action_create_dest_vport_hws(ctx, action, ib_port_num);
+	if (ret) {
+		DR_LOG(ERR, "Failed to create vport action HWS\n");
+		goto free_action;
+	}
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_push_vlan(struct mlx5dr_context *ctx, uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	if (mlx5dr_action_is_root_flags(flags)) {
+		DR_LOG(ERR, "Push vlan action not supported for root");
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_PUSH_VLAN);
+	if (!action)
+		return NULL;
+
+	ret = mlx5dr_action_create_stcs(action, NULL);
+	if (ret) {
+		DR_LOG(ERR, "Failed creating stc for push vlan\n");
+		goto free_action;
+	}
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_pop_vlan(struct mlx5dr_context *ctx, uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	if (mlx5dr_action_is_root_flags(flags)) {
+		DR_LOG(ERR, "Pop vlan action not supported for root");
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_POP_VLAN);
+	if (!action)
+		return NULL;
+
+	ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_POP);
+	if (ret) {
+		DR_LOG(ERR, "Failed to create remove stc for reformat");
+		goto free_action;
+	}
+
+	ret = mlx5dr_action_create_stcs(action, NULL);
+	if (ret) {
+		DR_LOG(ERR, "Failed creating stc for pop vlan\n");
+		goto free_shared;
+	}
+
+	return action;
+
+free_shared:
+	mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_POP);
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+static int
+mlx5dr_action_conv_reformat_type_to_action(uint32_t reformat_type,
+					   enum mlx5dr_action_type *action_type)
+{
+	switch (reformat_type) {
+	case MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2:
+		*action_type = MLX5DR_ACTION_TYP_TNL_L2_TO_L2;
+		break;
+	case MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2:
+		*action_type = MLX5DR_ACTION_TYP_L2_TO_TNL_L2;
+		break;
+	case MLX5DR_ACTION_REFORMAT_TYPE_TNL_L3_TO_L2:
+		*action_type = MLX5DR_ACTION_TYP_TNL_L3_TO_L2;
+		break;
+	case MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L3:
+		*action_type = MLX5DR_ACTION_TYP_L2_TO_TNL_L3;
+		break;
+	default:
+		DR_LOG(ERR, "Invalid reformat type requested");
+		rte_errno = ENOTSUP;
+		return rte_errno;
+	}
+	return 0;
+}
+
+static void
+mlx5dr_action_conv_reformat_to_verbs(uint32_t action_type,
+				     uint32_t *verb_reformat_type)
+{
+	switch (action_type) {
+	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
+		*verb_reformat_type =
+			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2;
+		break;
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
+		*verb_reformat_type =
+			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL;
+		break;
+	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
+		*verb_reformat_type =
+			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
+		break;
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
+		*verb_reformat_type =
+			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
+		break;
+	}
+}
+
+static int
+mlx5dr_action_conv_flags_to_ft_type(uint32_t flags, enum mlx5dv_flow_table_type *ft_type)
+{
+	if (flags & MLX5DR_ACTION_FLAG_ROOT_RX) {
+		*ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
+	} else if (flags & MLX5DR_ACTION_FLAG_ROOT_TX) {
+		*ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
+#ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE
+	} else if (flags & MLX5DR_ACTION_FLAG_ROOT_FDB) {
+		*ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
+#endif
+	} else {
+		rte_errno = ENOTSUP;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+mlx5dr_action_create_reformat_root(struct mlx5dr_action *action,
+				   size_t data_sz,
+				   void *data)
+{
+	enum mlx5dv_flow_table_type ft_type = 0; /*fix compilation warn*/
+	uint32_t verb_reformat_type = 0;
+	int ret;
+
+	/* Convert action to FT type and verbs reformat type */
+	ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type);
+	if (ret)
+		return rte_errno;
+
+	mlx5dr_action_conv_reformat_to_verbs(action->type, &verb_reformat_type);
+
+	/* Create the reformat type for root table */
+	action->flow_action =
+		mlx5_glue->dv_create_flow_action_packet_reformat_root(action->ctx->ibv_ctx,
+								      data_sz,
+								      data,
+								      verb_reformat_type,
+								      ft_type);
+	if (!action->flow_action) {
+		rte_errno = errno;
+		return rte_errno;
+	}
+
+	return 0;
+}
+
+static int mlx5dr_action_handle_reformat_args(struct mlx5dr_context *ctx,
+					      size_t data_sz,
+					      void *data,
+					      uint32_t bulk_size,
+					      struct mlx5dr_action *action)
+{
+	uint32_t args_log_size;
+	int ret;
+
+	if (data_sz % 2 != 0) {
+		DR_LOG(ERR, "Data size should be multiply of 2");
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+	action->reformat.header_size = data_sz;
+
+	args_log_size = mlx5dr_arg_data_size_to_arg_log_size(data_sz);
+	if (args_log_size >= MLX5DR_ARG_CHUNK_SIZE_MAX) {
+		DR_LOG(ERR, "Data size is bigger than supported");
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+	args_log_size += bulk_size;
+
+	if (!mlx5dr_arg_is_valid_arg_request_size(ctx, args_log_size)) {
+		DR_LOG(ERR, "Arg size %d does not fit FW requests",
+		       args_log_size);
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	action->reformat.arg_obj = mlx5dr_cmd_arg_create(ctx->ibv_ctx,
+							 args_log_size,
+							 ctx->pd_num);
+	if (!action->reformat.arg_obj) {
+		DR_LOG(ERR, "Failed to create arg for reformat");
+		return rte_errno;
+	}
+
+	/* When INLINE need to write the arg data */
+	if (action->flags & MLX5DR_ACTION_FLAG_SHARED) {
+		ret = mlx5dr_arg_write_inline_arg_data(ctx,
+						       action->reformat.arg_obj->id,
+						       data,
+						       data_sz);
+		if (ret) {
+			DR_LOG(ERR, "Failed to write inline arg for reformat");
+			goto free_arg;
+		}
+	}
+
+	return 0;
+
+free_arg:
+	mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
+	return ret;
+}
+
+static int mlx5dr_action_handle_l2_to_tunnel_l2(struct mlx5dr_context *ctx,
+						size_t data_sz,
+						void *data,
+						uint32_t bulk_size,
+						struct mlx5dr_action *action)
+{
+	int ret;
+
+	ret = mlx5dr_action_handle_reformat_args(ctx, data_sz, data, bulk_size,
+						 action);
+	if (ret) {
+		DR_LOG(ERR, "Failed to create args for reformat");
+		return ret;
+	}
+
+	ret = mlx5dr_action_create_stcs(action, NULL);
+	if (ret) {
+		DR_LOG(ERR, "Failed to create stc for reformat");
+		goto free_arg;
+	}
+
+	return 0;
+
+free_arg:
+	mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
+	return ret;
+}
+
+static int mlx5dr_action_get_shared_stc_offset(struct mlx5dr_context_common_res *common_res,
+					       enum mlx5dr_context_shared_stc_type stc_type)
+{
+	return common_res->shared_stc[stc_type]->remove_header.offset;
+}
+
+static int mlx5dr_action_handle_l2_to_tunnel_l3(struct mlx5dr_context *ctx,
+						size_t data_sz,
+						void *data,
+						uint32_t bulk_size,
+						struct mlx5dr_action *action)
+{
+	int ret;
+
+	ret = mlx5dr_action_handle_reformat_args(ctx, data_sz, data, bulk_size,
+						 action);
+	if (ret) {
+		DR_LOG(ERR, "Failed to create args for reformat");
+		return ret;
+	}
+
+	/* The action is remove-l2-header + insert-l3-header */
+	ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP);
+	if (ret) {
+		DR_LOG(ERR, "Failed to create remove stc for reformat");
+		goto free_arg;
+	}
+
+	ret = mlx5dr_action_create_stcs(action, NULL);
+	if (ret) {
+		DR_LOG(ERR, "Failed to create insert stc for reformat");
+		goto down_shared;
+	}
+
+	return 0;
+
+down_shared:
+	mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP);
+free_arg:
+	mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
+	return ret;
+}
+
+static void mlx5dr_action_prepare_decap_l3_actions(size_t data_sz,
+						   uint8_t *mh_data,
+						   int *num_of_actions)
+{
+	int actions;
+	uint32_t i;
+
+	/* Remove L2L3 outer headers */
+	MLX5_SET(stc_ste_param_remove, mh_data, action_type,
+		 MLX5_MODIFICATION_TYPE_REMOVE);
+	MLX5_SET(stc_ste_param_remove, mh_data, decap, 0x1);
+	MLX5_SET(stc_ste_param_remove, mh_data, remove_start_anchor,
+		 MLX5_HEADER_ANCHOR_PACKET_START);
+	MLX5_SET(stc_ste_param_remove, mh_data, remove_end_anchor,
+		 MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4);
+	mh_data += MLX5DR_ACTION_DOUBLE_SIZE; /* Assume every action is 2 dw */
+	actions = 1;
+
+	/* Add the new header using inline action 4Byte at a time, the header
+	 * is added in reversed order to the beginning of the packet to avoid
+	 * incorrect parsing by the HW. Since header is 14B or 18B an extra
+	 * two bytes are padded and later removed.
+	 */
+	for (i = 0; i < data_sz / MLX5DR_ACTION_INLINE_DATA_SIZE + 1; i++) {
+		MLX5_SET(stc_ste_param_insert, mh_data, action_type,
+			 MLX5_MODIFICATION_TYPE_INSERT);
+		MLX5_SET(stc_ste_param_insert, mh_data, inline_data, 0x1);
+		MLX5_SET(stc_ste_param_insert, mh_data, insert_anchor,
+			 MLX5_HEADER_ANCHOR_PACKET_START);
+		MLX5_SET(stc_ste_param_insert, mh_data, insert_size, 2);
+		mh_data += MLX5DR_ACTION_DOUBLE_SIZE;
+		actions++;
+	}
+
+	/* Remove first 2 extra bytes */
+	MLX5_SET(stc_ste_param_remove_words, mh_data, action_type,
+		 MLX5_MODIFICATION_TYPE_REMOVE_WORDS);
+	MLX5_SET(stc_ste_param_remove_words, mh_data, remove_start_anchor,
+		 MLX5_HEADER_ANCHOR_PACKET_START);
+	/* The hardware expects here size in words (2 bytes) */
+	MLX5_SET(stc_ste_param_remove_words, mh_data, remove_size, 1);
+	actions++;
+
+	*num_of_actions = actions;
+}
+
+static int
+mlx5dr_action_handle_tunnel_l3_to_l2(struct mlx5dr_context *ctx,
+				     size_t data_sz,
+				     void *data,
+				     uint32_t bulk_size,
+				     struct mlx5dr_action *action)
+{
+	uint8_t mh_data[MLX5DR_ACTION_REFORMAT_DATA_SIZE] = {0};
+	int num_of_actions;
+	int mh_data_size;
+	int ret;
+
+	if (data_sz != MLX5DR_ACTION_HDR_LEN_L2 &&
+	    data_sz != MLX5DR_ACTION_HDR_LEN_L2_W_VLAN) {
+		DR_LOG(ERR, "Data size is not supported for decap-l3\n");
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	mlx5dr_action_prepare_decap_l3_actions(data_sz, mh_data, &num_of_actions);
+
+	mh_data_size = num_of_actions * MLX5DR_MODIFY_ACTION_SIZE;
+
+	ret = mlx5dr_pat_arg_create_modify_header(ctx, action, mh_data_size,
+						  (__be64 *)mh_data, bulk_size);
+	if (ret) {
+		DR_LOG(ERR, "Failed allocating modify-header for decap-l3\n");
+		return ret;
+	}
+
+	ret = mlx5dr_action_create_stcs(action, NULL);
+	if (ret)
+		goto free_mh_obj;
+
+	if (action->flags & MLX5DR_ACTION_FLAG_SHARED) {
+		mlx5dr_action_prepare_decap_l3_data(data, mh_data, num_of_actions);
+		ret = mlx5dr_arg_write_inline_arg_data(ctx,
+						       action->modify_header.arg_obj->id,
+						       (uint8_t *)mh_data,
+						       num_of_actions *
+						       MLX5DR_MODIFY_ACTION_SIZE);
+		if (ret) {
+			DR_LOG(ERR, "Failed writing INLINE arg decap_l3");
+			goto clean_stc;
+		}
+	}
+
+	return 0;
+
+clean_stc:
+	mlx5dr_action_destroy_stcs(action);
+free_mh_obj:
+	mlx5dr_pat_arg_destroy_modify_header(ctx, action);
+	return ret;
+}
+
+static int
+mlx5dr_action_create_reformat_hws(struct mlx5dr_context *ctx,
+				  size_t data_sz,
+				  void *data,
+				  uint32_t bulk_size,
+				  struct mlx5dr_action *action)
+{
+	int ret;
+
+	switch (action->type) {
+	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
+		ret = mlx5dr_action_create_stcs(action, NULL);
+		break;
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
+		ret = mlx5dr_action_handle_l2_to_tunnel_l2(ctx, data_sz, data, bulk_size, action);
+		break;
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
+		ret = mlx5dr_action_handle_l2_to_tunnel_l3(ctx, data_sz, data, bulk_size, action);
+		break;
+	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
+		ret = mlx5dr_action_handle_tunnel_l3_to_l2(ctx, data_sz, data, bulk_size, action);
+		break;
+
+	default:
+		assert(false);
+		rte_errno = ENOTSUP;
+		return rte_errno;
+	}
+
+	return ret;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
+			      enum mlx5dr_action_reformat_type reformat_type,
+			      size_t data_sz,
+			      void *inline_data,
+			      uint32_t log_bulk_size,
+			      uint32_t flags)
+{
+	enum mlx5dr_action_type action_type;
+	struct mlx5dr_action *action;
+	int ret;
+
+	ret = mlx5dr_action_conv_reformat_type_to_action(reformat_type, &action_type);
+	if (ret)
+		return NULL;
+
+	action = mlx5dr_action_create_generic(ctx, flags, action_type);
+	if (!action)
+		return NULL;
+
+	if (mlx5dr_action_is_root_flags(flags)) {
+		if (log_bulk_size) {
+			DR_LOG(ERR, "Bulk reformat not supported over root");
+			rte_errno = ENOTSUP;
+			goto free_action;
+		}
+
+		ret = mlx5dr_action_create_reformat_root(action, data_sz, inline_data);
+		if (ret)
+			goto free_action;
+
+		return action;
+	}
+
+	if (!mlx5dr_action_is_hws_flags(flags) ||
+	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) {
+		DR_LOG(ERR, "Reformat flags don't fit HWS (flags: %x0x)\n",
+			flags);
+		rte_errno = EINVAL;
+		goto free_action;
+	}
+
+	ret = mlx5dr_action_create_reformat_hws(ctx, data_sz, inline_data, log_bulk_size, action);
+	if (ret) {
+		DR_LOG(ERR, "Failed to create reformat.\n");
+		rte_errno = EINVAL;
+		goto free_action;
+	}
+
+	return action;
+
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+static int
+mlx5dr_action_create_modify_header_root(struct mlx5dr_action *action,
+					size_t actions_sz,
+					__be64 *actions)
+{
+	enum mlx5dv_flow_table_type ft_type = 0;
+	int ret;
+
+	ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type);
+	if (ret)
+		return rte_errno;
+
+	action->flow_action =
+		mlx5_glue->dv_create_flow_action_modify_header_root(action->ctx->ibv_ctx,
+								    actions_sz,
+								    (uint64_t *)actions,
+								    ft_type);
+	if (!action->flow_action) {
+		rte_errno = errno;
+		return rte_errno;
+	}
+
+	return 0;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_modify_header(struct mlx5dr_context *ctx,
+				   size_t pattern_sz,
+				   __be64 pattern[],
+				   uint32_t log_bulk_size,
+				   uint32_t flags)
+{
+	struct mlx5dr_action *action;
+	int ret;
+
+	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_MODIFY_HDR);
+	if (!action)
+		return NULL;
+
+	if (mlx5dr_action_is_root_flags(flags)) {
+		if (log_bulk_size) {
+			DR_LOG(ERR, "Bulk modify-header not supported over root");
+			rte_errno = ENOTSUP;
+			goto free_action;
+		}
+		ret = mlx5dr_action_create_modify_header_root(action, pattern_sz, pattern);
+		if (ret)
+			goto free_action;
+
+		return action;
+	}
+
+	if (!mlx5dr_action_is_hws_flags(flags) ||
+	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) {
+		DR_LOG(ERR, "Flags don't fit hws (flags: %x0x, log_bulk_size: %d)\n",
+			flags, log_bulk_size);
+		rte_errno = EINVAL;
+		goto free_action;
+	}
+
+	if (pattern_sz / MLX5DR_MODIFY_ACTION_SIZE == 1) {
+		/* Optimize single modiy action to be used inline */
+		action->modify_header.single_action = pattern[0];
+		action->modify_header.num_of_actions = 1;
+		action->modify_header.single_action_type =
+			MLX5_GET(set_action_in, pattern, action_type);
+	} else {
+		/* Use multi action pattern and argument */
+		ret = mlx5dr_pat_arg_create_modify_header(ctx, action, pattern_sz,
+							  pattern, log_bulk_size);
+		if (ret) {
+			DR_LOG(ERR, "Failed allocating modify-header\n");
+			goto free_action;
+		}
+	}
+
+	ret = mlx5dr_action_create_stcs(action, NULL);
+	if (ret)
+		goto free_mh_obj;
+
+	return action;
+
+free_mh_obj:
+	if (action->modify_header.num_of_actions > 1)
+		mlx5dr_pat_arg_destroy_modify_header(ctx, action);
+free_action:
+	simple_free(action);
+	return NULL;
+}
+
+static void mlx5dr_action_destroy_hws(struct mlx5dr_action *action)
+{
+	switch (action->type) {
+	case MLX5DR_ACTION_TYP_TIR:
+	case MLX5DR_ACTION_TYP_MISS:
+	case MLX5DR_ACTION_TYP_TAG:
+	case MLX5DR_ACTION_TYP_DROP:
+	case MLX5DR_ACTION_TYP_CTR:
+	case MLX5DR_ACTION_TYP_FT:
+	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
+	case MLX5DR_ACTION_TYP_ASO_METER:
+	case MLX5DR_ACTION_TYP_ASO_CT:
+	case MLX5DR_ACTION_TYP_PUSH_VLAN:
+		mlx5dr_action_destroy_stcs(action);
+		break;
+	case MLX5DR_ACTION_TYP_POP_VLAN:
+		mlx5dr_action_destroy_stcs(action);
+		mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_POP);
+		break;
+	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
+	case MLX5DR_ACTION_TYP_MODIFY_HDR:
+		mlx5dr_action_destroy_stcs(action);
+		if (action->modify_header.num_of_actions > 1)
+			mlx5dr_pat_arg_destroy_modify_header(action->ctx, action);
+		break;
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
+		mlx5dr_action_destroy_stcs(action);
+		mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP);
+		mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
+		break;
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
+		mlx5dr_action_destroy_stcs(action);
+		mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
+		break;
+	}
+}
+
+static void mlx5dr_action_destroy_root(struct mlx5dr_action *action)
+{
+	switch (action->type) {
+	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
+	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
+	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
+	case MLX5DR_ACTION_TYP_MODIFY_HDR:
+		ibv_destroy_flow_action(action->flow_action);
+		break;
+	}
+}
+
+int mlx5dr_action_destroy(struct mlx5dr_action *action)
+{
+	if (mlx5dr_action_is_root_flags(action->flags))
+		mlx5dr_action_destroy_root(action);
+	else
+		mlx5dr_action_destroy_hws(action);
+
+	simple_free(action);
+	return 0;
+}
+
+/* Called under pthread_spin_lock(&ctx->ctrl_lock) */
+int mlx5dr_action_get_default_stc(struct mlx5dr_context *ctx,
+				  uint8_t tbl_type)
+{
+	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
+	struct mlx5dr_action_default_stc *default_stc;
+	int ret;
+
+	if (ctx->common_res[tbl_type].default_stc) {
+		ctx->common_res[tbl_type].default_stc->refcount++;
+		return 0;
+	}
+
+	default_stc = simple_calloc(1, sizeof(*default_stc));
+	if (!default_stc) {
+		DR_LOG(ERR, "Failed to allocate memory for default STCs");
+		rte_errno = ENOMEM;
+		return rte_errno;
+	}
+
+	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_NOP;
+	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW0;
+	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
+					     &default_stc->nop_ctr);
+	if (ret) {
+		DR_LOG(ERR, "Failed to allocate default counter STC");
+		goto free_default_stc;
+	}
+
+	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5;
+	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
+					     &default_stc->nop_dw5);
+	if (ret) {
+		DR_LOG(ERR, "Failed to allocate default NOP DW5 STC");
+		goto free_nop_ctr;
+	}
+
+	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW6;
+	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
+					     &default_stc->nop_dw6);
+	if (ret) {
+		DR_LOG(ERR, "Failed to allocate default NOP DW6 STC");
+		goto free_nop_dw5;
+	}
+
+	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW7;
+	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
+					     &default_stc->nop_dw7);
+	if (ret) {
+		DR_LOG(ERR, "Failed to allocate default NOP DW7 STC");
+		goto free_nop_dw6;
+	}
+
+	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW;
+	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
+	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
+					     &default_stc->default_hit);
+	if (ret) {
+		DR_LOG(ERR, "Failed to allocate default allow STC");
+		goto free_nop_dw7;
+	}
+
+	ctx->common_res[tbl_type].default_stc = default_stc;
+	ctx->common_res[tbl_type].default_stc->refcount++;
+
+	return 0;
+
+free_nop_dw7:
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7);
+free_nop_dw6:
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6);
+free_nop_dw5:
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5);
+free_nop_ctr:
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr);
+free_default_stc:
+	simple_free(default_stc);
+	return rte_errno;
+}
+
+void mlx5dr_action_put_default_stc(struct mlx5dr_context *ctx,
+				   uint8_t tbl_type)
+{
+	struct mlx5dr_action_default_stc *default_stc;
+
+	default_stc = ctx->common_res[tbl_type].default_stc;
+
+	default_stc = ctx->common_res[tbl_type].default_stc;
+	if (--default_stc->refcount)
+		return;
+
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->default_hit);
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7);
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6);
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5);
+	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr);
+	simple_free(default_stc);
+	ctx->common_res[tbl_type].default_stc = NULL;
+}
+
+static void mlx5dr_action_modify_write(struct mlx5dr_send_engine *queue,
+				       uint32_t arg_idx,
+				       uint8_t *arg_data,
+				       uint16_t num_of_actions)
+{
+	mlx5dr_arg_write(queue, NULL, arg_idx, arg_data,
+			 num_of_actions * MLX5DR_MODIFY_ACTION_SIZE);
+}
+
+void
+mlx5dr_action_prepare_decap_l3_data(uint8_t *src, uint8_t *dst,
+				    uint16_t num_of_actions)
+{
+	uint8_t *e_src;
+	int i;
+
+	/* num_of_actions = remove l3l2 + 4/5 inserts + remove extra 2 bytes
+	 * copy from end of src to the start of dst.
+	 * move to the end, 2 is the leftover from 14B or 18B
+	 */
+	if (num_of_actions == DECAP_L3_NUM_ACTIONS_W_NO_VLAN)
+		e_src = src + MLX5DR_ACTION_HDR_LEN_L2;
+	else
+		e_src = src + MLX5DR_ACTION_HDR_LEN_L2_W_VLAN;
+
+	/* Move dst over the first remove action + zero data */
+	dst += MLX5DR_ACTION_DOUBLE_SIZE;
+	/* Move dst over the first insert ctrl action */
+	dst += MLX5DR_ACTION_DOUBLE_SIZE / 2;
+	/* Actions:
+	 * no vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b.
+	 * with vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b.
+	 * the loop is without the last insertion.
+	 */
+	for (i = 0; i < num_of_actions - 3; i++) {
+		e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE;
+		memcpy(dst, e_src, MLX5DR_ACTION_INLINE_DATA_SIZE); /* data */
+		dst += MLX5DR_ACTION_DOUBLE_SIZE;
+	}
+	/* Copy the last 2 bytes after a gap of 2 bytes which will be removed */
+	e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE / 2;
+	dst += MLX5DR_ACTION_INLINE_DATA_SIZE / 2;
+	memcpy(dst, e_src, 2);
+}
+
+static struct mlx5dr_actions_wqe_setter *
+mlx5dr_action_setter_find_first(struct mlx5dr_actions_wqe_setter *setter,
+				uint8_t req_flags)
+{
+	/* Use a new setter if requested flags are taken */
+	while (setter->flags & req_flags)
+		setter++;
+
+	/* Use current setter in required flags are not used */
+	return setter;
+}
+
+static void
+mlx5dr_action_apply_stc(struct mlx5dr_actions_apply_data *apply,
+			enum mlx5dr_action_stc_idx stc_idx,
+			uint8_t action_idx)
+{
+	struct mlx5dr_action *action = apply->rule_action[action_idx].action;
+
+	apply->wqe_ctrl->stc_ix[stc_idx] =
+		htobe32(action->stc[apply->tbl_type].offset);
+}
+
+static void
+mlx5dr_action_setter_push_vlan(struct mlx5dr_actions_apply_data *apply,
+			       struct mlx5dr_actions_wqe_setter *setter)
+{
+	struct mlx5dr_rule_action *rule_action;
+
+	rule_action = &apply->rule_action[setter->idx_double];
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = rule_action->push_vlan.vlan_hdr;
+
+	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
+}
+
+static void
+mlx5dr_action_setter_modify_header(struct mlx5dr_actions_apply_data *apply,
+				   struct mlx5dr_actions_wqe_setter *setter)
+{
+	struct mlx5dr_rule_action *rule_action;
+	struct mlx5dr_action *action;
+	uint32_t arg_sz, arg_idx;
+	uint8_t *single_action;
+
+	rule_action = &apply->rule_action[setter->idx_double];
+	action = rule_action->action;
+	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
+
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
+
+	if (action->modify_header.num_of_actions == 1) {
+		if (action->modify_header.single_action_type ==
+		    MLX5_MODIFICATION_TYPE_COPY) {
+			apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = 0;
+			return;
+		}
+
+		if (action->flags & MLX5DR_ACTION_FLAG_SHARED)
+			single_action = (uint8_t *)&action->modify_header.single_action;
+		else
+			single_action = rule_action->modify_header.data;
+
+		apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] =
+			*(__be32 *)MLX5_ADDR_OF(set_action_in, single_action, data);
+	} else {
+		/* Argument offset multiple with number of args per these actions */
+		arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.num_of_actions);
+		arg_idx = rule_action->modify_header.offset * arg_sz;
+
+		apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
+
+		if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
+			apply->require_dep = 1;
+			mlx5dr_action_modify_write(apply->queue,
+						   action->modify_header.arg_obj->id + arg_idx,
+						   rule_action->modify_header.data,
+						   action->modify_header.num_of_actions);
+		}
+	}
+}
+
+static void
+mlx5dr_action_setter_insert_ptr(struct mlx5dr_actions_apply_data *apply,
+				struct mlx5dr_actions_wqe_setter *setter)
+{
+	struct mlx5dr_rule_action *rule_action;
+	uint32_t arg_idx, arg_sz;
+
+	rule_action = &apply->rule_action[setter->idx_double];
+
+	/* Argument offset multiple on args required for header size */
+	arg_sz = mlx5dr_arg_data_size_to_arg_size(rule_action->action->reformat.header_size);
+	arg_idx = rule_action->reformat.offset * arg_sz;
+
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
+
+	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
+
+	if (!(rule_action->action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
+		apply->require_dep = 1;
+		mlx5dr_arg_write(apply->queue, NULL,
+				 rule_action->action->reformat.arg_obj->id + arg_idx,
+				 rule_action->reformat.data,
+				 rule_action->action->reformat.header_size);
+	}
+}
+
+static void
+mlx5dr_action_setter_tnl_l3_to_l2(struct mlx5dr_actions_apply_data *apply,
+				  struct mlx5dr_actions_wqe_setter *setter)
+{
+	struct mlx5dr_rule_action *rule_action;
+	struct mlx5dr_action *action;
+	uint32_t arg_sz, arg_idx;
+
+	rule_action = &apply->rule_action[setter->idx_double];
+	action = rule_action->action;
+
+	/* Argument offset multiple on args required for num of actions */
+	arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.num_of_actions);
+	arg_idx = rule_action->reformat.offset * arg_sz;
+
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
+
+	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
+
+	if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
+		apply->require_dep = 1;
+		mlx5dr_arg_decapl3_write(apply->queue,
+					 action->modify_header.arg_obj->id + arg_idx,
+					 rule_action->reformat.data,
+					 action->modify_header.num_of_actions);
+	}
+}
+
+static void
+mlx5dr_action_setter_aso(struct mlx5dr_actions_apply_data *apply,
+			 struct mlx5dr_actions_wqe_setter *setter)
+{
+	struct mlx5dr_rule_action *rule_action;
+	uint32_t exe_aso_ctrl;
+	uint32_t offset;
+
+	rule_action = &apply->rule_action[setter->idx_double];
+
+	switch (rule_action->action->type) {
+	case MLX5DR_ACTION_TYP_ASO_METER:
+		/* exe_aso_ctrl format:
+		 * [STC only and reserved bits 29b][init_color 2b][meter_id 1b]
+		 */
+		offset = rule_action->aso_meter.offset / MLX5_ASO_METER_NUM_PER_OBJ;
+		exe_aso_ctrl = rule_action->aso_meter.offset % MLX5_ASO_METER_NUM_PER_OBJ;
+		exe_aso_ctrl |= rule_action->aso_meter.init_color <<
+				MLX5DR_ACTION_METER_INIT_COLOR_OFFSET;
+		break;
+	case MLX5DR_ACTION_TYP_ASO_CT:
+		/* exe_aso_ctrl CT format:
+		 * [STC only and reserved bits 31b][direction 1b]
+		 */
+		offset = rule_action->aso_ct.offset / MLX5_ASO_CT_NUM_PER_OBJ;
+		exe_aso_ctrl = rule_action->aso_ct.direction;
+		break;
+	default:
+		DR_LOG(ERR, "Unsupported ASO action type: %d", rule_action->action->type);
+		rte_errno = ENOTSUP;
+		return;
+	}
+
+	/* aso_object_offset format: [24B] */
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = htobe32(offset);
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(exe_aso_ctrl);
+
+	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
+}
+
+static void
+mlx5dr_action_setter_tag(struct mlx5dr_actions_apply_data *apply,
+			 struct mlx5dr_actions_wqe_setter *setter)
+{
+	struct mlx5dr_rule_action *rule_action;
+
+	rule_action = &apply->rule_action[setter->idx_single];
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = htobe32(rule_action->tag.value);
+	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single);
+}
+
+static void
+mlx5dr_action_setter_ctrl_ctr(struct mlx5dr_actions_apply_data *apply,
+			      struct mlx5dr_actions_wqe_setter *setter)
+{
+	struct mlx5dr_rule_action *rule_action;
+
+	rule_action = &apply->rule_action[setter->idx_ctr];
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW0] = htobe32(rule_action->counter.offset);
+	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_CTRL, setter->idx_ctr);
+}
+
+static void
+mlx5dr_action_setter_single(struct mlx5dr_actions_apply_data *apply,
+			    struct mlx5dr_actions_wqe_setter *setter)
+{
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
+	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single);
+}
+
+static void
+mlx5dr_action_setter_single_double_pop(struct mlx5dr_actions_apply_data *apply,
+				       __rte_unused struct mlx5dr_actions_wqe_setter *setter)
+{
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] =
+		htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res,
+						    MLX5DR_CONTEXT_SHARED_STC_POP));
+}
+
+static void
+mlx5dr_action_setter_hit(struct mlx5dr_actions_apply_data *apply,
+			 struct mlx5dr_actions_wqe_setter *setter)
+{
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0;
+	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_HIT, setter->idx_hit);
+}
+
+static void
+mlx5dr_action_setter_default_hit(struct mlx5dr_actions_apply_data *apply,
+				 __rte_unused struct mlx5dr_actions_wqe_setter *setter)
+{
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0;
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] =
+		htobe32(apply->common_res->default_stc->default_hit.offset);
+}
+
+static void
+mlx5dr_action_setter_hit_next_action(struct mlx5dr_actions_apply_data *apply,
+				     __rte_unused struct mlx5dr_actions_wqe_setter *setter)
+{
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = htobe32(apply->next_direct_idx << 6);
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] = htobe32(apply->jump_to_action_stc);
+}
+
+static void
+mlx5dr_action_setter_common_decap(struct mlx5dr_actions_apply_data *apply,
+				  __rte_unused struct mlx5dr_actions_wqe_setter *setter)
+{
+	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] =
+		htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res,
+							    MLX5DR_CONTEXT_SHARED_STC_DECAP));
+}
+
+int mlx5dr_action_template_process(struct mlx5dr_action_template *at)
+{
+	struct mlx5dr_actions_wqe_setter *start_setter = at->setters + 1;
+	enum mlx5dr_action_type *action_type = at->action_type_arr;
+	struct mlx5dr_actions_wqe_setter *setter = at->setters;
+	struct mlx5dr_actions_wqe_setter *pop_setter = NULL;
+	struct mlx5dr_actions_wqe_setter *last_setter;
+	int i;
+
+	/* Note: Given action combination must be valid */
+
+	/* Check if action were already processed */
+	if (at->num_of_action_stes)
+		return 0;
+
+	for (i = 0; i < MLX5DR_ACTION_MAX_STE; i++)
+		setter[i].set_hit = &mlx5dr_action_setter_hit_next_action;
+
+	/* The same action template setters can be used with jumbo or match
+	 * STE, to support both cases we reseve the first setter for cases
+	 * with jumbo STE to allow jump to the first action STE.
+	 * This extra setter can be reduced in some cases on rule creation.
+	 */
+	setter = start_setter;
+	last_setter = start_setter;
+
+	for (i = 0; i < at->num_actions; i++) {
+		switch (action_type[i]) {
+		case MLX5DR_ACTION_TYP_DROP:
+		case MLX5DR_ACTION_TYP_TIR:
+		case MLX5DR_ACTION_TYP_FT:
+		case MLX5DR_ACTION_TYP_VPORT:
+		case MLX5DR_ACTION_TYP_MISS:
+			/* Hit action */
+			last_setter->flags |= ASF_HIT;
+			last_setter->set_hit = &mlx5dr_action_setter_hit;
+			last_setter->idx_hit = i;
+			break;
+
+		case MLX5DR_ACTION_TYP_POP_VLAN:
+			/* Single remove header to header */
+			if (pop_setter) {
+				/* We have 2 pops, use the shared */
+				pop_setter->set_single = &mlx5dr_action_setter_single_double_pop;
+				break;
+			}
+			setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_MODIFY);
+			setter->flags |= ASF_SINGLE1 | ASF_REPARSE | ASF_REMOVE;
+			setter->set_single = &mlx5dr_action_setter_single;
+			setter->idx_single = i;
+			pop_setter = setter;
+			break;
+
+		case MLX5DR_ACTION_TYP_PUSH_VLAN:
+			/* Double insert inline */
+			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
+			setter->flags |= ASF_DOUBLE | ASF_REPARSE | ASF_MODIFY;
+			setter->set_double = &mlx5dr_action_setter_push_vlan;
+			setter->idx_double = i;
+			break;
+
+		case MLX5DR_ACTION_TYP_MODIFY_HDR:
+			/* Double modify header list */
+			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
+			setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_REPARSE;
+			setter->set_double = &mlx5dr_action_setter_modify_header;
+			setter->idx_double = i;
+			break;
+
+		case MLX5DR_ACTION_TYP_ASO_METER:
+		case MLX5DR_ACTION_TYP_ASO_CT:
+			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE);
+			setter->flags |= ASF_DOUBLE;
+			setter->set_double = &mlx5dr_action_setter_aso;
+			setter->idx_double = i;
+			break;
+
+		case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
+			/* Single remove header to header */
+			setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_MODIFY);
+			setter->flags |= ASF_SINGLE1 | ASF_REMOVE | ASF_REPARSE;
+			setter->set_single = &mlx5dr_action_setter_single;
+			setter->idx_single = i;
+			break;
+
+		case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
+			/* Double insert header with pointer */
+			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE);
+			setter->flags |= ASF_DOUBLE | ASF_REPARSE;
+			setter->set_double = &mlx5dr_action_setter_insert_ptr;
+			setter->idx_double = i;
+			break;
+
+		case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
+			/* Single remove + Double insert header with pointer */
+			setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_DOUBLE);
+			setter->flags |= ASF_SINGLE1 | ASF_DOUBLE | ASF_REPARSE | ASF_REMOVE;
+			setter->set_double = &mlx5dr_action_setter_insert_ptr;
+			setter->idx_double = i;
+			setter->set_single = &mlx5dr_action_setter_common_decap;
+			setter->idx_single = i;
+			break;
+
+		case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
+			/* Double modify header list with remove and push inline */
+			setter = mlx5dr_action_setter_find_first(last_setter,
+								 ASF_DOUBLE | ASF_REMOVE);
+			setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_REPARSE;
+			setter->set_double = &mlx5dr_action_setter_tnl_l3_to_l2;
+			setter->idx_double = i;
+			break;
+
+		case MLX5DR_ACTION_TYP_TAG:
+			/* Single TAG action, search for any room from the start */
+			setter = mlx5dr_action_setter_find_first(start_setter, ASF_SINGLE1);
+			setter->flags |= ASF_SINGLE1;
+			setter->set_single = &mlx5dr_action_setter_tag;
+			setter->idx_single = i;
+			break;
+
+		case MLX5DR_ACTION_TYP_CTR:
+			/* Control counter action
+			 * TODO: Current counter executed first. Support is needed
+			 *	 for single ation counter action which is done last.
+			 *	 Example: Decap + CTR
+			 */
+			setter = mlx5dr_action_setter_find_first(start_setter, ASF_CTR);
+			setter->flags |= ASF_CTR;
+			setter->set_ctr = &mlx5dr_action_setter_ctrl_ctr;
+			setter->idx_ctr = i;
+			break;
+
+		default:
+			DR_LOG(ERR, "Unsupported action type: %d", action_type[i]);
+			rte_errno = ENOTSUP;
+			assert(false);
+			return rte_errno;
+		}
+
+		last_setter = RTE_MAX(setter, last_setter);
+	}
+
+	/* Set default hit on the last STE if no hit action provided */
+	if (!(last_setter->flags & ASF_HIT))
+		last_setter->set_hit = &mlx5dr_action_setter_default_hit;
+
+	at->num_of_action_stes = last_setter - start_setter + 1;
+
+	/* Check if action template doesn't require any action DWs */
+	at->only_term = (at->num_of_action_stes == 1) &&
+		!(last_setter->flags & ~(ASF_CTR | ASF_HIT));
+
+	return 0;
+}
+
+struct mlx5dr_action_template *
+mlx5dr_action_template_create(const enum mlx5dr_action_type action_type[])
+{
+	struct mlx5dr_action_template *at;
+	uint8_t num_actions = 0;
+	int i;
+
+	at = simple_calloc(1, sizeof(*at));
+	if (!at) {
+		DR_LOG(ERR, "Failed to allocate action template");
+		rte_errno = ENOMEM;
+		return NULL;
+	}
+
+	while (action_type[num_actions++] != MLX5DR_ACTION_TYP_LAST)
+		;
+
+	at->num_actions = num_actions - 1;
+	at->action_type_arr = simple_calloc(num_actions, sizeof(*action_type));
+	if (!at->action_type_arr) {
+		DR_LOG(ERR, "Failed to allocate action type array");
+		rte_errno = ENOMEM;
+		goto free_at;
+	}
+
+	for (i = 0; i < num_actions; i++)
+		at->action_type_arr[i] = action_type[i];
+
+	return at;
+
+free_at:
+	simple_free(at);
+	return NULL;
+}
+
+int mlx5dr_action_template_destroy(struct mlx5dr_action_template *at)
+{
+	simple_free(at->action_type_arr);
+	simple_free(at);
+	return 0;
+}
drivers/net/mlx5/hws/mlx5dr_action.h new file +253 -0

253 lines not on this page · raw message

drivers/net/mlx5/hws/mlx5dr_pat_arg.c new file +511 -0

510 lines not on this page · raw message

drivers/net/mlx5/hws/mlx5dr_pat_arg.h new file +83 -0

83 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.18.1

Part of the diff is not shown here. View the raw message.

#129 lore raw

PATCH v6 17/18 net/mlx5/hws: Add HWS debug layer

In reply to Alex Vesker

From: Hamdan Igbaria <[email protected]>

The debug layer is used to generate a debug CSV file containing details of the context, table, matcher, rules and other useful debug information.

---
 drivers/net/mlx5/hws/mlx5dr_debug.c | 462 ++++++++++++++++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_debug.h |  28 ++
 2 files changed, 490 insertions(+)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_debug.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_debug.h
drivers/net/mlx5/hws/mlx5dr_debug.c new file +462 -0
new file mode 100644
index 0000000000..890a761c48
@@ -0,0 +1,462 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#include "mlx5dr_internal.h"
+
+const char *mlx5dr_debug_action_type_str[] = {
+	[MLX5DR_ACTION_TYP_LAST] = "LAST",
+	[MLX5DR_ACTION_TYP_TNL_L2_TO_L2] = "TNL_L2_TO_L2",
+	[MLX5DR_ACTION_TYP_L2_TO_TNL_L2] = "L2_TO_TNL_L2",
+	[MLX5DR_ACTION_TYP_TNL_L3_TO_L2] = "TNL_L3_TO_L2",
+	[MLX5DR_ACTION_TYP_L2_TO_TNL_L3] = "L2_TO_TNL_L3",
+	[MLX5DR_ACTION_TYP_DROP] = "DROP",
+	[MLX5DR_ACTION_TYP_TIR] = "TIR",
+	[MLX5DR_ACTION_TYP_FT] = "FT",
+	[MLX5DR_ACTION_TYP_CTR] = "CTR",
+	[MLX5DR_ACTION_TYP_TAG] = "TAG",
+	[MLX5DR_ACTION_TYP_MODIFY_HDR] = "MODIFY_HDR",
+	[MLX5DR_ACTION_TYP_VPORT] = "VPORT",
+	[MLX5DR_ACTION_TYP_MISS] = "DEFAULT_MISS",
+	[MLX5DR_ACTION_TYP_POP_VLAN] = "POP_VLAN",
+	[MLX5DR_ACTION_TYP_PUSH_VLAN] = "PUSH_VLAN",
+	[MLX5DR_ACTION_TYP_ASO_METER] = "ASO_METER",
+	[MLX5DR_ACTION_TYP_ASO_CT] = "ASO_CT",
+};
+
+static_assert(ARRAY_SIZE(mlx5dr_debug_action_type_str) == MLX5DR_ACTION_TYP_MAX,
+	      "Missing mlx5dr_debug_action_type_str");
+
+const char *mlx5dr_debug_action_type_to_str(enum mlx5dr_action_type action_type)
+{
+	return mlx5dr_debug_action_type_str[action_type];
+}
+
+static int
+mlx5dr_debug_dump_matcher_template_definer(FILE *f,
+					   struct mlx5dr_match_template *mt)
+{
+	struct mlx5dr_definer *definer = mt->definer;
+	int i, ret;
+
+	ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",%d,%d,",
+		      MLX5DR_DEBUG_RES_TYPE_MATCHER_TEMPLATE_DEFINER,
+		      (uint64_t)(uintptr_t)definer,
+		      (uint64_t)(uintptr_t)mt,
+		      definer->obj->id,
+		      definer->type);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	for (i = 0; i < DW_SELECTORS; i++) {
+		ret = fprintf(f, "0x%x%s", definer->dw_selector[i],
+			      (i == DW_SELECTORS - 1) ? "," : "-");
+		if (ret < 0) {
+			rte_errno = EINVAL;
+			return rte_errno;
+		}
+	}
+
+	for (i = 0; i < BYTE_SELECTORS; i++) {
+		ret = fprintf(f, "0x%x%s", definer->byte_selector[i],
+			      (i == BYTE_SELECTORS - 1) ? "," : "-");
+		if (ret < 0) {
+			rte_errno = EINVAL;
+			return rte_errno;
+		}
+	}
+
+	for (i = 0; i < MLX5DR_JUMBO_TAG_SZ; i++) {
+		ret = fprintf(f, "%02x", definer->mask.jumbo[i]);
+		if (ret < 0) {
+			rte_errno = EINVAL;
+			return rte_errno;
+		}
+	}
+
+	ret = fprintf(f, "\n");
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	return 0;
+}
+
+static int
+mlx5dr_debug_dump_matcher_match_template(FILE *f, struct mlx5dr_matcher *matcher)
+{
+	bool is_root = matcher->tbl->level == MLX5DR_ROOT_LEVEL;
+	int i, ret;
+
+	for (i = 0; i < matcher->num_of_mt; i++) {
+		struct mlx5dr_match_template *mt = matcher->mt[i];
+
+		ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",%d,%d\n",
+			      MLX5DR_DEBUG_RES_TYPE_MATCHER_MATCH_TEMPLATE,
+			      (uint64_t)(uintptr_t)mt,
+			      (uint64_t)(uintptr_t)matcher,
+			      is_root ? 0 : mt->fc_sz,
+			      mt->flags);
+		if (ret < 0) {
+			rte_errno = EINVAL;
+			return rte_errno;
+		}
+
+		if (!is_root) {
+			ret = mlx5dr_debug_dump_matcher_template_definer(f, mt);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int
+mlx5dr_debug_dump_matcher_action_template(FILE *f, struct mlx5dr_matcher *matcher)
+{
+	bool is_root = matcher->tbl->level == MLX5DR_ROOT_LEVEL;
+	enum mlx5dr_action_type action_type;
+	int i, j, ret;
+
+	for (i = 0; i < matcher->num_of_at; i++) {
+		struct mlx5dr_action_template *at = matcher->at[i];
+
+		ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",%d,%d,%d",
+			      MLX5DR_DEBUG_RES_TYPE_MATCHER_ACTION_TEMPLATE,
+			      (uint64_t)(uintptr_t)at,
+			      (uint64_t)(uintptr_t)matcher,
+			      at->only_term ? 0 : 1,
+			      is_root ? 0 : at->num_of_action_stes,
+			      at->num_actions);
+		if (ret < 0) {
+			rte_errno = EINVAL;
+			return rte_errno;
+		}
+
+		for (j = 0; j < at->num_actions; j++) {
+			action_type = at->action_type_arr[j];
+			ret = fprintf(f, ",%s", mlx5dr_debug_action_type_to_str(action_type));
+			if (ret < 0) {
+				rte_errno = EINVAL;
+				return rte_errno;
+			}
+		}
+
+		fprintf(f, "\n");
+	}
+
+	return 0;
+}
+
+static int
+mlx5dr_debug_dump_matcher_attr(FILE *f, struct mlx5dr_matcher *matcher)
+{
+	struct mlx5dr_matcher_attr *attr = &matcher->attr;
+	int ret;
+
+	ret = fprintf(f, "%d,0x%" PRIx64 ",%d,%d,%d,%d,%d,%d\n",
+		      MLX5DR_DEBUG_RES_TYPE_MATCHER_ATTR,
+		      (uint64_t)(uintptr_t)matcher,
+		      attr->priority,
+		      attr->mode,
+		      attr->table.sz_row_log,
+		      attr->table.sz_col_log,
+		      attr->optimize_using_rule_idx,
+		      attr->optimize_flow_src);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	return 0;
+}
+
+static int mlx5dr_debug_dump_matcher(FILE *f, struct mlx5dr_matcher *matcher)
+{
+	bool is_root = matcher->tbl->level == MLX5DR_ROOT_LEVEL;
+	enum mlx5dr_table_type tbl_type = matcher->tbl->type;
+	struct mlx5dr_devx_obj *ste_0, *ste_1 = NULL;
+	struct mlx5dr_pool_chunk *ste;
+	struct mlx5dr_pool *ste_pool;
+	int ret;
+
+	ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",%d,%d,0x%" PRIx64,
+		      MLX5DR_DEBUG_RES_TYPE_MATCHER,
+		      (uint64_t)(uintptr_t)matcher,
+		      (uint64_t)(uintptr_t)matcher->tbl,
+		      matcher->num_of_mt,
+		      is_root ? 0 : matcher->end_ft->id,
+		      matcher->col_matcher ? (uint64_t)(uintptr_t)matcher->col_matcher : 0);
+	if (ret < 0)
+		goto out_err;
+
+	ste = &matcher->match_ste.ste;
+	ste_pool = matcher->match_ste.pool;
+	if (ste_pool) {
+		ste_0 = mlx5dr_pool_chunk_get_base_devx_obj(ste_pool, ste);
+		if (tbl_type == MLX5DR_TABLE_TYPE_FDB)
+			ste_1 = mlx5dr_pool_chunk_get_base_devx_obj_mirror(ste_pool, ste);
+	} else {
+		ste_0 = NULL;
+		ste_1 = NULL;
+	}
+
+	ret = fprintf(f, ",%d,%d,%d,%d",
+		      matcher->match_ste.rtc_0 ? matcher->match_ste.rtc_0->id : 0,
+		      ste_0 ? (int)ste_0->id : -1,
+		      matcher->match_ste.rtc_1 ? matcher->match_ste.rtc_1->id : 0,
+		      ste_1 ? (int)ste_1->id : -1);
+	if (ret < 0)
+		goto out_err;
+
+	ste = &matcher->action_ste.ste;
+	ste_pool = matcher->action_ste.pool;
+	if (ste_pool) {
+		ste_0 = mlx5dr_pool_chunk_get_base_devx_obj(ste_pool, ste);
+		if (tbl_type == MLX5DR_TABLE_TYPE_FDB)
+			ste_1 = mlx5dr_pool_chunk_get_base_devx_obj_mirror(ste_pool, ste);
+	} else {
+		ste_0 = NULL;
+		ste_1 = NULL;
+	}
+
+	ret = fprintf(f, ",%d,%d,%d,%d\n",
+		      matcher->action_ste.rtc_0 ? matcher->action_ste.rtc_0->id : 0,
+		      ste_0 ? (int)ste_0->id : -1,
+		      matcher->action_ste.rtc_1 ? matcher->action_ste.rtc_1->id : 0,
+		      ste_1 ? (int)ste_1->id : -1);
+	if (ret < 0)
+		goto out_err;
+
+	ret = mlx5dr_debug_dump_matcher_attr(f, matcher);
+	if (ret)
+		return ret;
+
+	ret = mlx5dr_debug_dump_matcher_match_template(f, matcher);
+	if (ret)
+		return ret;
+
+	ret = mlx5dr_debug_dump_matcher_action_template(f, matcher);
+	if (ret)
+		return ret;
+
+	return 0;
+
+out_err:
+	rte_errno = EINVAL;
+	return rte_errno;
+}
+
+static int mlx5dr_debug_dump_table(FILE *f, struct mlx5dr_table *tbl)
+{
+	bool is_root = tbl->level == MLX5DR_ROOT_LEVEL;
+	struct mlx5dr_matcher *matcher;
+	int ret;
+
+	ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",%d,%d,%d,%d\n",
+		      MLX5DR_DEBUG_RES_TYPE_TABLE,
+		      (uint64_t)(uintptr_t)tbl,
+		      (uint64_t)(uintptr_t)tbl->ctx,
+		      is_root ? 0 : tbl->ft->id,
+		      tbl->type,
+		      is_root ? 0 : tbl->fw_ft_type,
+		      tbl->level);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	LIST_FOREACH(matcher, &tbl->head, next) {
+		ret = mlx5dr_debug_dump_matcher(f, matcher);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int
+mlx5dr_debug_dump_context_send_engine(FILE *f, struct mlx5dr_context *ctx)
+{
+	struct mlx5dr_send_engine *send_queue;
+	int ret, i, j;
+
+	for (i = 0; i < (int)ctx->queues; i++) {
+		send_queue = &ctx->send_queue[i];
+		ret = fprintf(f, "%d,0x%" PRIx64 ",%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+			      MLX5DR_DEBUG_RES_TYPE_CONTEXT_SEND_ENGINE,
+			      (uint64_t)(uintptr_t)ctx,
+			      i,
+			      send_queue->used_entries,
+			      send_queue->th_entries,
+			      send_queue->rings,
+			      send_queue->num_entries,
+			      send_queue->err,
+			      send_queue->completed.ci,
+			      send_queue->completed.pi,
+			      send_queue->completed.mask);
+		if (ret < 0) {
+			rte_errno = EINVAL;
+			return rte_errno;
+		}
+
+		for (j = 0; j < MLX5DR_NUM_SEND_RINGS; j++) {
+			struct mlx5dr_send_ring *send_ring = &send_queue->send_ring[j];
+			struct mlx5dr_send_ring_cq *cq = &send_ring->send_cq;
+			struct mlx5dr_send_ring_sq *sq = &send_ring->send_sq;
+
+			ret = fprintf(f, "%d,0x%" PRIx64 ",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+				      MLX5DR_DEBUG_RES_TYPE_CONTEXT_SEND_RING,
+				      (uint64_t)(uintptr_t)ctx,
+				      j,
+				      i,
+				      cq->cqn,
+				      cq->cons_index,
+				      cq->ncqe_mask,
+				      cq->buf_sz,
+				      cq->ncqe,
+				      cq->cqe_log_sz,
+				      cq->poll_wqe,
+				      cq->cqe_sz,
+				      sq->sqn,
+				      sq->obj->id,
+				      sq->cur_post,
+				      sq->buf_mask);
+			if (ret < 0) {
+				rte_errno = EINVAL;
+				return rte_errno;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int mlx5dr_debug_dump_context_caps(FILE *f, struct mlx5dr_context *ctx)
+{
+	struct mlx5dr_cmd_query_caps *caps = ctx->caps;
+	int ret;
+
+	ret = fprintf(f, "%d,0x%" PRIx64 ",%s,%d,%d,%d,%d,",
+		      MLX5DR_DEBUG_RES_TYPE_CONTEXT_CAPS,
+		      (uint64_t)(uintptr_t)ctx,
+		      caps->fw_ver,
+		      caps->wqe_based_update,
+		      caps->ste_format,
+		      caps->ste_alloc_log_max,
+		      caps->log_header_modify_argument_max_alloc);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	ret = fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+		      caps->flex_protocols,
+		      caps->rtc_reparse_mode,
+		      caps->rtc_index_mode,
+		      caps->ste_alloc_log_gran,
+		      caps->stc_alloc_log_max,
+		      caps->stc_alloc_log_gran,
+		      caps->rtc_log_depth_max,
+		      caps->format_select_gtpu_dw_0,
+		      caps->format_select_gtpu_dw_1,
+		      caps->format_select_gtpu_dw_2,
+		      caps->format_select_gtpu_ext_dw_0,
+		      caps->nic_ft.max_level,
+		      caps->nic_ft.reparse,
+		      caps->fdb_ft.max_level,
+		      caps->fdb_ft.reparse,
+		      caps->log_header_modify_argument_granularity);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	return 0;
+}
+
+static int mlx5dr_debug_dump_context_attr(FILE *f, struct mlx5dr_context *ctx)
+{
+	int ret;
+
+	ret = fprintf(f, "%u,0x%" PRIx64 ",%d,%zu,%d\n",
+		      MLX5DR_DEBUG_RES_TYPE_CONTEXT_ATTR,
+		      (uint64_t)(uintptr_t)ctx,
+		      ctx->pd_num,
+		      ctx->queues,
+		      ctx->send_queue->num_entries);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	return 0;
+}
+
+static int mlx5dr_debug_dump_context_info(FILE *f, struct mlx5dr_context *ctx)
+{
+	int ret;
+
+	ret = fprintf(f, "%d,0x%" PRIx64 ",%d,%s,%s\n",
+		      MLX5DR_DEBUG_RES_TYPE_CONTEXT,
+		      (uint64_t)(uintptr_t)ctx,
+		      ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT,
+		      mlx5_glue->get_device_name(ctx->ibv_ctx->device),
+		      DEBUG_VERSION);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return rte_errno;
+	}
+
+	ret = mlx5dr_debug_dump_context_attr(f, ctx);
+	if (ret)
+		return ret;
+
+	ret = mlx5dr_debug_dump_context_caps(f, ctx);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int mlx5dr_debug_dump_context(FILE *f, struct mlx5dr_context *ctx)
+{
+	struct mlx5dr_table *tbl;
+	int ret;
+
+	ret = mlx5dr_debug_dump_context_info(f, ctx);
+	if (ret)
+		return ret;
+
+	ret = mlx5dr_debug_dump_context_send_engine(f, ctx);
+	if (ret)
+		return ret;
+
+	LIST_FOREACH(tbl, &ctx->head, next) {
+		ret = mlx5dr_debug_dump_table(f, tbl);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int mlx5dr_debug_dump(struct mlx5dr_context *ctx, FILE *f)
+{
+	int ret;
+
+	if (!f || !ctx) {
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+
+	pthread_spin_lock(&ctx->ctrl_lock);
+	ret = mlx5dr_debug_dump_context(f, ctx);
+	pthread_spin_unlock(&ctx->ctrl_lock);
+
+	return -ret;
+}
drivers/net/mlx5/hws/mlx5dr_debug.h new file +28 -0
new file mode 100644
index 0000000000..cf00170f7d
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 NVIDIA Corporation & Affiliates
+ */
+
+#ifndef MLX5DR_DEBUG_H_
+#define MLX5DR_DEBUG_H_
+
+#define DEBUG_VERSION "1.0.DPDK"
+
+enum mlx5dr_debug_res_type {
+	MLX5DR_DEBUG_RES_TYPE_CONTEXT = 4000,
+	MLX5DR_DEBUG_RES_TYPE_CONTEXT_ATTR = 4001,
+	MLX5DR_DEBUG_RES_TYPE_CONTEXT_CAPS = 4002,
+	MLX5DR_DEBUG_RES_TYPE_CONTEXT_SEND_ENGINE = 4003,
+	MLX5DR_DEBUG_RES_TYPE_CONTEXT_SEND_RING = 4004,
+
+	MLX5DR_DEBUG_RES_TYPE_TABLE = 4100,
+
+	MLX5DR_DEBUG_RES_TYPE_MATCHER = 4200,
+	MLX5DR_DEBUG_RES_TYPE_MATCHER_ATTR = 4201,
+	MLX5DR_DEBUG_RES_TYPE_MATCHER_MATCH_TEMPLATE = 4202,
+	MLX5DR_DEBUG_RES_TYPE_MATCHER_ACTION_TEMPLATE = 4204,
+	MLX5DR_DEBUG_RES_TYPE_MATCHER_TEMPLATE_DEFINER = 4203,
+};
+
+const char *mlx5dr_debug_action_type_to_str(enum mlx5dr_action_type action_type);
+
+#endif /* MLX5DR_DEBUG_H_ */
Signature · 1 line
2.18.1
Acked-by on v6 17/18
#130 lore raw

RE: [v6 17/18] net/mlx5/hws: Add HWS debug layer

Quoted 11 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>; Hamdan Igbaria <[email protected]>
Subject: [v6 17/18] net/mlx5/hws: Add HWS debug layer

Quoted 7 lines

From: Hamdan Igbaria <[email protected]>

The debug layer is used to generate a debug CSV file containing details of the context, table, matcher, rules and other useful debug information.

#131 lore raw

PATCH v6 18/18 net/mlx5/hws: Enable HWS

In reply to Alex Vesker

Replace stub implenation of HWS with mlx5dr code.

---
 doc/guides/nics/mlx5.rst                     |   5 +-
 doc/guides/rel_notes/release_22_11.rst       |   4 +
 drivers/common/mlx5/linux/meson.build        |   9 +-
 drivers/net/mlx5/hws/meson.build             |  18 +
 drivers/net/mlx5/{mlx5_dr.h => hws/mlx5dr.h} | 201 ++++++++--
 drivers/net/mlx5/hws/mlx5dr_internal.h       |  93 +++++
 drivers/net/mlx5/meson.build                 |   7 +-
 drivers/net/mlx5/mlx5.c                      |   6 +-
 drivers/net/mlx5/mlx5.h                      |   7 +-
 drivers/net/mlx5/mlx5_devx.c                 |   2 +-
 drivers/net/mlx5/mlx5_dr.c                   | 383 -------------------
 drivers/net/mlx5/mlx5_flow.c                 |   2 +
 drivers/net/mlx5/mlx5_flow.h                 |  11 +-
 drivers/net/mlx5/mlx5_flow_hw.c              |  10 +-
 14 files changed, 326 insertions(+), 432 deletions(-)
 create mode 100644 drivers/net/mlx5/hws/meson.build
 rename drivers/net/mlx5/{mlx5_dr.h => hws/mlx5dr.h} (67%)
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_internal.h
 delete mode 100644 drivers/net/mlx5/mlx5_dr.c
doc/guides/nics/mlx5.rst +4 -1
index bb436892a0..303eb17714 100644
@@ -539,7 +539,10 @@ Limitations
 
     - WQE based high scaling and safer flow insertion/destruction.
     - Set ``dv_flow_en`` to 2 in order to enable HW steering.
-    - Async queue-based ``rte_flow_q`` APIs supported only.
+    - Async queue-based ``rte_flow_async`` APIs supported only.
+    - NIC ConnectX-5 and before are not supported.
+    - Partial match with item template is not supported.
+    - IPv6 5-tuple matching is not supported.
 
 - Match on GRE header supports the following fields:
 
doc/guides/rel_notes/release_22_11.rst +4 -0
index 1c3daf141d..cdc5837f1d 100644
@@ -249,6 +249,10 @@ New Features
   sysfs entries to adjust the minimum and maximum uncore frequency values,
   which works on Linux with Intel hardware only.
 
+* **Updated Nvidia mlx5 driver.**
+
+  * Added fully support for queue based async HW steering to the PMD.
+
 * **Rewritten pmdinfo script.**
 
   The ``dpdk-pmdinfo.py`` script was rewritten to produce valid JSON only.
drivers/common/mlx5/linux/meson.build +5 -4
index e6b32eb84d..84e2a1ad8c 100644
@@ -8,6 +8,7 @@ dlopen_ibverbs = (get_option('ibverbs_link') == 'dlopen')
 LIB_GLUE_BASE = 'librte_common_mlx5_glue.so'
 LIB_GLUE_VERSION = abi_version
 LIB_GLUE = LIB_GLUE_BASE + '.' + LIB_GLUE_VERSION
+mlx5_config = configuration_data()
 if dlopen_ibverbs
     dpdk_conf.set('RTE_IBVERBS_LINK_DLOPEN', 1)
     cflags += [
@@ -223,15 +224,15 @@ if  libmtcr_ul_found
         [ 'HAVE_MLX5_MSTFLINT', 'mstflint/mtcr.h', 'mopen' ],
     ]
 endif
-config = configuration_data()
+
 foreach arg:has_sym_args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2], dependencies: libs))
+    mlx5_config.set(arg[0], cc.has_header_symbol(arg[1], arg[2], dependencies: libs))
 endforeach
 foreach arg:has_member_args
     file_prefix = '#include <' + arg[1] + '>'
-    config.set(arg[0], cc.has_member(arg[2], arg[3], prefix : file_prefix, dependencies: libs))
+    mlx5_config.set(arg[0], cc.has_member(arg[2], arg[3], prefix : file_prefix, dependencies: libs))
 endforeach
-configure_file(output : 'mlx5_autoconf.h', configuration : config)
+configure_file(output : 'mlx5_autoconf.h', configuration : mlx5_config)
 
 # Build Glue Library
 if dlopen_ibverbs
drivers/net/mlx5/hws/meson.build new file +18 -0
new file mode 100644
index 0000000000..d2bb864fd2
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) 2022 NVIDIA Corporation & Affiliates
+
+includes += include_directories('.')
+sources += files(
+        'mlx5dr_context.c',
+        'mlx5dr_table.c',
+        'mlx5dr_matcher.c',
+        'mlx5dr_rule.c',
+        'mlx5dr_action.c',
+        'mlx5dr_buddy.c',
+        'mlx5dr_pool.c',
+        'mlx5dr_cmd.c',
+        'mlx5dr_send.c',
+        'mlx5dr_definer.c',
+        'mlx5dr_debug.c',
+        'mlx5dr_pat_arg.c',
+)
drivers/net/mlx5/hws/mlx5dr.h renamed from drivers/net/mlx5/mlx5_dr.h +170 -31

323 lines not on this page · raw message

drivers/net/mlx5/hws/mlx5dr_internal.h new file +93 -0

93 lines not on this page · raw message

drivers/net/mlx5/meson.build +5 -2
index 6a84d96380..6b947eaab5 100644
@@ -14,10 +14,8 @@ sources = files(
         'mlx5.c',
         'mlx5_ethdev.c',
         'mlx5_flow.c',
-        'mlx5_dr.c',
         'mlx5_flow_meter.c',
         'mlx5_flow_dv.c',
-        'mlx5_flow_hw.c',
         'mlx5_flow_aso.c',
         'mlx5_flow_flex.c',
         'mlx5_mac.c',
@@ -42,6 +40,7 @@ sources = files(
 
 if is_linux
     sources += files(
+            'mlx5_flow_hw.c',
             'mlx5_flow_verbs.c',
     )
     if (dpdk_conf.has('RTE_ARCH_X86_64')
@@ -72,3 +71,7 @@ endif
 testpmd_sources += files('mlx5_testpmd.c')
 
 subdir(exec_env)
+
+if (is_linux and mlx5_config.get('HAVE_IBV_FLOW_DV_SUPPORT', false))
+    subdir('hws')
+endif
drivers/net/mlx5/mlx5.c +3 -3
index b39ef1ecbe..a34fbcf74d 100644
@@ -1700,7 +1700,7 @@ mlx5_free_table_hash_list(struct mlx5_priv *priv)
 	*tbls = NULL;
 }
 
-#if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
+#ifdef HAVE_MLX5_HWS_SUPPORT
 /**
  * Allocate HW steering group hash list.
  *
@@ -1749,7 +1749,7 @@ mlx5_alloc_table_hash_list(struct mlx5_priv *priv __rte_unused)
 	int err = 0;
 
 	/* Tables are only used in DV and DR modes. */
-#if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
+#ifdef HAVE_MLX5_HWS_SUPPORT
 	struct mlx5_dev_ctx_shared *sh = priv->sh;
 	char s[MLX5_NAME_SIZE];
 
@@ -1942,7 +1942,7 @@ mlx5_dev_close(struct rte_eth_dev *dev)
 	/* Free the eCPRI flex parser resource. */
 	mlx5_flex_parser_ecpri_release(dev);
 	mlx5_flex_item_port_cleanup(dev);
-#if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
+#ifdef HAVE_MLX5_HWS_SUPPORT
 	flow_hw_resource_release(dev);
 	flow_hw_clear_port_info(dev);
 	if (priv->sh->config.dv_flow_en == 2)
drivers/net/mlx5/mlx5.h +6 -1
index aa328c3bc9..fc8e1190f3 100644
@@ -34,7 +34,12 @@
 #include "mlx5_os.h"
 #include "mlx5_autoconf.h"
 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
-#include "mlx5_dr.h"
+#ifndef RTE_EXEC_ENV_WINDOWS
+#define HAVE_MLX5_HWS_SUPPORT 1
+#else
+#define __be64 uint64_t
+#endif
+#include "hws/mlx5dr.h"
 #endif
 
 #define MLX5_SH(dev) (((struct mlx5_priv *)(dev)->data->dev_private)->sh)
drivers/net/mlx5/mlx5_devx.c +1 -1
index fe303a73bb..137e7dd4ac 100644
@@ -907,7 +907,7 @@ mlx5_devx_hrxq_new(struct rte_eth_dev *dev, struct mlx5_hrxq *hrxq,
 		rte_errno = errno;
 		goto error;
 	}
-#if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
+#ifdef HAVE_MLX5_HWS_SUPPORT
 	if (hrxq->hws_flags) {
 		hrxq->action = mlx5dr_action_create_dest_tir
 			(priv->dr_ctx,
drivers/net/mlx5/mlx5_dr.c deleted +0 -383

383 lines not on this page · raw message

drivers/net/mlx5/mlx5_flow.c +2 -0
index 1543d7f75e..1e32031443 100644
@@ -93,6 +93,8 @@ const struct mlx5_flow_driver_ops *flow_drv_ops[] = {
 	[MLX5_FLOW_TYPE_MIN] = &mlx5_flow_null_drv_ops,
 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
 	[MLX5_FLOW_TYPE_DV] = &mlx5_flow_dv_drv_ops,
+#endif
+#ifdef HAVE_MLX5_HWS_SUPPORT
 	[MLX5_FLOW_TYPE_HW] = &mlx5_flow_hw_drv_ops,
 #endif
 	[MLX5_FLOW_TYPE_VERBS] = &mlx5_flow_verbs_drv_ops,
drivers/net/mlx5/mlx5_flow.h +10 -1
index 98ae7c6bda..a274808802 100644
@@ -17,6 +17,7 @@
 #include <mlx5_prm.h>
 
 #include "mlx5.h"
+#include "hws/mlx5dr.h"
 
 /* E-Switch Manager port, used for rte_flow_item_port_id. */
 #define MLX5_PORT_ESW_MGR UINT32_MAX
@@ -1046,6 +1047,10 @@ struct rte_flow {
 
 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
 
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+
 /* HWS flow struct. */
 struct rte_flow_hw {
 	uint32_t idx; /* Flow index from indexed pool. */
@@ -1056,9 +1061,13 @@ struct rte_flow_hw {
 		struct mlx5_hrxq *hrxq; /* TIR action. */
 	};
 	struct rte_flow_template_table *table; /* The table flow allcated from. */
-	struct mlx5dr_rule rule; /* HWS layer data struct. */
+	uint8_t rule[0]; /* HWS layer data struct. */
 } __rte_packed;
 
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
 /* rte flow action translate to DR action struct. */
 struct mlx5_action_construct_data {
 	LIST_ENTRY(mlx5_action_construct_data) next;
drivers/net/mlx5/mlx5_flow_hw.c +5 -5
index 03725649c8..8de6757737 100644
@@ -1110,8 +1110,8 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev,
 				  actions, rule_acts, &acts_num);
 	ret = mlx5dr_rule_create(table->matcher,
 				 pattern_template_index, items,
-				 rule_acts, acts_num,
-				 &rule_attr, &flow->rule);
+				 action_template_index, rule_acts,
+				 &rule_attr, (struct mlx5dr_rule *)flow->rule);
 	if (likely(!ret))
 		return (struct rte_flow *)flow;
 	/* Flow created fail, return the descriptor and flow memory. */
@@ -1174,7 +1174,7 @@ flow_hw_async_flow_destroy(struct rte_eth_dev *dev,
 	job->user_data = user_data;
 	job->flow = fh;
 	rule_attr.user_data = job;
-	ret = mlx5dr_rule_destroy(&fh->rule, &rule_attr);
+	ret = mlx5dr_rule_destroy((struct mlx5dr_rule *)fh->rule, &rule_attr);
 	if (likely(!ret))
 		return 0;
 	priv->hw_q[queue].job_idx++;
@@ -1440,7 +1440,7 @@ flow_hw_table_create(struct rte_eth_dev *dev,
 		.data = &flow_attr,
 	};
 	struct mlx5_indexed_pool_config cfg = {
-		.size = sizeof(struct rte_flow_hw),
+		.size = sizeof(struct rte_flow_hw) + mlx5dr_rule_get_handle_size(),
 		.trunk_size = 1 << 12,
 		.per_core_cache = 1 << 13,
 		.need_lock = 1,
@@ -1501,7 +1501,7 @@ flow_hw_table_create(struct rte_eth_dev *dev,
 		tbl->its[i] = item_templates[i];
 	}
 	tbl->matcher = mlx5dr_matcher_create
-		(tbl->grp->tbl, mt, nb_item_templates, &matcher_attr);
+		(tbl->grp->tbl, mt, nb_item_templates, NULL, 0, &matcher_attr);
 	if (!tbl->matcher)
 		goto it_error;
 	tbl->nb_item_templates = nb_item_templates;
Signature · 1 line
2.18.1
Acked-by on v6 18/18
#132 lore raw

RE: [v6 18/18] net/mlx5/hws: Enable HWS

Quoted 10 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 18:58
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>; Matan Azrad <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>
Subject: [v6 18/18] net/mlx5/hws: Enable HWS

Quoted 3 lines

Replace stub implenation of HWS with mlx5dr code.

#133 lore raw
In reply to Alex Vesker

Hi,

Quoted 149 lines

-----Original Message-----
From: Alex Vesker <[email protected]>
Sent: Thursday, October 20, 2022 6:58 PM
To: Alex Vesker <[email protected]>; Slava Ovsiienko <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Suanming Mou <[email protected]>
Cc: [email protected]; Ori Kam <[email protected]>
Subject: [v6 00/18] net/mlx5: Add HW steering low level support

Mellanox ConnetX devices supports packet matching, packet modification and redirection. These functionalities are also referred to as flow-steering. To configure a steering rule, the rule is written to the device owned memory, this memory is accessed and cached by the device when processing a packet.

The highlight of this patchset is supporting HW Steering (HWS) which is the new technology supported in new ConnectX devices, HWS allows configuring steering rules directly to the HW using special HW queues with minimal CPU effort.

This patchset is the internal low layer implementation for HWS used by the mlx5 PMD. The mlx5dr (direct rule) is layer that bridges between the PMD and the HW by configuring the HW offloads based on the PMD logic

v2:
Fix check patch and cosmetic changes

v3:

(quoted diff) +0 -2
-Fix unsupported items
-Fix compilation with mlx5dv dependency

v4:
-Fix compile on Windows

v5:
-Fix compile on old rdma-core or no rdma core

v6:

(quoted diff) +0 -3
-Fix meson style and improve configure
-Checkpatch and compilation fixes
-Fix action number issue

Alex Vesker (8):
net/mlx5: Add additional glue functions for HWS
net/mlx5/hws: Add HWS send layer
net/mlx5/hws: Add HWS definer layer
net/mlx5/hws: Add HWS context object
net/mlx5/hws: Add HWS table object
net/mlx5/hws: Add HWS matcher object
net/mlx5/hws: Add HWS rule object
net/mlx5/hws: Enable HWS

Bing Zhao (2):
common/mlx5: query set capability of registers
net/mlx5: provide the available tag registers

Dariusz Sosnowski (1):
net/mlx5: add port to metadata conversion

Erez Shitrit (3):
net/mlx5/hws: Add HWS command layer
net/mlx5/hws: Add HWS pool and buddy
net/mlx5/hws: Add HWS action object

Hamdan Igbaria (1):
net/mlx5/hws: Add HWS debug layer

Suanming Mou (3):
net/mlx5: split flow item translation
net/mlx5: split flow item matcher and value translation net/mlx5: add hardware steering item translation function

 doc/guides/nics/features/default.ini         |    1 +
 doc/guides/nics/features/mlx5.ini            |    1 +
 doc/guides/nics/mlx5.rst                     |    5 +-
 doc/guides/rel_notes/release_22_11.rst       |    4 +
 drivers/common/mlx5/linux/meson.build        |   11 +-
 drivers/common/mlx5/linux/mlx5_glue.c        |  121 +-
 drivers/common/mlx5/linux/mlx5_glue.h        |   17 +
 drivers/common/mlx5/mlx5_devx_cmds.c         |   30 +
 drivers/common/mlx5/mlx5_devx_cmds.h         |    2 +
 drivers/common/mlx5/mlx5_prm.h               |  652 ++++-
 drivers/net/mlx5/hws/meson.build             |   18 +
 drivers/net/mlx5/{mlx5_dr.h => hws/mlx5dr.h} |  201 +-
 drivers/net/mlx5/hws/mlx5dr_action.c         | 2237 +++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_action.h         |  253 ++
 drivers/net/mlx5/hws/mlx5dr_buddy.c          |  200 ++
 drivers/net/mlx5/hws/mlx5dr_buddy.h          |   22 +
 drivers/net/mlx5/hws/mlx5dr_cmd.c            |  948 +++++++
 drivers/net/mlx5/hws/mlx5dr_cmd.h            |  230 ++
 drivers/net/mlx5/hws/mlx5dr_context.c        |  223 ++
 drivers/net/mlx5/hws/mlx5dr_context.h        |   40 +
 drivers/net/mlx5/hws/mlx5dr_debug.c          |  462 ++++
 drivers/net/mlx5/hws/mlx5dr_debug.h          |   28 +
 drivers/net/mlx5/hws/mlx5dr_definer.c        | 1968 ++++++++++++++
 drivers/net/mlx5/hws/mlx5dr_definer.h        |  585 ++++
 drivers/net/mlx5/hws/mlx5dr_internal.h       |   93 +
 drivers/net/mlx5/hws/mlx5dr_matcher.c        |  919 +++++++
 drivers/net/mlx5/hws/mlx5dr_matcher.h        |   76 +
 drivers/net/mlx5/hws/mlx5dr_pat_arg.c        |  511 ++++
 drivers/net/mlx5/hws/mlx5dr_pat_arg.h        |   83 +
 drivers/net/mlx5/hws/mlx5dr_pool.c           |  672 +++++
 drivers/net/mlx5/hws/mlx5dr_pool.h           |  152 ++
 drivers/net/mlx5/hws/mlx5dr_rule.c           |  528 ++++
 drivers/net/mlx5/hws/mlx5dr_rule.h           |   50 +
 drivers/net/mlx5/hws/mlx5dr_send.c           |  844 ++++++
 drivers/net/mlx5/hws/mlx5dr_send.h           |  275 ++
 drivers/net/mlx5/hws/mlx5dr_table.c          |  248 ++
 drivers/net/mlx5/hws/mlx5dr_table.h          |   44 +
 drivers/net/mlx5/linux/mlx5_os.c             |   12 +-
 drivers/net/mlx5/meson.build                 |    7 +-
 drivers/net/mlx5/mlx5.c                      |    9 +-
 drivers/net/mlx5/mlx5.h                      |    8 +-
 drivers/net/mlx5/mlx5_defs.h                 |    2 +
 drivers/net/mlx5/mlx5_devx.c                 |    2 +-
 drivers/net/mlx5/mlx5_dr.c                   |  383 ---
 drivers/net/mlx5/mlx5_flow.c                 |   29 +-
 drivers/net/mlx5/mlx5_flow.h                 |  174 +-
 drivers/net/mlx5/mlx5_flow_dv.c              | 2567 +++++++++---------
 drivers/net/mlx5/mlx5_flow_hw.c              |  115 +-
 48 files changed, 14368 insertions(+), 1694 deletions(-)  create mode 100644
drivers/net/mlx5/hws/meson.build  rename drivers/net/mlx5/{mlx5_dr.h =>
hws/mlx5dr.h} (67%)  create mode 100644
drivers/net/mlx5/hws/mlx5dr_action.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_action.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_buddy.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_buddy.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_cmd.c  create mode
100644 drivers/net/mlx5/hws/mlx5dr_cmd.h  create mode 100644
drivers/net/mlx5/hws/mlx5dr_context.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_context.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_debug.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_debug.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_definer.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_definer.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_internal.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_matcher.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_matcher.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_pat_arg.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_pat_arg.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_pool.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_pool.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_rule.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_rule.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_send.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_send.h
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_table.c
 create mode 100644 drivers/net/mlx5/hws/mlx5dr_table.h
 delete mode 100644 drivers/net/mlx5/mlx5_dr.c
Quoted 2 lines

--
2.18.1

Series applied to next-net-mlx with small modifications to the commit logs,

Kindest regards,
Raslan Darawsheh