]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
net/mlx5: DR, Modify header copy support
authorHamdan Igbaria <hamdani@mellanox.com>
Thu, 9 Jan 2020 11:27:16 +0000 (13:27 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Thu, 23 Jan 2020 06:28:34 +0000 (22:28 -0800)
Modify header supports ADD/SET and from this patch
also COPY. Copy allows to copy header fields and
metadata.

Signed-off-by: Hamdan Igbaria <hamdani@mellanox.com>
Signed-off-by: Alex Vesker <valex@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h

index ad32b88a83dc98a39af4e0b2afaf03d304134d7f..286fcec5eff23290e17a7686e641bfc6b5d33870 100644 (file)
@@ -1410,16 +1410,83 @@ dr_action_modify_sw_to_hw_set(struct mlx5dr_domain *dmn,
        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
 dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn,
                          __be64 *sw_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;
        int ret;
 
        *hw_action = 0;
+       *ret_src_hw_info = NULL;
 
        /* Get SW modify 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,
        case MLX5_ACTION_TYPE_SET:
                ret = dr_action_modify_sw_to_hw_set(dmn, sw_action,
                                                    hw_action,
-                                                   ret_hw_info);
+                                                   ret_dst_hw_info);
                break;
 
        case MLX5_ACTION_TYPE_ADD:
                ret = dr_action_modify_sw_to_hw_add(dmn, sw_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;
 
        default:
@@ -1495,6 +1569,43 @@ dr_action_modify_check_add_field_limitation(struct mlx5dr_action *action,
        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
 dr_action_modify_check_field_limitation(struct mlx5dr_action *action,
                                        const __be64 *sw_action)
@@ -1516,6 +1627,11 @@ dr_action_modify_check_field_limitation(struct mlx5dr_action *action,
                                                                  sw_action);
                break;
 
+       case MLX5_ACTION_TYPE_COPY:
+               ret = dr_action_modify_check_copy_field_limitation(action,
+                                                                  sw_action);
+               break;
+
        default:
                mlx5dr_info(dmn, "Unsupported action %d modify action\n",
                            action_type);
@@ -1541,7 +1657,8 @@ static int dr_actions_convert_modify_header(struct mlx5dr_action *action,
                                            u32 *num_hw_actions,
                                            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;
        u32 l3_type = MLX5DR_ACTION_MDFY_HW_HDR_L3_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,
                ret = dr_action_modify_sw_to_hw(dmn,
                                                sw_action,
                                                &hw_action,
-                                               &hw_action_info);
+                                               &hw_dst_action_info,
+                                               &hw_src_action_info);
                if (ret)
                        return ret;
 
                /* Due to a HW limitation we cannot modify 2 different L3 types */
-               if (l3_type && hw_action_info->l3_type &&
-                   hw_action_info->l3_type != l3_type) {
+               if (l3_type && hw_dst_action_info->l3_type &&
+                   hw_dst_action_info->l3_type != l3_type) {
                        mlx5dr_dbg(dmn, "Action list can't support two different L3 types\n");
                        return -EINVAL;
                }
-               if (hw_action_info->l3_type)
-                       l3_type = hw_action_info->l3_type;
+               if (hw_dst_action_info->l3_type)
+                       l3_type = hw_dst_action_info->l3_type;
 
                /* Due to a HW limitation we cannot modify two different L4 types */
-               if (l4_type && hw_action_info->l4_type &&
-                   hw_action_info->l4_type != l4_type) {
+               if (l4_type && hw_dst_action_info->l4_type &&
+                   hw_dst_action_info->l4_type != l4_type) {
                        mlx5dr_dbg(dmn, "Action list can't support two different L4 types\n");
                        return -EINVAL;
                }
-               if (hw_action_info->l4_type)
-                       l4_type = hw_action_info->l4_type;
+               if (hw_dst_action_info->l4_type)
+                       l4_type = hw_dst_action_info->l4_type;
 
                /* HW reads and executes two actions at once this means we
                 * 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
                         * modify actions doesn't exceeds the limit
                         */
@@ -1605,7 +1725,7 @@ static int dr_actions_convert_modify_header(struct mlx5dr_action *action,
                                return -EINVAL;
                        }
                }
-               hw_field = hw_action_info->hw_field;
+               hw_field = hw_dst_action_info->hw_field;
 
                hw_actions[hw_idx] = hw_action;
                hw_idx++;
index 1722f4668269eedc03e8899d743d47360d015c44..e01c3766c7de4a2f0a39a16c7a15357999e1f93c 100644 (file)
@@ -32,6 +32,7 @@ enum {
 };
 
 enum {
+       MLX5DR_ACTION_MDFY_HW_OP_COPY           = 0x1,
        MLX5DR_ACTION_MDFY_HW_OP_SET            = 0x2,
        MLX5DR_ACTION_MDFY_HW_OP_ADD            = 0x3,
 };
@@ -625,4 +626,19 @@ struct mlx5_ifc_dr_action_hw_set_bits {
        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 */