]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net/mlx5: LAG, extend shared FDB API with group_id filter
authorShay Drory <shayd@nvidia.com>
Sun, 31 May 2026 11:39:46 +0000 (14:39 +0300)
committerJakub Kicinski <kuba@kernel.org>
Thu, 4 Jun 2026 00:42:20 +0000 (17:42 -0700)
Add a group_id parameter to mlx5_lag_shared_fdb_create() and
mlx5_lag_shared_fdb_destroy() to scope shared FDB operations to a
specific SD group.

When group_id is U32_MAX, the functions operate on all LAG devices. When
group_id is non-zero, they operate only on devices in that SD group
without issuing FW LAG commands, since SD LAG is a pure software
construct.

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-7-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c
drivers/net/ethernet/mellanox/mlx5/core/lib/sd.h

index 03cb02c7000d924e24e1fcc267376dc601b2a652..3decb49e9f197eb79844ea08b98b2fcf48dc3e3e 100644 (file)
@@ -370,6 +370,22 @@ int mlx5_lag_get_dev_index_by_seq(struct mlx5_lag *ldev, int seq)
        return -ENOENT;
 }
 
+/* Return the appropriate iterator filter for a device in LAG:
+ * - SD shared FDB active: iterate only the device's SD group
+ * - SD group exists but shared FDB not active: iterate all devices
+ * - No SD: iterate ports only
+ */
+static u32 mlx5_lag_get_filter(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
+{
+       struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev);
+
+       if (pf && pf->sd_fdb_active)
+               return pf->group_id;
+       if (pf && pf->group_id)
+               return MLX5_LAG_FILTER_ALL;
+       return MLX5_LAG_FILTER_PORTS;
+}
+
 /* Reverse of mlx5_lag_get_dev_index_by_seq: given a device, return its
  * sequence number in the LAG. Master is always 0, others numbered
  * sequentially starting from 1.
@@ -379,11 +395,13 @@ int mlx5_lag_get_dev_seq(struct mlx5_core_dev *dev)
        struct mlx5_lag *ldev = mlx5_lag_dev(dev);
        int master_idx, i, num = 1;
        struct lag_func *pf;
+       u32 filter;
 
        if (!ldev)
                return -ENOENT;
 
-       master_idx = mlx5_lag_get_master_idx(ldev);
+       filter = mlx5_lag_get_filter(ldev, dev);
+       master_idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, 0, filter);
        if (master_idx < 0)
                return -ENOENT;
 
@@ -391,7 +409,7 @@ int mlx5_lag_get_dev_seq(struct mlx5_core_dev *dev)
        if (pf && pf->dev == dev)
                return 0;
 
-       mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
+       mlx5_lag_for_each(i, 0, ldev, filter) {
                if (i == master_idx)
                        continue;
                pf = mlx5_lag_pf(ldev, i);
@@ -403,6 +421,69 @@ int mlx5_lag_get_dev_seq(struct mlx5_core_dev *dev)
 }
 EXPORT_SYMBOL(mlx5_lag_get_dev_seq);
 
+/* seq 0 = master, then all remaining devices */
+static int mlx5_lag_get_dev_index_by_seq_all(struct mlx5_lag *ldev, int seq)
+{
+       int master_idx, i, num = 0;
+
+       master_idx = mlx5_lag_get_master_idx(ldev);
+
+       if (master_idx >= 0) {
+               if (seq == 0)
+                       return master_idx;
+               num++;
+       }
+
+       mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) {
+               if (i == master_idx)
+                       continue;
+               if (num == seq)
+                       return i;
+               num++;
+       }
+       return -ENOENT;
+}
+
+/* From group POV, port-marked entry is the lag master */
+static int mlx5_lag_get_dev_index_by_seq_group(struct mlx5_lag *ldev, int seq,
+                                              u32 group_id)
+{
+       int i, num = 0;
+
+       mlx5_lag_for_each(i, 0, ldev, group_id) {
+               if (xa_get_mark(&ldev->pfs, i, MLX5_LAG_XA_MARK_PORT)) {
+                       if (seq == 0)
+                               return i;
+                       num++;
+                       break;
+               }
+       }
+
+       mlx5_lag_for_each(i, 0, ldev, group_id) {
+               if (xa_get_mark(&ldev->pfs, i, MLX5_LAG_XA_MARK_PORT))
+                       continue;
+               if (num == seq)
+                       return i;
+               num++;
+       }
+       return -ENOENT;
+}
+
+int mlx5_lag_get_dev_index_by_seq_filter(struct mlx5_lag *ldev, int seq,
+                                        u32 filter)
+{
+       if (!ldev)
+               return -ENOENT;
+
+       if (!filter || filter == MLX5_LAG_FILTER_PORTS)
+               return mlx5_lag_get_dev_index_by_seq(ldev, seq);
+
+       if (filter == MLX5_LAG_FILTER_ALL)
+               return mlx5_lag_get_dev_index_by_seq_all(ldev, seq);
+
+       return mlx5_lag_get_dev_index_by_seq_group(ldev, seq, filter);
+}
+
 /* Devcom events for LAG master marking */
 #define LAG_DEVCOM_PAIR                (0)
 #define LAG_DEVCOM_UNPAIR      (1)
