@@ -266,6 +266,7 @@ static int effective_prio(const struct i915_request *rq)
266
266
prio |= I915_PRIORITY_NOSEMAPHORE ;
267
267
268
268
/* Restrict mere WAIT boosts from triggering preemption */
269
+ BUILD_BUG_ON (__NO_PREEMPTION & ~I915_PRIORITY_MASK ); /* only internal */
269
270
return prio | __NO_PREEMPTION ;
270
271
}
271
272
@@ -830,6 +831,81 @@ last_active(const struct intel_engine_execlists *execlists)
830
831
return * last ;
831
832
}
832
833
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
+
833
909
static void execlists_dequeue (struct intel_engine_cs * engine )
834
910
{
835
911
struct intel_engine_execlists * const execlists = & engine -> execlists ;
@@ -923,6 +999,32 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
923
999
*/
924
1000
last -> hw_context -> lrc_desc |= CTX_DESC_FORCE_RESTORE ;
925
1001
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 ;
926
1028
} else {
927
1029
/*
928
1030
* Otherwise if we already have a request pending
@@ -1247,6 +1349,9 @@ static void process_csb(struct intel_engine_cs *engine)
1247
1349
sizeof (* execlists -> pending ));
1248
1350
execlists -> pending [0 ] = NULL ;
1249
1351
1352
+ if (enable_timeslice (engine ))
1353
+ mod_timer (& execlists -> timer , jiffies + 1 );
1354
+
1250
1355
if (!inject_preempt_hang (execlists ))
1251
1356
ring_set_paused (engine , 0 );
1252
1357
} else if (status & GEN8_CTX_STATUS_PREEMPTED ) {
@@ -1317,6 +1422,15 @@ static void execlists_submission_tasklet(unsigned long data)
1317
1422
spin_unlock_irqrestore (& engine -> active .lock , flags );
1318
1423
}
1319
1424
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
+
1320
1434
static void queue_request (struct intel_engine_cs * engine ,
1321
1435
struct i915_sched_node * node ,
1322
1436
int prio )
@@ -2542,6 +2656,7 @@ static int gen8_init_rcs_context(struct i915_request *rq)
2542
2656
2543
2657
static void execlists_park (struct intel_engine_cs * engine )
2544
2658
{
2659
+ del_timer_sync (& engine -> execlists .timer );
2545
2660
intel_engine_park (engine );
2546
2661
}
2547
2662
@@ -2639,6 +2754,7 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine)
2639
2754
2640
2755
tasklet_init (& engine -> execlists .tasklet ,
2641
2756
execlists_submission_tasklet , (unsigned long )engine );
2757
+ timer_setup (& engine -> execlists .timer , execlists_submission_timer , 0 );
2642
2758
2643
2759
logical_ring_default_vfuncs (engine );
2644
2760
logical_ring_default_irqs (engine );
0 commit comments