From f022c32a8059afc20c22463c533bae0039ac697a Mon Sep 17 00:00:00 2001 From: Knut Omang Date: Fri, 22 Jul 2016 14:30:24 +0200 Subject: [PATCH] sif: pqp: Be less aggressive in invoking cond_resched() This commit attempts to avoid unnecessary or potentially dangerous calls to cond_resched() in the privileged QP completion polling code. Privileged QP requests typically takes a few microseconds to complete. Since we usually need the result of the operation to be able to continue, user code usually calls poll_cq_waitfor() to busy wait for the completion of the request. This commit adds two measures to make this logic better: 1) Avoid rescheduling while interrupts have been turned off: The driver was using the in_interrupt() test to avoid calling cond_resched() from interrupt context, and leaving the rest of the decision making of whether or not to reschedule to cond_resched(). Testing indicates that this could lead to deadlock prone calls to schedule(), as cond_resched() would actually allow rescheduling if interrupts have been disabled. Switch this logic to use irqs_disabled() instead, which will cover both the interrupt case and the cases where interrupts have been disabled by the caller. 2) Busywait for the completion for a few cycles before even trying to reschedule or cpu_relax. Measurements indicate that 10 tries are enough to cover a large fraction of cases on a lightly loaded system. Orabug: 23733539 Change-Id: Ief35e1828d4dde9b692640f259c3df80ccdb553b Signed-off-by: Knut Omang Reviewed-by: Francisco Trivino-Garcia --- drivers/infiniband/hw/sif/sif_pqp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/sif/sif_pqp.c b/drivers/infiniband/hw/sif/sif_pqp.c index fd22824e29af..6b9228d92bee 100644 --- a/drivers/infiniband/hw/sif/sif_pqp.c +++ b/drivers/infiniband/hw/sif/sif_pqp.c @@ -635,6 +635,7 @@ int poll_cq_waitfor(struct sif_cqe *lcqe) struct sif_cq *cq = pqp->cq; struct sif_dev *sdev = to_sdev(cq->ibcq.device); int ret = 0; + int waitcnt = 0; volatile bool *written = &lcqe->written; u64 min_resp_ticks = sdev->min_resp_ticks; @@ -651,6 +652,7 @@ int poll_cq_waitfor(struct sif_cqe *lcqe) } else if (ret < 0) break; else if (ret == 0) { + waitcnt++; if (time_is_before_jiffies(pqp->timeout)) { if (sif_feature(pcie_trigger)) force_pcie_link_retrain(sdev); @@ -666,7 +668,11 @@ int poll_cq_waitfor(struct sif_cqe *lcqe) ret = -ETIMEDOUT; break; } - if (!in_interrupt()) /* TBD: Fix this as well */ + + /* Allow some pure busy wait before we attempt to reschedule/relax */ + if (waitcnt < 10) + continue; + if (!irqs_disabled()) cond_resched(); else cpu_relax(); @@ -713,7 +719,7 @@ static int poll_cq_waitfor_any(struct sif_pqp *pqp, struct sif_cqe *first_err) ret = -ETIMEDOUT; break; } - if (!in_interrupt()) /* TBD: Fix this as well */ + if (!irqs_disabled()) cond_resched(); else cpu_relax(); -- 2.50.1