Commit 7dc84de9 authored by Roi Dayan's avatar Roi Dayan Committed by Saeed Mahameed

net/mlx5: E-Switch, Protect changing mode while adding rules

We re-use the native NIC port net device instance for the Uplink
representor, a driver currently cannot unbind TC setup callback
actively, hence protect changing E-Switch mode while adding rules.
Signed-off-by: default avatarRoi Dayan <roid@nvidia.com>
Reviewed-by: default avatarParav Pandit <parav@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent c55479d0
...@@ -4323,6 +4323,11 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv, ...@@ -4323,6 +4323,11 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow; struct mlx5e_tc_flow *flow;
int err = 0; int err = 0;
if (!mlx5_esw_hold(priv->mdev))
return -EAGAIN;
mlx5_esw_get(priv->mdev);
rcu_read_lock(); rcu_read_lock();
flow = rhashtable_lookup(tc_ht, &f->cookie, tc_ht_params); flow = rhashtable_lookup(tc_ht, &f->cookie, tc_ht_params);
if (flow) { if (flow) {
...@@ -4360,11 +4365,14 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv, ...@@ -4360,11 +4365,14 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
if (err) if (err)
goto err_free; goto err_free;
mlx5_esw_release(priv->mdev);
return 0; return 0;
err_free: err_free:
mlx5e_flow_put(priv, flow); mlx5e_flow_put(priv, flow);
out: out:
mlx5_esw_put(priv->mdev);
mlx5_esw_release(priv->mdev);
return err; return err;
} }
...@@ -4404,6 +4412,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv, ...@@ -4404,6 +4412,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
trace_mlx5e_delete_flower(f); trace_mlx5e_delete_flower(f);
mlx5e_flow_put(priv, flow); mlx5e_flow_put(priv, flow);
mlx5_esw_put(priv->mdev);
return 0; return 0;
errout: errout:
......
...@@ -435,6 +435,7 @@ static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw) ...@@ -435,6 +435,7 @@ static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw)
esw->fdb_table.legacy.addr_grp = NULL; esw->fdb_table.legacy.addr_grp = NULL;
esw->fdb_table.legacy.allmulti_grp = NULL; esw->fdb_table.legacy.allmulti_grp = NULL;
esw->fdb_table.legacy.promisc_grp = NULL; esw->fdb_table.legacy.promisc_grp = NULL;
atomic64_set(&esw->user_count, 0);
} }
static int esw_create_legacy_table(struct mlx5_eswitch *esw) static int esw_create_legacy_table(struct mlx5_eswitch *esw)
...@@ -442,6 +443,7 @@ static int esw_create_legacy_table(struct mlx5_eswitch *esw) ...@@ -442,6 +443,7 @@ static int esw_create_legacy_table(struct mlx5_eswitch *esw)
int err; int err;
memset(&esw->fdb_table.legacy, 0, sizeof(struct legacy_fdb)); memset(&esw->fdb_table.legacy, 0, sizeof(struct legacy_fdb));
atomic64_set(&esw->user_count, 0);
err = esw_create_legacy_vepa_table(esw); err = esw_create_legacy_vepa_table(esw);
if (err) if (err)
...@@ -2581,3 +2583,94 @@ void mlx5_esw_event_notifier_unregister(struct mlx5_eswitch *esw, struct notifie ...@@ -2581,3 +2583,94 @@ void mlx5_esw_event_notifier_unregister(struct mlx5_eswitch *esw, struct notifie
{ {
blocking_notifier_chain_unregister(&esw->n_head, nb); blocking_notifier_chain_unregister(&esw->n_head, nb);
} }
/**
* mlx5_esw_hold() - Try to take a read lock on esw mode lock.
* @mdev: mlx5 core device.
*
* Should be called by esw resources callers.
*
* Return: true on success or false.
*/
bool mlx5_esw_hold(struct mlx5_core_dev *mdev)
{
struct mlx5_eswitch *esw = mdev->priv.eswitch;
/* e.g. VF doesn't have eswitch so nothing to do */
if (!ESW_ALLOWED(esw))
return true;
if (down_read_trylock(&esw->mode_lock) != 0)
return true;
return false;
}
/**
* mlx5_esw_release() - Release a read lock on esw mode lock.
* @mdev: mlx5 core device.
*/
void mlx5_esw_release(struct mlx5_core_dev *mdev)
{
struct mlx5_eswitch *esw = mdev->priv.eswitch;
if (ESW_ALLOWED(esw))
up_read(&esw->mode_lock);
}
/**
* mlx5_esw_get() - Increase esw user count.
* @mdev: mlx5 core device.
*/
void mlx5_esw_get(struct mlx5_core_dev *mdev)
{
struct mlx5_eswitch *esw = mdev->priv.eswitch;
if (ESW_ALLOWED(esw))
atomic64_inc(&esw->user_count);
}
/**
* mlx5_esw_put() - Decrease esw user count.
* @mdev: mlx5 core device.
*/
void mlx5_esw_put(struct mlx5_core_dev *mdev)
{
struct mlx5_eswitch *esw = mdev->priv.eswitch;
if (ESW_ALLOWED(esw))
atomic64_dec_if_positive(&esw->user_count);
}
/**
* mlx5_esw_try_lock() - Take a write lock on esw mode lock.
* @esw: eswitch device.
*
* Should be called by esw mode change routine.
*
* Return:
* * 0 - esw mode if successfully locked and refcount is 0.
* * -EBUSY - refcount is not 0.
* * -EINVAL - In the middle of switching mode or lock is already held.
*/
int mlx5_esw_try_lock(struct mlx5_eswitch *esw)
{
if (down_write_trylock(&esw->mode_lock) == 0)
return -EINVAL;
if (atomic64_read(&esw->user_count) > 0) {
up_write(&esw->mode_lock);
return -EBUSY;
}
return esw->mode;
}
/**
* mlx5_esw_unlock() - Release write lock on esw mode lock
* @esw: eswitch device.
*/
void mlx5_esw_unlock(struct mlx5_eswitch *esw)
{
up_write(&esw->mode_lock);
}
...@@ -272,6 +272,7 @@ struct mlx5_eswitch { ...@@ -272,6 +272,7 @@ struct mlx5_eswitch {
* user commands, i.e. sriov state change, devlink commands. * user commands, i.e. sriov state change, devlink commands.
*/ */
struct rw_semaphore mode_lock; struct rw_semaphore mode_lock;
atomic64_t user_count;
struct { struct {
bool enabled; bool enabled;
...@@ -761,6 +762,14 @@ struct mlx5_esw_event_info { ...@@ -761,6 +762,14 @@ struct mlx5_esw_event_info {
int mlx5_esw_event_notifier_register(struct mlx5_eswitch *esw, struct notifier_block *n); int mlx5_esw_event_notifier_register(struct mlx5_eswitch *esw, struct notifier_block *n);
void mlx5_esw_event_notifier_unregister(struct mlx5_eswitch *esw, struct notifier_block *n); void mlx5_esw_event_notifier_unregister(struct mlx5_eswitch *esw, struct notifier_block *n);
bool mlx5_esw_hold(struct mlx5_core_dev *dev);
void mlx5_esw_release(struct mlx5_core_dev *dev);
void mlx5_esw_get(struct mlx5_core_dev *dev);
void mlx5_esw_put(struct mlx5_core_dev *dev);
int mlx5_esw_try_lock(struct mlx5_eswitch *esw);
void mlx5_esw_unlock(struct mlx5_eswitch *esw);
#else /* CONFIG_MLX5_ESWITCH */ #else /* CONFIG_MLX5_ESWITCH */
/* eswitch API stubs */ /* eswitch API stubs */
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; } static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
......
...@@ -1854,6 +1854,7 @@ static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw) ...@@ -1854,6 +1854,7 @@ static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
/* Holds true only as long as DMFS is the default */ /* Holds true only as long as DMFS is the default */
mlx5_flow_namespace_set_mode(esw->fdb_table.offloads.ns, mlx5_flow_namespace_set_mode(esw->fdb_table.offloads.ns,
MLX5_FLOW_STEERING_MODE_DMFS); MLX5_FLOW_STEERING_MODE_DMFS);
atomic64_set(&esw->user_count, 0);
} }
static int esw_create_offloads_table(struct mlx5_eswitch *esw) static int esw_create_offloads_table(struct mlx5_eswitch *esw)
...@@ -2584,6 +2585,7 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw) ...@@ -2584,6 +2585,7 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb)); memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb));
mutex_init(&esw->fdb_table.offloads.vports.lock); mutex_init(&esw->fdb_table.offloads.vports.lock);
hash_init(esw->fdb_table.offloads.vports.table); hash_init(esw->fdb_table.offloads.vports.table);
atomic64_set(&esw->user_count, 0);
indir = mlx5_esw_indir_table_init(); indir = mlx5_esw_indir_table_init();
if (IS_ERR(indir)) { if (IS_ERR(indir)) {
...@@ -2925,8 +2927,14 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, ...@@ -2925,8 +2927,14 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
if (esw_mode_from_devlink(mode, &mlx5_mode)) if (esw_mode_from_devlink(mode, &mlx5_mode))
return -EINVAL; return -EINVAL;
down_write(&esw->mode_lock); err = mlx5_esw_try_lock(esw);
cur_mlx5_mode = esw->mode; if (err < 0) {
NL_SET_ERR_MSG_MOD(extack, "Can't change mode, E-Switch is busy");
return err;
}
cur_mlx5_mode = err;
err = 0;
if (cur_mlx5_mode == mlx5_mode) if (cur_mlx5_mode == mlx5_mode)
goto unlock; goto unlock;
...@@ -2938,7 +2946,7 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, ...@@ -2938,7 +2946,7 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
err = -EINVAL; err = -EINVAL;
unlock: unlock:
up_write(&esw->mode_lock); mlx5_esw_unlock(esw);
return err; return err;
} }
......
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