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 <knut.omang@oracle.com>
Reviewed-by: Francisco Trivino-Garcia <francisco.trivino@oracle.com>
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;
} 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);
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();
ret = -ETIMEDOUT;
break;
}
- if (!in_interrupt()) /* TBD: Fix this as well */
+ if (!irqs_disabled())
cond_resched();
else
cpu_relax();