@@ -512,6 +593,14 @@ static bool __mlx5_lag_is_sriov(struct mlx5_lag *ldev)
        return ldev->mode == MLX5_LAG_MODE_SRIOV;
 }
 
+static bool __mlx5_lag_is_sd_active(struct mlx5_lag *ldev,
+                                   struct mlx5_core_dev *dev)
+{
+       struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev);
+
+       return pf && pf->sd_fdb_active;
+}
+
 /* Create a mapping between steering slots and active ports.
  * As we have ldev->buckets slots per port first assume the native
  * mapping should be used.
@@ -927,27 +1016,19 @@ int mlx5_deactivate_lag(struct mlx5_lag *ldev)
        u32 in[MLX5_ST_SZ_DW(destroy_lag_in)] = {};
        bool roce_lag = __mlx5_lag_is_roce(ldev);
        unsigned long flags = ldev->mode_flags;
-       struct mlx5_eswitch *master_esw;
        struct mlx5_core_dev *dev0;
        int err;
-       int i;
 
        if (master_idx < 0)
                return -EINVAL;
 
        dev0 = mlx5_lag_pf(ldev, master_idx)->dev;
-       master_esw = dev0->priv.eswitch;
        ldev->mode = MLX5_LAG_MODE_NONE;
        ldev->mode_flags = 0;
        mlx5_lag_mp_reset(ldev);
 
        if (test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags)) {
-               mlx5_ldev_for_each(i, 0, ldev) {
-                       if (i == master_idx)
-                               continue;
-                       mlx5_eswitch_offloads_single_fdb_del_one(master_esw,
-                                                                mlx5_lag_pf(ldev, i)->dev->priv.eswitch);
-               }
+               mlx5_lag_destroy_single_fdb(ldev);
                clear_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags);
        }
 
@@ -1026,7 +1107,7 @@ bool mlx5_lag_check_prereq(struct mlx5_lag *ldev)
        return true;
 }
 
-static void mlx5_lag_assert_locked_transition(struct mlx5_lag *ldev)
+static void mlx5_lag_assert_locked_transition(struct mlx5_lag *ldev, u32 filter)
 {
        struct mlx5_devcom_comp_dev *devcom = NULL;
        struct lag_func *pf;
@@ -1034,17 +1115,21 @@ static void mlx5_lag_assert_locked_transition(struct mlx5_lag *ldev)
 
        lockdep_assert_held(&ldev->lock);
 
-       i = mlx5_get_next_lag_func(ldev, 0, MLX5_LAG_FILTER_PORTS);
+       i = mlx5_get_next_lag_func(ldev, 0, filter);
        if (i < MLX5_MAX_PORTS) {
                pf = mlx5_lag_pf(ldev, i);
-               devcom = pf->dev->priv.hca_devcom_comp;
+               if (filter == MLX5_LAG_FILTER_PORTS ||
+                   filter == MLX5_LAG_FILTER_ALL)
+                       devcom = pf->dev->priv.hca_devcom_comp;
+               else
+                       devcom = mlx5_sd_get_devcom(pf->dev);
        }
        mlx5_devcom_comp_assert_locked(devcom);
 }
 
-static void mlx5_lag_drop_lock_for_reps(struct mlx5_lag *ldev)
+static void mlx5_lag_drop_lock_for_reps(struct mlx5_lag *ldev, u32 filter)
 {
-       mlx5_lag_assert_locked_transition(ldev);
+       mlx5_lag_assert_locked_transition(ldev, filter);
 
        /* Keep PF membership stable while ldev->lock is dropped. Device add
         * and remove paths observe mode_changes_in_progress and retry.
@@ -1075,21 +1160,22 @@ void mlx5_lag_rescan_dev_locked(struct mlx5_lag *ldev,
         * callbacks and take reps_lock. Drop ldev->lock so the only ordering
         * remains reps_lock -> ldev->lock from representor callbacks.
         */
