Commit 47e9766d authored by Mika Kuoppala's avatar Mika Kuoppala Committed by Daniel Vetter

drm/i915: Fix timeout with missed interrupts in __wait_seqno

Commit 094f9a54 ("drm/i915: Fix __wait_seqno to use true infinite
timeouts") added support for __wait_seqno to detect missing interrupts and
go around them by polling. As there is also timeout detection in
__wait_seqno, the polling and timeout detection were done with the same
timer.

When there has been missed interrupts and polling is needed, the timer is
set to trigger in (now + 1) jiffies in future, instead of the caller
specified timeout.

Now when io_schedule() returns, we calculate the jiffies left to timeout
using the timer expiration value. As the current jiffies is now bound to be
always equal or greater than the expiration value, the timeout_jiffies will
become zero or negative and we return -ETIME to caller even tho the
timeout was never reached.

Fix this by decoupling timeout calculation from timer expiration.

v2: Commit message with some sense in it (Chris Wilson)

v3: add parenthesis on timeout_expire calculation

v4: don't read jiffies without timeout (Chris Wilson)
Signed-off-by: default avatarMika Kuoppala <mika.kuoppala@intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent f9dcb0df
...@@ -1017,7 +1017,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, ...@@ -1017,7 +1017,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
drm_i915_private_t *dev_priv = ring->dev->dev_private; drm_i915_private_t *dev_priv = ring->dev->dev_private;
struct timespec before, now; struct timespec before, now;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
long timeout_jiffies; unsigned long timeout_expire;
int ret; int ret;
WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n"); WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n");
...@@ -1025,7 +1025,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, ...@@ -1025,7 +1025,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
return 0; return 0;
timeout_jiffies = timeout ? timespec_to_jiffies_timeout(timeout) : 1; timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0;
if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) { if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) {
gen6_rps_boost(dev_priv); gen6_rps_boost(dev_priv);
...@@ -1044,7 +1044,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, ...@@ -1044,7 +1044,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
getrawmonotonic(&before); getrawmonotonic(&before);
for (;;) { for (;;) {
struct timer_list timer; struct timer_list timer;
unsigned long expire;
prepare_to_wait(&ring->irq_queue, &wait, prepare_to_wait(&ring->irq_queue, &wait,
interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
...@@ -1070,23 +1069,22 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, ...@@ -1070,23 +1069,22 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
break; break;
} }
if (timeout_jiffies <= 0) { if (timeout && time_after_eq(jiffies, timeout_expire)) {
ret = -ETIME; ret = -ETIME;
break; break;
} }
timer.function = NULL; timer.function = NULL;
if (timeout || missed_irq(dev_priv, ring)) { if (timeout || missed_irq(dev_priv, ring)) {
unsigned long expire;
setup_timer_on_stack(&timer, fake_irq, (unsigned long)current); setup_timer_on_stack(&timer, fake_irq, (unsigned long)current);
expire = jiffies + (missed_irq(dev_priv, ring) ? 1: timeout_jiffies); expire = missed_irq(dev_priv, ring) ? jiffies + 1 : timeout_expire;
mod_timer(&timer, expire); mod_timer(&timer, expire);
} }
io_schedule(); io_schedule();
if (timeout)
timeout_jiffies = expire - jiffies;
if (timer.function) { if (timer.function) {
del_singleshot_timer_sync(&timer); del_singleshot_timer_sync(&timer);
destroy_timer_on_stack(&timer); destroy_timer_on_stack(&timer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment