@@ -266,6 +266,7 @@ static int effective_prio(const struct i915_request *rq)
266266 prio |= I915_PRIORITY_NOSEMAPHORE ;
267267
268268 /* Restrict mere WAIT boosts from triggering preemption */
269+ BUILD_BUG_ON (__NO_PREEMPTION & ~I915_PRIORITY_MASK ); /* only internal */
269270 return prio | __NO_PREEMPTION ;
270271}
271272
@@ -830,6 +831,81 @@ last_active(const struct intel_engine_execlists *execlists)
830831 return * last ;
831832}
832833
834+ static void
835+ defer_request (struct i915_request * const rq , struct list_head * const pl )
836+ {
837+ struct i915_dependency * p ;
838+
839+ /*
840+ * We want to move the interrupted request to the back of
841+ * the round-robin list (i.e. its priority level), but
842+ * in doing so, we must then move all requests that were in
843+ * flight and were waiting for the interrupted request to
844+ * be run after it again.
845+ */
846+ list_move_tail (& rq -> sched .link , pl );
847+
848+ list_for_each_entry (p , & rq -> sched .waiters_list , wait_link ) {
849+ struct i915_request * w =
850+ container_of (p -> waiter , typeof (* w ), sched );
851+
852+ /* Leave semaphores spinning on the other engines */
853+ if (w -> engine != rq -> engine )
854+ continue ;
855+
856+ /* No waiter should start before the active request completed */
857+ GEM_BUG_ON (i915_request_started (w ));
858+
859+ GEM_BUG_ON (rq_prio (w ) > rq_prio (rq ));
860+ if (rq_prio (w ) < rq_prio (rq ))
861+ continue ;
862+
863+ if (list_empty (& w -> sched .link ))
864+ continue ; /* Not yet submitted; unready */
865+
866+ /*
867+ * This should be very shallow as it is limited by the
868+ * number of requests that can fit in a ring (<64) and
869+ * the number of contexts that can be in flight on this
870+ * engine.
871+ */
872+ defer_request (w , pl );
873+ }
874+ }
875+
876+ static void defer_active (struct intel_engine_cs * engine )
877+ {
878+ struct i915_request * rq ;
879+
880+ rq = __unwind_incomplete_requests (engine );
881+ if (!rq )
882+ return ;
883+
884+ defer_request (rq , i915_sched_lookup_priolist (engine , rq_prio (rq )));
885+ }
886+
887+ static bool
888+ need_timeslice (struct intel_engine_cs * engine , const struct i915_request * rq )
889+ {
890+ int hint ;
891+
892+ if (list_is_last (& rq -> sched .link , & engine -> active .requests ))
893+ return false;
894+
895+ hint = max (rq_prio (list_next_entry (rq , sched .link )),
896+ engine -> execlists .queue_priority_hint );
897+
898+ return hint >= rq_prio (rq );
899+ }
900+
901+ static bool
902+ enable_timeslice (struct intel_engine_cs * engine )
903+ {
904+ struct i915_request * last = last_active (& engine -> execlists );
905+
906+ return last && need_timeslice (engine , last );
907+ }
908+
833909static void execlists_dequeue (struct intel_engine_cs * engine )
834910{
835911 struct intel_engine_execlists * const execlists = & engine -> execlists ;
@@ -923,6 +999,32 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
923999 */
9241000 last -> hw_context -> lrc_desc |= CTX_DESC_FORCE_RESTORE ;
9251001 last = NULL ;
1002+ } else if (need_timeslice (engine , last ) &&
1003+ !timer_pending (& engine -> execlists .timer )) {
1004+ GEM_TRACE ("%s: expired last=%llx:%lld, prio=%d, hint=%d\n" ,
1005+ engine -> name ,
1006+ last -> fence .context ,
1007+ last -> fence .seqno ,
1008+ last -> sched .attr .priority ,
1009+ execlists -> queue_priority_hint );
1010+
1011+ ring_set_paused (engine , 1 );
1012+ defer_active (engine );
1013+
1014+ /*
1015+ * Unlike for preemption, if we rewind and continue
1016+ * executing the same context as previously active,
1017+ * the order of execution will remain the same and
1018+ * the tail will only advance. We do not need to
1019+ * force a full context restore, as a lite-restore
1020+ * is sufficient to resample the monotonic TAIL.
1021+ *
1022+ * If we switch to any other context, similarly we
1023+ * will not rewind TAIL of current context, and
1024+ * normal save/restore will preserve state and allow
1025+ * us to later continue executing the same request.
1026+ */
1027+ last = NULL ;
9261028 } else {
9271029 /*
9281030 * Otherwise if we already have a request pending
@@ -1247,6 +1349,9 @@ static void process_csb(struct intel_engine_cs *engine)
12471349 sizeof (* execlists -> pending ));
12481350 execlists -> pending [0 ] = NULL ;
12491351
1352+ if (enable_timeslice (engine ))
1353+ mod_timer (& execlists -> timer , jiffies + 1 );
1354+
12501355 if (!inject_preempt_hang (execlists ))
12511356 ring_set_paused (engine , 0 );
12521357 } else if (status & GEN8_CTX_STATUS_PREEMPTED ) {
@@ -1317,6 +1422,15 @@ static void execlists_submission_tasklet(unsigned long data)
13171422 spin_unlock_irqrestore (& engine -> active .lock , flags );
13181423}
13191424
1425+ static void execlists_submission_timer (struct timer_list * timer )
1426+ {
1427+ struct intel_engine_cs * engine =
1428+ from_timer (engine , timer , execlists .timer );
1429+
1430+ /* Kick the tasklet for some interrupt coalescing and reset handling */
1431+ tasklet_hi_schedule (& engine -> execlists .tasklet );
1432+ }
1433+
13201434static void queue_request (struct intel_engine_cs * engine ,
13211435 struct i915_sched_node * node ,
13221436 int prio )
@@ -2542,6 +2656,7 @@ static int gen8_init_rcs_context(struct i915_request *rq)
25422656
25432657static void execlists_park (struct intel_engine_cs * engine )
25442658{
2659+ del_timer_sync (& engine -> execlists .timer );
25452660 intel_engine_park (engine );
25462661}
25472662
@@ -2639,6 +2754,7 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine)
26392754
26402755 tasklet_init (& engine -> execlists .tasklet ,
26412756 execlists_submission_tasklet , (unsigned long )engine );
2757+ timer_setup (& engine -> execlists .timer , execlists_submission_timer , 0 );
26422758
26432759 logical_ring_default_vfuncs (engine );
26442760 logical_ring_default_irqs (engine );
0 commit comments