-       mlx5_lag_drop_lock_for_reps(ldev);
+       mlx5_lag_drop_lock_for_reps(ldev, mlx5_lag_get_filter(ldev, dev));
        mlx5_rescan_drivers_locked(dev);
        mlx5_lag_retake_lock_after_reps(ldev);
 }
 
-static void mlx5_lag_rescan_devices_locked(struct mlx5_lag *ldev, bool enable)
+static void mlx5_lag_rescan_devices_locked_filter(struct mlx5_lag *ldev,
+                                                 bool enable, u32 filter)
 {
        struct mlx5_core_dev *devs[MLX5_MAX_PORTS];
        struct lag_func *pf;
        int num_devs = 0;
        int i;
 
-       mlx5_lag_assert_locked_transition(ldev);
+       mlx5_lag_assert_locked_transition(ldev, filter);
 
-       mlx5_ldev_for_each(i, 0, ldev) {
+       mlx5_lag_for_each(i, 0, ldev, filter) {
                pf = mlx5_lag_pf(ldev, i);
                if (pf->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)
                        continue;
@@ -1101,30 +1187,40 @@ static void mlx5_lag_rescan_devices_locked(struct mlx5_lag *ldev, bool enable)
                devs[num_devs++] = pf->dev;
        }
 
-       mlx5_lag_drop_lock_for_reps(ldev);
+       mlx5_lag_drop_lock_for_reps(ldev, filter);
        for (i = 0; i < num_devs; i++)
                mlx5_rescan_drivers_locked(devs[i]);
        mlx5_lag_retake_lock_after_reps(ldev);
 }
 
+void mlx5_lag_add_devices_filter(struct mlx5_lag *ldev, u32 filter)
+{
+       mlx5_lag_rescan_devices_locked_filter(ldev, true, filter);
+}
+
 void mlx5_lag_add_devices(struct mlx5_lag *ldev)
 {
-       mlx5_lag_rescan_devices_locked(ldev, true);
+       mlx5_lag_add_devices_filter(ldev, MLX5_LAG_FILTER_PORTS);
+}
+
+void mlx5_lag_remove_devices_filter(struct mlx5_lag *ldev, u32 filter)
+{
+       mlx5_lag_rescan_devices_locked_filter(ldev, false, filter);
 }
 
 void mlx5_lag_remove_devices(struct mlx5_lag *ldev)
 {
-       mlx5_lag_rescan_devices_locked(ldev, false);
+       mlx5_lag_remove_devices_filter(ldev, MLX5_LAG_FILTER_PORTS);
 }
 
 static int mlx5_lag_reload_ib_reps_unlocked(struct mlx5_lag *ldev, u32 flags,
-                                           bool cont_on_fail)
+                                           u32 filter, bool cont_on_fail)
 {
        struct lag_func *pf;
        int ret;
        int i;
 
-       mlx5_ldev_for_each(i, 0, ldev) {
+       mlx5_lag_for_each(i, 0, ldev, filter) {
                pf = mlx5_lag_pf(ldev, i);
                if (!(pf->dev->priv.flags & flags)) {
                        struct mlx5_eswitch *esw;
@@ -1142,7 +1238,7 @@ static int mlx5_lag_reload_ib_reps_unlocked(struct mlx5_lag *ldev, u32 flags,
 }
 
 static int mlx5_lag_reload_ib_reps(struct mlx5_lag *ldev, u32 flags,
-                                  bool cont_on_fail)
+                                  u32 filter, bool cont_on_fail)
 {
        int ret;
 
@@ -1152,21 +1248,18 @@ static int mlx5_lag_reload_ib_reps(struct mlx5_lag *ldev, u32 flags,
         * load/unload callbacks can re-enter LAG netdev add/remove and take
         * ldev->lock. Keep the ordering reps_lock -> ldev->lock.
         */
-       mlx5_lag_drop_lock_for_reps(ldev);
-       ret = mlx5_lag_reload_ib_reps_unlocked(ldev, flags, cont_on_fail);
+       mlx5_lag_drop_lock_for_reps(ldev, filter);
+       ret = mlx5_lag_reload_ib_reps_unlocked(ldev, flags, filter,
+                                              cont_on_fail);
        mlx5_lag_retake_lock_after_reps(ldev);
 
        return ret;
 }
 
 int mlx5_lag_reload_ib_reps_from_locked(struct mlx5_lag *ldev, u32 flags,
-                                       bool cont_on_fail)
+                                       u32 filter, bool cont_on_fail)
 {
-       int ret;
-
-       ret = mlx5_lag_reload_ib_reps(ldev, flags, cont_on_fail);
-
-       return ret;
+       return mlx5_lag_reload_ib_reps(ldev, flags, filter, cont_on_fail);
 }
 
 void mlx5_disable_lag(struct mlx5_lag *ldev)
@@ -1182,7 +1275,7 @@ void mlx5_disable_lag(struct mlx5_lag *ldev)
                return;
 
        if (shared_fdb) {
-               mlx5_lag_shared_fdb_destroy(ldev);
+               mlx5_lag_shared_fdb_destroy(ldev, 0);
                return;
        }
 
@@ -1420,7 +1513,8 @@ static void mlx5_do_bond(struct mlx5_lag *ldev)
 
                if (shared_fdb) {
                        err = mlx5_lag_shared_fdb_create(ldev, &tracker,
-                                                        MLX5_LAG_MODE_SRIOV);
+                                                        MLX5_LAG_MODE_SRIOV,
+                                                        0);
                        if (err)
                                return;
                } else {
@@ -2261,7 +2355,8 @@ bool mlx5_lag_is_active(struct mlx5_core_dev *dev)
 
        spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
-       res  = ldev && __mlx5_lag_is_active(ldev);
+       res  = ldev && (__mlx5_lag_is_active(ldev) ||
+                       __mlx5_lag_is_sd_active(ldev, dev));
        spin_unlock_irqrestore(&lag_lock, flags);
 
        return res;
@@ -2294,10 +2389,17 @@ bool mlx5_lag_is_master(struct mlx5_core_dev *dev)
 
        spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
-       idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
-       if (ldev && __mlx5_lag_is_active(ldev) && idx >= 0) {
-               pf = mlx5_lag_pf(ldev, idx);
-               res = pf && dev == pf->dev;
+       if (ldev) {
+               u32 filter;
+
+               filter = mlx5_lag_get_filter(ldev, dev);
+               idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1,
+                                                          filter);
+               if ((__mlx5_lag_is_active(ldev) ||
+                    __mlx5_lag_is_sd_active(ldev, dev)) && idx >= 0) {
+                       pf = mlx5_lag_pf(ldev, idx);
+                       res = pf && dev == pf->dev;
+               }
        }
        spin_unlock_irqrestore(&lag_lock, flags);
 
@@ -2324,11 +2426,16 @@ bool mlx5_lag_is_shared_fdb(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev;
        unsigned long flags;
-       bool res;
+       bool res = false;
 
        spin_lock_irqsave(&lag_lock, flags);
        ldev = mlx5_lag_dev(dev);
-       res = ldev && test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags);
+       if (ldev) {
+               res = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB,
+                              &ldev->mode_flags);
+               if (__mlx5_lag_is_sd(ldev, dev) && !__mlx5_lag_is_active(ldev))
+                       res = __mlx5_lag_is_sd_active(ldev, dev);
+       }
        spin_unlock_irqrestore(&lag_lock, flags);
 
        return res;
@@ -2429,7 +2536,7 @@ struct mlx5_core_dev *mlx5_lag_get_next_peer_mdev(struct mlx5_core_dev *dev, int
 
        if (*i == MLX5_MAX_PORTS)
                goto unlock;
-       mlx5_ldev_for_each(idx, *i, ldev) {
+       mlx5_lag_for_each(idx, *i, ldev, mlx5_lag_get_filter(ldev, dev)) {
                pf = mlx5_lag_pf(ldev, idx);
                if (pf->dev != dev)
                        break;
index 9e95d5109e4a69a4e8e1fbdb1f6a3f9a05ea664d..82b82bdb16dd3ad0250d3bb879828d1c74880c19 100644 (file)
@@ -148,6 +148,14 @@ mlx5_lag_pf_by_dev(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
        return NULL;
 }
 
+static inline bool
+__mlx5_lag_is_sd(struct mlx5_lag *ldev, struct mlx5_core_dev *dev)
+{
+       struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev);
+
+       return pf && pf->group_id != 0;
+}
+
 static inline bool
 __mlx5_lag_is_active(struct mlx5_lag *ldev)
 {
@@ -163,25 +171,31 @@ mlx5_lag_is_ready(struct mlx5_lag *ldev)
 #ifdef CONFIG_MLX5_ESWITCH
 int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev,
                               struct lag_tracker *tracker,
-                              enum mlx5_lag_mode mode);
-void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev);
+                              enum mlx5_lag_mode mode,
+                              u32 group_id);
+void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev, u32 group_id);
 int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev);
