diff options
| author | Mark Bloch <mbloch@nvidia.com> | 2026-04-28 08:10:16 +0300 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-04-30 03:46:27 +0300 |
| commit | 2a110ee54e8911aa6f66baec52252ce4431afe91 (patch) | |
| tree | d4463e319873582f45557d48efdc692161aaa2b8 | |
| parent | f950ddb57ce46eee0d2b8f1d6ea47f835c224103 (diff) | |
| download | linux-2a110ee54e8911aa6f66baec52252ce4431afe91.tar.xz | |
net/mlx5: E-Switch, introduce generic work queue dispatch helper
Each E-Switch work item requires the same boilerplate: acquire the
devlink lock, check whether the work is stale, dispatch to the
appropriate handler, and release the lock. Factor this out.
Add a func callback to mlx5_host_work so the generic handler
esw_wq_handler() can dispatch to the right function without
duplicating locking logic. Introduce mlx5_esw_add_work() as the
single enqueue point: it stamps the work item with the current
generation counter and queues it onto the E-Switch work queue.
Refactor esw_vfs_changed_event_handler() to match the new contract:
it no longer receives work_gen or out as parameters. It queries
mlx5_esw_query_functions() itself and owns the kvfree() of the
result. The devlink lock is acquired and released by esw_wq_handler()
before dispatching, so the handler runs with the lock already held.
Update mlx5_esw_funcs_changed_handler() to use mlx5_esw_add_work().
Signed-off-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20260428051018.219093-3-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 77 |
2 files changed, 45 insertions, 33 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 0c3d2bdebf8c..e3ab8a30c174 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -336,6 +336,7 @@ struct mlx5_host_work { struct work_struct work; struct mlx5_eswitch *esw; int work_gen; + void (*func)(struct mlx5_eswitch *esw); }; struct mlx5_esw_functions { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index b2e7294d3a5c..23af5a12dc07 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -3655,20 +3655,15 @@ static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw) mutex_destroy(&esw->fdb_table.offloads.vports.lock); } -static void -esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, int work_gen, - const u32 *out) +static void esw_vfs_changed_event_handler(struct mlx5_eswitch *esw) { - struct devlink *devlink; bool host_pf_disabled; u16 new_num_vfs; + const u32 *out; - devlink = priv_to_devlink(esw->dev); - devl_lock(devlink); - - /* Stale work from one or more mode changes ago. Bail out. */ - if (work_gen != atomic_read(&esw->generation)) - goto unlock; + out = mlx5_esw_query_functions(esw->dev); + if (IS_ERR(out)) + return; new_num_vfs = MLX5_GET(query_esw_functions_out, out, host_params_context.host_num_of_vfs); @@ -3676,7 +3671,7 @@ esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, int work_gen, host_params_context.host_pf_disabled); if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_disabled) - goto unlock; + goto free; /* Number of VFs can only change from "0 to x" or "x to 0". */ if (esw->esw_funcs.num_vfs > 0) { @@ -3686,54 +3681,70 @@ esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, int work_gen, err = mlx5_eswitch_load_vf_vports(esw, new_num_vfs, MLX5_VPORT_UC_ADDR_CHANGE); - if (err) { - devl_unlock(devlink); - return; - } + if (err) + goto free; } esw->esw_funcs.num_vfs = new_num_vfs; -unlock: - devl_unlock(devlink); +free: + kvfree(out); } -static void esw_functions_changed_event_handler(struct work_struct *work) +static void esw_wq_handler(struct work_struct *work) { struct mlx5_host_work *host_work; struct mlx5_eswitch *esw; - const u32 *out; + struct devlink *devlink; host_work = container_of(work, struct mlx5_host_work, work); esw = host_work->esw; + devlink = priv_to_devlink(esw->dev); - out = mlx5_esw_query_functions(esw->dev); - if (IS_ERR(out)) - goto out; + devl_lock(devlink); - esw_vfs_changed_event_handler(esw, host_work->work_gen, out); - kvfree(out); -out: + /* Stale work from one or more mode changes ago. Bail out. */ + if (host_work->work_gen != atomic_read(&esw->generation)) + goto unlock; + + host_work->func(esw); + +unlock: + devl_unlock(devlink); kfree(host_work); } -int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data) +static int mlx5_esw_add_work(struct mlx5_eswitch *esw, + void (*func)(struct mlx5_eswitch *esw)) { - struct mlx5_esw_functions *esw_funcs; struct mlx5_host_work *host_work; - struct mlx5_eswitch *esw; host_work = kzalloc_obj(*host_work, GFP_ATOMIC); if (!host_work) - return NOTIFY_DONE; - - esw_funcs = mlx5_nb_cof(nb, struct mlx5_esw_functions, nb); - esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs); + return -ENOMEM; host_work->esw = esw; host_work->work_gen = atomic_read(&esw->generation); - INIT_WORK(&host_work->work, esw_functions_changed_event_handler); + host_work->func = func; + INIT_WORK(&host_work->work, esw_wq_handler); queue_work(esw->work_queue, &host_work->work); + return 0; +} + +int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, + unsigned long type, void *data) +{ + struct mlx5_esw_functions *esw_funcs; + struct mlx5_eswitch *esw; + int ret; + + esw_funcs = mlx5_nb_cof(nb, struct mlx5_esw_functions, nb); + esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs); + + ret = mlx5_esw_add_work(esw, esw_vfs_changed_event_handler); + if (ret) + return NOTIFY_DONE; + return NOTIFY_OK; } |
