net/mlx5: HWS, fix simple rules rehash error flow
authorYevgeny Kliteynik <kliteyn@nvidia.com>
Sun, 17 Aug 2025 20:23:18 +0000 (23:23 +0300)
committerJakub Kicinski <kuba@kernel.org>
Wed, 20 Aug 2025 02:35:13 +0000 (19:35 -0700)
Moving rules from matcher to matcher should not fail.
However, if it does fail due to various reasons, the error flow
should allow the kernel to continue functioning (albeit with broken
steering rules) instead of going into series of soft lock-ups or
some other problematic behaviour.

This patch fixes the error flow for moving simple rules:
 - If new rule creation fails before it was even enqeued, do not
   poll for completion
 - If TIMEOUT happened while moving the rule, no point trying
   to poll for completions for other rules. Something is broken,
   completion won't come, just abort the rehash sequence.
 - If some other completion with error received, don't give up.
   Continue handling rest of the rules to minimize the damage.
 - Make sure that the first error code that was received will
   be actually returned to the caller instead of replacing it
   with the generic error code.

All the aforementioned issues stem from the same bad error flow,
so no point fixing them one by one and leaving partially broken
code - fixing them in one patch.

Fixes: ef94799a8741 ("net/mlx5: HWS, rework rehash loop")
Signed-off-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Vlad Dogaru <vdogaru@nvidia.com>
Signed-off-by: Mark Bloch <mbloch@nvidia.com>
Link: https://patch.msgid.link/20250817202323.308604-3-mbloch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c

index 92de4b761a83403af34ca882a58bbcf7e656f8ec..0219a49b23264d9aea1d74a095d38ace1faf5619 100644 (file)
@@ -74,9 +74,9 @@ static void hws_bwc_matcher_init_attr(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;
+       int drain_error = 0, move_error = 0, poll_error = 0;
        u16 bwc_queues = mlx5hws_bwc_queues(ctx);
        struct mlx5hws_rule_attr rule_attr;
        struct mlx5hws_bwc_rule *bwc_rule;
@@ -99,11 +99,15 @@ hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher)
                        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;
+                       if (unlikely(ret)) {
+                               if (!move_error) {
+                                       mlx5hws_err(ctx,
+                                                   "Moving BWC rule: move failed (%d), attempting to move rest of the rules\n",
+                                                   ret);
+                                       move_error = ret;
+                               }
+                               /* Rule wasn't queued, no need to poll */
+                               continue;
                        }
 
                        pending_rules++;
@@ -111,11 +115,19 @@ hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher)
                                                     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;
+                       if (unlikely(ret)) {
+                               if (ret == -ETIMEDOUT) {
+                                       mlx5hws_err(ctx,
+                                                   "Moving BWC rule: timeout polling for completions (%d), aborting rehash\n",
+                                                   ret);
+                                       return ret;
+                               }
+                               if (!poll_error) {
+                                       mlx5hws_err(ctx,
+                                                   "Moving BWC rule: polling for completions failed (%d), attempting to move rest of the rules\n",
+                                                   ret);
+                                       poll_error = ret;
+                               }
                        }
                }
 
@@ -126,17 +138,30 @@ hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher)
                                                     rule_attr.queue_id,
                                                     &pending_rules,
                                                     true);
-                       if (unlikely(ret && !drain_error)) {
-                               mlx5hws_err(ctx,
-                                           "Moving BWC rule: drain failed (%d), attempting to move rest of the rules\n",
-                                           ret);
-                               drain_error = true;
+                       if (unlikely(ret)) {
+                               if (ret == -ETIMEDOUT) {
+                                       mlx5hws_err(ctx,
+                                                   "Moving bwc rule: timeout draining completions (%d), aborting rehash\n",
+                                                   ret);
+                                       return ret;
+                               }
+                               if (!drain_error) {
+                                       mlx5hws_err(ctx,
+                                                   "Moving bwc rule: drain failed (%d), attempting to move rest of the rules\n",
+                                                   ret);
+                                       drain_error = ret;
+                               }
                        }
                }
        }
 
-       if (move_error || poll_error || drain_error)
-               ret = -EINVAL;
+       /* Return the first error that happened */
+       if (unlikely(move_error))
+               return move_error;
+       if (unlikely(poll_error))
+               return poll_error;
+       if (unlikely(drain_error))
+               return drain_error;
 
        return ret;
 }