]> www.infradead.org Git - users/hch/misc.git/commitdiff
net/mlx5: fs, add HWS packet reformat API function
authorMoshe Shemesh <moshe@nvidia.com>
Thu, 9 Jan 2025 16:05:36 +0000 (18:05 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 14 Jan 2025 03:21:08 +0000 (19:21 -0800)
Add packet reformat alloc and dealloc API functions to provide packet
reformat actions for steering rules.

Add HWS action pools for each of the following packet reformat types:
- decapl3: decapsulate l3 tunnel to l2
- encapl2: encapsulate l2 to tunnel l2
- encapl3: encapsulate l2 to tunnel l3
- insert_hdr: insert header

In addition cache remove header action for remove vlan header as this is
currently the only use case of remove header action in the driver.

Signed-off-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20250109160546.1733647-6-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/Makefile
drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
drivers/net/ethernet/mellanox/mlx5/core/fs_pool.c
drivers/net/ethernet/mellanox/mlx5/core/fs_pool.h
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.c
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws.h
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws_pools.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws_pools.h [new file with mode: 0644]
include/linux/mlx5/mlx5_ifc.h

index 0008b22417c8f8a110fe7af8917ab4154707160c..d9a8817bb33c5658c589dc1ca0550dfdee6e6d14 100644 (file)
@@ -152,6 +152,7 @@ mlx5_core-$(CONFIG_MLX5_HW_STEERING) += steering/hws/cmd.o \
                                        steering/hws/debug.o \
                                        steering/hws/vport.o \
                                        steering/hws/bwc_complex.o \
+                                       steering/hws/fs_hws_pools.o \
                                        steering/hws/fs_hws.o
 
 #
index 915cd3277dfbe06b142e368770c8e613d9734b52..b40e5310bef74d01817672a782c455dc546af1e2 100644 (file)
@@ -75,6 +75,7 @@ struct mlx5_pkt_reformat {
        enum mlx5_flow_resource_owner owner;
        union {
                struct mlx5_fs_dr_action fs_dr_action;
+               struct mlx5_fs_hws_action fs_hws_action;
                u32 id;
        };
 };
index d8e1c4ebd364695fa3879c6d0e66a8e03b3516de..94d9caacd50fd154b7f07a6854172da5e4c3d3c7 100644 (file)
@@ -449,7 +449,8 @@ static void mlx5_fc_init(struct mlx5_fc *counter, struct mlx5_fc_bulk *bulk,
        counter->id = id;
 }
 
-static struct mlx5_fs_bulk *mlx5_fc_bulk_create(struct mlx5_core_dev *dev)
+static struct mlx5_fs_bulk *mlx5_fc_bulk_create(struct mlx5_core_dev *dev,
+                                               void *pool_ctx)
 {
        enum mlx5_fc_bulk_alloc_bitmask alloc_bitmask;
        struct mlx5_fc_bulk *fc_bulk;
@@ -518,7 +519,7 @@ static const struct mlx5_fs_pool_ops mlx5_fc_pool_ops = {
 static void
 mlx5_fc_pool_init(struct mlx5_fs_pool *fc_pool, struct mlx5_core_dev *dev)
 {
-       mlx5_fs_pool_init(fc_pool, dev, &mlx5_fc_pool_ops);
+       mlx5_fs_pool_init(fc_pool, dev, &mlx5_fc_pool_ops, NULL);
 }
 
 static void mlx5_fc_pool_cleanup(struct mlx5_fs_pool *fc_pool)
index b891d7b9e3e0cf1782b36a27a51c2ea5ed5b2324..f6c226664602ec6151b35047943ed2e5fe1419ef 100644 (file)
@@ -56,11 +56,12 @@ static int mlx5_fs_bulk_release_index(struct mlx5_fs_bulk *fs_bulk, int index)
 }
 
 void mlx5_fs_pool_init(struct mlx5_fs_pool *pool, struct mlx5_core_dev *dev,
-                      const struct mlx5_fs_pool_ops *ops)
+                      const struct mlx5_fs_pool_ops *ops, void *pool_ctx)
 {
        WARN_ON_ONCE(!ops || !ops->bulk_destroy || !ops->bulk_create ||
                     !ops->update_threshold);
        pool->dev = dev;
+       pool->pool_ctx = pool_ctx;
        mutex_init(&pool->pool_lock);
        INIT_LIST_HEAD(&pool->fully_used);
        INIT_LIST_HEAD(&pool->partially_used);
@@ -91,7 +92,7 @@ mlx5_fs_pool_alloc_new_bulk(struct mlx5_fs_pool *fs_pool)
        struct mlx5_core_dev *dev = fs_pool->dev;
        struct mlx5_fs_bulk *new_bulk;
 
-       new_bulk = fs_pool->ops->bulk_create(dev);
+       new_bulk = fs_pool->ops->bulk_create(dev, fs_pool->pool_ctx);
        if (new_bulk)
                fs_pool->available_units += new_bulk->bulk_len;
        fs_pool->ops->update_threshold(fs_pool);
index 3b149863260c742d037f13c32f28913f43da6126..f04ec3107498b2334e285cc5feb7c3588d8834c0 100644 (file)
@@ -21,7 +21,8 @@ struct mlx5_fs_pool;
 
 struct mlx5_fs_pool_ops {
        int (*bulk_destroy)(struct mlx5_core_dev *dev, struct mlx5_fs_bulk *bulk);
-       struct mlx5_fs_bulk * (*bulk_create)(struct mlx5_core_dev *dev);
+       struct mlx5_fs_bulk * (*bulk_create)(struct mlx5_core_dev *dev,
+                                            void *pool_ctx);
        void (*update_threshold)(struct mlx5_fs_pool *pool);
 };
 
@@ -44,7 +45,7 @@ void mlx5_fs_bulk_cleanup(struct mlx5_fs_bulk *fs_bulk);
 int mlx5_fs_bulk_get_free_amount(struct mlx5_fs_bulk *bulk);
 
 void mlx5_fs_pool_init(struct mlx5_fs_pool *pool, struct mlx5_core_dev *dev,
-                      const struct mlx5_fs_pool_ops *ops);
+                      const struct mlx5_fs_pool_ops *ops, void *pool_ctx);
 void mlx5_fs_pool_cleanup(struct mlx5_fs_pool *pool);
 int mlx5_fs_pool_acquire_index(struct mlx5_fs_pool *fs_pool,
                               struct mlx5_fs_pool_index *pool_index);
index 5987710f87062dd23a03b75aa05958aa149bcbd9..a584aa16d2d1e7e652b2def071014d987095bf85 100644 (file)
@@ -4,22 +4,31 @@
 #include <mlx5_core.h>
 #include <fs_core.h>
 #include <fs_cmd.h>
+#include "fs_hws_pools.h"
 #include "mlx5hws.h"
 
 #define MLX5HWS_CTX_MAX_NUM_OF_QUEUES 16
 #define MLX5HWS_CTX_QUEUE_SIZE 256
 
-static int mlx5_fs_init_hws_actions_pool(struct mlx5_fs_hws_context *fs_ctx)
+static struct mlx5hws_action *
+mlx5_fs_create_action_remove_header_vlan(struct mlx5hws_context *ctx);
+static void
+mlx5_fs_destroy_pr_pool(struct mlx5_fs_pool *pool, struct xarray *pr_pools,
+                       unsigned long index);
+
+static int mlx5_fs_init_hws_actions_pool(struct mlx5_core_dev *dev,
+                                        struct mlx5_fs_hws_context *fs_ctx)
 {
        u32 flags = MLX5HWS_ACTION_FLAG_HWS_FDB | MLX5HWS_ACTION_FLAG_SHARED;
        struct mlx5_fs_hws_actions_pool *hws_pool = &fs_ctx->hws_pool;
        struct mlx5hws_action_reformat_header reformat_hdr = {};
        struct mlx5hws_context *ctx = fs_ctx->hws_ctx;
        enum mlx5hws_action_type action_type;
+       int err = -ENOSPC;
 
        hws_pool->tag_action = mlx5hws_action_create_tag(ctx, flags);
        if (!hws_pool->tag_action)
-               return -ENOSPC;
+               return err;
        hws_pool->pop_vlan_action = mlx5hws_action_create_pop_vlan(ctx, flags);
        if (!hws_pool->pop_vlan_action)
                goto destroy_tag;
@@ -35,8 +44,28 @@ static int mlx5_fs_init_hws_actions_pool(struct mlx5_fs_hws_context *fs_ctx)
                                               &reformat_hdr, 0, flags);
        if (!hws_pool->decapl2_action)
                goto destroy_drop;
+       hws_pool->remove_hdr_vlan_action =
+               mlx5_fs_create_action_remove_header_vlan(ctx);
+       if (!hws_pool->remove_hdr_vlan_action)
+               goto destroy_decapl2;
+       err = mlx5_fs_hws_pr_pool_init(&hws_pool->insert_hdr_pool, dev, 0,
+                                      MLX5HWS_ACTION_TYP_INSERT_HEADER);
+       if (err)
+               goto destroy_remove_hdr;
+       err = mlx5_fs_hws_pr_pool_init(&hws_pool->dl3tnltol2_pool, dev, 0,
+                                      MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2);
+       if (err)
+               goto cleanup_insert_hdr;
+       xa_init(&hws_pool->el2tol3tnl_pools);
+       xa_init(&hws_pool->el2tol2tnl_pools);
        return 0;
 
+cleanup_insert_hdr:
+       mlx5_fs_hws_pr_pool_cleanup(&hws_pool->insert_hdr_pool);
+destroy_remove_hdr:
+       mlx5hws_action_destroy(hws_pool->remove_hdr_vlan_action);
+destroy_decapl2:
+       mlx5hws_action_destroy(hws_pool->decapl2_action);
 destroy_drop:
        mlx5hws_action_destroy(hws_pool->drop_action);
 destroy_push_vlan:
@@ -45,13 +74,24 @@ destroy_pop_vlan:
        mlx5hws_action_destroy(hws_pool->pop_vlan_action);
 destroy_tag:
        mlx5hws_action_destroy(hws_pool->tag_action);
-       return -ENOSPC;
+       return err;
 }
 
 static void mlx5_fs_cleanup_hws_actions_pool(struct mlx5_fs_hws_context *fs_ctx)
 {
        struct mlx5_fs_hws_actions_pool *hws_pool = &fs_ctx->hws_pool;
-
+       struct mlx5_fs_pool *pool;
+       unsigned long i;
+
+       xa_for_each(&hws_pool->el2tol2tnl_pools, i, pool)
+               mlx5_fs_destroy_pr_pool(pool, &hws_pool->el2tol2tnl_pools, i);
+       xa_destroy(&hws_pool->el2tol2tnl_pools);
+       xa_for_each(&hws_pool->el2tol3tnl_pools, i, pool)
+               mlx5_fs_destroy_pr_pool(pool, &hws_pool->el2tol3tnl_pools, i);
+       xa_destroy(&hws_pool->el2tol3tnl_pools);
+       mlx5_fs_hws_pr_pool_cleanup(&hws_pool->dl3tnltol2_pool);
+       mlx5_fs_hws_pr_pool_cleanup(&hws_pool->insert_hdr_pool);
+       mlx5hws_action_destroy(hws_pool->remove_hdr_vlan_action);
        mlx5hws_action_destroy(hws_pool->decapl2_action);
        mlx5hws_action_destroy(hws_pool->drop_action);
        mlx5hws_action_destroy(hws_pool->push_vlan_action);
@@ -74,7 +114,7 @@ static int mlx5_cmd_hws_create_ns(struct mlx5_flow_root_namespace *ns)
                mlx5_core_err(ns->dev, "Failed to create hws flow namespace\n");
                return -EINVAL;
        }
