Commit baac8351 authored by Jianbo Liu's avatar Jianbo Liu Committed by Saeed Mahameed

net/mlx5e: Reduce eswitch mode_lock protection context

Currently eswitch mode_lock is so heavy, for example, it's locked
during the whole process of the mode change, which may need to hold
other locks. As the mode_lock is also used by IPSec to block mode and
encap change now, it is easy to cause lock dependency.

Since some of protections are also done by devlink lock, the eswitch
mode_lock is not needed at those places, and thus the possibility of
lockdep issue is reduced.

Fixes: c8e350e6 ("net/mlx5e: Make TC and IPsec offloads mutually exclusive on a netdev")
Signed-off-by: default avatarJianbo Liu <jianbol@nvidia.com>
Signed-off-by: default avatarLeon Romanovsky <leonro@nvidia.com>
parent c2bf84f1
...@@ -2110,8 +2110,11 @@ static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev) ...@@ -2110,8 +2110,11 @@ static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
struct mlx5_eswitch *esw = mdev->priv.eswitch; struct mlx5_eswitch *esw = mdev->priv.eswitch;
int err = 0; int err = 0;
if (esw) if (esw) {
down_write(&esw->mode_lock); err = mlx5_esw_lock(esw);
if (err)
return err;
}
if (mdev->num_block_ipsec) { if (mdev->num_block_ipsec) {
err = -EBUSY; err = -EBUSY;
...@@ -2122,7 +2125,7 @@ static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev) ...@@ -2122,7 +2125,7 @@ static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
unlock: unlock:
if (esw) if (esw)
up_write(&esw->mode_lock); mlx5_esw_unlock(esw);
return err; return err;
} }
......
...@@ -1463,7 +1463,7 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs) ...@@ -1463,7 +1463,7 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
{ {
int err; int err;
lockdep_assert_held(&esw->mode_lock); devl_assert_locked(priv_to_devlink(esw->dev));
if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) { if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
esw_warn(esw->dev, "FDB is not supported, aborting ...\n"); esw_warn(esw->dev, "FDB is not supported, aborting ...\n");
...@@ -1531,7 +1531,6 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs) ...@@ -1531,7 +1531,6 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)
if (toggle_lag) if (toggle_lag)
mlx5_lag_disable_change(esw->dev); mlx5_lag_disable_change(esw->dev);
down_write(&esw->mode_lock);
if (!mlx5_esw_is_fdb_created(esw)) { if (!mlx5_esw_is_fdb_created(esw)) {
ret = mlx5_eswitch_enable_locked(esw, num_vfs); ret = mlx5_eswitch_enable_locked(esw, num_vfs);
} else { } else {
...@@ -1554,8 +1553,6 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs) ...@@ -1554,8 +1553,6 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)
} }
} }
up_write(&esw->mode_lock);
if (toggle_lag) if (toggle_lag)
mlx5_lag_enable_change(esw->dev); mlx5_lag_enable_change(esw->dev);
...@@ -1569,12 +1566,11 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) ...@@ -1569,12 +1566,11 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf)
return; return;
devl_assert_locked(priv_to_devlink(esw->dev)); devl_assert_locked(priv_to_devlink(esw->dev));
down_write(&esw->mode_lock);
/* If driver is unloaded, this function is called twice by remove_one() /* If driver is unloaded, this function is called twice by remove_one()
* and mlx5_unload(). Prevent the second call. * and mlx5_unload(). Prevent the second call.
*/ */
if (!esw->esw_funcs.num_vfs && !esw->esw_funcs.num_ec_vfs && !clear_vf) if (!esw->esw_funcs.num_vfs && !esw->esw_funcs.num_ec_vfs && !clear_vf)
goto unlock; return;
esw_info(esw->dev, "Unload vfs: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n", esw_info(esw->dev, "Unload vfs: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n",
esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS", esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
...@@ -1603,9 +1599,6 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) ...@@ -1603,9 +1599,6 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf)
esw->esw_funcs.num_vfs = 0; esw->esw_funcs.num_vfs = 0;
else else
esw->esw_funcs.num_ec_vfs = 0; esw->esw_funcs.num_ec_vfs = 0;
unlock:
up_write(&esw->mode_lock);
} }
/* Free resources for corresponding eswitch mode. It is called by devlink /* Free resources for corresponding eswitch mode. It is called by devlink
...@@ -1647,10 +1640,8 @@ void mlx5_eswitch_disable(struct mlx5_eswitch *esw) ...@@ -1647,10 +1640,8 @@ void mlx5_eswitch_disable(struct mlx5_eswitch *esw)
devl_assert_locked(priv_to_devlink(esw->dev)); devl_assert_locked(priv_to_devlink(esw->dev));
mlx5_lag_disable_change(esw->dev); mlx5_lag_disable_change(esw->dev);
down_write(&esw->mode_lock);
mlx5_eswitch_disable_locked(esw); mlx5_eswitch_disable_locked(esw);
esw->mode = MLX5_ESWITCH_LEGACY; esw->mode = MLX5_ESWITCH_LEGACY;
up_write(&esw->mode_lock);
mlx5_lag_enable_change(esw->dev); mlx5_lag_enable_change(esw->dev);
} }
...@@ -2254,8 +2245,13 @@ bool mlx5_esw_hold(struct mlx5_core_dev *mdev) ...@@ -2254,8 +2245,13 @@ bool mlx5_esw_hold(struct mlx5_core_dev *mdev)
if (!mlx5_esw_allowed(esw)) if (!mlx5_esw_allowed(esw))
return true; return true;
if (down_read_trylock(&esw->mode_lock) != 0) if (down_read_trylock(&esw->mode_lock) != 0) {
if (esw->eswitch_operation_in_progress) {
up_read(&esw->mode_lock);
return false;
}
return true; return true;
}
return false; return false;
} }
...@@ -2312,7 +2308,8 @@ int mlx5_esw_try_lock(struct mlx5_eswitch *esw) ...@@ -2312,7 +2308,8 @@ int mlx5_esw_try_lock(struct mlx5_eswitch *esw)
if (down_write_trylock(&esw->mode_lock) == 0) if (down_write_trylock(&esw->mode_lock) == 0)
return -EINVAL; return -EINVAL;
if (atomic64_read(&esw->user_count) > 0) { if (esw->eswitch_operation_in_progress ||
atomic64_read(&esw->user_count) > 0) {
up_write(&esw->mode_lock); up_write(&esw->mode_lock);
return -EBUSY; return -EBUSY;
} }
...@@ -2320,6 +2317,18 @@ int mlx5_esw_try_lock(struct mlx5_eswitch *esw) ...@@ -2320,6 +2317,18 @@ int mlx5_esw_try_lock(struct mlx5_eswitch *esw)
return esw->mode; return esw->mode;
} }
int mlx5_esw_lock(struct mlx5_eswitch *esw)
{
down_write(&esw->mode_lock);
if (esw->eswitch_operation_in_progress) {
up_write(&esw->mode_lock);
return -EBUSY;
}
return 0;
}
/** /**
* mlx5_esw_unlock() - Release write lock on esw mode lock * mlx5_esw_unlock() - Release write lock on esw mode lock
* @esw: eswitch device. * @esw: eswitch device.
......
...@@ -383,6 +383,7 @@ struct mlx5_eswitch { ...@@ -383,6 +383,7 @@ struct mlx5_eswitch {
struct xarray paired; struct xarray paired;
struct mlx5_devcom_comp_dev *devcom; struct mlx5_devcom_comp_dev *devcom;
u16 enabled_ipsec_vf_count; u16 enabled_ipsec_vf_count;
bool eswitch_operation_in_progress;
}; };
void esw_offloads_disable(struct mlx5_eswitch *esw); void esw_offloads_disable(struct mlx5_eswitch *esw);
...@@ -827,6 +828,7 @@ void mlx5_esw_release(struct mlx5_core_dev *dev); ...@@ -827,6 +828,7 @@ void mlx5_esw_release(struct mlx5_core_dev *dev);
void mlx5_esw_get(struct mlx5_core_dev *dev); void mlx5_esw_get(struct mlx5_core_dev *dev);
void mlx5_esw_put(struct mlx5_core_dev *dev); void mlx5_esw_put(struct mlx5_core_dev *dev);
int mlx5_esw_try_lock(struct mlx5_eswitch *esw); int mlx5_esw_try_lock(struct mlx5_eswitch *esw);
int mlx5_esw_lock(struct mlx5_eswitch *esw);
void mlx5_esw_unlock(struct mlx5_eswitch *esw); void mlx5_esw_unlock(struct mlx5_eswitch *esw);
void esw_vport_change_handle_locked(struct mlx5_vport *vport); void esw_vport_change_handle_locked(struct mlx5_vport *vport);
......
...@@ -3733,13 +3733,16 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, ...@@ -3733,13 +3733,16 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
goto unlock; goto unlock;
} }
esw->eswitch_operation_in_progress = true;
up_write(&esw->mode_lock);
mlx5_eswitch_disable_locked(esw); mlx5_eswitch_disable_locked(esw);
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) { if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
if (mlx5_devlink_trap_get_num_active(esw->dev)) { if (mlx5_devlink_trap_get_num_active(esw->dev)) {
NL_SET_ERR_MSG_MOD(extack, NL_SET_ERR_MSG_MOD(extack,
"Can't change mode while devlink traps are active"); "Can't change mode while devlink traps are active");
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unlock; goto skip;
} }
err = esw_offloads_start(esw, extack); err = esw_offloads_start(esw, extack);
} else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) { } else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
...@@ -3749,6 +3752,9 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, ...@@ -3749,6 +3752,9 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
err = -EINVAL; err = -EINVAL;
} }
skip:
down_write(&esw->mode_lock);
esw->eswitch_operation_in_progress = false;
unlock: unlock:
mlx5_esw_unlock(esw); mlx5_esw_unlock(esw);
enable_lag: enable_lag:
...@@ -3759,16 +3765,12 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, ...@@ -3759,16 +3765,12 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
{ {
struct mlx5_eswitch *esw; struct mlx5_eswitch *esw;
int err;
esw = mlx5_devlink_eswitch_get(devlink); esw = mlx5_devlink_eswitch_get(devlink);
if (IS_ERR(esw)) if (IS_ERR(esw))
return PTR_ERR(esw); return PTR_ERR(esw);
down_read(&esw->mode_lock); return esw_mode_to_devlink(esw->mode, mode);
err = esw_mode_to_devlink(esw->mode, mode);
up_read(&esw->mode_lock);
return err;
} }
static int mlx5_esw_vports_inline_set(struct mlx5_eswitch *esw, u8 mlx5_mode, static int mlx5_esw_vports_inline_set(struct mlx5_eswitch *esw, u8 mlx5_mode,
...@@ -3862,11 +3864,15 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode, ...@@ -3862,11 +3864,15 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
if (err) if (err)
goto out; goto out;
esw->eswitch_operation_in_progress = true;
up_write(&esw->mode_lock);
err = mlx5_esw_vports_inline_set(esw, mlx5_mode, extack); err = mlx5_esw_vports_inline_set(esw, mlx5_mode, extack);
if (err) if (!err)
goto out; esw->offloads.inline_mode = mlx5_mode;
esw->offloads.inline_mode = mlx5_mode; down_write(&esw->mode_lock);
esw->eswitch_operation_in_progress = false;
up_write(&esw->mode_lock); up_write(&esw->mode_lock);
return 0; return 0;
...@@ -3878,16 +3884,12 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode, ...@@ -3878,16 +3884,12 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode) int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
{ {
struct mlx5_eswitch *esw; struct mlx5_eswitch *esw;
int err;
esw = mlx5_devlink_eswitch_get(devlink); esw = mlx5_devlink_eswitch_get(devlink);
if (IS_ERR(esw)) if (IS_ERR(esw))
return PTR_ERR(esw); return PTR_ERR(esw);
down_read(&esw->mode_lock); return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
err = esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
up_read(&esw->mode_lock);
return err;
} }
bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev) bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev)
...@@ -3969,6 +3971,9 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, ...@@ -3969,6 +3971,9 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
goto unlock; goto unlock;
} }
esw->eswitch_operation_in_progress = true;
up_write(&esw->mode_lock);
esw_destroy_offloads_fdb_tables(esw); esw_destroy_offloads_fdb_tables(esw);
esw->offloads.encap = encap; esw->offloads.encap = encap;
...@@ -3982,6 +3987,9 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, ...@@ -3982,6 +3987,9 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
(void)esw_create_offloads_fdb_tables(esw); (void)esw_create_offloads_fdb_tables(esw);
} }
down_write(&esw->mode_lock);
esw->eswitch_operation_in_progress = false;
unlock: unlock:
up_write(&esw->mode_lock); up_write(&esw->mode_lock);
return err; return err;
...@@ -3996,9 +4004,7 @@ int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, ...@@ -3996,9 +4004,7 @@ int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
if (IS_ERR(esw)) if (IS_ERR(esw))
return PTR_ERR(esw); return PTR_ERR(esw);
down_read(&esw->mode_lock);
*encap = esw->offloads.encap; *encap = esw->offloads.encap;
up_read(&esw->mode_lock);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment