Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/i915: Spin until breadcrumb threads are complete

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>

+17 -26
+2 -3
drivers/gpu/drm/i915/i915_gem_request.c
··· 241 241 242 242 /* If the seqno wraps around, we need to clear the breadcrumb rbtree */ 243 243 if (!i915_seqno_passed(seqno, atomic_read(&timeline->next_seqno))) { 244 - while (intel_kick_waiters(i915) || intel_kick_signalers(i915)) 245 - yield(); 246 - yield(); 244 + while (intel_breadcrumbs_busy(i915)) 245 + cond_resched(); /* spin until threads are complete */ 247 246 } 248 247 atomic_set(&timeline->next_seqno, seqno); 249 248
+14 -21
drivers/gpu/drm/i915/intel_breadcrumbs.c
··· 629 629 cancel_fake_irq(engine); 630 630 } 631 631 632 - unsigned int intel_kick_waiters(struct drm_i915_private *i915) 633 - { 634 - struct intel_engine_cs *engine; 635 - enum intel_engine_id id; 636 - unsigned int mask = 0; 637 - 638 - /* To avoid the task_struct disappearing beneath us as we wake up 639 - * the process, we must first inspect the task_struct->state under the 640 - * RCU lock, i.e. as we call wake_up_process() we must be holding the 641 - * rcu_read_lock(). 642 - */ 643 - for_each_engine(engine, i915, id) 644 - if (unlikely(intel_engine_wakeup(engine))) 645 - mask |= intel_engine_flag(engine); 646 - 647 - return mask; 648 - } 649 - 650 - unsigned int intel_kick_signalers(struct drm_i915_private *i915) 632 + unsigned int intel_breadcrumbs_busy(struct drm_i915_private *i915) 651 633 { 652 634 struct intel_engine_cs *engine; 653 635 enum intel_engine_id id; 654 636 unsigned int mask = 0; 655 637 656 638 for_each_engine(engine, i915, id) { 657 - if (unlikely(READ_ONCE(engine->breadcrumbs.first_signal))) { 658 - wake_up_process(engine->breadcrumbs.signaler); 639 + struct intel_breadcrumbs *b = &engine->breadcrumbs; 640 + 641 + spin_lock_irq(&b->lock); 642 + 643 + if (b->first_wait) { 644 + wake_up_process(b->first_wait->tsk); 659 645 mask |= intel_engine_flag(engine); 660 646 } 647 + 648 + if (b->first_signal) { 649 + wake_up_process(b->signaler); 650 + mask |= intel_engine_flag(engine); 651 + } 652 + 653 + spin_unlock_irq(&b->lock); 661 654 } 662 655 663 656 return mask;
+1 -2
drivers/gpu/drm/i915/intel_ringbuffer.h
··· 578 578 579 579 void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine); 580 580 void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine); 581 - unsigned int intel_kick_waiters(struct drm_i915_private *i915); 582 - unsigned int intel_kick_signalers(struct drm_i915_private *i915); 581 + unsigned int intel_breadcrumbs_busy(struct drm_i915_private *i915); 583 582 584 583 #endif /* _INTEL_RINGBUFFER_H_ */