public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Tariq Toukan <tariqt@nvidia.com>
To: "David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Eric Dumazet <edumazet@google.com>,
	"Andrew Lunn" <andrew+netdev@lunn.ch>
Cc: Gal Pressman <gal@nvidia.com>,
	Leon Romanovsky <leonro@nvidia.com>,
	"Saeed Mahameed" <saeedm@nvidia.com>,
	Leon Romanovsky <leon@kernel.org>,
	Tariq Toukan <tariqt@nvidia.com>, <netdev@vger.kernel.org>,
	<linux-rdma@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	Moshe Shemesh <moshe@nvidia.com>, Mark Bloch <mbloch@nvidia.com>,
	Vlad Dogaru <vdogaru@nvidia.com>,
	Yevgeny Kliteynik <kliteyn@nvidia.com>,
	Michal Kubiak <michal.kubiak@intel.com>
Subject: [PATCH net-next V2 11/12] net/mlx5: HWS, Free unused action STE tables
Date: Thu, 10 Apr 2025 22:17:41 +0300	[thread overview]
Message-ID: <1744312662-356571-12-git-send-email-tariqt@nvidia.com> (raw)
In-Reply-To: <1744312662-356571-1-git-send-email-tariqt@nvidia.com>

From: Vlad Dogaru <vdogaru@nvidia.com>

Periodically check for unused action STE tables and free their
associated resources. In order to do this safely, add a per-queue lock
to synchronize the garbage collect work with regular operations on
steering rules.

Signed-off-by: Vlad Dogaru <vdogaru@nvidia.com>
Reviewed-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 .../mlx5/core/steering/hws/action_ste_pool.c  | 88 ++++++++++++++++++-
 .../mlx5/core/steering/hws/action_ste_pool.h  | 11 +++
 .../mellanox/mlx5/core/steering/hws/context.h |  1 +
 3 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.c
index cb6ad8411631..5766a9c82f96 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.c
@@ -159,6 +159,7 @@ hws_action_ste_table_alloc(struct mlx5hws_action_ste_pool_element *parent_elem)
 
 	action_tbl->parent_elem = parent_elem;
 	INIT_LIST_HEAD(&action_tbl->list_node);
+	action_tbl->last_used = jiffies;
 	list_add(&action_tbl->list_node, &parent_elem->available);
 	parent_elem->log_sz = log_sz;
 
