]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net/mlx5: fs, add mlx5_fs_pool API
authorMoshe Shemesh <moshe@nvidia.com>
Thu, 19 Dec 2024 17:58:34 +0000 (19:58 +0200)
committerJakub Kicinski <kuba@kernel.org>
Mon, 23 Dec 2024 18:34:45 +0000 (10:34 -0800)
Refactor fc_pool API to create generic fs_pool API, as HW steering has
more flow steering elements which can take advantage of the same pool of
bulks API. Change fs_counters code to use the fs_pool API.

Note, removed __counted_by from struct mlx5_fc_bulk as bulk_len is now
inner struct member. It will be added back once __counted_by can support
inner struct members.

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/20241219175841.1094544-5-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_counters.c
drivers/net/ethernet/mellanox/mlx5/core/fs_pool.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/fs_pool.h [new file with mode: 0644]

index be3d0876c521d17ba15bbf292b637faf67154be6..79fe09de0a9fd1928fa274004554b7885c7700a2 100644 (file)
@@ -17,7 +17,7 @@ mlx5_core-y :=        main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
                fs_counters.o fs_ft_pool.o rl.o lag/debugfs.o lag/lag.o dev.o events.o wq.o lib/gid.o \
                lib/devcom.o lib/pci_vsc.o lib/dm.o lib/fs_ttc.o diag/fs_tracepoint.o \
                diag/fw_tracer.o diag/crdump.o devlink.o diag/rsc_dump.o diag/reporter_vnic.o \
-               fw_reset.o qos.o lib/tout.o lib/aso.o wc.o
+               fw_reset.o qos.o lib/tout.o lib/aso.o wc.o fs_pool.o
 
 #
 # Netdev basic
index 7d56deaa460972a8d7bab9999f808e28f58f5061..d8e1c4ebd364695fa3879c6d0e66a8e03b3516de 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/mlx5/fs.h>
 #include "mlx5_core.h"
 #include "fs_core.h"
+#include "fs_pool.h"
 #include "fs_cmd.h"
 
 #define MLX5_FC_STATS_PERIOD msecs_to_jiffies(1000)
@@ -65,17 +66,6 @@ struct mlx5_fc {
        u64 lastbytes;
 };
 