+void mlx5_lag_destroy_single_fdb(struct mlx5_lag *ldev);
 bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev);
+bool mlx5_lag_shared_fdb_supported_filter(struct mlx5_lag *ldev, u32 filter);
 #else
 static inline int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev,
                                             struct lag_tracker *tracker,
-                                            enum mlx5_lag_mode mode)
+                                            enum mlx5_lag_mode mode,
+                                            u32 group_id)
 {
        return -EOPNOTSUPP;
 }
 
-static inline void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev) {}
+static inline void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev,
+                                              u32 group_id) {}
 
 static inline int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev)
 {
        return -EOPNOTSUPP;
 }
 
+static inline void mlx5_lag_destroy_single_fdb(struct mlx5_lag *ldev) {}
 static inline bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev)
 {
        return false;
@@ -211,11 +225,13 @@ void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev);
 void mlx5_ldev_remove_debugfs(struct dentry *dbg);
 void mlx5_disable_lag(struct mlx5_lag *ldev);
 void mlx5_lag_remove_devices(struct mlx5_lag *ldev);
+void mlx5_lag_remove_devices_filter(struct mlx5_lag *ldev, u32 filter);
 int mlx5_deactivate_lag(struct mlx5_lag *ldev);
 void mlx5_lag_add_devices(struct mlx5_lag *ldev);
 void mlx5_lag_rescan_dev_locked(struct mlx5_lag *ldev,
                                struct mlx5_core_dev *dev,
                                bool enable);