@@ -236,6 +237,8 @@ static int hws_action_ste_pool_init(struct mlx5hws_context *ctx,
 	enum mlx5hws_pool_optimize opt;
 	int err;
 
+	mutex_init(&pool->lock);
+
 	/* Rules which are added for both RX and TX must use the same action STE
 	 * indices for both. If we were to use a single table, then RX-only and
 	 * TX-only rules would waste the unused entries. Thus, we use separate
@@ -247,6 +250,7 @@ static int hws_action_ste_pool_init(struct mlx5hws_context *ctx,
 						       opt);
 		if (err)
 			goto destroy_elems;
+		pool->elems[opt].parent_pool = pool;
 	}
 
 	return 0;
@@ -267,6 +271,58 @@ static void hws_action_ste_pool_destroy(struct mlx5hws_action_ste_pool *pool)
 		hws_action_ste_pool_element_destroy(&pool->elems[opt]);
 }
 
+static void hws_action_ste_pool_element_collect_stale(
+	struct mlx5hws_action_ste_pool_element *elem, struct list_head *cleanup)
+{
+	struct mlx5hws_action_ste_table *action_tbl, *p;
+	unsigned long expire_time, now;
+
+	expire_time = secs_to_jiffies(MLX5HWS_ACTION_STE_POOL_EXPIRE_SECONDS);
+	now = jiffies;
+
+	list_for_each_entry_safe(action_tbl, p, &elem->available, list_node) {
+		if (mlx5hws_pool_full(action_tbl->pool) &&
+		    time_before(action_tbl->last_used + expire_time, now))
+			list_move(&action_tbl->list_node, cleanup);
+	}
+}
+
+static void hws_action_ste_table_cleanup_list(struct list_head *cleanup)
+{
+	struct mlx5hws_action_ste_table *action_tbl, *p;
+
+	list_for_each_entry_safe(action_tbl, p, cleanup, list_node)
+		hws_action_ste_table_destroy(action_tbl);
+}
+
+static void hws_action_ste_pool_cleanup(struct work_struct *work)
+{
+	enum mlx5hws_pool_optimize opt;
+	struct mlx5hws_context *ctx;
+	LIST_HEAD(cleanup);
+	int i;
+
+	ctx = container_of(work, struct mlx5hws_context,
+			   action_ste_cleanup.work);
+
+	for (i = 0; i < ctx->queues; i++) {
+		struct mlx5hws_action_ste_pool *p = &ctx->action_ste_pool[i];
+
+		mutex_lock(&p->lock);
+		for (opt = MLX5HWS_POOL_OPTIMIZE_NONE;
+		     opt < MLX5HWS_POOL_OPTIMIZE_MAX; opt++)
+			hws_action_ste_pool_element_collect_stale(
+				&p->elems[opt], &cleanup);
+		mutex_unlock(&p->lock);
+	}
+
+	hws_action_ste_table_cleanup_list(&cleanup);
+
+	schedule_delayed_work(&ctx->action_ste_cleanup,
+			      secs_to_jiffies(
+				  MLX5HWS_ACTION_STE_POOL_CLEANUP_SECONDS));
+}
+
 int mlx5hws_action_ste_pool_init(struct mlx5hws_context *ctx)
 {
 	struct mlx5hws_action_ste_pool *pool;
@@ -285,6 +341,12 @@ int mlx5hws_action_ste_pool_init(struct mlx5hws_context *ctx)
 
 	ctx->action_ste_pool = pool;
 
+	INIT_DELAYED_WORK(&ctx->action_ste_cleanup,
+			  hws_action_ste_pool_cleanup);
+	schedule_delayed_work(
+		&ctx->action_ste_cleanup,
+		secs_to_jiffies(MLX5HWS_ACTION_STE_POOL_CLEANUP_SECONDS));
+
 	return 0;
 
 free_pool:
@@ -300,6 +362,8 @@ void mlx5hws_action_ste_pool_uninit(struct mlx5hws_context *ctx)
 	size_t queues = ctx->queues;
 	int i;
 
+	cancel_delayed_work_sync(&ctx->action_ste_cleanup);
+
 	for (i = 0; i < queues; i++)
 		hws_action_ste_pool_destroy(&ctx->action_ste_pool[i]);
 
@@ -330,6 +394,7 @@ hws_action_ste_table_chunk_alloc(struct mlx5hws_action_ste_table *action_tbl,
 		return err;
 
 	chunk->action_tbl = action_tbl;
+	action_tbl->last_used = jiffies;
 
 	return 0;
 }
@@ -346,6 +411,8 @@ int mlx5hws_action_ste_chunk_alloc(struct mlx5hws_action_ste_pool *pool,
 	if (skip_rx && skip_tx)
 		return -EINVAL;
 
+	mutex_lock(&pool->lock);
+
 	elem = hws_action_ste_choose_elem(pool, skip_rx, skip_tx);
 
 	mlx5hws_dbg(elem->ctx,
@@ -362,26 +429,39 @@ int mlx5hws_action_ste_chunk_alloc(struct mlx5hws_action_ste_pool *pool,
 
 	if (!found) {
 		action_tbl = hws_action_ste_table_alloc(elem);
-		if (IS_ERR(action_tbl))
-			return PTR_ERR(action_tbl);
+		if (IS_ERR(action_tbl)) {
+			err = PTR_ERR(action_tbl);
+			goto out;
+		}
 
 		err = hws_action_ste_table_chunk_alloc(action_tbl, chunk);
 		if (err)
-			return err;
+			goto out;
 	}
 
 	if (mlx5hws_pool_empty(action_tbl->pool))
 		list_move(&action_tbl->list_node, &elem->full);
 
-	return 0;
+	err = 0;
+
+out:
+	mutex_unlock(&pool->lock);
+
+	return err;
 }
 
 void mlx5hws_action_ste_chunk_free(struct mlx5hws_action_ste_chunk *chunk)
 {
+	struct mutex *lock = &chunk->action_tbl->parent_elem->parent_pool->lock;
+
 	mlx5hws_dbg(chunk->action_tbl->pool->ctx,
 		    "Freeing action STEs offset %d order %d\n",
 		    chunk->ste.offset, chunk->ste.order);
+
+	mutex_lock(lock);
 	mlx5hws_pool_chunk_free(chunk->action_tbl->pool, &chunk->ste);
+	chunk->action_tbl->last_used = jiffies;
 	list_move(&chunk->action_tbl->list_node,
 		  &chunk->action_tbl->parent_elem->available);
+	mutex_unlock(lock);
 }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.h
index 2de660a63223..a8ba97359e31 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.h
@@ -8,6 +8,9 @@
 #define MLX5HWS_ACTION_STE_TABLE_STEP_LOG_SZ 1
 #define MLX5HWS_ACTION_STE_TABLE_MAX_LOG_SZ 20
 
+#define MLX5HWS_ACTION_STE_POOL_CLEANUP_SECONDS 300
+#define MLX5HWS_ACTION_STE_POOL_EXPIRE_SECONDS 300
+
 struct mlx5hws_action_ste_pool_element;
 
 struct mlx5hws_action_ste_table {
@@ -19,10 +22,12 @@ struct mlx5hws_action_ste_table {
 	u32 rtc_0_id;
 	u32 rtc_1_id;
 	struct list_head list_node;
+	unsigned long last_used;
 };
 
 struct mlx5hws_action_ste_pool_element {
 	struct mlx5hws_context *ctx;
+	struct mlx5hws_action_ste_pool *parent_pool;
 	size_t log_sz;  /* Size of the largest table so far. */
 	enum mlx5hws_pool_optimize opt;
 	struct list_head available;
@@ -33,6 +38,12 @@ struct mlx5hws_action_ste_pool_element {
  * per queue.
  */
 struct mlx5hws_action_ste_pool {
+	/* Protects the entire pool. We have one pool per queue and only one
+	 * operation can be active per rule at a given time. Thus this lock
+	 * protects solely against concurrent garbage collection and we expect
+	 * very little contention.
+	 */
+	struct mutex lock;
 	struct mlx5hws_action_ste_pool_element elems[MLX5HWS_POOL_OPTIMIZE_MAX];
 };
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h
index e987e93bbc6e..3f8938c73dc0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h
@@ -40,6 +40,7 @@ struct mlx5hws_context {
 	u32 pd_num;
 	struct mlx5hws_pool *stc_pool;
 	struct mlx5hws_action_ste_pool *action_ste_pool; /* One per queue */
+	struct delayed_work action_ste_cleanup;
 	struct mlx5hws_context_common_res common_res;
 	struct mlx5hws_pattern_cache *pattern_cache;
 	struct mlx5hws_definer_cache *definer_cache;
-- 
2.31.1


  parent reply	other threads:[~2025-04-10 19:19 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-10 19:17 [PATCH net-next V2 00/12] net/mlx5: HWS, Refactor action STE handling Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 01/12] net/mlx5: HWS, Fix matcher action template attach Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 02/12] net/mlx5: HWS, Remove unused element array Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 03/12] net/mlx5: HWS, Make pool single resource Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 04/12] net/mlx5: HWS, Refactor pool implementation Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 05/12] net/mlx5: HWS, Cleanup after pool refactoring Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 06/12] net/mlx5: HWS, Add fullness tracking to pool Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 07/12] net/mlx5: HWS, Fix pool size optimization Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 08/12] net/mlx5: HWS, Implement action STE pool Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 09/12] net/mlx5: HWS, Use the new " Tariq Toukan
2025-04-10 19:17 ` [PATCH net-next V2 10/12] net/mlx5: HWS, Cleanup matcher action STE table Tariq Toukan
2025-04-10 19:17 ` Tariq Toukan [this message]
2025-04-10 19:17 ` [PATCH net-next V2 12/12] net/mlx5: HWS, Export action STE tables to debugfs Tariq Toukan
2025-04-11 11:29 ` [PATCH net-next V2 00/12] net/mlx5: HWS, Refactor action STE handling Michal Kubiak
2025-04-15  0:40 ` patchwork-bot+netdevbpf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1744312662-356571-12-git-send-email-tariqt@nvidia.com \
    --to=tariqt@nvidia.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=gal@nvidia.com \
    --cc=kliteyn@nvidia.com \
    --cc=kuba@kernel.org \
    --cc=leon@kernel.org \
    --cc=leonro@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=mbloch@nvidia.com \
    --cc=michal.kubiak@intel.com \
    --cc=moshe@nvidia.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=saeedm@nvidia.com \
    --cc=vdogaru@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox