210 lines
6.9 KiB
Diff
210 lines
6.9 KiB
Diff
From a380ec59fea7f1801a94b324bd7f688f2d3be0dd Mon Sep 17 00:00:00 2001
|
|
From: Kamal Heib <kheib@redhat.com>
|
|
Date: Thu, 16 Apr 2026 17:42:05 -0400
|
|
Subject: [PATCH] net/mlx5: HWS, rework rehash loop
|
|
|
|
JIRA: https://redhat.atlassian.net/browse/RHEL-169055
|
|
|
|
commit ef94799a87415790d4297cf06075f99b70c420cd
|
|
Author: Yevgeny Kliteynik <kliteyn@nvidia.com>
|
|
Date: Sun May 11 22:38:09 2025 +0300
|
|
|
|
net/mlx5: HWS, rework rehash loop
|
|
|
|
Reworking the rehash loop - simplifying the code and making it less
|
|
error prone:
|
|
- Instead of doing round-robin on all the queues with batch of rules in
|
|
each cycle, just go over all the queues and move all the rules that
|
|
belong to this queue.
|
|
- If at some stage of moving the rule we get a failure (which should
|
|
not happen), this can't be rolled back. So instead of aborting
|
|
rehash and leaving the matcher in a broken state, allow the loop
|
|
to continue: attempt to move the rest of the rules and delete the
|
|
old matcher. A rule that failed to move to a new matcher will loose
|
|
its match STE once the rehash is completed and the old matcher is
|
|
deleted, so the rule won't match any traffic any more. This rule's
|
|
packets will fall back to the steering pipeline w/o HW offload.
|
|
Rehash procedure will return an error, which will cause the rule
|
|
insertion to fail for the rule that started this whole rehash.
|
|
|
|
Signed-off-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
|
|
Reviewed-by: Vlad Dogaru <vdogaru@nvidia.com>
|
|
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
|
|
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
|
|
Link: https://patch.msgid.link/1746992290-568936-10-git-send-email-tariqt@nvidia.com
|
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
|
|
Signed-off-by: Kamal Heib <kheib@redhat.com>
|
|
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
|
|
index 456fac895f5e..9e057f808ea5 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
|
|
@@ -610,95 +610,69 @@ hws_bwc_matcher_find_at(struct mlx5hws_bwc_matcher *bwc_matcher,
|
|
|
|
static int hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher)
|
|
{
|
|
+ bool move_error = false, poll_error = false, drain_error = false;
|
|
struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx;
|
|
+ struct mlx5hws_matcher *matcher = bwc_matcher->matcher;
|
|
u16 bwc_queues = mlx5hws_bwc_queues(ctx);
|
|
- struct mlx5hws_bwc_rule **bwc_rules;
|
|
struct mlx5hws_rule_attr rule_attr;
|
|
- u32 *pending_rules;
|
|
- int i, j, ret = 0;
|
|
- bool all_done;
|
|
- u16 burst_th;
|
|
+ struct mlx5hws_bwc_rule *bwc_rule;
|
|
+ struct mlx5hws_send_engine *queue;
|
|
+ struct list_head *rules_list;
|
|
+ u32 pending_rules;
|
|
+ int i, ret = 0;
|
|
|
|
mlx5hws_bwc_rule_fill_attr(bwc_matcher, 0, 0, &rule_attr);
|
|
|
|
- pending_rules = kcalloc(bwc_queues, sizeof(*pending_rules), GFP_KERNEL);
|
|
- if (!pending_rules)
|
|
- return -ENOMEM;
|
|
-
|
|
- bwc_rules = kcalloc(bwc_queues, sizeof(*bwc_rules), GFP_KERNEL);
|
|
- if (!bwc_rules) {
|
|
- ret = -ENOMEM;
|
|
- goto free_pending_rules;
|
|
- }
|
|
-
|
|
for (i = 0; i < bwc_queues; i++) {
|
|
if (list_empty(&bwc_matcher->rules[i]))
|
|
- bwc_rules[i] = NULL;
|
|
- else
|
|
- bwc_rules[i] = list_first_entry(&bwc_matcher->rules[i],
|
|
- struct mlx5hws_bwc_rule,
|
|
- list_node);
|
|
- }
|
|
+ continue;
|
|
|
|
- do {
|
|
- all_done = true;
|
|
+ pending_rules = 0;
|
|
+ rule_attr.queue_id = mlx5hws_bwc_get_queue_id(ctx, i);
|
|
+ rules_list = &bwc_matcher->rules[i];
|
|
|
|
- for (i = 0; i < bwc_queues; i++) {
|
|
- rule_attr.queue_id = mlx5hws_bwc_get_queue_id(ctx, i);
|
|
- burst_th = hws_bwc_get_burst_th(ctx, rule_attr.queue_id);
|
|
-
|
|
- for (j = 0; j < burst_th && bwc_rules[i]; j++) {
|
|
- rule_attr.burst = !!((j + 1) % burst_th);
|
|
- ret = mlx5hws_matcher_resize_rule_move(bwc_matcher->matcher,
|
|
- bwc_rules[i]->rule,
|
|
- &rule_attr);
|
|
- if (unlikely(ret)) {
|
|
- mlx5hws_err(ctx,
|
|
- "Moving BWC rule failed during rehash (%d)\n",
|
|
- ret);
|
|
- goto free_bwc_rules;
|
|
- }
|
|
+ list_for_each_entry(bwc_rule, rules_list, list_node) {
|
|
+ ret = mlx5hws_matcher_resize_rule_move(matcher,
|
|
+ bwc_rule->rule,
|
|
+ &rule_attr);
|
|
+ if (unlikely(ret && !move_error)) {
|
|
+ mlx5hws_err(ctx,
|
|
+ "Moving BWC rule: move failed (%d), attempting to move rest of the rules\n",
|
|
+ ret);
|
|
+ move_error = true;
|
|
+ }
|
|
|
|
- all_done = false;
|
|
- pending_rules[i]++;
|
|
- bwc_rules[i] = list_is_last(&bwc_rules[i]->list_node,
|
|
- &bwc_matcher->rules[i]) ?
|
|
- NULL : list_next_entry(bwc_rules[i], list_node);
|
|
-
|
|
- ret = mlx5hws_bwc_queue_poll(ctx,
|
|
- rule_attr.queue_id,
|
|
- &pending_rules[i],
|
|
- false);
|
|
- if (unlikely(ret)) {
|
|
- mlx5hws_err(ctx,
|
|
- "Moving BWC rule failed during rehash (%d)\n",
|
|
- ret);
|
|
- goto free_bwc_rules;
|
|
- }
|
|
+ pending_rules++;
|
|
+ ret = mlx5hws_bwc_queue_poll(ctx,
|
|
+ rule_attr.queue_id,
|
|
+ &pending_rules,
|
|
+ false);
|
|
+ if (unlikely(ret && !poll_error)) {
|
|
+ mlx5hws_err(ctx,
|
|
+ "Moving BWC rule: poll failed (%d), attempting to move rest of the rules\n",
|
|
+ ret);
|
|
+ poll_error = true;
|
|
}
|
|
}
|
|
- } while (!all_done);
|
|
-
|
|
- /* drain all the bwc queues */
|
|
- for (i = 0; i < bwc_queues; i++) {
|
|
- if (pending_rules[i]) {
|
|
- u16 queue_id = mlx5hws_bwc_get_queue_id(ctx, i);
|
|
|
|
- mlx5hws_send_engine_flush_queue(&ctx->send_queue[queue_id]);
|
|
- ret = mlx5hws_bwc_queue_poll(ctx, queue_id,
|
|
- &pending_rules[i], true);
|
|
- if (unlikely(ret)) {
|
|
+ if (pending_rules) {
|
|
+ queue = &ctx->send_queue[rule_attr.queue_id];
|
|
+ mlx5hws_send_engine_flush_queue(queue);
|
|
+ ret = mlx5hws_bwc_queue_poll(ctx,
|
|
+ rule_attr.queue_id,
|
|
+ &pending_rules,
|
|
+ true);
|
|
+ if (unlikely(ret && !drain_error)) {
|
|
mlx5hws_err(ctx,
|
|
- "Moving BWC rule failed during rehash (%d)\n", ret);
|
|
- goto free_bwc_rules;
|
|
+ "Moving BWC rule: drain failed (%d), attempting to move rest of the rules\n",
|
|
+ ret);
|
|
+ drain_error = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
-free_bwc_rules:
|
|
- kfree(bwc_rules);
|
|
-free_pending_rules:
|
|
- kfree(pending_rules);
|
|
+ if (move_error || poll_error || drain_error)
|
|
+ ret = -EINVAL;
|
|
|
|
return ret;
|
|
}
|
|
@@ -742,15 +716,18 @@ static int hws_bwc_matcher_move(struct mlx5hws_bwc_matcher *bwc_matcher)
|
|
}
|
|
|
|
ret = hws_bwc_matcher_move_all(bwc_matcher);
|
|
- if (ret) {
|
|
- mlx5hws_err(ctx, "Rehash error: moving rules failed\n");
|
|
- return -ENOMEM;
|
|
- }
|
|
+ if (ret)
|
|
+ mlx5hws_err(ctx, "Rehash error: moving rules failed, attempting to remove the old matcher\n");
|
|
+
|
|
+ /* Error during rehash can't be rolled back.
|
|
+ * The best option here is to allow the rehash to complete and remove
|
|
+ * the old matcher - can't leave the matcher in the 'in_resize' state.
|
|
+ */
|
|
|
|
bwc_matcher->matcher = new_matcher;
|
|
mlx5hws_matcher_destroy(old_matcher);
|
|
|
|
- return 0;
|
|
+ return ret;
|
|
}
|
|
|
|
static int
|
|
--
|
|
2.50.1 (Apple Git-155)
|
|
|