summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2017-03-15 22:07:24 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2017-03-15 22:45:39 +0100
commita5cae7b8edefe01a77ad6288367026f65fbfb91d (patch)
tree4daffd2336e19a936cc25c248dc446d2458b8f7f
parentdrm/i915/breadcrumbs: Update bottom-half before marking as complete (diff)
downloadlinux-a5cae7b8edefe01a77ad6288367026f65fbfb91d.tar.xz
linux-a5cae7b8edefe01a77ad6288367026f65fbfb91d.zip
drm/i915/breadcrumbs: Disable interrupt bottom-half first on idling
Before walking the rbtree of waiters (marking them as complete and waking them), decouple the interrupt handler. This prevents a race between the missed waiter waking up and removing its intel_wait (which skips checking the lock) and the interrupt handler dereferencing the intel_wait. (Though we do not expect to encounter waiters during idle!) Fixes: e1c0c91bdaec ("drm/i915: Wake up all waiters before idling") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/20170315210726.12095-3-chris@chris-wilson.co.uk
-rw-r--r--drivers/gpu/drm/i915/intel_breadcrumbs.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c
index 438f874a2068..e2dbd919d82f 100644
--- a/drivers/gpu/drm/i915/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c
@@ -179,7 +179,7 @@ void __intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
{
struct intel_breadcrumbs *b = &engine->breadcrumbs;
- struct intel_wait *wait, *n;
+ struct intel_wait *wait, *n, *first;
if (!b->irq_armed)
return;
@@ -190,18 +190,19 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
*/
spin_lock_irq(&b->rb_lock);
+
+ spin_lock(&b->irq_lock);
+ first = fetch_and_zero(&b->irq_wait);
+ __intel_engine_disarm_breadcrumbs(engine);
+ spin_unlock(&b->irq_lock);
+
rbtree_postorder_for_each_entry_safe(wait, n, &b->waiters, node) {
RB_CLEAR_NODE(&wait->node);
- if (wake_up_process(wait->tsk) && wait == b->irq_wait)
+ if (wake_up_process(wait->tsk) && wait == first)
missed_breadcrumb(engine);
}
b->waiters = RB_ROOT;
- spin_lock(&b->irq_lock);
- b->irq_wait = NULL;
- __intel_engine_disarm_breadcrumbs(engine);
- spin_unlock(&b->irq_lock);
-
spin_unlock_irq(&b->rb_lock);
}