@@ -234,6 +234,9 @@ static void execlists_init_reg_state(u32 *reg_state,
234234 const struct intel_engine_cs * engine ,
235235 const struct intel_ring * ring ,
236236 bool close );
237+ static void
238+ __execlists_update_reg_state (const struct intel_context * ce ,
239+ const struct intel_engine_cs * engine );
237240
238241static void mark_eio (struct i915_request * rq )
239242{
@@ -246,6 +249,31 @@ static void mark_eio(struct i915_request *rq)
246249 i915_request_mark_complete (rq );
247250}
248251
252+ static struct i915_request * active_request (struct i915_request * rq )
253+ {
254+ const struct intel_context * const ce = rq -> hw_context ;
255+ struct i915_request * active = NULL ;
256+ struct list_head * list ;
257+
258+ if (!i915_request_is_active (rq )) /* unwound, but incomplete! */
259+ return rq ;
260+
261+ rcu_read_lock ();
262+ list = & rcu_dereference (rq -> timeline )-> requests ;
263+ list_for_each_entry_from_reverse (rq , list , link ) {
264+ if (i915_request_completed (rq ))
265+ break ;
266+
267+ if (rq -> hw_context != ce )
268+ break ;
269+
270+ active = rq ;
271+ }
272+ rcu_read_unlock ();
273+
274+ return active ;
275+ }
276+
249277static inline u32 intel_hws_preempt_address (struct intel_engine_cs * engine )
250278{
251279 return (i915_ggtt_offset (engine -> status_page .vma ) +
@@ -972,6 +1000,58 @@ static void kick_siblings(struct i915_request *rq, struct intel_context *ce)
9721000 tasklet_schedule (& ve -> base .execlists .tasklet );
9731001}
9741002
1003+ static void restore_default_state (struct intel_context * ce ,
1004+ struct intel_engine_cs * engine )
1005+ {
1006+ u32 * regs = ce -> lrc_reg_state ;
1007+
1008+ if (engine -> pinned_default_state )
1009+ memcpy (regs , /* skip restoring the vanilla PPHWSP */
1010+ engine -> pinned_default_state + LRC_STATE_PN * PAGE_SIZE ,
1011+ engine -> context_size - PAGE_SIZE );
1012+
1013+ execlists_init_reg_state (regs , ce , engine , ce -> ring , false);
1014+ }
1015+
1016+ static void reset_active (struct i915_request * rq ,
1017+ struct intel_engine_cs * engine )
1018+ {
1019+ struct intel_context * const ce = rq -> hw_context ;
1020+
1021+ /*
1022+ * The executing context has been cancelled. We want to prevent
1023+ * further execution along this context and propagate the error on
1024+ * to anything depending on its results.
1025+ *
1026+ * In __i915_request_submit(), we apply the -EIO and remove the
1027+ * requests' payloads for any banned requests. But first, we must
1028+ * rewind the context back to the start of the incomplete request so
1029+ * that we do not jump back into the middle of the batch.
1030+ *
1031+ * We preserve the breadcrumbs and semaphores of the incomplete
1032+ * requests so that inter-timeline dependencies (i.e other timelines)
1033+ * remain correctly ordered. And we defer to __i915_request_submit()
1034+ * so that all asynchronous waits are correctly handled.
1035+ */
1036+ GEM_TRACE ("%s(%s): { rq=%llx:%lld }\n" ,
1037+ __func__ , engine -> name , rq -> fence .context , rq -> fence .seqno );
1038+
1039+ /* On resubmission of the active request, payload will be scrubbed */
1040+ rq = active_request (rq );
1041+ if (rq )
1042+ ce -> ring -> head = intel_ring_wrap (ce -> ring , rq -> head );
1043+ else
1044+ ce -> ring -> head = ce -> ring -> tail ;
1045+ intel_ring_update_space (ce -> ring );
1046+
1047+ /* Scrub the context image to prevent replaying the previous batch */
1048+ restore_default_state (ce , engine );
1049+ __execlists_update_reg_state (ce , engine );
1050+
1051+ /* We've switched away, so this should be a no-op, but intent matters */
1052+ ce -> lrc_desc |= CTX_DESC_FORCE_RESTORE ;
1053+ }
1054+
9751055static inline void
9761056__execlists_schedule_out (struct i915_request * rq ,
9771057 struct intel_engine_cs * const engine )
@@ -982,6 +1062,9 @@ __execlists_schedule_out(struct i915_request *rq,
9821062 execlists_context_status_change (rq , INTEL_CONTEXT_SCHEDULE_OUT );
9831063 intel_gt_pm_put (engine -> gt );
9841064
1065+ if (unlikely (i915_gem_context_is_banned (ce -> gem_context )))
1066+ reset_active (rq , engine );
1067+
9851068 /*
9861069 * If this is part of a virtual engine, its next request may
9871070 * have been blocked waiting for access to the active context.
@@ -1380,6 +1463,10 @@ static unsigned long active_preempt_timeout(struct intel_engine_cs *engine)
13801463 if (!rq )
13811464 return 0 ;
13821465
1466+ /* Force a fast reset for terminated contexts (ignoring sysfs!) */
1467+ if (unlikely (i915_gem_context_is_banned (rq -> gem_context )))
1468+ return 1 ;
1469+
13831470 return READ_ONCE (engine -> props .preempt_timeout_ms );
13841471}
13851472
@@ -2792,29 +2879,6 @@ static void reset_csb_pointers(struct intel_engine_cs *engine)
27922879 & execlists -> csb_status [reset_value ]);
27932880}
27942881
2795- static struct i915_request * active_request (struct i915_request * rq )
2796- {
2797- const struct intel_context * const ce = rq -> hw_context ;
2798- struct i915_request * active = NULL ;
2799- struct list_head * list ;
2800-
2801- if (!i915_request_is_active (rq )) /* unwound, but incomplete! */
2802- return rq ;
2803-
2804- list = & i915_request_active_timeline (rq )-> requests ;
2805- list_for_each_entry_from_reverse (rq , list , link ) {
2806- if (i915_request_completed (rq ))
2807- break ;
2808-
2809- if (rq -> hw_context != ce )
2810- break ;
2811-
2812- active = rq ;
2813- }
2814-
2815- return active ;
2816- }
2817-
28182882static void __execlists_reset_reg_state (const struct intel_context * ce ,
28192883 const struct intel_engine_cs * engine )
28202884{
@@ -2831,7 +2895,6 @@ static void __execlists_reset(struct intel_engine_cs *engine, bool stalled)
28312895 struct intel_engine_execlists * const execlists = & engine -> execlists ;
28322896 struct intel_context * ce ;
28332897 struct i915_request * rq ;
2834- u32 * regs ;
28352898
28362899 mb (); /* paranoia: read the CSB pointers from after the reset */
28372900 clflush (execlists -> csb_write );
@@ -2907,13 +2970,7 @@ static void __execlists_reset(struct intel_engine_cs *engine, bool stalled)
29072970 * to recreate its own state.
29082971 */
29092972 GEM_BUG_ON (!intel_context_is_pinned (ce ));
2910- regs = ce -> lrc_reg_state ;
2911- if (engine -> pinned_default_state ) {
2912- memcpy (regs , /* skip restoring the vanilla PPHWSP */
2913- engine -> pinned_default_state + LRC_STATE_PN * PAGE_SIZE ,
2914- engine -> context_size - PAGE_SIZE );
2915- }
2916- execlists_init_reg_state (regs , ce , engine , ce -> ring , false);
2973+ restore_default_state (ce , engine );
29172974
29182975out_replay :
29192976 GEM_TRACE ("%s replay {head:%04x, tail:%04x\n" ,
@@ -4574,16 +4631,8 @@ void intel_lr_context_reset(struct intel_engine_cs *engine,
45744631 * future request will be after userspace has had the opportunity
45754632 * to recreate its own state.
45764633 */
4577- if (scrub ) {
4578- u32 * regs = ce -> lrc_reg_state ;
4579-
4580- if (engine -> pinned_default_state ) {
4581- memcpy (regs , /* skip restoring the vanilla PPHWSP */
4582- engine -> pinned_default_state + LRC_STATE_PN * PAGE_SIZE ,
4583- engine -> context_size - PAGE_SIZE );
4584- }
4585- execlists_init_reg_state (regs , ce , engine , ce -> ring , false);
4586- }
4634+ if (scrub )
4635+ restore_default_state (ce , engine );
45874636
45884637 /* Rerun the request; its payload has been neutered (if guilty). */
45894638 ce -> ring -> head = head ;
0 commit comments