{
struct intel_breadcrumbs *b = READ_ONCE(rq->engine)->breadcrumbs;
struct intel_context *ce = rq->context;
+ unsigned long flags;
bool release;
if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags))
return;
- spin_lock(&ce->signal_lock);
+ spin_lock_irqsave(&ce->signal_lock, flags);
list_del_rcu(&rq->signal_link);
release = remove_signaling_context(b, ce);
- spin_unlock(&ce->signal_lock);
+ spin_unlock_irqrestore(&ce->signal_lock, flags);
if (release)
intel_context_put(ce);
static void kick_siblings(struct i915_request *rq, struct intel_context *ce)
{
struct virtual_engine *ve = container_of(ce, typeof(*ve), context);
+ struct intel_engine_cs *engine = rq->engine;
+
+ /* Flush concurrent rcu iterators in signal_irq_work */
+ if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &rq->fence.flags)) {
+ /*
+ * After this point, the rq may be transferred to a new
+ * sibling, so before we clear ce->inflight make sure that
+ * the context has been removed from the b->signalers and
+ * furthermore we need to make sure that the concurrent
+ * iterator in signal_irq_work is no longer following
+ * ce->signal_link.
+ */
+ i915_request_cancel_breadcrumb(rq);
+ irq_work_sync(&engine->breadcrumbs->irq_work);
+ }
if (READ_ONCE(ve->request))
tasklet_hi_schedule(&ve->base.execlists.tasklet);