From a5cae7b8edefe01a77ad6288367026f65fbfb91d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 15 Mar 2017 21:07:24 +0000 Subject: 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 Cc: Mika Kuoppala Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/20170315210726.12095-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_breadcrumbs.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_breadcrumbs.c') 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); } -- cgit v1.2.3-59-g8ed1b