diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx5/core/cq.c')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/cq.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c index 4caa1b6f40ba..1fd403713baf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c @@ -71,6 +71,7 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, { unsigned long flags; struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv; + bool schedule_tasklet = false; spin_lock_irqsave(&tasklet_ctx->lock, flags); /* When migrating CQs between EQs will be implemented, please note @@ -80,9 +81,19 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, */ if (list_empty_careful(&cq->tasklet_ctx.list)) { mlx5_cq_hold(cq); + /* If the tasklet CQ work list isn't empty, mlx5_cq_tasklet_cb() + * is scheduled/running and hasn't processed the list yet, so it + * will see this added CQ when it runs. If the list is empty, + * the tasklet needs to be scheduled to pick up the CQ. The + * spinlock avoids any race with the tasklet accessing the list. + */ + schedule_tasklet = list_empty(&tasklet_ctx->list); list_add_tail(&cq->tasklet_ctx.list, &tasklet_ctx->list); } spin_unlock_irqrestore(&tasklet_ctx->lock, flags); + + if (schedule_tasklet) + tasklet_schedule(&tasklet_ctx->task); } /* Callers must verify outbox status in case of err */ |