drm/i915: Spin until breadcrumb threads are complete
authorChris Wilson <chris@chris-wilson.co.uk>
Tue, 8 Nov 2016 14:37:19 +0000 (14:37 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Wed, 9 Nov 2016 15:01:52 +0000 (15:01 +0000)
When we need to reset the global seqno on wraparound, we have to wait
until the current rbtrees are drained (or otherwise the next waiter will
be out of sequence). The current mechanism to kick and spin until
complete, may exit too early as it would break if the target thread was
currently running. Instead, we must wake up the threads, but keep
spinning until the trees have been deleted.

In order to appease Tvrtko, busy spin rather than yield().

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161108143719.32215-1-chris@chris-wilson.co.uk
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
drivers/gpu/drm/i915/i915_gem_request.c
drivers/gpu/drm/i915/intel_breadcrumbs.c
drivers/gpu/drm/i915/intel_ringbuffer.h

index 0b3b051a5683397489ca5cc1241f301cc5963383..5050464c54018f1b196480a7291fb5af4c5cc9ae 100644 (file)
@@ -241,9 +241,8 @@ static int i915_gem_init_global_seqno(struct drm_i915_private *i915, u32 seqno)
 
        /* If the seqno wraps around, we need to clear the breadcrumb rbtree */
        if (!i915_seqno_passed(seqno, atomic_read(&timeline->next_seqno))) {
-               while (intel_kick_waiters(i915) || intel_kick_signalers(i915))
-                       yield();
-               yield();
+               while (intel_breadcrumbs_busy(i915))
+                       cond_resched(); /* spin until threads are complete */
        }
        atomic_set(&timeline->next_seqno, seqno);
 
index c410d3d6465f2b5c51d1e2007c333c3c18e9ce84..c9c46a538edb1cd33a3a9530cf3815bb1e8d03c2 100644 (file)
@@ -629,35 +629,28 @@ void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine)
        cancel_fake_irq(engine);
 }
 
-unsigned int intel_kick_waiters(struct drm_i915_private *i915)
+unsigned int intel_breadcrumbs_busy(struct drm_i915_private *i915)
 {
        struct intel_engine_cs *engine;
        enum intel_engine_id id;
        unsigned int mask = 0;
 
-       /* To avoid the task_struct disappearing beneath us as we wake up
-        * the process, we must first inspect the task_struct->state under the
-        * RCU lock, i.e. as we call wake_up_process() we must be holding the
-        * rcu_read_lock().
-        */
-       for_each_engine(engine, i915, id)
-               if (unlikely(intel_engine_wakeup(engine)))
-                       mask |= intel_engine_flag(engine);
+       for_each_engine(engine, i915, id) {
+               struct intel_breadcrumbs *b = &engine->breadcrumbs;
 
-       return mask;
-}
+               spin_lock_irq(&b->lock);
 
-unsigned int intel_kick_signalers(struct drm_i915_private *i915)
-{
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
-       unsigned int mask = 0;
+               if (b->first_wait) {
+                       wake_up_process(b->first_wait->tsk);
+                       mask |= intel_engine_flag(engine);
+               }
 
-       for_each_engine(engine, i915, id) {
-               if (unlikely(READ_ONCE(engine->breadcrumbs.first_signal))) {
-                       wake_up_process(engine->breadcrumbs.signaler);
+               if (b->first_signal) {
+                       wake_up_process(b->signaler);
                        mask |= intel_engine_flag(engine);
                }
+
+               spin_unlock_irq(&b->lock);
        }
 
        return mask;
index 642b54692d0d9697b3c8c8117dc96f84ac18a957..d1a728791ad47e53db778284838512cca8a99c63 100644 (file)
@@ -578,7 +578,6 @@ static inline bool intel_engine_wakeup(const struct intel_engine_cs *engine)
 
 void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine);
 void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
-unsigned int intel_kick_waiters(struct drm_i915_private *i915);
-unsigned int intel_kick_signalers(struct drm_i915_private *i915);
+unsigned int intel_breadcrumbs_busy(struct drm_i915_private *i915);
 
 #endif /* _INTEL_RINGBUFFER_H_ */