net/mlx5: Use devl_ API in mlx5e_devlink_port_register
As part of the flows invoked by mlx5_devlink_eswitch_mode_set() get to mlx5_rescan_drivers_locked() which can call mlx5e_probe()/mlx5e_remove and register/unregister mlx5e driver ports accordingly. This can lead to deadlock once mlx5_devlink_eswitch_mode_set() will use devlink lock. Use devl_port_register/unregister() instead of devlink_port_register/unregister() and add devlink instance locks in the driver paths to this function to have it locked while calling devl_ API function. If remove or probe were called by module init or module cleanup flows, need to lock devlink just before calling devl_port_register(), otherwise it is called by attach/detach or register/unregister flow and we can have the flow locked. Added flag to distinguish between these cases. This will be used by the downstream patch to invoke mlx5_devlink_eswitch_mode_set() with devlink locked. Signed-off-by: Moshe Shemesh <moshe@nvidia.com> Signed-off-by: Saeed Mahameed <saeedm@nvidia.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
df539fc62b
commit
7b19119f4c
@ -335,13 +335,16 @@ static void del_adev(struct auxiliary_device *adev)
|
||||
|
||||
int mlx5_attach_device(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(dev);
|
||||
struct mlx5_priv *priv = &dev->priv;
|
||||
struct auxiliary_device *adev;
|
||||
struct auxiliary_driver *adrv;
|
||||
int ret = 0, i;
|
||||
|
||||
devl_lock(devlink);
|
||||
mutex_lock(&mlx5_intf_mutex);
|
||||
priv->flags &= ~MLX5_PRIV_FLAGS_DETACH;
|
||||
priv->flags |= MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
|
||||
for (i = 0; i < ARRAY_SIZE(mlx5_adev_devices); i++) {
|
||||
if (!priv->adev[i]) {
|
||||
bool is_supported = false;
|
||||
@ -389,19 +392,24 @@ int mlx5_attach_device(struct mlx5_core_dev *dev)
|
||||
break;
|
||||
}
|
||||
}
|
||||
priv->flags &= ~MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
|
||||
mutex_unlock(&mlx5_intf_mutex);
|
||||
devl_unlock(devlink);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mlx5_detach_device(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(dev);
|
||||
struct mlx5_priv *priv = &dev->priv;
|
||||
struct auxiliary_device *adev;
|
||||
struct auxiliary_driver *adrv;
|
||||
pm_message_t pm = {};
|
||||
int i;
|
||||
|
||||
devl_lock(devlink);
|
||||
mutex_lock(&mlx5_intf_mutex);
|
||||
priv->flags |= MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
|
||||
for (i = ARRAY_SIZE(mlx5_adev_devices) - 1; i >= 0; i--) {
|
||||
if (!priv->adev[i])
|
||||
continue;
|
||||
@ -430,18 +438,24 @@ skip_suspend:
|
||||
del_adev(&priv->adev[i]->adev);
|
||||
priv->adev[i] = NULL;
|
||||
}
|
||||
priv->flags &= ~MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
|
||||
priv->flags |= MLX5_PRIV_FLAGS_DETACH;
|
||||
mutex_unlock(&mlx5_intf_mutex);
|
||||
devl_unlock(devlink);
|
||||
}
|
||||
|
||||
int mlx5_register_device(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct devlink *devlink;
|
||||
int ret;
|
||||
|
||||
devlink = priv_to_devlink(dev);
|
||||
devl_lock(devlink);
|
||||
mutex_lock(&mlx5_intf_mutex);
|
||||
dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV;
|
||||
ret = mlx5_rescan_drivers_locked(dev);
|
||||
mutex_unlock(&mlx5_intf_mutex);
|
||||
devl_unlock(devlink);
|
||||
if (ret)
|
||||
mlx5_unregister_device(dev);
|
||||
|
||||
@ -450,10 +464,15 @@ int mlx5_register_device(struct mlx5_core_dev *dev)
|
||||
|
||||
void mlx5_unregister_device(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct devlink *devlink;
|
||||
|
||||
devlink = priv_to_devlink(dev);
|
||||
devl_lock(devlink);
|
||||
mutex_lock(&mlx5_intf_mutex);
|
||||
dev->priv.flags = MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV;
|
||||
mlx5_rescan_drivers_locked(dev);
|
||||
mutex_unlock(&mlx5_intf_mutex);
|
||||
devl_unlock(devlink);
|
||||
}
|
||||
|
||||
static int add_drivers(struct mlx5_core_dev *dev)
|
||||
@ -526,16 +545,22 @@ del_adev:
|
||||
int mlx5_rescan_drivers_locked(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct mlx5_priv *priv = &dev->priv;
|
||||
int err = 0;
|
||||
|
||||
lockdep_assert_held(&mlx5_intf_mutex);
|
||||
if (priv->flags & MLX5_PRIV_FLAGS_DETACH)
|
||||
return 0;
|
||||
|
||||
priv->flags |= MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
|
||||
delete_drivers(dev);
|
||||
if (priv->flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
return add_drivers(dev);
|
||||
err = add_drivers(dev);
|
||||
|
||||
out:
|
||||
priv->flags &= ~MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW;
|
||||
return err;
|
||||
}
|
||||
|
||||
bool mlx5_same_hw_devs(struct mlx5_core_dev *dev, struct mlx5_core_dev *peer_dev)
|
||||
|
@ -21,6 +21,7 @@ int mlx5e_devlink_port_register(struct mlx5e_priv *priv)
|
||||
struct netdev_phys_item_id ppid = {};
|
||||
struct devlink_port *dl_port;
|
||||
unsigned int dl_port_index;
|
||||
int ret;
|
||||
|
||||
if (mlx5_core_is_pf(priv->mdev)) {
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
|
||||
@ -41,7 +42,13 @@ int mlx5e_devlink_port_register(struct mlx5e_priv *priv)
|
||||
memset(dl_port, 0, sizeof(*dl_port));
|
||||
devlink_port_attrs_set(dl_port, &attrs);
|
||||
|
||||
return devlink_port_register(devlink, dl_port, dl_port_index);
|
||||
if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW))
|
||||
devl_lock(devlink);
|
||||
ret = devl_port_register(devlink, dl_port, dl_port_index);
|
||||
if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW))
|
||||
devl_unlock(devlink);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mlx5e_devlink_port_type_eth_set(struct mlx5e_priv *priv)
|
||||
@ -54,8 +61,13 @@ void mlx5e_devlink_port_type_eth_set(struct mlx5e_priv *priv)
|
||||
void mlx5e_devlink_port_unregister(struct mlx5e_priv *priv)
|
||||
{
|
||||
struct devlink_port *dl_port = mlx5e_devlink_get_dl_port(priv);
|
||||
struct devlink *devlink = priv_to_devlink(priv->mdev);
|
||||
|
||||
devlink_port_unregister(dl_port);
|
||||
if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW))
|
||||
devl_lock(devlink);
|
||||
devl_port_unregister(dl_port);
|
||||
if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW))
|
||||
devl_unlock(devlink);
|
||||
}
|
||||
|
||||
struct devlink_port *mlx5e_get_devlink_port(struct net_device *dev)
|
||||
|
@ -3400,7 +3400,9 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
|
||||
err = esw_offloads_start(esw, extack);
|
||||
} else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
|
||||
err = esw_offloads_stop(esw, extack);
|
||||
devl_lock(devlink);
|
||||
mlx5_rescan_drivers(esw->dev);
|
||||
devl_unlock(devlink);
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
@ -551,6 +551,10 @@ enum {
|
||||
* creation/deletion on drivers rescan. Unset during device attach.
|
||||
*/
|
||||
MLX5_PRIV_FLAGS_DETACH = 1 << 2,
|
||||
/* Distinguish between mlx5e_probe/remove called by module init/cleanup
|
||||
* and called by other flows which can already hold devlink lock
|
||||
*/
|
||||
MLX5_PRIV_FLAGS_MLX5E_LOCKED_FLOW = 1 << 3,
|
||||
};
|
||||
|
||||
struct mlx5_adev {
|
||||
|
Loading…
x
Reference in New Issue
Block a user