Rather than continue to fix up the timeouts to work around the interface
impedence in wait_event_*(), open code the combination of
wait_event[_interruptible][_timeout]. And note the code size reduction,
and dare say readability?, in doing so..

v2: In order to satisfy the debug requirement of logging missed
interrupts with the real world requirments of making machines work even
if interrupts are hosed, we revert to polling after detecting a missed
interrupt.

Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_drv.h |   1 +
 drivers/gpu/drm/i915/i915_gem.c | 103 ++++++++++++++++++++++------------------
 drivers/gpu/drm/i915/i915_irq.c |   8 ++--
 3 files changed, 63 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 321159f..ad298f4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -658,6 +658,7 @@ enum intel_sbi_destination {
 #define QUIRK_LVDS_SSC_DISABLE (1<<1)
 #define QUIRK_INVERT_BRIGHTNESS (1<<2)
 #define QUIRK_NO_PCH_PWM_ENABLE (1<<3)
+#define QUIRK_MISSED_SEQNO_INTERRUPTS (1<<4)
 
 struct intel_fbdev;
 struct intel_fbc_work;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4f1ca12..b265def 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1067,6 +1067,11 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 
seqno)
        return ret;
 }
 
+static void fake_irq(unsigned long data)
+{
+       wake_up((wait_queue_head_t *)data);
+}
+
 /**
  * __wait_seqno - wait until execution of seqno has finished
  * @ring: the ring expected to report seqno
@@ -1090,10 +1095,9 @@ static int __wait_seqno(struct intel_ring_buffer *ring, 
u32 seqno,
                        bool interruptible, struct timespec *timeout)
 {
        drm_i915_private_t *dev_priv = ring->dev->dev_private;
-       struct timespec before, now, wait_time={1,0};
-       unsigned long timeout_jiffies;
-       long end;
-       bool wait_forever = true;
+       struct timespec before, now;
+       DEFINE_WAIT(wait);
+       long timeout_jiffies;
        int ret;
 
        WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n");
@@ -1101,51 +1105,68 @@ static int __wait_seqno(struct intel_ring_buffer *ring, 
u32 seqno,
        if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
                return 0;
 
-       trace_i915_gem_request_wait_begin(ring, seqno);
-
-       if (timeout != NULL) {
-               wait_time = *timeout;
-               wait_forever = false;
-       }
-
-       timeout_jiffies = timespec_to_jiffies_timeout(&wait_time);
+       timeout_jiffies = timeout ? timespec_to_jiffies_timeout(timeout) : 0;
 
        if (WARN_ON(!ring->irq_get(ring)))
                return -ENODEV;
 
-       /* Record current time in case interrupted by signal, or wedged * */
+       /* Record current time in case interrupted by signal, or wedged */
+       trace_i915_gem_request_wait_begin(ring, seqno);
        getrawmonotonic(&before);
+       for (;;) {
+               struct timer_list timer;
 
-#define EXIT_COND \
-       (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \
-        i915_reset_in_progress(&dev_priv->gpu_error) || \
-        reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter))
-       do {
-               if (interruptible)
-                       end = wait_event_interruptible_timeout(ring->irq_queue,
-                                                              EXIT_COND,
-                                                              timeout_jiffies);
-               else
-                       end = wait_event_timeout(ring->irq_queue, EXIT_COND,
-                                                timeout_jiffies);
+               prepare_to_wait(&ring->irq_queue, &wait,
+                               interruptible ? TASK_INTERRUPTIBLE : 
TASK_UNINTERRUPTIBLE);
 
                /* We need to check whether any gpu reset happened in between
                 * the caller grabbing the seqno and now ... */
-               if (reset_counter != 
atomic_read(&dev_priv->gpu_error.reset_counter))
-                       end = -EAGAIN;
+               if (reset_counter != 
atomic_read(&dev_priv->gpu_error.reset_counter)) {
+                       /* ... but upgrade the -EGAIN to an -EIO if the gpu
+                        * is truely gone. */
+                       ret = i915_gem_check_wedge(&dev_priv->gpu_error, 
interruptible);
+                       if (ret == 0)
+                               ret = -EAGAIN;
+                       break;
+               }
 
-               /* ... but upgrade the -EGAIN to an -EIO if the gpu is truely
-                * gone. */
-               ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible);
-               if (ret)
-                       end = ret;
-       } while (end == 0 && wait_forever);
+               if (i915_seqno_passed(ring->get_seqno(ring, false), seqno)) {
+                       ret = 0;
+                       break;
+               }
 
+               if (interruptible && signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               timer.function = NULL;
+               if (dev_priv->quirks & QUIRK_MISSED_SEQNO_INTERRUPTS) {
+                       setup_timer_on_stack(&timer, fake_irq, (unsigned 
long)&ring->irq_queue);
+                       mod_timer(&timer, round_jiffies_up_relative(HZ/100));
+               }
+
+               if (timeout) {
+                       if (timeout_jiffies == 0) {
+                               ret = -ETIME;
+                               break;
+                       }
+
+                       timeout_jiffies = schedule_timeout(timeout_jiffies);
+               } else
+                       schedule();
+
+               if (timer.function) {
+                       del_singleshot_timer_sync(&timer);
+                       destroy_timer_on_stack(&timer);
+               }
+       }
        getrawmonotonic(&now);
+       trace_i915_gem_request_wait_end(ring, seqno);
 
        ring->irq_put(ring);
-       trace_i915_gem_request_wait_end(ring, seqno);
-#undef EXIT_COND
+
+       finish_wait(&ring->irq_queue, &wait);
 
        if (timeout) {
                struct timespec sleep_time = timespec_sub(now, before);
@@ -1154,17 +1175,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, 
u32 seqno,
                        set_normalized_timespec(timeout, 0, 0);
        }
 
-       switch (end) {
-       case -EIO:
-       case -EAGAIN: /* Wedged */
-       case -ERESTARTSYS: /* Signal */
-               return (int)end;
-       case 0: /* Timeout */
-               return -ETIME;
-       default: /* Completed */
-               WARN_ON(end < 0); /* We're not aware of other errors */
-               return 0;
-       }
+       return ret;
 }
 
 /**
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b7532cb..fefb87a 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1992,10 +1992,12 @@ static void i915_hangcheck_elapsed(unsigned long data)
                        if (ring_idle(ring, seqno)) {
                                if (waitqueue_active(&ring->irq_queue)) {
                                        /* Issue a wake-up to catch stuck h/w. 
*/
-                                       DRM_ERROR("Hangcheck timer elapsed... 
%s idle\n",
-                                                 ring->name);
+                                       if ((dev_priv->quirks & 
QUIRK_MISSED_SEQNO_INTERRUPTS) == 0) {
+                                               DRM_ERROR("Hangcheck timer 
elapsed... %s idle\n",
+                                                         ring->name);
+                                               dev_priv->quirks |= 
QUIRK_MISSED_SEQNO_INTERRUPTS;
+                                       }
                                        wake_up_all(&ring->irq_queue);
-                                       ring->hangcheck.score += HUNG;
                                } else
                                        busy = false;
                        } else {
-- 
1.8.4.rc3

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to