-struct mlx5_fc_pool {
-       struct mlx5_core_dev *dev;
-       struct mutex pool_lock; /* protects pool lists */
-       struct list_head fully_used;
-       struct list_head partially_used;
-       struct list_head unused;
-       int available_fcs;
-       int used_fcs;
-       int threshold;
-};
-
 struct mlx5_fc_stats {
        struct xarray counters;
 
@@ -86,13 +76,13 @@ struct mlx5_fc_stats {
        int bulk_query_len;
        bool bulk_query_alloc_failed;
        unsigned long next_bulk_query_alloc;
-       struct mlx5_fc_pool fc_pool;
+       struct mlx5_fs_pool fc_pool;
 };
 
-static void mlx5_fc_pool_init(struct mlx5_fc_pool *fc_pool, struct mlx5_core_dev *dev);
-static void mlx5_fc_pool_cleanup(struct mlx5_fc_pool *fc_pool);
-static struct mlx5_fc *mlx5_fc_pool_acquire_counter(struct mlx5_fc_pool *fc_pool);
-static void mlx5_fc_pool_release_counter(struct mlx5_fc_pool *fc_pool, struct mlx5_fc *fc);
+static void mlx5_fc_pool_init(struct mlx5_fs_pool *fc_pool, struct mlx5_core_dev *dev);
+static void mlx5_fc_pool_cleanup(struct mlx5_fs_pool *fc_pool);
+static struct mlx5_fc *mlx5_fc_pool_acquire_counter(struct mlx5_fs_pool *fc_pool);
+static void mlx5_fc_pool_release_counter(struct mlx5_fs_pool *fc_pool, struct mlx5_fc *fc);
 
 static int get_init_bulk_query_len(struct mlx5_core_dev *dev)
 {
@@ -447,11 +437,9 @@ void mlx5_fc_update_sampling_interval(struct mlx5_core_dev *dev,
 /* Flow counter bluks */
 
 struct mlx5_fc_bulk {
-       struct list_head pool_list;
+       struct mlx5_fs_bulk fs_bulk;
        u32 base_id;
-       int bulk_len;
-       unsigned long *bitmask;
-       struct mlx5_fc fcs[] __counted_by(bulk_len);
+       struct mlx5_fc fcs[];
 };
 
 static void mlx5_fc_init(struct mlx5_fc *counter, struct mlx5_fc_bulk *bulk,
@@ -461,16 +449,10 @@ static void mlx5_fc_init(struct mlx5_fc *counter, struct mlx5_fc_bulk *bulk,
        counter->id = id;
 }
 
-static int mlx5_fc_bulk_get_free_fcs_amount(struct mlx5_fc_bulk *bulk)
-{
-       return bitmap_weight(bulk->bitmask, bulk->bulk_len);
-}
-
-static struct mlx5_fc_bulk *mlx5_fc_bulk_create(struct mlx5_core_dev *dev)
+static struct mlx5_fs_bulk *mlx5_fc_bulk_create(struct mlx5_core_dev *dev)
 {
        enum mlx5_fc_bulk_alloc_bitmask alloc_bitmask;
-       struct mlx5_fc_bulk *bulk;
-       int err = -ENOMEM;
+       struct mlx5_fc_bulk *fc_bulk;
        int bulk_len;
        u32 base_id;
        int i;
@@ -478,71 +460,97 @@ static struct mlx5_fc_bulk *mlx5_fc_bulk_create(struct mlx5_core_dev *dev)
        alloc_bitmask = MLX5_CAP_GEN(dev, flow_counter_bulk_alloc);
        bulk_len = alloc_bitmask > 0 ? MLX5_FC_BULK_NUM_FCS(alloc_bitmask) : 1;
 
-       bulk = kvzalloc(struct_size(bulk, fcs, bulk_len), GFP_KERNEL);
-       if (!bulk)
-               goto err_alloc_bulk;
+       fc_bulk = kvzalloc(struct_size(fc_bulk, fcs, bulk_len), GFP_KERNEL);
+       if (!fc_bulk)
+               return NULL;
 
-       bulk->bitmask = kvcalloc(BITS_TO_LONGS(bulk_len), sizeof(unsigned long),
-                                GFP_KERNEL);
-       if (!bulk->bitmask)
-               goto err_alloc_bitmask;
+       if (mlx5_fs_bulk_init(dev, &fc_bulk->fs_bulk, bulk_len))
+               goto fc_bulk_free;
 
-       err = mlx5_cmd_fc_bulk_alloc(dev, alloc_bitmask, &base_id);
-       if (err)
-               goto err_mlx5_cmd_bulk_alloc;
-
-       bulk->base_id = base_id;
-       bulk->bulk_len = bulk_len;
-       for (i = 0; i < bulk_len; i++) {
-               mlx5_fc_init(&bulk->fcs[i], bulk, base_id + i);
-               set_bit(i, bulk->bitmask);
-       }
+       if (mlx5_cmd_fc_bulk_alloc(dev, alloc_bitmask, &base_id))
+               goto fs_bulk_cleanup;
+       fc_bulk->base_id = base_id;
+       for (i = 0; i < bulk_len; i++)
+               mlx5_fc_init(&fc_bulk->fcs[i], fc_bulk, base_id + i);
 
-       return bulk;
+       return &fc_bulk->fs_bulk;
 
-err_mlx5_cmd_bulk_alloc:
-       kvfree(bulk->bitmask);
-err_alloc_bitmask:
-       kvfree(bulk);
-err_alloc_bulk:
-       return ERR_PTR(err);
+fs_bulk_cleanup:
+       mlx5_fs_bulk_cleanup(&fc_bulk->fs_bulk);
+fc_bulk_free:
+       kvfree(fc_bulk);
+       return NULL;
 }
 
 static int
-mlx5_fc_bulk_destroy(struct mlx5_core_dev *dev, struct mlx5_fc_bulk *bulk)
+mlx5_fc_bulk_destroy(struct mlx5_core_dev *dev, struct mlx5_fs_bulk *fs_bulk)
 {
-       if (mlx5_fc_bulk_get_free_fcs_amount(bulk) < bulk->bulk_len) {
+       struct mlx5_fc_bulk *fc_bulk = container_of(fs_bulk,
+                                                   struct mlx5_fc_bulk,
+                                                   fs_bulk);
+
+       if (mlx5_fs_bulk_get_free_amount(fs_bulk) < fs_bulk->bulk_len) {
                mlx5_core_err(dev, "Freeing bulk before all counters were released\n");
                return -EBUSY;
        }
 
-       mlx5_cmd_fc_free(dev, bulk->base_id);
-       kvfree(bulk->bitmask);
-       kvfree(bulk);
+       mlx5_cmd_fc_free(dev, fc_bulk->base_id);
+       mlx5_fs_bulk_cleanup(fs_bulk);
+       kvfree(fc_bulk);
 
        return 0;
 }
 
-static struct mlx5_fc *mlx5_fc_bulk_acquire_fc(struct mlx5_fc_bulk *bulk)
+static void mlx5_fc_pool_update_threshold(struct mlx5_fs_pool *fc_pool)
 {
-       int free_fc_index = find_first_bit(bulk->bitmask, bulk->bulk_len);
+       fc_pool->threshold = min_t(int, MLX5_FC_POOL_MAX_THRESHOLD,
+                                  fc_pool->used_units / MLX5_FC_POOL_USED_BUFF_RATIO);
+}
 
-       if (free_fc_index >= bulk->bulk_len)
-               return ERR_PTR(-ENOSPC);
+/* Flow counters pool API */
 
-       clear_bit(free_fc_index, bulk->bitmask);
-       return &bulk->fcs[free_fc_index];
+static const struct mlx5_fs_pool_ops mlx5_fc_pool_ops = {
+       .bulk_destroy = mlx5_fc_bulk_destroy,
+       .bulk_create = mlx5_fc_bulk_create,
+       .update_threshold = mlx5_fc_pool_update_threshold,
+};
+
+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);
 }
 
-static int mlx5_fc_bulk_release_fc(struct mlx5_fc_bulk *bulk, struct mlx5_fc *fc)
+static void mlx5_fc_pool_cleanup(struct mlx5_fs_pool *fc_pool)
 {
-       int fc_index = fc->id - bulk->base_id;
+       mlx5_fs_pool_cleanup(fc_pool);
+}
 
-       if (test_bit(fc_index, bulk->bitmask))
-               return -EINVAL;
+static struct mlx5_fc *
+mlx5_fc_pool_acquire_counter(struct mlx5_fs_pool *fc_pool)
+{
+       struct mlx5_fs_pool_index pool_index = {};
+       struct mlx5_fc_bulk *fc_bulk;
+       int err;
 
-       set_bit(fc_index, bulk->bitmask);
-       return 0;
+       err = mlx5_fs_pool_acquire_index(fc_pool, &pool_index);
+       if (err)
+               return ERR_PTR(err);
+       fc_bulk = container_of(pool_index.fs_bulk, struct mlx5_fc_bulk, fs_bulk);
+       return &fc_bulk->fcs[pool_index.index];
+}
+
+static void
+mlx5_fc_pool_release_counter(struct mlx5_fs_pool *fc_pool, struct mlx5_fc *fc)
+{
+       struct mlx5_fs_bulk *fs_bulk = &fc->bulk->fs_bulk;
+       struct mlx5_fs_pool_index pool_index = {};
+       struct mlx5_core_dev *dev = fc_pool->dev;
+
+       pool_index.fs_bulk = fs_bulk;
+       pool_index.index = fc->id - fc->bulk->base_id;
+       if (mlx5_fs_pool_release_index(fc_pool, &pool_index))
+               mlx5_core_warn(dev, "Attempted to release a counter which is not acquired\n");
 }
 
 /**
@@ -573,7 +581,7 @@ mlx5_fc_local_create(u32 counter_id, u32 offset, u32 bulk_size)
        counter->type = MLX5_FC_TYPE_LOCAL;
        counter->id = counter_id;
        fc_bulk->base_id = counter_id - offset;
-       fc_bulk->bulk_len = bulk_size;
+       fc_bulk->fs_bulk.bulk_len = bulk_size;
        counter->bulk = fc_bulk;
        return counter;
 }
@@ -588,141 +596,3 @@ void mlx5_fc_local_destroy(struct mlx5_fc *counter)
        kfree(counter);
 }
 EXPORT_SYMBOL(mlx5_fc_local_destroy);
-
-/* Flow counters pool API */
-
-static void mlx5_fc_pool_init(struct mlx5_fc_pool *fc_pool, struct mlx5_core_dev *dev)
-{
-       fc_pool->dev = dev;
-       mutex_init(&fc_pool->pool_lock);
-       INIT_LIST_HEAD(&fc_pool->fully_used);
-       INIT_LIST_HEAD(&fc_pool->partially_used);
-       INIT_LIST_HEAD(&fc_pool->unused);
-       fc_pool->available_fcs = 0;
-       fc_pool->used_fcs = 0;
-       fc_pool->threshold = 0;
-}
-
-static void mlx5_fc_pool_cleanup(struct mlx5_fc_pool *fc_pool)
-{
-       struct mlx5_core_dev *dev = fc_pool->dev;
-       struct mlx5_fc_bulk *bulk;
-       struct mlx5_fc_bulk *tmp;
-
-       list_for_each_entry_safe(bulk, tmp, &fc_pool->fully_used, pool_list)
-               mlx5_fc_bulk_destroy(dev, bulk);
-       list_for_each_entry_safe(bulk, tmp, &fc_pool->partially_used, pool_list)
-               mlx5_fc_bulk_destroy(dev, bulk);
-       list_for_each_entry_safe(bulk, tmp, &fc_pool->unused, pool_list)
-               mlx5_fc_bulk_destroy(dev, bulk);
-}
-
-static void mlx5_fc_pool_update_threshold(struct mlx5_fc_pool *fc_pool)
-{
-       fc_pool->threshold = min_t(int, MLX5_FC_POOL_MAX_THRESHOLD,
-                                  fc_pool->used_fcs / MLX5_FC_POOL_USED_BUFF_RATIO);
-}
-
-static struct mlx5_fc_bulk *
-mlx5_fc_pool_alloc_new_bulk(struct mlx5_fc_pool *fc_pool)
-{
-       struct mlx5_core_dev *dev = fc_pool->dev;
-       struct mlx5_fc_bulk *new_bulk;
-
-       new_bulk = mlx5_fc_bulk_create(dev);
-       if (!IS_ERR(new_bulk))
-               fc_pool->available_fcs += new_bulk->bulk_len;
-       mlx5_fc_pool_update_threshold(fc_pool);
-       return new_bulk;
-}
-
-static void
-mlx5_fc_pool_free_bulk(struct mlx5_fc_pool *fc_pool, struct mlx5_fc_bulk *bulk)
-{
-       struct mlx5_core_dev *dev = fc_pool->dev;
-
-       fc_pool->available_fcs -= bulk->bulk_len;
-       mlx5_fc_bulk_destroy(dev, bulk);
-       mlx5_fc_pool_update_threshold(fc_pool);
-}
-
-static struct mlx5_fc *
-mlx5_fc_pool_acquire_from_list(struct list_head *src_list,
-                              struct list_head *next_list,
-                              bool move_non_full_bulk)
-{
-       struct mlx5_fc_bulk *bulk;
-       struct mlx5_fc *fc;
-
-       if (list_empty(src_list))
-               return ERR_PTR(-ENODATA);
-
-       bulk = list_first_entry(src_list, struct mlx5_fc_bulk, pool_list);
-       fc = mlx5_fc_bulk_acquire_fc(bulk);
-       if (move_non_full_bulk || mlx5_fc_bulk_get_free_fcs_amount(bulk) == 0)
-               list_move(&bulk->pool_list, next_list);
-       return fc;
-}
-
-static struct mlx5_fc *
-mlx5_fc_pool_acquire_counter(struct mlx5_fc_pool *fc_pool)
-{
-       struct mlx5_fc_bulk *new_bulk;
-       struct mlx5_fc *fc;
-
-       mutex_lock(&fc_pool->pool_lock);
-
-       fc = mlx5_fc_pool_acquire_from_list(&fc_pool->partially_used,
-                                           &fc_pool->fully_used, false);
-       if (IS_ERR(fc))
-               fc = mlx5_fc_pool_acquire_from_list(&fc_pool->unused,
-                                                   &fc_pool->partially_used,
-                                                   true);
-       if (IS_ERR(fc)) {
-               new_bulk = mlx5_fc_pool_alloc_new_bulk(fc_pool);
-               if (IS_ERR(new_bulk)) {
-                       fc = ERR_CAST(new_bulk);
-                       goto out;
-               }
-               fc = mlx5_fc_bulk_acquire_fc(new_bulk);
-               list_add(&new_bulk->pool_list, &fc_pool->partially_used);
-       }
-       fc_pool->available_fcs--;
-       fc_pool->used_fcs++;
-
-out:
-       mutex_unlock(&fc_pool->pool_lock);
-       return fc;
-}
-
-static void
-mlx5_fc_pool_release_counter(struct mlx5_fc_pool *fc_pool, struct mlx5_fc *fc)
-{
-       struct mlx5_core_dev *dev = fc_pool->dev;
-       struct mlx5_fc_bulk *bulk = fc->bulk;
-       int bulk_free_fcs_amount;
-
-       mutex_lock(&fc_pool->pool_lock);
-
-       if (mlx5_fc_bulk_release_fc(bulk, fc)) {
-               mlx5_core_warn(dev, "Attempted to release a counter which is not acquired\n");
-               goto unlock;
-       }
-
-       fc_pool->available_fcs++;
-       fc_pool->used_fcs--;
-
-       bulk_free_fcs_amount = mlx5_fc_bulk_get_free_fcs_amount(bulk);
-       if (bulk_free_fcs_amount == 1)
-               list_move_tail(&bulk->pool_list, &fc_pool->partially_used);
-       if (bulk_free_fcs_amount == bulk->bulk_len) {
-               list_del(&bulk->pool_list);
-               if (fc_pool->available_fcs > fc_pool->threshold)
-                       mlx5_fc_pool_free_bulk(fc_pool, bulk);
-               else
-                       list_add(&bulk->pool_list, &fc_pool->unused);
-       }
-
-unlock:
-       mutex_unlock(&fc_pool->pool_lock);
-}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_pool.c
new file mode 100644 (file)
index 0000000..b891d7b
--- /dev/null
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
+
+#include <mlx5_core.h>
+#include "fs_pool.h"
+
+int mlx5_fs_bulk_init(struct mlx5_core_dev *dev, struct mlx5_fs_bulk *fs_bulk,
+                     int bulk_len)
+{
+       int i;
+
+       fs_bulk->bitmask = kvcalloc(BITS_TO_LONGS(bulk_len), sizeof(unsigned long),
+                                   GFP_KERNEL);
+       if (!fs_bulk->bitmask)
+               return -ENOMEM;
+
+       fs_bulk->bulk_len = bulk_len;
+       for (i = 0; i < bulk_len; i++)
+               set_bit(i, fs_bulk->bitmask);
+
+       return 0;
+}
+
+void mlx5_fs_bulk_cleanup(struct mlx5_fs_bulk *fs_bulk)
+{
+       kvfree(fs_bulk->bitmask);
+}
+
+int mlx5_fs_bulk_get_free_amount(struct mlx5_fs_bulk *bulk)
+{
+       return bitmap_weight(bulk->bitmask, bulk->bulk_len);
+}
+
+static int mlx5_fs_bulk_acquire_index(struct mlx5_fs_bulk *fs_bulk,
+                                     struct mlx5_fs_pool_index *pool_index)
+{
+       int free_index = find_first_bit(fs_bulk->bitmask, fs_bulk->bulk_len);
+
+       WARN_ON_ONCE(!pool_index || !fs_bulk);
+       if (free_index >= fs_bulk->bulk_len)
+               return -ENOSPC;
+
+       clear_bit(free_index, fs_bulk->bitmask);
+       pool_index->fs_bulk = fs_bulk;
+       pool_index->index = free_index;
+       return 0;
+}
+
+static int mlx5_fs_bulk_release_index(struct mlx5_fs_bulk *fs_bulk, int index)
+{
+       if (test_bit(index, fs_bulk->bitmask))
+               return -EINVAL;
+
+       set_bit(index, fs_bulk->bitmask);
+       return 0;
+}
+
+void mlx5_fs_pool_init(struct mlx5_fs_pool *pool, struct mlx5_core_dev *dev,
+                      const struct mlx5_fs_pool_ops *ops)
+{
+       WARN_ON_ONCE(!ops || !ops->bulk_destroy || !ops->bulk_create ||
+                    !ops->update_threshold);
+       pool->dev = dev;
+       mutex_init(&pool->pool_lock);
+       INIT_LIST_HEAD(&pool->fully_used);
+       INIT_LIST_HEAD(&pool->partially_used);
+       INIT_LIST_HEAD(&pool->unused);
+       pool->available_units = 0;
+       pool->used_units = 0;
+       pool->threshold = 0;
+       pool->ops = ops;
+}
+
+void mlx5_fs_pool_cleanup(struct mlx5_fs_pool *pool)
+{
+       struct mlx5_core_dev *dev = pool->dev;
+       struct mlx5_fs_bulk *bulk;
+       struct mlx5_fs_bulk *tmp;
+
+       list_for_each_entry_safe(bulk, tmp, &pool->fully_used, pool_list)
+               pool->ops->bulk_destroy(dev, bulk);
+       list_for_each_entry_safe(bulk, tmp, &pool->partially_used, pool_list)
+               pool->ops->bulk_destroy(dev, bulk);
+       list_for_each_entry_safe(bulk, tmp, &pool->unused, pool_list)
+               pool->ops->bulk_destroy(dev, bulk);
+}
+
+static struct mlx5_fs_bulk *
+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);
+       if (new_bulk)
+               fs_pool->available_units += new_bulk->bulk_len;
+       fs_pool->ops->update_threshold(fs_pool);
+       return new_bulk;
+}
+
+static void
+mlx5_fs_pool_free_bulk(struct mlx5_fs_pool *fs_pool, struct mlx5_fs_bulk *bulk)
+{
+       struct mlx5_core_dev *dev = fs_pool->dev;
+
+       fs_pool->available_units -= bulk->bulk_len;
+       fs_pool->ops->bulk_destroy(dev, bulk);
+       fs_pool->ops->update_threshold(fs_pool);
+}
+
+static int
+mlx5_fs_pool_acquire_from_list(struct list_head *src_list,
+                              struct list_head *next_list,
+                              bool move_non_full_bulk,
+                              struct mlx5_fs_pool_index *pool_index)
+{
+       struct mlx5_fs_bulk *fs_bulk;
+       int err;
+
+       if (list_empty(src_list))
+               return -ENODATA;
+
+       fs_bulk = list_first_entry(src_list, struct mlx5_fs_bulk, pool_list);
+       err = mlx5_fs_bulk_acquire_index(fs_bulk, pool_index);
+       if (move_non_full_bulk || mlx5_fs_bulk_get_free_amount(fs_bulk) == 0)
+               list_move(&fs_bulk->pool_list, next_list);
+       return err;
+}
+
+int mlx5_fs_pool_acquire_index(struct mlx5_fs_pool *fs_pool,
+                              struct mlx5_fs_pool_index *pool_index)
+{
+       struct mlx5_fs_bulk *new_bulk;
+       int err;
+
+       mutex_lock(&fs_pool->pool_lock);
+
+       err = mlx5_fs_pool_acquire_from_list(&fs_pool->partially_used,
+                                            &fs_pool->fully_used, false,
+                                            pool_index);
+       if (err)
+               err = mlx5_fs_pool_acquire_from_list(&fs_pool->unused,
+                                                    &fs_pool->partially_used,
+                                                    true, pool_index);
+       if (err) {
+               new_bulk = mlx5_fs_pool_alloc_new_bulk(fs_pool);
+               if (!new_bulk) {
+                       err = -ENOENT;
+                       goto out;
+               }
+               err = mlx5_fs_bulk_acquire_index(new_bulk, pool_index);
+               WARN_ON_ONCE(err);
+               list_add(&new_bulk->pool_list, &fs_pool->partially_used);
+       }
+       fs_pool->available_units--;
+       fs_pool->used_units++;
+
+out:
+       mutex_unlock(&fs_pool->pool_lock);
+       return err;
+}
+
+int mlx5_fs_pool_release_index(struct mlx5_fs_pool *fs_pool,
+                              struct mlx5_fs_pool_index *pool_index)
+{
+       struct mlx5_fs_bulk *bulk = pool_index->fs_bulk;
+       int bulk_free_amount;
+       int err;
+
+       mutex_lock(&fs_pool->pool_lock);
+
+       /* TBD would rather return void if there was no warn here in original code */
+       err = mlx5_fs_bulk_release_index(bulk, pool_index->index);
+       if (err)
+               goto unlock;
+
+       fs_pool->available_units++;
+       fs_pool->used_units--;
+
+       bulk_free_amount = mlx5_fs_bulk_get_free_amount(bulk);
+       if (bulk_free_amount == 1)
+               list_move_tail(&bulk->pool_list, &fs_pool->partially_used);
+       if (bulk_free_amount == bulk->bulk_len) {
+               list_del(&bulk->pool_list);
+               if (fs_pool->available_units > fs_pool->threshold)
+                       mlx5_fs_pool_free_bulk(fs_pool, bulk);
+               else
+                       list_add(&bulk->pool_list, &fs_pool->unused);
+       }
+
+unlock:
+       mutex_unlock(&fs_pool->pool_lock);
+       return err;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_pool.h
new file mode 100644 (file)
index 0000000..3b14986
--- /dev/null
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
+
+#ifndef __MLX5_FS_POOL_H__
+#define __MLX5_FS_POOL_H__
+
+#include <linux/mlx5/driver.h>
+
+struct mlx5_fs_bulk {
+       struct list_head pool_list;
+       int bulk_len;
+       unsigned long *bitmask;
+};
+
+struct mlx5_fs_pool_index {
+       struct mlx5_fs_bulk *fs_bulk;
+       int index;
+};
+
+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);
+       void (*update_threshold)(struct mlx5_fs_pool *pool);
+};
+
+struct mlx5_fs_pool {
+       struct mlx5_core_dev *dev;
+       void *pool_ctx;
+       const struct mlx5_fs_pool_ops *ops;
+       struct mutex pool_lock; /* protects pool lists */
+       struct list_head fully_used;
+       struct list_head partially_used;
+       struct list_head unused;
+       int available_units;
+       int used_units;
+       int threshold;
+};
+
+int mlx5_fs_bulk_init(struct mlx5_core_dev *dev, struct mlx5_fs_bulk *fs_bulk,
+                     int bulk_len);
+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);
+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);
+int mlx5_fs_pool_release_index(struct mlx5_fs_pool *fs_pool,
+                              struct mlx5_fs_pool_index *pool_index);
+
+#endif /* __MLX5_FS_POOL_H__ */