diff options
author | Mika Kuoppala <mika.kuoppala@linux.intel.com> | 2013-12-10 10:02:43 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-12-12 09:27:21 -0500 |
commit | 47e9766df0298739aab87c9874a21feb71560953 (patch) | |
tree | d1ffa8dcd2c87573f61b340565483b67d914ed28 /drivers | |
parent | f9dcb0dfee98406c9c64e1aad10af427d644b78f (diff) |
drm/i915: Fix timeout with missed interrupts in __wait_seqno
Commit 094f9a54e355 ("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: Mika Kuoppala <mika.kuoppala@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 14 |
1 files changed, 6 insertions, 8 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index df83fec174e9..279387a2fef5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -1017,7 +1017,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, | |||
1017 | drm_i915_private_t *dev_priv = ring->dev->dev_private; | 1017 | drm_i915_private_t *dev_priv = ring->dev->dev_private; |
1018 | struct timespec before, now; | 1018 | struct timespec before, now; |
1019 | DEFINE_WAIT(wait); | 1019 | DEFINE_WAIT(wait); |
1020 | long timeout_jiffies; | 1020 | unsigned long timeout_expire; |
1021 | int ret; | 1021 | int ret; |
1022 | 1022 | ||
1023 | WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n"); | 1023 | 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 | if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) | 1025 | if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) |
1026 | return 0; | 1026 | return 0; |
1027 | 1027 | ||
1028 | timeout_jiffies = timeout ? timespec_to_jiffies_timeout(timeout) : 1; | 1028 | timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0; |
1029 | 1029 | ||
1030 | if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) { | 1030 | if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) { |
1031 | gen6_rps_boost(dev_priv); | 1031 | gen6_rps_boost(dev_priv); |
@@ -1044,7 +1044,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, | |||
1044 | getrawmonotonic(&before); | 1044 | getrawmonotonic(&before); |
1045 | for (;;) { | 1045 | for (;;) { |
1046 | struct timer_list timer; | 1046 | struct timer_list timer; |
1047 | unsigned long expire; | ||
1048 | 1047 | ||
1049 | prepare_to_wait(&ring->irq_queue, &wait, | 1048 | prepare_to_wait(&ring->irq_queue, &wait, |
1050 | interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); | 1049 | interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); |
@@ -1070,23 +1069,22 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, | |||
1070 | break; | 1069 | break; |
1071 | } | 1070 | } |
1072 | 1071 | ||
1073 | if (timeout_jiffies <= 0) { | 1072 | if (timeout && time_after_eq(jiffies, timeout_expire)) { |
1074 | ret = -ETIME; | 1073 | ret = -ETIME; |
1075 | break; | 1074 | break; |
1076 | } | 1075 | } |
1077 | 1076 | ||
1078 | timer.function = NULL; | 1077 | timer.function = NULL; |
1079 | if (timeout || missed_irq(dev_priv, ring)) { | 1078 | if (timeout || missed_irq(dev_priv, ring)) { |
1079 | unsigned long expire; | ||
1080 | |||
1080 | setup_timer_on_stack(&timer, fake_irq, (unsigned long)current); | 1081 | setup_timer_on_stack(&timer, fake_irq, (unsigned long)current); |
1081 | expire = jiffies + (missed_irq(dev_priv, ring) ? 1: timeout_jiffies); | 1082 | expire = missed_irq(dev_priv, ring) ? jiffies + 1 : timeout_expire; |
1082 | mod_timer(&timer, expire); | 1083 | mod_timer(&timer, expire); |
1083 | } | 1084 | } |
1084 | 1085 | ||
1085 | io_schedule(); | 1086 | io_schedule(); |
1086 | 1087 | ||
1087 | if (timeout) | ||
1088 | timeout_jiffies = expire - jiffies; | ||
1089 | |||
1090 | if (timer.function) { | 1088 | if (timer.function) { |
1091 | del_singleshot_timer_sync(&timer); | 1089 | del_singleshot_timer_sync(&timer); |
1092 | destroy_timer_on_stack(&timer); | 1090 | destroy_timer_on_stack(&timer); |