On an SD device, vport representors are not functional until the SD
group is combined and shared FDB is active. Skip the initial load and
the reload paths in that window; reps are loaded as part of the SD LAG
activation flow once it becomes active.
In addition, explicitly unload representors when SD LAG is destroyed.
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/20260612113904.537595-14-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
void mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw,
struct mlx5_eswitch *slave_esw);
int mlx5_eswitch_reload_ib_reps(struct mlx5_eswitch *esw);
+void mlx5_eswitch_unload_reps(struct mlx5_eswitch *esw);
bool mlx5_eswitch_is_peer(struct mlx5_eswitch *esw,
struct mlx5_eswitch *peer_esw);
return 0;
}
+static inline void
+mlx5_eswitch_unload_reps(struct mlx5_eswitch *esw) {}
+
static inline bool
mlx5_eswitch_block_encap(struct mlx5_core_dev *dev, bool from_fdb)
{
int rep_type;
int err;
+ if (vport_num != MLX5_VPORT_UPLINK &&
+ mlx5_get_sd(esw->dev) && !mlx5_lag_is_active(esw->dev))
+ return 0;
+
rep = mlx5_eswitch_get_rep(esw, vport_num);
for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
err = __esw_offloads_load_rep(esw, rep, rep_type,
esw_vport_destroy_offloads_acl_tables(esw, vport);
}
+void mlx5_eswitch_unload_reps(struct mlx5_eswitch *esw)
+{
+ struct mlx5_eswitch_rep *rep;
+ unsigned long i;
+
+ if (!esw || esw->mode != MLX5_ESWITCH_OFFLOADS)
+ return;
+
+ mlx5_esw_for_each_rep(esw, i, rep) {
+ if (rep->vport == MLX5_VPORT_UPLINK)
+ continue;
+ mlx5_esw_offloads_rep_unload(esw, rep->vport);
+ }
+}
+
int mlx5_eswitch_reload_ib_reps(struct mlx5_eswitch *esw)
{
struct mlx5_eswitch_rep *rep;
if (!mlx5_sd_is_primary(esw->dev) &&
rep->vport == MLX5_VPORT_UPLINK)
continue;
+ if (rep->vport != MLX5_VPORT_UPLINK &&
+ mlx5_get_sd(esw->dev) && !mlx5_lag_is_active(esw->dev))
+ continue;
+
if (atomic_read(&rep->rep_data[REP_ETH].state) == REP_LOADED)
__esw_offloads_load_rep(esw, rep, REP_IB, NULL);
}
return;
}
+ if (mlx5_get_sd(esw->dev) && !mlx5_lag_is_active(esw->dev))
+ return;
+
mlx5_esw_for_each_vport(esw, i, vport) {
if (!vport)
continue;
return mlx5_lag_reload_ib_reps(ldev, flags, filter, cont_on_fail);
}
+static void mlx5_lag_unload_reps_unlocked(struct mlx5_lag *ldev, u32 filter)
+{
+ struct lag_func *pf;
+ int i;
+
+ mlx5_lag_for_each(i, 0, ldev, filter) {
+ struct mlx5_eswitch *esw;
+
+ pf = mlx5_lag_pf(ldev, i);
+ esw = pf->dev->priv.eswitch;
+ mlx5_esw_reps_block(esw);
+ mlx5_eswitch_unload_reps(esw);
+ mlx5_esw_reps_unblock(esw);
+ }
+}
+
+void mlx5_lag_unload_reps_from_locked(struct mlx5_lag *ldev, u32 filter)
+{
+ /* Same lock dance as mlx5_lag_reload_ib_reps: drop ldev->lock around
+ * the per-eswitch reps_lock to keep the reps_lock -> ldev->lock order.
+ */
+ mlx5_lag_drop_lock_for_reps(ldev, filter);
+ mlx5_lag_unload_reps_unlocked(ldev, filter);
+ mlx5_lag_retake_lock_after_reps(ldev);
+}
+
void mlx5_disable_lag(struct mlx5_lag *ldev)
{
bool shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags);
int mlx5_lag_num_netdevs(struct mlx5_lag *ldev);
int mlx5_lag_reload_ib_reps_from_locked(struct mlx5_lag *ldev, u32 flags,
u32 filter, bool cont_on_fail);
+void mlx5_lag_unload_reps_from_locked(struct mlx5_lag *ldev, u32 filter);
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);
pf->sd_fdb_active = false;
}
mlx5_lag_destroy_single_fdb_filter(ldev, group_id);
+ mlx5_lag_unload_reps_from_locked(ldev, filter);
}
mlx5_lag_add_devices_filter(ldev, filter);