Commit 31d1356b authored by Moshe Shemesh's avatar Moshe Shemesh Committed by Jakub Kicinski
Browse files

net/mlx5: fs, add mlx5_fs_pool API



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: default avatarMoshe Shemesh <moshe@nvidia.com>
Reviewed-by: default avatarYevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: default avatarMark Bloch <mbloch@nvidia.com>
Signed-off-by: default avatarTariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20241219175841.1094544-5-tariqt@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 95f68e06
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+78 −208
Original line number Diff line number Diff line
@@ -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;

	bulk->bitmask = kvcalloc(BITS_TO_LONGS(bulk_len), sizeof(unsigned long),
				 GFP_KERNEL);
	if (!bulk->bitmask)
		goto err_alloc_bitmask;
	fc_bulk = kvzalloc(struct_size(fc_bulk, fcs, bulk_len), GFP_KERNEL);
	if (!fc_bulk)
		return NULL;

	err = mlx5_cmd_fc_bulk_alloc(dev, alloc_bitmask, &base_id);
	if (err)
		goto err_mlx5_cmd_bulk_alloc;
	if (mlx5_fs_bulk_init(dev, &fc_bulk->fs_bulk, bulk_len))
		goto fc_bulk_free;

	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 */

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,
};

	clear_bit(free_fc_index, bulk->bitmask);
	return &bulk->fcs[free_fc_index];
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 void mlx5_fc_pool_cleanup(struct mlx5_fs_pool *fc_pool)
{
	mlx5_fs_pool_cleanup(fc_pool);
}

static int mlx5_fc_bulk_release_fc(struct mlx5_fc_bulk *bulk, struct mlx5_fc *fc)
static struct mlx5_fc *
mlx5_fc_pool_acquire_counter(struct mlx5_fs_pool *fc_pool)
{
	int fc_index = fc->id - bulk->base_id;
	struct mlx5_fs_pool_index pool_index = {};
	struct mlx5_fc_bulk *fc_bulk;
	int err;

	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];
}

	if (test_bit(fc_index, bulk->bitmask))
		return -EINVAL;
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;

	set_bit(fc_index, bulk->bitmask);
	return 0;
	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);
}
+194 −0
Original line number Diff line number Diff line
// 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;
}
+54 −0
Original line number Diff line number Diff line
/* 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__ */