}
}
+static void mlx5_eswitch_invalidate_wq(struct mlx5_eswitch *esw)
+{
+ atomic_inc(&esw->generation);
+ wake_up_all(&esw->work_queue_wait);
+}
+
static void mlx5_eswitch_event_handler_unregister(struct mlx5_eswitch *esw)
{
if (esw->mode == MLX5_ESWITCH_OFFLOADS &&
- mlx5_eswitch_is_funcs_handler(esw->dev)) {
+ mlx5_eswitch_is_funcs_handler(esw->dev))
mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);
- atomic_inc(&esw->generation);
- }
}
static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw)
if (toggle_lag)
mlx5_lag_disable_change(esw->dev);
+ mlx5_eswitch_invalidate_wq(esw);
+
if (!mlx5_esw_is_fdb_created(esw)) {
ret = mlx5_eswitch_enable_locked(esw, num_vfs);
} else {
esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
esw->esw_funcs.num_vfs, esw->esw_funcs.num_ec_vfs, esw->enabled_vports);
+ mlx5_eswitch_invalidate_wq(esw);
+
if (!mlx5_core_is_ecpf(esw->dev)) {
mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
if (clear_vf)
mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
mlx5_eswitch_event_handler_unregister(esw);
+ mlx5_eswitch_invalidate_wq(esw);
esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n",
esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
mutex_init(&esw->state_lock);
init_rwsem(&esw->mode_lock);
refcount_set(&esw->qos.refcnt, 0);
+ init_waitqueue_head(&esw->work_queue_wait);
atomic_set(&esw->generation, 0);
esw->enabled_vports = 0;
esw_info(esw->dev, "cleanup\n");
- mlx5_esw_qos_cleanup(esw);
+ mlx5_eswitch_invalidate_wq(esw);
destroy_workqueue(esw->work_queue);
+ mlx5_esw_qos_cleanup(esw);
WARN_ON(refcount_read(&esw->qos.refcnt));
mutex_destroy(&esw->state_lock);
WARN_ON(!xa_empty(&esw->offloads.vhca_map));
struct mlx5_host_work *host_work;
struct mlx5_eswitch *esw;
struct devlink *devlink;
+ int work_gen;
host_work = container_of(work, struct mlx5_host_work, work);
esw = host_work->esw;
+ work_gen = host_work->work_gen;
devlink = priv_to_devlink(esw->dev);
- devl_lock(devlink);
+ /* Do not block on devlink lock until stale work is filtered out.
+ * Teardown can invalidate the generation and then wait for this
+ * workqueue while holding devlink lock.
+ */
+ for (;;) {
+ if (work_gen != atomic_read(&esw->generation))
+ goto free;
+
+ if (devl_trylock(devlink))
+ break;
+
+ wait_event_timeout(esw->work_queue_wait,
+ work_gen != atomic_read(&esw->generation),
+ msecs_to_jiffies(60));
+ }
/* Stale work from one or more mode changes ago. Bail out. */
- if (host_work->work_gen != atomic_read(&esw->generation))
+ if (work_gen != atomic_read(&esw->generation))
goto unlock;
host_work->func(esw);
unlock:
devl_unlock(devlink);
+free:
kfree(host_work);
}