Commit c21a49b3 authored by Hamdan Igbaria's avatar Hamdan Igbaria Committed by Saeed Mahameed

net/mlx5: DR, Modify header copy support

Modify header supports ADD/SET and from this patch
also COPY. Copy allows to copy header fields and
metadata.
Signed-off-by: default avatarHamdan Igbaria <hamdani@mellanox.com>
Signed-off-by: default avatarAlex Vesker <valex@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent a51dcc10
...@@ -1410,16 +1410,83 @@ dr_action_modify_sw_to_hw_set(struct mlx5dr_domain *dmn, ...@@ -1410,16 +1410,83 @@ dr_action_modify_sw_to_hw_set(struct mlx5dr_domain *dmn,
return 0; return 0;
} }
static int
dr_action_modify_sw_to_hw_copy(struct mlx5dr_domain *dmn,
__be64 *sw_action,
__be64 *hw_action,
const struct dr_action_modify_field_conv **ret_dst_hw_info,
const struct dr_action_modify_field_conv **ret_src_hw_info)
{
u8 src_offset, dst_offset, src_max_length, dst_max_length, length;
const struct dr_action_modify_field_conv *hw_dst_action_info;
const struct dr_action_modify_field_conv *hw_src_action_info;
u16 src_field, dst_field;
/* Get SW modify action data */
src_field = MLX5_GET(copy_action_in, sw_action, src_field);
dst_field = MLX5_GET(copy_action_in, sw_action, dst_field);
src_offset = MLX5_GET(copy_action_in, sw_action, src_offset);
dst_offset = MLX5_GET(copy_action_in, sw_action, dst_offset);
length = MLX5_GET(copy_action_in, sw_action, length);
/* Convert SW data to HW modify action format */
hw_src_action_info = dr_action_modify_get_hw_info(src_field);
hw_dst_action_info = dr_action_modify_get_hw_info(dst_field);
if (!hw_src_action_info || !hw_dst_action_info) {
mlx5dr_dbg(dmn, "Modify copy action invalid field given\n");
return -EINVAL;
}
/* PRM defines that length zero specific length of 32bits */
length = length ? length : 32;
src_max_length = hw_src_action_info->end -
hw_src_action_info->start + 1;
dst_max_length = hw_dst_action_info->end -
hw_dst_action_info->start + 1;
if (length + src_offset > src_max_length ||
length + dst_offset > dst_max_length) {
mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n");
return -EINVAL;
}
MLX5_SET(dr_action_hw_copy, hw_action,
opcode, MLX5DR_ACTION_MDFY_HW_OP_COPY);
MLX5_SET(dr_action_hw_copy, hw_action, destination_field_code,
hw_dst_action_info->hw_field);
MLX5_SET(dr_action_hw_copy, hw_action, destination_left_shifter,
hw_dst_action_info->start + dst_offset);
MLX5_SET(dr_action_hw_copy, hw_action, destination_length,
length == 32 ? 0 : length);
MLX5_SET(dr_action_hw_copy, hw_action, source_field_code,
hw_src_action_info->hw_field);
MLX5_SET(dr_action_hw_copy, hw_action, source_left_shifter,
hw_src_action_info->start + dst_offset);
*ret_dst_hw_info = hw_dst_action_info;
*ret_src_hw_info = hw_src_action_info;
return 0;
}
static int static int
dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn, dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn,
__be64 *sw_action, __be64 *sw_action,
__be64 *hw_action, __be64 *hw_action,
const struct dr_action_modify_field_conv **ret_hw_info) const struct dr_action_modify_field_conv **ret_dst_hw_info,
const struct dr_action_modify_field_conv **ret_src_hw_info)
{ {
u8 action; u8 action;
int ret; int ret;
*hw_action = 0; *hw_action = 0;
*ret_src_hw_info = NULL;
/* Get SW modify action type */ /* Get SW modify action type */
action = MLX5_GET(set_action_in, sw_action, action_type); action = MLX5_GET(set_action_in, sw_action, action_type);
...@@ -1428,13 +1495,20 @@ dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn, ...@@ -1428,13 +1495,20 @@ dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn,
case MLX5_ACTION_TYPE_SET: case MLX5_ACTION_TYPE_SET:
ret = dr_action_modify_sw_to_hw_set(dmn, sw_action, ret = dr_action_modify_sw_to_hw_set(dmn, sw_action,
hw_action, hw_action,
ret_hw_info); ret_dst_hw_info);
break; break;
case MLX5_ACTION_TYPE_ADD: case MLX5_ACTION_TYPE_ADD:
ret = dr_action_modify_sw_to_hw_add(dmn, sw_action, ret = dr_action_modify_sw_to_hw_add(dmn, sw_action,
hw_action, hw_action,
ret_hw_info); ret_dst_hw_info);
break;
case MLX5_ACTION_TYPE_COPY:
ret = dr_action_modify_sw_to_hw_copy(dmn, sw_action,
hw_action,
ret_dst_hw_info,
ret_src_hw_info);
break; break;
default: default:
...@@ -1495,6 +1569,43 @@ dr_action_modify_check_add_field_limitation(struct mlx5dr_action *action, ...@@ -1495,6 +1569,43 @@ dr_action_modify_check_add_field_limitation(struct mlx5dr_action *action,
return 0; return 0;
} }
static int
dr_action_modify_check_copy_field_limitation(struct mlx5dr_action *action,
const __be64 *sw_action)
{
struct mlx5dr_domain *dmn = action->rewrite.dmn;
u16 sw_fields[2];
int i;
sw_fields[0] = MLX5_GET(copy_action_in, sw_action, src_field);
sw_fields[1] = MLX5_GET(copy_action_in, sw_action, dst_field);
for (i = 0; i < 2; i++) {
if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_A) {
action->rewrite.allow_rx = 0;
if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) {
mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n",
sw_fields[i]);
return -EINVAL;
}
} else if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_B) {
action->rewrite.allow_tx = 0;
if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) {
mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n",
sw_fields[i]);
return -EINVAL;
}
}
}
if (!action->rewrite.allow_rx && !action->rewrite.allow_tx) {
mlx5dr_dbg(dmn, "Modify copy actions not supported on both RX and TX\n");
return -EINVAL;
}
return 0;
}
static int static int
dr_action_modify_check_field_limitation(struct mlx5dr_action *action, dr_action_modify_check_field_limitation(struct mlx5dr_action *action,
const __be64 *sw_action) const __be64 *sw_action)
...@@ -1516,6 +1627,11 @@ dr_action_modify_check_field_limitation(struct mlx5dr_action *action, ...@@ -1516,6 +1627,11 @@ dr_action_modify_check_field_limitation(struct mlx5dr_action *action,
sw_action); sw_action);
break; break;
case MLX5_ACTION_TYPE_COPY:
ret = dr_action_modify_check_copy_field_limitation(action,
sw_action);
break;
default: default:
mlx5dr_info(dmn, "Unsupported action %d modify action\n", mlx5dr_info(dmn, "Unsupported action %d modify action\n",
action_type); action_type);
...@@ -1541,7 +1657,8 @@ static int dr_actions_convert_modify_header(struct mlx5dr_action *action, ...@@ -1541,7 +1657,8 @@ static int dr_actions_convert_modify_header(struct mlx5dr_action *action,
u32 *num_hw_actions, u32 *num_hw_actions,
bool *modify_ttl) bool *modify_ttl)
{ {
const struct dr_action_modify_field_conv *hw_action_info; const struct dr_action_modify_field_conv *hw_dst_action_info;
const struct dr_action_modify_field_conv *hw_src_action_info;
u16 hw_field = MLX5DR_ACTION_MDFY_HW_FLD_RESERVED; u16 hw_field = MLX5DR_ACTION_MDFY_HW_FLD_RESERVED;
u32 l3_type = MLX5DR_ACTION_MDFY_HW_HDR_L3_NONE; u32 l3_type = MLX5DR_ACTION_MDFY_HW_HDR_L3_NONE;
u32 l4_type = MLX5DR_ACTION_MDFY_HW_HDR_L4_NONE; u32 l4_type = MLX5DR_ACTION_MDFY_HW_HDR_L4_NONE;
...@@ -1570,32 +1687,35 @@ static int dr_actions_convert_modify_header(struct mlx5dr_action *action, ...@@ -1570,32 +1687,35 @@ static int dr_actions_convert_modify_header(struct mlx5dr_action *action,
ret = dr_action_modify_sw_to_hw(dmn, ret = dr_action_modify_sw_to_hw(dmn,
sw_action, sw_action,
&hw_action, &hw_action,
&hw_action_info); &hw_dst_action_info,
&hw_src_action_info);
if (ret) if (ret)
return ret; return ret;
/* Due to a HW limitation we cannot modify 2 different L3 types */ /* Due to a HW limitation we cannot modify 2 different L3 types */
if (l3_type && hw_action_info->l3_type && if (l3_type && hw_dst_action_info->l3_type &&
hw_action_info->l3_type != l3_type) { hw_dst_action_info->l3_type != l3_type) {
mlx5dr_dbg(dmn, "Action list can't support two different L3 types\n"); mlx5dr_dbg(dmn, "Action list can't support two different L3 types\n");
return -EINVAL; return -EINVAL;
} }
if (hw_action_info->l3_type) if (hw_dst_action_info->l3_type)
l3_type = hw_action_info->l3_type; l3_type = hw_dst_action_info->l3_type;
/* Due to a HW limitation we cannot modify two different L4 types */ /* Due to a HW limitation we cannot modify two different L4 types */
if (l4_type && hw_action_info->l4_type && if (l4_type && hw_dst_action_info->l4_type &&
hw_action_info->l4_type != l4_type) { hw_dst_action_info->l4_type != l4_type) {
mlx5dr_dbg(dmn, "Action list can't support two different L4 types\n"); mlx5dr_dbg(dmn, "Action list can't support two different L4 types\n");
return -EINVAL; return -EINVAL;
} }
if (hw_action_info->l4_type) if (hw_dst_action_info->l4_type)
l4_type = hw_action_info->l4_type; l4_type = hw_dst_action_info->l4_type;
/* HW reads and executes two actions at once this means we /* HW reads and executes two actions at once this means we
* need to create a gap if two actions access the same field * need to create a gap if two actions access the same field
*/ */
if ((hw_idx % 2) && hw_field == hw_action_info->hw_field) { if ((hw_idx % 2) && (hw_field == hw_dst_action_info->hw_field ||
(hw_src_action_info &&
hw_field == hw_src_action_info->hw_field))) {
/* Check if after gap insertion the total number of HW /* Check if after gap insertion the total number of HW
* modify actions doesn't exceeds the limit * modify actions doesn't exceeds the limit
*/ */
...@@ -1605,7 +1725,7 @@ static int dr_actions_convert_modify_header(struct mlx5dr_action *action, ...@@ -1605,7 +1725,7 @@ static int dr_actions_convert_modify_header(struct mlx5dr_action *action,
return -EINVAL; return -EINVAL;
} }
} }
hw_field = hw_action_info->hw_field; hw_field = hw_dst_action_info->hw_field;
hw_actions[hw_idx] = hw_action; hw_actions[hw_idx] = hw_action;
hw_idx++; hw_idx++;
......
...@@ -32,6 +32,7 @@ enum { ...@@ -32,6 +32,7 @@ enum {
}; };
enum { enum {
MLX5DR_ACTION_MDFY_HW_OP_COPY = 0x1,
MLX5DR_ACTION_MDFY_HW_OP_SET = 0x2, MLX5DR_ACTION_MDFY_HW_OP_SET = 0x2,
MLX5DR_ACTION_MDFY_HW_OP_ADD = 0x3, MLX5DR_ACTION_MDFY_HW_OP_ADD = 0x3,
}; };
...@@ -625,4 +626,19 @@ struct mlx5_ifc_dr_action_hw_set_bits { ...@@ -625,4 +626,19 @@ struct mlx5_ifc_dr_action_hw_set_bits {
u8 inline_data[0x20]; u8 inline_data[0x20];
}; };
struct mlx5_ifc_dr_action_hw_copy_bits {
u8 opcode[0x8];
u8 destination_field_code[0x8];
u8 reserved_at_10[0x2];
u8 destination_left_shifter[0x6];
u8 reserved_at_18[0x2];
u8 destination_length[0x6];
u8 reserved_at_20[0x8];
u8 source_field_code[0x8];
u8 reserved_at_30[0x2];
u8 source_left_shifter[0x6];
u8 reserved_at_38[0x8];
};
#endif /* MLX5_IFC_DR_H */ #endif /* MLX5_IFC_DR_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment