*/
        struct timer_list preempt;
 
+       /**
+        * @preempt_target: active request at the time of the preemption request
+        *
+        * We force a preemption to occur if the pending contexts have not
+        * been promoted to active upon receipt of the CS ack event within
+        * the timeout. This timeout maybe chosen based on the target,
+        * using a very short timeout if the context is no longer schedulable.
+        * That short timeout may not be applicable to other contexts, so
+        * if a context switch should happen within before the preemption
+        * timeout, we may shoot early at an innocent context. To prevent this,
+        * we record which context was active at the time of the preemption
+        * request and only reset that context upon the timeout.
+        */
+       const struct i915_request *preempt_target;
+
        /**
         * @ccid: identifier for contexts submitted to this engine
         */
 
        if (!rq)
                return 0;
 
+       /* Only allow ourselves to force reset the currently active context */
+       engine->execlists.preempt_target = rq;
+
        /* Force a fast reset for terminated contexts (ignoring sysfs!) */
        if (unlikely(intel_context_is_banned(rq->context) || bad_request(rq)))
                return INTEL_CONTEXT_BANNED_PREEMPT_TIMEOUT_MS;
        GEM_BUG_ON(inactive - post > ARRAY_SIZE(post));
 
        if (unlikely(preempt_timeout(engine))) {
+               const struct i915_request *rq = *engine->execlists.active;
+
+               /*
+                * If after the preempt-timeout expired, we are still on the
+                * same active request/context as before we initiated the
+                * preemption, reset the engine.
+                *
+                * However, if we have processed a CS event to switch contexts,
+                * but not yet processed the CS event for the pending
+                * preemption, reset the timer allowing the new context to
+                * gracefully exit.
+                */
                cancel_timer(&engine->execlists.preempt);
-               engine->execlists.error_interrupt |= ERROR_PREEMPT;
+               if (rq == engine->execlists.preempt_target)
+                       engine->execlists.error_interrupt |= ERROR_PREEMPT;
+               else
+                       set_timer_ms(&engine->execlists.preempt,
+                                    active_preempt_timeout(engine, rq));
        }
 
        if (unlikely(READ_ONCE(engine->execlists.error_interrupt))) {