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.
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;
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);
}
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)
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.
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);
}
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;
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.
* 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;
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;
}
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;
* 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)
return;
if (shared_fdb) {
- mlx5_lag_shared_fdb_destroy(ldev);
+ mlx5_lag_shared_fdb_destroy(ldev, 0);
return;
}
if (shared_fdb) {
err = mlx5_lag_shared_fdb_create(ldev, &tracker,
- MLX5_LAG_MODE_SRIOV);
+ MLX5_LAG_MODE_SRIOV,
+ 0);
if (err)
return;
} else {
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;
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);
{
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;
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;
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)
{
#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;
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
}
/* 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) \
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);
!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);
{
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);
}
}
#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;
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;
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)
}
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)
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);
}
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)
{
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++)