+void mlx5_lag_add_devices_filter(struct mlx5_lag *ldev, u32 filter);
 struct mlx5_devcom_comp_dev *mlx5_lag_get_devcom_comp(struct mlx5_lag *ldev);
 
 #ifdef CONFIG_MLX5_ESWITCH
@@ -238,8 +254,8 @@ static inline bool mlx5_lag_is_supported(struct mlx5_core_dev *dev)
 }
 
 /* Iterator filter constants for mlx5_lag_for_each() */
-#define MLX5_LAG_FILTER_ALL   0        /* iterate ALL devices */
-#define MLX5_LAG_FILTER_PORTS U32_MAX  /* iterate ports only (XA_MARK_PORT) */
+#define MLX5_LAG_FILTER_PORTS 0        /* iterate ports only (XA_MARK_PORT) */
+#define MLX5_LAG_FILTER_ALL   U32_MAX  /* iterate ALL devices */
 /* any other value = iterate devices with that specific group_id */
 
 #define mlx5_lag_for_each(i, start_index, ldev, filter) \
@@ -264,10 +280,12 @@ int mlx5_get_pre_lag_func(struct mlx5_lag *ldev, int start_idx, int end_idx,
                          u32 filter);
 int mlx5_get_next_lag_func(struct mlx5_lag *ldev, int start_idx, u32 filter);
 int mlx5_lag_get_dev_index_by_seq(struct mlx5_lag *ldev, int seq);
