Skip to content

Commit 0ac2043

Browse files
calebsanderkuba-moo
authored andcommitted
mlx5/core: Schedule EQ comp tasklet only if necessary
Currently, the mlx5_eq_comp_int() interrupt handler schedules a tasklet to call mlx5_cq_tasklet_cb() if it processes any completions. For CQs whose completions don't need to be processed in tasklet context, this adds unnecessary overhead. In a heavy TCP workload, we see 4% of CPU time spent on the tasklet_trylock() in tasklet_action_common(), with a smaller amount spent on the atomic operations in tasklet_schedule(), tasklet_clear_sched(), and locking the spinlock in mlx5_cq_tasklet_cb(). TCP completions are handled by mlx5e_completion_event(), which schedules NAPI to poll the queue, so they don't need tasklet processing. Schedule the tasklet in mlx5_add_cq_to_tasklet() instead to avoid this overhead. mlx5_add_cq_to_tasklet() is responsible for enqueuing the CQs to be processed in tasklet context, so it can schedule the tasklet. CQs that need tasklet processing have their interrupt comp handler set to mlx5_add_cq_to_tasklet(), so they will schedule the tasklet. CQs that don't need tasklet processing won't schedule the tasklet. To avoid scheduling the tasklet multiple times during the same interrupt, only schedule the tasklet in mlx5_add_cq_to_tasklet() if the tasklet work queue was empty before the new CQ was pushed to it. The additional branch in mlx5_add_cq_to_tasklet(), called for each EQE, may add a small cost for the userspace Infiniband CQs whose completions are processed in tasklet context. But this seems worth it to avoid the tasklet overhead for CQs that don't need it. Note that the mlx4 driver works the same way: it schedules the tasklet in mlx4_add_cq_to_tasklet() and only if the work queue was empty before. Signed-off-by: Caleb Sander Mateos <[email protected]> Reviewed-by: Parav Pandit <[email protected]> Acked-by: Tariq Toukan <[email protected]> Acked-by: Saeed Mahameed <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent e4e3fd0 commit 0ac2043

File tree

2 files changed

+12
-4
lines changed
  • drivers/net/ethernet/mellanox/mlx5/core

2 files changed

+12
-4
lines changed

drivers/net/ethernet/mellanox/mlx5/core/cq.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
7171
{
7272
unsigned long flags;
7373
struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
74+
bool schedule_tasklet = false;
7475

7576
spin_lock_irqsave(&tasklet_ctx->lock, flags);
7677
/* 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,
8081
*/
8182
if (list_empty_careful(&cq->tasklet_ctx.list)) {
8283
mlx5_cq_hold(cq);
84+
/* If the tasklet CQ work list isn't empty, mlx5_cq_tasklet_cb()
85+
* is scheduled/running and hasn't processed the list yet, so it
86+
* will see this added CQ when it runs. If the list is empty,
87+
* the tasklet needs to be scheduled to pick up the CQ. The
88+
* spinlock avoids any race with the tasklet accessing the list.
89+
*/
90+
schedule_tasklet = list_empty(&tasklet_ctx->list);
8391
list_add_tail(&cq->tasklet_ctx.list, &tasklet_ctx->list);
8492
}
8593
spin_unlock_irqrestore(&tasklet_ctx->lock, flags);
94+
95+
if (schedule_tasklet)
96+
tasklet_schedule(&tasklet_ctx->task);
8697
}
8798

8899
/* Callers must verify outbox status in case of err */

drivers/net/ethernet/mellanox/mlx5/core/eq.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ static int mlx5_eq_comp_int(struct notifier_block *nb,
114114
struct mlx5_eq *eq = &eq_comp->core;
115115
struct mlx5_eqe *eqe;
116116
int num_eqes = 0;
117-
u32 cqn = -1;
118117

119118
while ((eqe = next_eqe_sw(eq))) {
120119
struct mlx5_core_cq *cq;
120+
u32 cqn;
121121

122122
/* Make sure we read EQ entry contents after we've
123123
* checked the ownership bit.
@@ -144,9 +144,6 @@ static int mlx5_eq_comp_int(struct notifier_block *nb,
144144

145145
eq_update_ci(eq, 1);
146146

147-
if (cqn != -1)
148-
tasklet_schedule(&eq_comp->tasklet_ctx.task);
149-
150147
return 0;
151148
}
152149

0 commit comments

Comments
 (0)