summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShay Drory <shayd@nvidia.com>2026-05-31 14:39:47 +0300
committerJakub Kicinski <kuba@kernel.org>2026-06-03 17:42:20 -0700
commit3c103110835d269aa50c6569c57ae230c893c756 (patch)
tree3b23f303d6280061d643c62f47ff39385dc96ffb
parent3cbce590b7f2e9f056ed803a05f9ee09ac4a49a7 (diff)
downloadlinux-3c103110835d269aa50c6569c57ae230c893c756.tar.gz
linux-3c103110835d269aa50c6569c57ae230c893c756.zip
net/mlx5: SD, introduce Socket Direct LAG
Register SD secondary devices with the existing LAG structure by adding them to the primary's ldev xarray with a shared group_id. This ties the SD LAG lifecycle to the SD group lifecycle. Add sd_lag_state debugfs entry for LAG state visibility. To avoid race between this entry and LAG deletion, have debugfs creation and deletion done last on SD init and first on SD cleanup. Signed-off-by: Shay Drory <shayd@nvidia.com> Reviewed-by: Mark Bloch <mbloch@nvidia.com> Signed-off-by: Tariq Toukan <tariqt@nvidia.com> Link: https://patch.msgid.link/20260531113954.395443-8-tariqt@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c135
1 files changed, 121 insertions, 14 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c
index bbd77ae11e84..e341d814873a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c
@@ -2,6 +2,7 @@
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#include "lib/sd.h"
+#include "../lag/lag.h"
#include "mlx5_core.h"
#include "lib/mlx5.h"
#include "fs_cmd.h"
@@ -223,6 +224,108 @@ static void sd_cleanup(struct mlx5_core_dev *dev)
kfree(sd);
}
+static int sd_lag_state_show(struct seq_file *file, void *priv)
+{
+ struct mlx5_core_dev *dev = file->private;
+ struct mlx5_lag *ldev;
+ struct lag_func *pf;
+ bool active = false;
+ int i;
+
+ ldev = mlx5_lag_dev(dev);
+ if (!ldev)
+ return -EINVAL;
+
+ mutex_lock(&ldev->lock);
+ mlx5_ldev_for_each(i, 0, ldev) {
+ pf = mlx5_lag_pf(ldev, i);
+ if (pf->dev == dev) {
+ active = pf->sd_fdb_active;
+ break;
+ }
+ }
+ mutex_unlock(&ldev->lock);
+
+ seq_printf(file, "%s\n", active ? "active" : "disabled");
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(sd_lag_state);
+
+/* SD LAG integration is optional. If LAG isn't available on this device
+ * (e.g. lag caps are off), or registering secondaries fails, just warn
+ * and continue - SD can operate without the LAG-side bookkeeping.
+ */
+static void sd_lag_init(struct mlx5_core_dev *dev)
+{
+ struct mlx5_core_dev *primary = mlx5_sd_get_primary(dev);
+ struct mlx5_sd *sd = mlx5_get_sd(primary);
+ struct mlx5_core_dev *pos, *to;
+ struct mlx5_lag *ldev;
+ struct lag_func *pf;
+ int err;
+ int i;
+
+ ldev = mlx5_lag_dev(primary);
+ if (!ldev) {
+ sd_warn(primary, "%s: no ldev (LAG caps off?), skipping\n",
+ __func__);
+ return;
+ }
+
+ mutex_lock(&ldev->lock);
+ pf = mlx5_lag_pf_by_dev(ldev, primary);
+ if (!pf) {
+ sd_warn(primary, "%s: primary not registered in ldev, skipping\n",
+ __func__);
+ goto out;
+ }
+
+ pf->group_id = sd->group_id;
+
+ mlx5_sd_for_each_secondary(i, primary, pos) {
+ err = mlx5_ldev_add_mdev(ldev, pos, sd->group_id);
+ if (err) {
+ sd_warn(primary, "%s: failed to add secondary %s to ldev: %d\n",
+ __func__, dev_name(pos->device), err);
+ goto err;
+ }
+ }
+
+out:
+ mutex_unlock(&ldev->lock);
+ return;
+
+err:
+ to = pos;
+ mlx5_sd_for_each_secondary_to(i, primary, to, pos)
+ mlx5_ldev_remove_mdev(ldev, pos);
+ pf->group_id = 0;
+ mutex_unlock(&ldev->lock);
+}
+
+static void sd_lag_cleanup(struct mlx5_core_dev *dev)
+{
+ struct mlx5_core_dev *primary = mlx5_sd_get_primary(dev);
+ struct mlx5_core_dev *pos;
+ struct mlx5_lag *ldev;
+ struct lag_func *pf;
+ int i;
+
+ ldev = mlx5_lag_dev(primary);
+ if (!ldev)
+ return;
+
+ mutex_lock(&ldev->lock);
+ mlx5_sd_for_each_secondary(i, primary, pos)
+ mlx5_ldev_remove_mdev(ldev, pos);
+
+ pf = mlx5_lag_pf_by_dev(ldev, primary);
+ if (pf)
+ pf->group_id = 0;
+ mutex_unlock(&ldev->lock);
+}
+
static int sd_register(struct mlx5_core_dev *dev)
{
struct mlx5_devcom_comp_dev *devcom, *pos;
@@ -473,27 +576,32 @@ int mlx5_sd_init(struct mlx5_core_dev *dev)
if (err)
goto err_sd_unregister;
+ mlx5_sd_for_each_secondary(i, primary, pos) {
+ err = sd_cmd_set_secondary(pos, primary, alias_key);
+ if (err)
+ goto err_unset_secondaries;
+ }
+
+ sd_lag_init(primary);
+
primary_sd->dfs =
debugfs_create_dir("multi-pf",
mlx5_debugfs_get_dev_root(primary));
- debugfs_create_x32("group_id", 0400, primary_sd->dfs,
- &primary_sd->group_id);
- debugfs_create_file("primary", 0400, primary_sd->dfs, primary,
- &dev_fops);
-
mlx5_sd_for_each_secondary(i, primary, pos) {
char name[32];
- err = sd_cmd_set_secondary(pos, primary, alias_key);
- if (err)
- goto err_unset_secondaries;
-
snprintf(name, sizeof(name), "secondary_%d", i - 1);
debugfs_create_file(name, 0400, primary_sd->dfs, pos,
&dev_fops);
-
}
+ debugfs_create_file("sd_lag_state", 0400, primary_sd->dfs, primary,
+ &sd_lag_state_fops);
+ debugfs_create_x32("group_id", 0400, primary_sd->dfs,
+ &primary_sd->group_id);
+ debugfs_create_file("primary", 0400, primary_sd->dfs, primary,
+ &dev_fops);
+
sd_info(primary, "group id %#x, size %d, combined\n",
sd->group_id, mlx5_devcom_comp_get_size(sd->devcom));
sd_print_group(primary);
@@ -508,8 +616,6 @@ err_unset_secondaries:
mlx5_sd_for_each_secondary_to(i, primary, to, pos)
sd_cmd_unset_secondary(pos);
sd_cmd_unset_primary(primary);
- debugfs_remove_recursive(primary_sd->dfs);
- primary_sd->dfs = NULL;
err_sd_unregister:
mlx5_sd_for_each_secondary(i, primary, pos) {
struct mlx5_sd *peer_sd = mlx5_get_sd(pos);
@@ -548,11 +654,12 @@ void mlx5_sd_cleanup(struct mlx5_core_dev *dev)
if (primary_sd->state != MLX5_SD_STATE_UP)
goto out_clear_peers;
+ debugfs_remove_recursive(primary_sd->dfs);
+ primary_sd->dfs = NULL;
+ sd_lag_cleanup(primary);
mlx5_sd_for_each_secondary(i, primary, pos)
sd_cmd_unset_secondary(pos);
sd_cmd_unset_primary(primary);
- debugfs_remove_recursive(primary_sd->dfs);
- primary_sd->dfs = NULL;
sd_info(primary, "group id %#x, uncombined\n", sd->group_id);
primary_sd->state = MLX5_SD_STATE_DOWN;