+int mlx5_lag_get_dev_index_by_seq_filter(struct mlx5_lag *ldev, int seq,
+                                        u32 filter);
 int mlx5_lag_num_devs(struct mlx5_lag *ldev);
 int mlx5_lag_num_netdevs(struct mlx5_lag *ldev);
 int mlx5_lag_reload_ib_reps_from_locked(struct mlx5_lag *ldev, u32 flags,
-                                       bool cont_on_fail);
+                                       u32 filter, bool cont_on_fail);
 int mlx5_ldev_add_mdev(struct mlx5_lag *ldev, struct mlx5_core_dev *dev,
                       u32 group_id);
 void mlx5_ldev_remove_mdev(struct mlx5_lag *ldev, struct mlx5_core_dev *dev);
index 64e2d1dd5308734349423fc3bdbe82e559066818..2cb44084e239a3a68557e0d6a9f950ee4293d849 100644 (file)
@@ -85,14 +85,15 @@ static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev)
            !MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table) ||
            !MLX5_CAP_GEN(dev0, create_lag_when_not_master_up) ||
            !mlx5_lag_check_prereq(ldev) ||
-           !mlx5_lag_shared_fdb_supported(ldev))
+           !mlx5_lag_shared_fdb_supported_filter(ldev, MLX5_LAG_FILTER_ALL))
                return -EOPNOTSUPP;
 
        err = mlx5_mpesw_metadata_set(ldev);
        if (err)
                return err;
 
-       err = mlx5_lag_shared_fdb_create(ldev, NULL, MLX5_LAG_MODE_MPESW);
+       err = mlx5_lag_shared_fdb_create(ldev, NULL, MLX5_LAG_MODE_MPESW,
+                                        MLX5_LAG_FILTER_ALL);
        if (err) {
                mlx5_core_warn(dev0, "Failed to create LAG in MPESW mode (%d)\n", err);
                mlx5_mpesw_metadata_cleanup(ldev);
@@ -106,7 +107,7 @@ void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev)
 {
        if (ldev->mode == MLX5_LAG_MODE_MPESW) {
                mlx5_mpesw_metadata_cleanup(ldev);
-               mlx5_lag_shared_fdb_destroy(ldev);
+               mlx5_lag_shared_fdb_destroy(ldev, MLX5_LAG_FILTER_ALL);
        }
 }
 
index b5cbe34097203669282ac96d2bd1d9a97ae7a23a..1371e14c4c13121ba89f53252bd66f284df5b3c6 100644 (file)
@@ -8,19 +8,19 @@
 #include "lag.h"
 #include "eswitch.h"
 
-bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev)
+bool mlx5_lag_shared_fdb_supported_filter(struct mlx5_lag *ldev, u32 filter)
 {
+       int idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1,
+                                                      filter);
        struct mlx5_core_dev *dev0, *dev;
        bool ret = false;
-       int idx;
        int i;
 
-       idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
        if (idx < 0)
                return false;
 
        dev0 = mlx5_lag_pf(ldev, idx)->dev;
-       mlx5_ldev_for_each(i, 0, ldev) {
+       mlx5_lag_for_each(i, 0, ldev, filter) {
                if (i == idx)
                        continue;
                dev = mlx5_lag_pf(ldev, i)->dev;
@@ -42,9 +42,16 @@ bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev)
        return ret;
 }
 
-int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev)
+bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev)
 {
-       int master_idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
+       return mlx5_lag_shared_fdb_supported_filter(ldev,
+                                                   MLX5_LAG_FILTER_PORTS);
+}
+
+static int mlx5_lag_create_single_fdb_filter(struct mlx5_lag *ldev, u32 filter)
+{
+       int master_idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1,
+                                                            filter);
        struct mlx5_eswitch *master_esw;
        struct mlx5_core_dev *dev0;
        int i, j;
@@ -55,7 +62,7 @@ int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev)
 
        dev0 = mlx5_lag_pf(ldev, master_idx)->dev;
        master_esw = dev0->priv.eswitch;
-       mlx5_ldev_for_each(i, 0, ldev) {
+       mlx5_lag_for_each(i, 0, ldev, filter) {
                struct mlx5_eswitch *slave_esw;
 
                if (i == master_idx)
@@ -71,7 +78,7 @@ int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev)
        }
        return 0;
 err:
-       mlx5_ldev_for_each_reverse(j, i, 0, ldev) {
+       mlx5_lag_for_each_reverse(j, i, 0, ldev, filter) {
                struct mlx5_eswitch *slave_esw;
 
                if (j == master_idx)
@@ -82,59 +89,147 @@ err:
        return err;
 }
 
+static void mlx5_lag_destroy_single_fdb_filter(struct mlx5_lag *ldev,
+                                              u32 filter)
+{
+       int master_idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1,
+                                                            filter);
+       struct mlx5_eswitch *master_esw;
+       struct mlx5_eswitch *peer_esw;
+       int i;
+
+       if (master_idx < 0)
+               return;
+
+       master_esw = mlx5_lag_pf(ldev, master_idx)->dev->priv.eswitch;
+       mlx5_lag_for_each(i, 0, ldev, filter) {
+               if (i == master_idx)
+                       continue;
+
+               peer_esw = mlx5_lag_pf(ldev, i)->dev->priv.eswitch;
+               mlx5_eswitch_offloads_single_fdb_del_one(master_esw, peer_esw);
+       }
+}
+
+int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev)
+{
+       return mlx5_lag_create_single_fdb_filter(ldev, MLX5_LAG_FILTER_ALL);
+}
+
+void mlx5_lag_destroy_single_fdb(struct mlx5_lag *ldev)
+{
+       mlx5_lag_destroy_single_fdb_filter(ldev, MLX5_LAG_FILTER_ALL);
+}
+
+/**
+ * mlx5_lag_shared_fdb_create - Create shared FDB LAG
+ * @ldev: LAG device
+ * @tracker: LAG tracker (NULL for SD)
+ * @mode: LAG mode (unused for SD)
+ * @group_id: SD group ID; 0 (MLX5_LAG_FILTER_PORTS) for ports LAG;
+ *            MLX5_LAG_FILTER_ALL for all-device (mpesw) LAG
+ *
+ * When group_id is 0 (MLX5_LAG_FILTER_PORTS) or MLX5_LAG_FILTER_ALL,
+ * activates a FW LAG with shared FDB.
+ * When group_id is a specific SD group ID, creates a software-only shared
+ * FDB scoped to that group (no FW LAG commands).
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
 int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev,
                               struct lag_tracker *tracker,
-                              enum mlx5_lag_mode mode)
+                              enum mlx5_lag_mode mode,
+                              u32 group_id)
 {
-       int idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
+       u32 filter = group_id ? group_id : MLX5_LAG_FILTER_PORTS;
+       int idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1,
+                                                      filter);
        struct mlx5_core_dev *dev0;
+       struct lag_func *pf;
        int err;
+       int i;
 
        if (idx < 0)
                return -EINVAL;
 
        dev0 = mlx5_lag_pf(ldev, idx)->dev;
 
-       mlx5_lag_remove_devices(ldev);
-
-       err = mlx5_activate_lag(ldev, tracker, mode, true);
-       if (err) {
-               mlx5_core_warn(dev0, "Failed to create LAG in shared FDB mode (%d)\n",
-                              err);
-               goto err_add_devices;
+       mlx5_lag_remove_devices_filter(ldev, filter);
+
+       if (filter == MLX5_LAG_FILTER_PORTS || filter == MLX5_LAG_FILTER_ALL) {
+               err = mlx5_activate_lag(ldev, tracker, mode, true);
+               if (err) {
+                       mlx5_core_warn(dev0,
+                                      "Failed to create LAG in shared FDB mode (%d)\n",
+                                      err);
+                       goto err_add_devices;
+               }
+       } else {
+               err = mlx5_lag_create_single_fdb_filter(ldev, group_id);
+               if (err) {
+                       mlx5_core_warn(dev0,
+                                      "Failed to create SD shared FDB (%d)\n",
+                                      err);
+                       goto err_add_devices;
+               }
+               mlx5_lag_for_each(i, 0, ldev, filter) {
+                       pf = mlx5_lag_pf(ldev, i);
+                       pf->sd_fdb_active = true;
+               }
+               BLOCKING_INIT_NOTIFIER_HEAD(&dev0->priv.lag_nh);
        }
 
        mlx5_lag_rescan_dev_locked(ldev, dev0, true);
-       err = mlx5_lag_reload_ib_reps_from_locked(ldev, 0, false);
+       err = mlx5_lag_reload_ib_reps_from_locked(ldev, 0, filter, false);
        if (err) {
                mlx5_core_err(dev0, "Failed to enable lag\n");
                goto err_rescan_drivers;
        }
 
-       mlx5_lag_set_vports_agg_speed(ldev);
+       if (filter == MLX5_LAG_FILTER_PORTS || filter == MLX5_LAG_FILTER_ALL)
+               mlx5_lag_set_vports_agg_speed(ldev);
        return 0;
 
 err_rescan_drivers:
        mlx5_lag_rescan_dev_locked(ldev, dev0, false);
-       mlx5_deactivate_lag(ldev);
+       if (filter == MLX5_LAG_FILTER_PORTS || filter == MLX5_LAG_FILTER_ALL) {
+               mlx5_deactivate_lag(ldev);
+       } else {
+               mlx5_lag_for_each(i, 0, ldev, filter) {
+                       pf = mlx5_lag_pf(ldev, i);
+                       pf->sd_fdb_active = false;
+               }
+               mlx5_lag_destroy_single_fdb_filter(ldev, group_id);
+       }
 err_add_devices:
-       mlx5_lag_add_devices(ldev);
-       mlx5_lag_reload_ib_reps_from_locked(ldev, 0, true);
+       mlx5_lag_add_devices_filter(ldev, filter);
+       mlx5_lag_reload_ib_reps_from_locked(ldev, 0, filter, true);
        return err;
 }
 
-void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev)
+void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev, u32 group_id)
 {
+       u32 filter = group_id ? group_id : MLX5_LAG_FILTER_PORTS;
+       struct lag_func *pf;
        int err;
+       int i;
 
-       mlx5_lag_remove_devices(ldev);
+       mlx5_lag_remove_devices_filter(ldev, filter);
 
-       err = mlx5_deactivate_lag(ldev);
-       if (err)
-               return;
+       if (filter == MLX5_LAG_FILTER_PORTS || filter == MLX5_LAG_FILTER_ALL) {
+               err = mlx5_deactivate_lag(ldev);
+               if (err)
+                       return;
+       } else {
+               mlx5_lag_for_each(i, 0, ldev, filter) {
+                       pf = mlx5_lag_pf(ldev, i);
+                       pf->sd_fdb_active = false;
+               }
+               mlx5_lag_destroy_single_fdb_filter(ldev, group_id);
+       }
 
-       mlx5_lag_add_devices(ldev);
+       mlx5_lag_add_devices_filter(ldev, filter);
        mlx5_lag_reload_ib_reps_from_locked(ldev,
                                            MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV,
-                                           true);
+                                           filter, true);
 }
index 6e199161b0083af954c9fcbf53c3255c255951c7..bbd77ae11e848da3361f6a0e5aeb9d3d367567b7 100644 (file)
@@ -57,6 +57,16 @@ static struct mlx5_core_dev *mlx5_sd_get_primary(struct mlx5_core_dev *dev)
        return sd->primary ? dev : sd->primary_dev;
 }
 
+struct mlx5_devcom_comp_dev *mlx5_sd_get_devcom(struct mlx5_core_dev *dev)
+{
+       struct mlx5_sd *sd = mlx5_get_sd(dev);
+
+       if (!sd)
+               return NULL;
+
+       return sd->devcom;
+}
+
 struct mlx5_core_dev *
 mlx5_sd_primary_get_peer(struct mlx5_core_dev *primary, int idx)
 {
index 9bfd5b9756b507d8c7e3c2ccebd5ac1b13c4e18b..2ab259095d7ef11801fa4c9868f8ae827c1bdd4e 100644 (file)
@@ -21,6 +21,16 @@ void mlx5_sd_put_adev(struct auxiliary_device *actual_adev,
 int mlx5_sd_init(struct mlx5_core_dev *dev);
 void mlx5_sd_cleanup(struct mlx5_core_dev *dev);
 
+#ifdef CONFIG_MLX5_CORE_EN
+struct mlx5_devcom_comp_dev *mlx5_sd_get_devcom(struct mlx5_core_dev *dev);
+#else
+static inline struct mlx5_devcom_comp_dev *
+mlx5_sd_get_devcom(struct mlx5_core_dev *dev)
+{
+       return NULL;
+}
+#endif
+
 #define mlx5_sd_for_each_dev_from_to(i, primary, ix_from, to, pos)     \
        for (i = ix_from;                                                       \
             (pos = mlx5_sd_primary_get_peer(primary, i)) && pos != (to); i++)