-       err = mlx5_fs_init_hws_actions_pool(&ns->fs_hws_context);
+       err = mlx5_fs_init_hws_actions_pool(ns->dev, &ns->fs_hws_context);
        if (err) {
                mlx5_core_err(ns->dev, "Failed to init hws actions pool\n");
                mlx5hws_context_close(ns->fs_hws_context.hws_ctx);
@@ -251,6 +291,247 @@ static int mlx5_cmd_hws_destroy_flow_group(struct mlx5_flow_root_namespace *ns,
        return mlx5hws_bwc_matcher_destroy(fg->fs_hws_matcher.matcher);
 }
 
+static struct mlx5hws_action *
+mlx5_fs_create_action_remove_header_vlan(struct mlx5hws_context *ctx)
+{
+       u32 flags = MLX5HWS_ACTION_FLAG_HWS_FDB | MLX5HWS_ACTION_FLAG_SHARED;
+       struct mlx5hws_action_remove_header_attr remove_hdr_vlan = {};
+
+       /* MAC anchor not supported in HWS reformat, use VLAN anchor */
+       remove_hdr_vlan.anchor = MLX5_REFORMAT_CONTEXT_ANCHOR_VLAN_START;
+       remove_hdr_vlan.offset = 0;
+       remove_hdr_vlan.size = sizeof(struct vlan_hdr);
+       return mlx5hws_action_create_remove_header(ctx, &remove_hdr_vlan, flags);
+}
+
+static struct mlx5hws_action *
+mlx5_fs_get_action_remove_header_vlan(struct mlx5_fs_hws_context *fs_ctx,
+                                     struct mlx5_pkt_reformat_params *params)
+{
+       if (!params ||
+           params->param_0 != MLX5_REFORMAT_CONTEXT_ANCHOR_MAC_START ||
+           params->param_1 != offsetof(struct vlan_ethhdr, h_vlan_proto) ||
+           params->size != sizeof(struct vlan_hdr))
+               return NULL;
+
+       return fs_ctx->hws_pool.remove_hdr_vlan_action;
+}
+
+static int
+mlx5_fs_verify_insert_header_params(struct mlx5_core_dev *mdev,
+                                   struct mlx5_pkt_reformat_params *params)
+{
+       if ((!params->data && params->size) || (params->data && !params->size) ||
+           MLX5_CAP_GEN_2(mdev, max_reformat_insert_size) < params->size ||
+           MLX5_CAP_GEN_2(mdev, max_reformat_insert_offset) < params->param_1) {
+               mlx5_core_err(mdev, "Invalid reformat params for INSERT_HDR\n");
+               return -EINVAL;
+       }
+       if (params->param_0 != MLX5_FS_INSERT_HDR_VLAN_ANCHOR ||
+           params->param_1 != MLX5_FS_INSERT_HDR_VLAN_OFFSET ||
+           params->size != MLX5_FS_INSERT_HDR_VLAN_SIZE) {
+               mlx5_core_err(mdev, "Only vlan insert header supported\n");
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static int
+mlx5_fs_verify_encap_decap_params(struct mlx5_core_dev *dev,
+                                 struct mlx5_pkt_reformat_params *params)
+{
+       if (params->param_0 || params->param_1) {
+               mlx5_core_err(dev, "Invalid reformat params\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static struct mlx5_fs_pool *
+mlx5_fs_get_pr_encap_pool(struct mlx5_core_dev *dev, struct xarray *pr_pools,
+                         enum mlx5hws_action_type reformat_type, size_t size)
+{
+       struct mlx5_fs_pool *pr_pool;
+       unsigned long index = size;
+       int err;
+
+       pr_pool = xa_load(pr_pools, index);
+       if (pr_pool)
+               return pr_pool;
+
+       pr_pool = kzalloc(sizeof(*pr_pool), GFP_KERNEL);
+       if (!pr_pool)
+               return ERR_PTR(-ENOMEM);
+       err = mlx5_fs_hws_pr_pool_init(pr_pool, dev, size, reformat_type);
+       if (err)
+               goto free_pr_pool;
+       err = xa_insert(pr_pools, index, pr_pool, GFP_KERNEL);
+       if (err)
+               goto cleanup_pr_pool;
+       return pr_pool;
+
+cleanup_pr_pool:
+       mlx5_fs_hws_pr_pool_cleanup(pr_pool);
+free_pr_pool:
+       kfree(pr_pool);
+       return ERR_PTR(err);
+}
+
+static void
+mlx5_fs_destroy_pr_pool(struct mlx5_fs_pool *pool, struct xarray *pr_pools,
+                       unsigned long index)
+{
+       xa_erase(pr_pools, index);
+       mlx5_fs_hws_pr_pool_cleanup(pool);
+       kfree(pool);
+}
+
+static int
+mlx5_cmd_hws_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
+                                  struct mlx5_pkt_reformat_params *params,
+                                  enum mlx5_flow_namespace_type namespace,
+                                  struct mlx5_pkt_reformat *pkt_reformat)
+{
+       struct mlx5_fs_hws_context *fs_ctx = &ns->fs_hws_context;
+       struct mlx5_fs_hws_actions_pool *hws_pool;
+       struct mlx5hws_action *hws_action = NULL;
+       struct mlx5_fs_hws_pr *pr_data = NULL;
+       struct mlx5_fs_pool *pr_pool = NULL;
+       struct mlx5_core_dev *dev = ns->dev;
+       u8 hdr_idx = 0;
+       int err;
+
+       if (!params)
+               return -EINVAL;
+
+       hws_pool = &fs_ctx->hws_pool;
+
+       switch (params->type) {
+       case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
+       case MLX5_REFORMAT_TYPE_L2_TO_NVGRE:
+       case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
+               if (mlx5_fs_verify_encap_decap_params(dev, params))
+                       return -EINVAL;
+               pr_pool = mlx5_fs_get_pr_encap_pool(dev, &hws_pool->el2tol2tnl_pools,
+                                                   MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2,
+                                                   params->size);
+               if (IS_ERR(pr_pool))
+                       return PTR_ERR(pr_pool);
+               break;
+       case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
+               if (mlx5_fs_verify_encap_decap_params(dev, params))
+                       return -EINVAL;
+               pr_pool = mlx5_fs_get_pr_encap_pool(dev, &hws_pool->el2tol3tnl_pools,
+                                                   MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3,
+                                                   params->size);
+               if (IS_ERR(pr_pool))
+                       return PTR_ERR(pr_pool);
+               break;
+       case MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2:
+               if (mlx5_fs_verify_encap_decap_params(dev, params))
+                       return -EINVAL;
+               pr_pool = &hws_pool->dl3tnltol2_pool;
+               hdr_idx = params->size == ETH_HLEN ?
+                         MLX5_FS_DL3TNLTOL2_MAC_HDR_IDX :
+                         MLX5_FS_DL3TNLTOL2_MAC_VLAN_HDR_IDX;
+               break;
+       case MLX5_REFORMAT_TYPE_INSERT_HDR:
+               err = mlx5_fs_verify_insert_header_params(dev, params);
+               if (err)
+                       return err;
+               pr_pool = &hws_pool->insert_hdr_pool;
+               break;
+       case MLX5_REFORMAT_TYPE_REMOVE_HDR:
+               hws_action = mlx5_fs_get_action_remove_header_vlan(fs_ctx, params);
+               if (!hws_action)
+                       mlx5_core_err(dev, "Only vlan remove header supported\n");
+               break;
+       default:
+               mlx5_core_err(ns->dev, "Packet-reformat not supported(%d)\n",
+                             params->type);
+               return -EOPNOTSUPP;
+       }
+
+       if (pr_pool) {
+               pr_data = mlx5_fs_hws_pr_pool_acquire_pr(pr_pool);
+               if (IS_ERR_OR_NULL(pr_data))
+                       return !pr_data ? -EINVAL : PTR_ERR(pr_data);
+               hws_action = pr_data->bulk->hws_action;
+               if (!hws_action) {
+                       mlx5_core_err(dev,
+                                     "Failed allocating packet-reformat action\n");
+                       err = -EINVAL;
+                       goto release_pr;
+               }
+               pr_data->data = kmemdup(params->data, params->size, GFP_KERNEL);
+               if (!pr_data->data) {
+                       err = -ENOMEM;
+                       goto release_pr;
+               }
+               pr_data->hdr_idx = hdr_idx;
+               pr_data->data_size = params->size;
+               pkt_reformat->fs_hws_action.pr_data = pr_data;
+       }
+
+       pkt_reformat->owner = MLX5_FLOW_RESOURCE_OWNER_SW;
+       pkt_reformat->fs_hws_action.hws_action = hws_action;
+       return 0;
+
+release_pr:
+       if (pr_pool && pr_data)
+               mlx5_fs_hws_pr_pool_release_pr(pr_pool, pr_data);
+       return err;
+}
+
+static void mlx5_cmd_hws_packet_reformat_dealloc(struct mlx5_flow_root_namespace *ns,
+                                                struct mlx5_pkt_reformat *pkt_reformat)
+{
+       struct mlx5_fs_hws_actions_pool *hws_pool = &ns->fs_hws_context.hws_pool;
+       struct mlx5_core_dev *dev = ns->dev;
+       struct mlx5_fs_hws_pr *pr_data;
+       struct mlx5_fs_pool *pr_pool;
+
+       if (pkt_reformat->reformat_type == MLX5_REFORMAT_TYPE_REMOVE_HDR)
+               return;
+
+       if (!pkt_reformat->fs_hws_action.pr_data) {
+               mlx5_core_err(ns->dev, "Failed release packet-reformat\n");
+               return;
+       }
+       pr_data = pkt_reformat->fs_hws_action.pr_data;
+
+       switch (pkt_reformat->reformat_type) {
+       case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
+       case MLX5_REFORMAT_TYPE_L2_TO_NVGRE:
+       case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
+               pr_pool = mlx5_fs_get_pr_encap_pool(dev, &hws_pool->el2tol2tnl_pools,
+                                                   MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2,
+                                                   pr_data->data_size);
+               break;
+       case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
+               pr_pool = mlx5_fs_get_pr_encap_pool(dev, &hws_pool->el2tol2tnl_pools,
+                                                   MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2,
+                                                   pr_data->data_size);
+               break;
+       case MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2:
+               pr_pool = &hws_pool->dl3tnltol2_pool;
+               break;
+       case MLX5_REFORMAT_TYPE_INSERT_HDR:
+               pr_pool = &hws_pool->insert_hdr_pool;
+               break;
+       default:
+               mlx5_core_err(ns->dev, "Unknown packet-reformat type\n");
+               return;
+       }
+       if (!pkt_reformat->fs_hws_action.pr_data || IS_ERR(pr_pool)) {
+               mlx5_core_err(ns->dev, "Failed release packet-reformat\n");
+               return;
+       }
+       kfree(pr_data->data);
+       mlx5_fs_hws_pr_pool_release_pr(pr_pool, pr_data);
+       pkt_reformat->fs_hws_action.pr_data = NULL;
+}
+
 static const struct mlx5_flow_cmds mlx5_flow_cmds_hws = {
        .create_flow_table = mlx5_cmd_hws_create_flow_table,
        .destroy_flow_table = mlx5_cmd_hws_destroy_flow_table,
@@ -258,6 +539,8 @@ static const struct mlx5_flow_cmds mlx5_flow_cmds_hws = {
        .update_root_ft = mlx5_cmd_hws_update_root_ft,
        .create_flow_group = mlx5_cmd_hws_create_flow_group,
        .destroy_flow_group = mlx5_cmd_hws_destroy_flow_group,
+       .packet_reformat_alloc = mlx5_cmd_hws_packet_reformat_alloc,
+       .packet_reformat_dealloc = mlx5_cmd_hws_packet_reformat_dealloc,
        .create_ns = mlx5_cmd_hws_create_ns,
        .destroy_ns = mlx5_cmd_hws_destroy_ns,
        .set_peer = mlx5_cmd_hws_set_peer,
index a2580b39d7285f8a69db4eb1fbee6193643cb8a0..19786838f6d6d5290d81ab0fc3ac5fb4dd64741c 100644 (file)
@@ -5,6 +5,7 @@
 #define _MLX5_FS_HWS_
 
 #include "mlx5hws.h"
+#include "fs_hws_pools.h"
 
 struct mlx5_fs_hws_actions_pool {
        struct mlx5hws_action *tag_action;
@@ -12,6 +13,11 @@ struct mlx5_fs_hws_actions_pool {
        struct mlx5hws_action *push_vlan_action;
        struct mlx5hws_action *drop_action;
        struct mlx5hws_action *decapl2_action;
+       struct mlx5hws_action *remove_hdr_vlan_action;
+       struct mlx5_fs_pool insert_hdr_pool;
+       struct mlx5_fs_pool dl3tnltol2_pool;
+       struct xarray el2tol3tnl_pools;
+       struct xarray el2tol2tnl_pools;
 };
 
 struct mlx5_fs_hws_context {
@@ -24,6 +30,12 @@ struct mlx5_fs_hws_table {
        bool miss_ft_set;
 };
 
+struct mlx5_fs_hws_action {
+       struct mlx5hws_action *hws_action;
+       struct mlx5_fs_pool *fs_pool;
+       struct mlx5_fs_hws_pr *pr_data;
+};
+
 struct mlx5_fs_hws_matcher {
        struct mlx5hws_bwc_matcher *matcher;
 };
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws_pools.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws_pools.c
new file mode 100644 (file)
index 0000000..b12b96c
--- /dev/null
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2025 NVIDIA Corporation & Affiliates */
+
+#include <mlx5_core.h>
+#include "fs_hws_pools.h"
+
+#define MLX5_FS_HWS_DEFAULT_BULK_LEN 65536
+#define MLX5_FS_HWS_POOL_MAX_THRESHOLD BIT(18)
+#define MLX5_FS_HWS_POOL_USED_BUFF_RATIO 10
+
+static struct mlx5hws_action *
+mlx5_fs_dl3tnltol2_bulk_action_create(struct mlx5hws_context *ctx)
+{
+       struct mlx5hws_action_reformat_header reformat_hdr[2] = {};
+       u32 flags = MLX5HWS_ACTION_FLAG_HWS_FDB;
+       enum mlx5hws_action_type reformat_type;
+       u32 log_bulk_size;
+
+       reformat_type = MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2;
+       reformat_hdr[MLX5_FS_DL3TNLTOL2_MAC_HDR_IDX].sz = ETH_HLEN;
+       reformat_hdr[MLX5_FS_DL3TNLTOL2_MAC_VLAN_HDR_IDX].sz = ETH_HLEN + VLAN_HLEN;
+
+       log_bulk_size = ilog2(MLX5_FS_HWS_DEFAULT_BULK_LEN);
+       return mlx5hws_action_create_reformat(ctx, reformat_type, 2,
+                                             reformat_hdr, log_bulk_size, flags);
+}
+
+static struct mlx5hws_action *
+mlx5_fs_el2tol3tnl_bulk_action_create(struct mlx5hws_context *ctx, size_t data_size)
+{
+       struct mlx5hws_action_reformat_header reformat_hdr = {};
+       u32 flags = MLX5HWS_ACTION_FLAG_HWS_FDB;
+       enum mlx5hws_action_type reformat_type;
+       u32 log_bulk_size;
+
+       reformat_type = MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3;
+       reformat_hdr.sz = data_size;
+
+       log_bulk_size = ilog2(MLX5_FS_HWS_DEFAULT_BULK_LEN);
+       return mlx5hws_action_create_reformat(ctx, reformat_type, 1,
+                                             &reformat_hdr, log_bulk_size, flags);
+}
+
+static struct mlx5hws_action *
+mlx5_fs_el2tol2tnl_bulk_action_create(struct mlx5hws_context *ctx, size_t data_size)
+{
+       struct mlx5hws_action_reformat_header reformat_hdr = {};
+       u32 flags = MLX5HWS_ACTION_FLAG_HWS_FDB;
+       enum mlx5hws_action_type reformat_type;
+       u32 log_bulk_size;
+
+       reformat_type = MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2;
+       reformat_hdr.sz = data_size;
+
+       log_bulk_size = ilog2(MLX5_FS_HWS_DEFAULT_BULK_LEN);
+       return mlx5hws_action_create_reformat(ctx, reformat_type, 1,
+                                             &reformat_hdr, log_bulk_size, flags);
+}
+
+static struct mlx5hws_action *
+mlx5_fs_insert_hdr_bulk_action_create(struct mlx5hws_context *ctx)
+{
+       struct mlx5hws_action_insert_header insert_hdr = {};
+       u32 flags = MLX5HWS_ACTION_FLAG_HWS_FDB;
+       u32 log_bulk_size;
+
+       log_bulk_size = ilog2(MLX5_FS_HWS_DEFAULT_BULK_LEN);
+       insert_hdr.hdr.sz = MLX5_FS_INSERT_HDR_VLAN_SIZE;
+       insert_hdr.anchor = MLX5_FS_INSERT_HDR_VLAN_ANCHOR;
+       insert_hdr.offset = MLX5_FS_INSERT_HDR_VLAN_OFFSET;
+
+       return mlx5hws_action_create_insert_header(ctx, 1, &insert_hdr,
+                                                  log_bulk_size, flags);
+}
+
+static struct mlx5hws_action *
+mlx5_fs_pr_bulk_action_create(struct mlx5_core_dev *dev,
+                             struct mlx5_fs_hws_pr_pool_ctx *pr_pool_ctx)
+{
+       struct mlx5_flow_root_namespace *root_ns;
+       struct mlx5hws_context *ctx;
+       size_t encap_data_size;
+
+       root_ns = mlx5_get_root_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
+       if (!root_ns || root_ns->mode != MLX5_FLOW_STEERING_MODE_HMFS)
+               return NULL;
+
+       ctx = root_ns->fs_hws_context.hws_ctx;
+       if (!ctx)
+               return NULL;
+
+       encap_data_size = pr_pool_ctx->encap_data_size;
+       switch (pr_pool_ctx->reformat_type) {
+       case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
+               return mlx5_fs_dl3tnltol2_bulk_action_create(ctx);
+       case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
+               return mlx5_fs_el2tol3tnl_bulk_action_create(ctx, encap_data_size);
+       case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
+               return mlx5_fs_el2tol2tnl_bulk_action_create(ctx, encap_data_size);
+       case MLX5HWS_ACTION_TYP_INSERT_HEADER:
+               return mlx5_fs_insert_hdr_bulk_action_create(ctx);
+       default:
+               return NULL;
+       }
+       return NULL;
+}
+
+static struct mlx5_fs_bulk *
+mlx5_fs_hws_pr_bulk_create(struct mlx5_core_dev *dev, void *pool_ctx)
+{
+       struct mlx5_fs_hws_pr_pool_ctx *pr_pool_ctx;
+       struct mlx5_fs_hws_pr_bulk *pr_bulk;
+       int bulk_len;
+       int i;
+
+       if (!pool_ctx)
+               return NULL;
+       pr_pool_ctx = pool_ctx;
+       bulk_len = MLX5_FS_HWS_DEFAULT_BULK_LEN;
+       pr_bulk = kvzalloc(struct_size(pr_bulk, prs_data, bulk_len), GFP_KERNEL);
+       if (!pr_bulk)
+               return NULL;
+
+       if (mlx5_fs_bulk_init(dev, &pr_bulk->fs_bulk, bulk_len))
+               goto free_pr_bulk;
+
+       for (i = 0; i < bulk_len; i++) {
+               pr_bulk->prs_data[i].bulk = pr_bulk;
+               pr_bulk->prs_data[i].offset = i;
+       }
+
+       pr_bulk->hws_action = mlx5_fs_pr_bulk_action_create(dev, pr_pool_ctx);
+       if (!pr_bulk->hws_action)
+               goto cleanup_fs_bulk;
+
+       return &pr_bulk->fs_bulk;
+
+cleanup_fs_bulk:
+       mlx5_fs_bulk_cleanup(&pr_bulk->fs_bulk);
+free_pr_bulk:
+       kvfree(pr_bulk);
+       return NULL;
+}
+
+static int
+mlx5_fs_hws_pr_bulk_destroy(struct mlx5_core_dev *dev, struct mlx5_fs_bulk *fs_bulk)
+{
+       struct mlx5_fs_hws_pr_bulk *pr_bulk;
+
+       pr_bulk = container_of(fs_bulk, struct mlx5_fs_hws_pr_bulk, fs_bulk);
+       if (mlx5_fs_bulk_get_free_amount(fs_bulk) < fs_bulk->bulk_len) {
+               mlx5_core_err(dev, "Freeing bulk before all reformats were released\n");
+               return -EBUSY;
+       }
+
+       mlx5hws_action_destroy(pr_bulk->hws_action);
+       mlx5_fs_bulk_cleanup(fs_bulk);
+       kvfree(pr_bulk);
+
+       return 0;
+}
+
+static void mlx5_hws_pool_update_threshold(struct mlx5_fs_pool *hws_pool)
+{
+       hws_pool->threshold = min_t(int, MLX5_FS_HWS_POOL_MAX_THRESHOLD,
+                                   hws_pool->used_units / MLX5_FS_HWS_POOL_USED_BUFF_RATIO);
+}
+
+static const struct mlx5_fs_pool_ops mlx5_fs_hws_pr_pool_ops = {
+       .bulk_create = mlx5_fs_hws_pr_bulk_create,
+       .bulk_destroy = mlx5_fs_hws_pr_bulk_destroy,
+       .update_threshold = mlx5_hws_pool_update_threshold,
+};
+
+int mlx5_fs_hws_pr_pool_init(struct mlx5_fs_pool *pr_pool,
+                            struct mlx5_core_dev *dev, size_t encap_data_size,
+                            enum mlx5hws_action_type reformat_type)
+{
+       struct mlx5_fs_hws_pr_pool_ctx *pr_pool_ctx;
+
+       if (reformat_type != MLX5HWS_ACTION_TYP_INSERT_HEADER &&
+           reformat_type != MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2 &&
+           reformat_type != MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3 &&
+           reformat_type != MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2)
+               return -EOPNOTSUPP;
+
+       pr_pool_ctx = kzalloc(sizeof(*pr_pool_ctx), GFP_KERNEL);
+       if (!pr_pool_ctx)
+               return -ENOMEM;
+       pr_pool_ctx->reformat_type = reformat_type;
+       pr_pool_ctx->encap_data_size = encap_data_size;
+       mlx5_fs_pool_init(pr_pool, dev, &mlx5_fs_hws_pr_pool_ops, pr_pool_ctx);
+       return 0;
+}
+
+void mlx5_fs_hws_pr_pool_cleanup(struct mlx5_fs_pool *pr_pool)
+{
+       struct mlx5_fs_hws_pr_pool_ctx *pr_pool_ctx;
+
+       mlx5_fs_pool_cleanup(pr_pool);
+       pr_pool_ctx = pr_pool->pool_ctx;
+       if (!pr_pool_ctx)
+               return;
+       kfree(pr_pool_ctx);
+}
+
+struct mlx5_fs_hws_pr *
+mlx5_fs_hws_pr_pool_acquire_pr(struct mlx5_fs_pool *pr_pool)
+{
+       struct mlx5_fs_pool_index pool_index = {};
+       struct mlx5_fs_hws_pr_bulk *pr_bulk;
+       int err;
+
+       err = mlx5_fs_pool_acquire_index(pr_pool, &pool_index);
+       if (err)
+               return ERR_PTR(err);
+       pr_bulk = container_of(pool_index.fs_bulk, struct mlx5_fs_hws_pr_bulk,
+                              fs_bulk);
+       return &pr_bulk->prs_data[pool_index.index];
+}
+
+void mlx5_fs_hws_pr_pool_release_pr(struct mlx5_fs_pool *pr_pool,
+                                   struct mlx5_fs_hws_pr *pr_data)
+{
+       struct mlx5_fs_bulk *fs_bulk = &pr_data->bulk->fs_bulk;
+       struct mlx5_fs_pool_index pool_index = {};
+       struct mlx5_core_dev *dev = pr_pool->dev;
+
+       pool_index.fs_bulk = fs_bulk;
+       pool_index.index = pr_data->offset;
+       if (mlx5_fs_pool_release_index(pr_pool, &pool_index))
+               mlx5_core_warn(dev, "Attempted to release packet reformat which is not acquired\n");
+}
+
+struct mlx5hws_action *mlx5_fs_hws_pr_get_action(struct mlx5_fs_hws_pr *pr_data)
+{
+       return pr_data->bulk->hws_action;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws_pools.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws_pools.h
new file mode 100644 (file)
index 0000000..544b277
--- /dev/null
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2025 NVIDIA Corporation & Affiliates */
+
+#ifndef __MLX5_FS_HWS_POOLS_H__
+#define __MLX5_FS_HWS_POOLS_H__
+
+#include <linux/if_vlan.h>
+#include "fs_pool.h"
+#include "fs_core.h"
+
+#define MLX5_FS_INSERT_HDR_VLAN_ANCHOR MLX5_REFORMAT_CONTEXT_ANCHOR_MAC_START
+#define MLX5_FS_INSERT_HDR_VLAN_OFFSET offsetof(struct vlan_ethhdr, h_vlan_proto)
+#define MLX5_FS_INSERT_HDR_VLAN_SIZE sizeof(struct vlan_hdr)
+
+enum {
+       MLX5_FS_DL3TNLTOL2_MAC_HDR_IDX = 0,
+       MLX5_FS_DL3TNLTOL2_MAC_VLAN_HDR_IDX,
+};
+
+struct mlx5_fs_hws_pr {
+       struct mlx5_fs_hws_pr_bulk *bulk;
+       u32 offset;
+       u8 hdr_idx;
+       u8 *data;
+       size_t data_size;
+};
+
+struct mlx5_fs_hws_pr_bulk {
+       struct mlx5_fs_bulk fs_bulk;
+       struct mlx5hws_action *hws_action;
+       struct mlx5_fs_hws_pr prs_data[];
+};
+
+struct mlx5_fs_hws_pr_pool_ctx {
+       enum mlx5hws_action_type reformat_type;
+       size_t encap_data_size;
+};
+
+int mlx5_fs_hws_pr_pool_init(struct mlx5_fs_pool *pr_pool,
+                            struct mlx5_core_dev *dev, size_t encap_data_size,
+                            enum mlx5hws_action_type reformat_type);
+void mlx5_fs_hws_pr_pool_cleanup(struct mlx5_fs_pool *pr_pool);
+
+struct mlx5_fs_hws_pr *mlx5_fs_hws_pr_pool_acquire_pr(struct mlx5_fs_pool *pr_pool);
+void mlx5_fs_hws_pr_pool_release_pr(struct mlx5_fs_pool *pr_pool,
+                                   struct mlx5_fs_hws_pr *pr_data);
+struct mlx5hws_action *mlx5_fs_hws_pr_get_action(struct mlx5_fs_hws_pr *pr_data);
+#endif /* __MLX5_FS_HWS_POOLS_H__ */
index 370f533da107bc1e04c7aadbe32c5eb851ef09e3..bb99a35fc6a23afd9497975fa46893adcda3b130 100644 (file)
@@ -7025,6 +7025,7 @@ struct mlx5_ifc_alloc_packet_reformat_context_out_bits {
 
 enum {
        MLX5_REFORMAT_CONTEXT_ANCHOR_MAC_START = 0x1,
+       MLX5_REFORMAT_CONTEXT_ANCHOR_VLAN_START = 0x2,
        MLX5_REFORMAT_CONTEXT_ANCHOR_IP_START = 0x7,
        MLX5_REFORMAT_CONTEXT_ANCHOR_TCP_UDP_START = 0x9,
 };