Commit cced5e2f authored by Chris Wilson's avatar Chris Wilson

drm/i915: Take a reference whilst processing the signaler request

The plan in the near-future is to allow requests to be removed from the
signaler. We can no longer then rely on holding a reference to the
request for the duration it is in the signaling tree, and instead must
obtain a reference to the request for the current operation using RCU.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170223074422.4125-10-chris@chris-wilson.co.uk
parent 754c9fd5
...@@ -496,7 +496,11 @@ static int intel_breadcrumbs_signaler(void *arg) ...@@ -496,7 +496,11 @@ static int intel_breadcrumbs_signaler(void *arg)
* need to wait for a new interrupt from the GPU or for * need to wait for a new interrupt from the GPU or for
* a new client. * a new client.
*/ */
request = READ_ONCE(b->first_signal); rcu_read_lock();
request = rcu_dereference(b->first_signal);
if (request)
request = i915_gem_request_get_rcu(request);
rcu_read_unlock();
if (signal_complete(request)) { if (signal_complete(request)) {
local_bh_disable(); local_bh_disable();
dma_fence_signal(&request->fence); dma_fence_signal(&request->fence);
...@@ -515,24 +519,28 @@ static int intel_breadcrumbs_signaler(void *arg) ...@@ -515,24 +519,28 @@ static int intel_breadcrumbs_signaler(void *arg)
* the oldest before picking the next one. * the oldest before picking the next one.
*/ */
spin_lock_irq(&b->lock); spin_lock_irq(&b->lock);
if (request == b->first_signal) { if (request == rcu_access_pointer(b->first_signal)) {
struct rb_node *rb = struct rb_node *rb =
rb_next(&request->signaling.node); rb_next(&request->signaling.node);
b->first_signal = rb ? to_signaler(rb) : NULL; rcu_assign_pointer(b->first_signal,
rb ? to_signaler(rb) : NULL);
} }
rb_erase(&request->signaling.node, &b->signals); rb_erase(&request->signaling.node, &b->signals);
spin_unlock_irq(&b->lock); spin_unlock_irq(&b->lock);
i915_gem_request_put(request); i915_gem_request_put(request);
} else { } else {
if (kthread_should_stop()) if (kthread_should_stop()) {
GEM_BUG_ON(request);
break; break;
}
schedule(); schedule();
if (kthread_should_park()) if (kthread_should_park())
kthread_parkme(); kthread_parkme();
} }
i915_gem_request_put(request);
} while (1); } while (1);
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
...@@ -597,7 +605,7 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request) ...@@ -597,7 +605,7 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request)
rb_link_node(&request->signaling.node, parent, p); rb_link_node(&request->signaling.node, parent, p);
rb_insert_color(&request->signaling.node, &b->signals); rb_insert_color(&request->signaling.node, &b->signals);
if (first) if (first)
smp_store_mb(b->first_signal, request); rcu_assign_pointer(b->first_signal, request);
spin_unlock(&b->lock); spin_unlock(&b->lock);
...@@ -670,7 +678,7 @@ void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine) ...@@ -670,7 +678,7 @@ void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine)
/* The engines should be idle and all requests accounted for! */ /* The engines should be idle and all requests accounted for! */
WARN_ON(READ_ONCE(b->first_wait)); WARN_ON(READ_ONCE(b->first_wait));
WARN_ON(!RB_EMPTY_ROOT(&b->waiters)); WARN_ON(!RB_EMPTY_ROOT(&b->waiters));
WARN_ON(READ_ONCE(b->first_signal)); WARN_ON(rcu_access_pointer(b->first_signal));
WARN_ON(!RB_EMPTY_ROOT(&b->signals)); WARN_ON(!RB_EMPTY_ROOT(&b->signals));
if (!IS_ERR_OR_NULL(b->signaler)) if (!IS_ERR_OR_NULL(b->signaler))
...@@ -691,7 +699,7 @@ bool intel_breadcrumbs_busy(struct intel_engine_cs *engine) ...@@ -691,7 +699,7 @@ bool intel_breadcrumbs_busy(struct intel_engine_cs *engine)
busy |= intel_engine_flag(engine); busy |= intel_engine_flag(engine);
} }
if (b->first_signal) { if (rcu_access_pointer(b->first_signal)) {
wake_up_process(b->signaler); wake_up_process(b->signaler);
busy |= intel_engine_flag(engine); busy |= intel_engine_flag(engine);
} }
......
...@@ -242,7 +242,7 @@ struct intel_engine_cs { ...@@ -242,7 +242,7 @@ struct intel_engine_cs {
struct rb_root signals; /* sorted by retirement */ struct rb_root signals; /* sorted by retirement */
struct intel_wait *first_wait; /* oldest waiter by retirement */ struct intel_wait *first_wait; /* oldest waiter by retirement */
struct task_struct *signaler; /* used for fence signalling */ struct task_struct *signaler; /* used for fence signalling */
struct drm_i915_gem_request *first_signal; struct drm_i915_gem_request __rcu *first_signal;
struct timer_list fake_irq; /* used after a missed interrupt */ struct timer_list fake_irq; /* used after a missed interrupt */
struct timer_list hangcheck; /* detect missed interrupts */ struct timer_list hangcheck; /* detect missed interrupts */
......
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