summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c
diff options
context:
space:
mode:
authorWei Zhang <weizhang@nvidia.com>2023-10-12 22:27:36 +0300
committerSaeed Mahameed <saeedm@nvidia.com>2023-10-14 20:16:29 +0300
commit3f7f31fff2510272334f3d0374c432bdaa4f1536 (patch)
tree7a1dd34061dacfe7e8527704d99bcf3d32ae7ae1 /drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c
parent85605fb694f084ba017c93c150e668882445ce73 (diff)
downloadlinux-3f7f31fff2510272334f3d0374c432bdaa4f1536.tar.xz
net/mlx5: Parallelize vhca event handling
At present, mlx5 driver have a general purpose event handler which not only handles vhca event but also many other events. This incurs a huge bottleneck because the event handler is implemented by single threaded workqueue and all events are forced to be handled in serial manner even though application tries to create multiple SFs simultaneously. Introduce a dedicated vhca event handler which manages SFs parallel creation. Signed-off-by: Wei Zhang <weizhang@nvidia.com> Reviewed-by: Moshe Shemesh <moshe@nvidia.com> Reviewed-by: Shay Drory <shayd@nvidia.com> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com> Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c')
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c57
1 files changed, 54 insertions, 3 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c
index d908fba968f0..c6fd729de8b2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c
@@ -21,6 +21,15 @@ struct mlx5_vhca_event_work {
struct mlx5_vhca_state_event event;
};
+struct mlx5_vhca_event_handler {
+ struct workqueue_struct *wq;
+};
+
+struct mlx5_vhca_events {
+ struct mlx5_core_dev *dev;
+ struct mlx5_vhca_event_handler handler[MLX5_DEV_MAX_WQS];
+};
+
int mlx5_cmd_query_vhca_state(struct mlx5_core_dev *dev, u16 function_id, u32 *out, u32 outlen)
{
u32 in[MLX5_ST_SZ_DW(query_vhca_state_in)] = {};
@@ -99,6 +108,12 @@ static void mlx5_vhca_state_work_handler(struct work_struct *_work)
kfree(work);
}
+static void
+mlx5_vhca_events_work_enqueue(struct mlx5_core_dev *dev, int idx, struct work_struct *work)
+{
+ queue_work(dev->priv.vhca_events->handler[idx].wq, work);
+}
+
static int
mlx5_vhca_state_change_notifier(struct notifier_block *nb, unsigned long type, void *data)
{
@@ -106,6 +121,7 @@ mlx5_vhca_state_change_notifier(struct notifier_block *nb, unsigned long type, v
mlx5_nb_cof(nb, struct mlx5_vhca_state_notifier, nb);
struct mlx5_vhca_event_work *work;
struct mlx5_eqe *eqe = data;
+ int wq_idx;
work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work)
@@ -113,7 +129,8 @@ mlx5_vhca_state_change_notifier(struct notifier_block *nb, unsigned long type, v
INIT_WORK(&work->work, &mlx5_vhca_state_work_handler);
work->notifier = notifier;
work->event.function_id = be16_to_cpu(eqe->data.vhca_state.function_id);
- mlx5_events_work_enqueue(notifier->dev, &work->work);
+ wq_idx = work->event.function_id % MLX5_DEV_MAX_WQS;
+ mlx5_vhca_events_work_enqueue(notifier->dev, wq_idx, &work->work);
return NOTIFY_OK;
}
@@ -132,28 +149,62 @@ void mlx5_vhca_state_cap_handle(struct mlx5_core_dev *dev, void *set_hca_cap)
int mlx5_vhca_event_init(struct mlx5_core_dev *dev)
{
struct mlx5_vhca_state_notifier *notifier;
+ char wq_name[MLX5_CMD_WQ_MAX_NAME];
+ struct mlx5_vhca_events *events;
+ int err, i;
if (!mlx5_vhca_event_supported(dev))
return 0;
- notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
- if (!notifier)
+ events = kzalloc(sizeof(*events), GFP_KERNEL);
+ if (!events)
return -ENOMEM;
+ events->dev = dev;
+ dev->priv.vhca_events = events;
+ for (i = 0; i < MLX5_DEV_MAX_WQS; i++) {
+ snprintf(wq_name, MLX5_CMD_WQ_MAX_NAME, "mlx5_vhca_event%d", i);
+ events->handler[i].wq = create_singlethread_workqueue(wq_name);
+ if (!events->handler[i].wq) {
+ err = -ENOMEM;
+ goto err_create_wq;
+ }
+ }
+
+ notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
+ if (!notifier) {
+ err = -ENOMEM;
+ goto err_notifier;
+ }
+
dev->priv.vhca_state_notifier = notifier;
notifier->dev = dev;
BLOCKING_INIT_NOTIFIER_HEAD(&notifier->n_head);
MLX5_NB_INIT(&notifier->nb, mlx5_vhca_state_change_notifier, VHCA_STATE_CHANGE);
return 0;
+
+err_notifier:
+err_create_wq:
+ for (--i; i >= 0; i--)
+ destroy_workqueue(events->handler[i].wq);
+ kfree(events);
+ return err;
}
void mlx5_vhca_event_cleanup(struct mlx5_core_dev *dev)
{
+ struct mlx5_vhca_events *vhca_events;
+ int i;
+
if (!mlx5_vhca_event_supported(dev))
return;
kfree(dev->priv.vhca_state_notifier);
dev->priv.vhca_state_notifier = NULL;
+ vhca_events = dev->priv.vhca_events;
+ for (i = 0; i < MLX5_DEV_MAX_WQS; i++)
+ destroy_workqueue(vhca_events->handler[i].wq);
+ kvfree(vhca_events);
}
void mlx5_vhca_event_start(struct mlx5_core_dev *dev)