@@ -101,18 +101,37 @@ static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
101101 intel_gt_pm_put_async (b -> irq_engine -> gt );
102102}
103103
104+ static void intel_breadcrumbs_disarm_irq (struct intel_breadcrumbs * b )
105+ {
106+ spin_lock (& b -> irq_lock );
107+ if (b -> irq_armed )
108+ __intel_breadcrumbs_disarm_irq (b );
109+ spin_unlock (& b -> irq_lock );
110+ }
111+
104112static void add_signaling_context (struct intel_breadcrumbs * b ,
105113 struct intel_context * ce )
106114{
107- intel_context_get (ce );
108- list_add_tail (& ce -> signal_link , & b -> signalers );
115+ lockdep_assert_held (& ce -> signal_lock );
116+
117+ spin_lock (& b -> signalers_lock );
118+ list_add_rcu (& ce -> signal_link , & b -> signalers );
119+ spin_unlock (& b -> signalers_lock );
109120}
110121
111- static void remove_signaling_context (struct intel_breadcrumbs * b ,
122+ static bool remove_signaling_context (struct intel_breadcrumbs * b ,
112123 struct intel_context * ce )
113124{
114- list_del (& ce -> signal_link );
115- intel_context_put (ce );
125+ lockdep_assert_held (& ce -> signal_lock );
126+
127+ if (!list_empty (& ce -> signals ))
128+ return false;
129+
130+ spin_lock (& b -> signalers_lock );
131+ list_del_rcu (& ce -> signal_link );
132+ spin_unlock (& b -> signalers_lock );
133+
134+ return true;
116135}
117136
118137static inline bool __request_completed (const struct i915_request * rq )
@@ -175,6 +194,8 @@ static void add_retire(struct intel_breadcrumbs *b, struct intel_timeline *tl)
175194
176195static bool __signal_request (struct i915_request * rq )
177196{
197+ GEM_BUG_ON (test_bit (I915_FENCE_FLAG_SIGNAL , & rq -> fence .flags ));
198+
178199 if (!__dma_fence_signal (& rq -> fence )) {
179200 i915_request_put (rq );
180201 return false;
@@ -195,15 +216,12 @@ static void signal_irq_work(struct irq_work *work)
195216 struct intel_breadcrumbs * b = container_of (work , typeof (* b ), irq_work );
196217 const ktime_t timestamp = ktime_get ();
197218 struct llist_node * signal , * sn ;
198- struct intel_context * ce , * cn ;
199- struct list_head * pos , * next ;
219+ struct intel_context * ce ;
200220
201221 signal = NULL ;
202222 if (unlikely (!llist_empty (& b -> signaled_requests )))
203223 signal = llist_del_all (& b -> signaled_requests );
204224
205- spin_lock (& b -> irq_lock );
206-
207225 /*
208226 * Keep the irq armed until the interrupt after all listeners are gone.
209227 *
@@ -229,47 +247,44 @@ static void signal_irq_work(struct irq_work *work)
229247 * interrupt draw less ire from other users of the system and tools
230248 * like powertop.
231249 */
232- if (!signal && b -> irq_armed && list_empty (& b -> signalers ))
233- __intel_breadcrumbs_disarm_irq (b );
250+ if (!signal && READ_ONCE ( b -> irq_armed ) && list_empty (& b -> signalers ))
251+ intel_breadcrumbs_disarm_irq (b );
234252
235- list_for_each_entry_safe (ce , cn , & b -> signalers , signal_link ) {
236- GEM_BUG_ON (list_empty (& ce -> signals ));
253+ rcu_read_lock ();
254+ list_for_each_entry_rcu (ce , & b -> signalers , signal_link ) {
255+ struct i915_request * rq ;
237256
238- list_for_each_safe (pos , next , & ce -> signals ) {
239- struct i915_request * rq =
240- list_entry (pos , typeof (* rq ), signal_link );
257+ list_for_each_entry_rcu (rq , & ce -> signals , signal_link ) {
258+ bool release ;
241259
242- GEM_BUG_ON (!check_signal_order (ce , rq ));
243260 if (!__request_completed (rq ))
244261 break ;
245262
263+ if (!test_and_clear_bit (I915_FENCE_FLAG_SIGNAL ,
264+ & rq -> fence .flags ))
265+ break ;
266+
246267 /*
247268 * Queue for execution after dropping the signaling
248269 * spinlock as the callback chain may end up adding
249270 * more signalers to the same context or engine.
250271 */
251- clear_bit (I915_FENCE_FLAG_SIGNAL , & rq -> fence .flags );
272+ spin_lock (& ce -> signal_lock );
273+ list_del_rcu (& rq -> signal_link );
274+ release = remove_signaling_context (b , ce );
275+ spin_unlock (& ce -> signal_lock );
276+
252277 if (__signal_request (rq ))
253278 /* We own signal_node now, xfer to local list */
254279 signal = slist_add (& rq -> signal_node , signal );
255- }
256280
257- /*
258- * We process the list deletion in bulk, only using a list_add
259- * (not list_move) above but keeping the status of
260- * rq->signal_link known with the I915_FENCE_FLAG_SIGNAL bit.
261- */
262- if (!list_is_first (pos , & ce -> signals )) {
263- /* Advance the list to the first incomplete request */
264- __list_del_many (& ce -> signals , pos );
265- if (& ce -> signals == pos ) { /* now empty */
281+ if (release ) {
266282 add_retire (b , ce -> timeline );
267- remove_signaling_context ( b , ce );
283+ intel_context_put ( ce );
268284 }
269285 }
270286 }
271-
272- spin_unlock (& b -> irq_lock );
287+ rcu_read_unlock ();
273288
274289 llist_for_each_safe (signal , sn , signal ) {
275290 struct i915_request * rq =
@@ -298,14 +313,15 @@ intel_breadcrumbs_create(struct intel_engine_cs *irq_engine)
298313 if (!b )
299314 return NULL ;
300315
301- spin_lock_init (& b -> irq_lock );
316+ b -> irq_engine = irq_engine ;
317+
318+ spin_lock_init (& b -> signalers_lock );
302319 INIT_LIST_HEAD (& b -> signalers );
303320 init_llist_head (& b -> signaled_requests );
304321
322+ spin_lock_init (& b -> irq_lock );
305323 init_irq_work (& b -> irq_work , signal_irq_work );
306324
307- b -> irq_engine = irq_engine ;
308-
309325 return b ;
310326}
311327
@@ -347,9 +363,9 @@ void intel_breadcrumbs_free(struct intel_breadcrumbs *b)
347363 kfree (b );
348364}
349365
350- static void insert_breadcrumb (struct i915_request * rq ,
351- struct intel_breadcrumbs * b )
366+ static void insert_breadcrumb (struct i915_request * rq )
352367{
368+ struct intel_breadcrumbs * b = READ_ONCE (rq -> engine )-> breadcrumbs ;
353369 struct intel_context * ce = rq -> context ;
354370 struct list_head * pos ;
355371
@@ -371,6 +387,7 @@ static void insert_breadcrumb(struct i915_request *rq,
371387 }
372388
373389 if (list_empty (& ce -> signals )) {
390+ intel_context_get (ce );
374391 add_signaling_context (b , ce );
375392 pos = & ce -> signals ;
376393 } else {
@@ -396,8 +413,9 @@ static void insert_breadcrumb(struct i915_request *rq,
396413 break ;
397414 }
398415 }
399- list_add (& rq -> signal_link , pos );
416+ list_add_rcu (& rq -> signal_link , pos );
400417 GEM_BUG_ON (!check_signal_order (ce , rq ));
418+ GEM_BUG_ON (test_bit (DMA_FENCE_FLAG_SIGNALED_BIT , & rq -> fence .flags ));
401419 set_bit (I915_FENCE_FLAG_SIGNAL , & rq -> fence .flags );
402420
403421 /*
@@ -410,7 +428,7 @@ static void insert_breadcrumb(struct i915_request *rq,
410428
411429bool i915_request_enable_breadcrumb (struct i915_request * rq )
412430{
413- struct intel_breadcrumbs * b ;
431+ struct intel_context * ce = rq -> context ;
414432
415433 /* Serialises with i915_request_retire() using rq->lock */
416434 if (test_bit (DMA_FENCE_FLAG_SIGNALED_BIT , & rq -> fence .flags ))
@@ -425,67 +443,30 @@ bool i915_request_enable_breadcrumb(struct i915_request *rq)
425443 if (!test_bit (I915_FENCE_FLAG_ACTIVE , & rq -> fence .flags ))
426444 return true;
427445
428- /*
429- * rq->engine is locked by rq->engine->active.lock. That however
430- * is not known until after rq->engine has been dereferenced and
431- * the lock acquired. Hence we acquire the lock and then validate
432- * that rq->engine still matches the lock we hold for it.
433- *
434- * Here, we are using the breadcrumb lock as a proxy for the
435- * rq->engine->active.lock, and we know that since the breadcrumb
436- * will be serialised within i915_request_submit/i915_request_unsubmit,
437- * the engine cannot change while active as long as we hold the
438- * breadcrumb lock on that engine.
439- *
440- * From the dma_fence_enable_signaling() path, we are outside of the
441- * request submit/unsubmit path, and so we must be more careful to
442- * acquire the right lock.
443- */
444- b = READ_ONCE (rq -> engine )-> breadcrumbs ;
445- spin_lock (& b -> irq_lock );
446- while (unlikely (b != READ_ONCE (rq -> engine )-> breadcrumbs )) {
447- spin_unlock (& b -> irq_lock );
448- b = READ_ONCE (rq -> engine )-> breadcrumbs ;
449- spin_lock (& b -> irq_lock );
450- }
451-
452- /*
453- * Now that we are finally serialised with request submit/unsubmit,
454- * [with b->irq_lock] and with i915_request_retire() [via checking
455- * SIGNALED with rq->lock] confirm the request is indeed active. If
456- * it is no longer active, the breadcrumb will be attached upon
457- * i915_request_submit().
458- */
446+ spin_lock (& ce -> signal_lock );
459447 if (test_bit (I915_FENCE_FLAG_ACTIVE , & rq -> fence .flags ))
460- insert_breadcrumb (rq , b );
461-
462- spin_unlock (& b -> irq_lock );
448+ insert_breadcrumb (rq );
449+ spin_unlock (& ce -> signal_lock );
463450
464451 return true;
465452}
466453
467454void i915_request_cancel_breadcrumb (struct i915_request * rq )
468455{
469- struct intel_breadcrumbs * b = rq -> engine -> breadcrumbs ;
456+ struct intel_context * ce = rq -> context ;
457+ bool release ;
470458
471- /*
472- * We must wait for b->irq_lock so that we know the interrupt handler
473- * has released its reference to the intel_context and has completed
474- * the DMA_FENCE_FLAG_SIGNALED_BIT/I915_FENCE_FLAG_SIGNAL dance (if
475- * required).
476- */
477- spin_lock (& b -> irq_lock );
478- if (test_bit (I915_FENCE_FLAG_SIGNAL , & rq -> fence .flags )) {
479- struct intel_context * ce = rq -> context ;
459+ if (!test_and_clear_bit (I915_FENCE_FLAG_SIGNAL , & rq -> fence .flags ))
460+ return ;
480461
481- list_del (& rq -> signal_link );
482- if (list_empty (& ce -> signals ))
483- remove_signaling_context (b , ce );
462+ spin_lock (& ce -> signal_lock );
463+ list_del_rcu (& rq -> signal_link );
464+ release = remove_signaling_context (rq -> engine -> breadcrumbs , ce );
465+ spin_unlock (& ce -> signal_lock );
466+ if (release )
467+ intel_context_put (ce );
484468
485- clear_bit (I915_FENCE_FLAG_SIGNAL , & rq -> fence .flags );
486- i915_request_put (rq );
487- }
488- spin_unlock (& b -> irq_lock );
469+ i915_request_put (rq );
489470}
490471
491472static void print_signals (struct intel_breadcrumbs * b , struct drm_printer * p )
@@ -495,18 +476,17 @@ static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
495476
496477 drm_printf (p , "Signals:\n" );
497478
498- spin_lock_irq ( & b -> irq_lock );
499- list_for_each_entry (ce , & b -> signalers , signal_link ) {
500- list_for_each_entry (rq , & ce -> signals , signal_link ) {
479+ rcu_read_lock ( );
480+ list_for_each_entry_rcu (ce , & b -> signalers , signal_link ) {
481+ list_for_each_entry_rcu (rq , & ce -> signals , signal_link )
501482 drm_printf (p , "\t[%llx:%llx%s] @ %dms\n" ,
502483 rq -> fence .context , rq -> fence .seqno ,
503484 i915_request_completed (rq ) ? "!" :
504485 i915_request_started (rq ) ? "*" :
505486 "" ,
506487 jiffies_to_msecs (jiffies - rq -> emitted_jiffies ));
507- }
508488 }
509- spin_unlock_irq ( & b -> irq_lock );
489+ rcu_read_unlock ( );
510490}
511491
512492void intel_engine_print_breadcrumbs (struct intel_engine_cs * engine ,
0 commit comments