diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 7989881545f1..e6a71d4a6261 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -535,6 +535,33 @@ static void inject_preempt_context(struct intel_engine_cs *engine)
 	execlists_set_active(execlists, EXECLISTS_ACTIVE_PREEMPT);
 }
 
+static int try_preempt_reset(struct intel_engine_execlists *execlists)
+{
+	struct intel_engine_cs *engine =
+		container_of(execlists, typeof(*engine), execlists);
+	int err = -EBUSY;
+
+	if (!test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted) &&
+	    tasklet_trylock(&execlists->tasklet)) {
+		unsigned long *lock = &engine->i915->gpu_error.flags;
+		unsigned int bit = I915_RESET_ENGINE + engine->id;
+
+		if (!test_and_set_bit(bit, lock)) {
+			tasklet_disable_nosync(&engine->execlists.tasklet);
+			err = i915_reset_engine(engine,
+						"preemption time out");
+			tasklet_enable(&engine->execlists.tasklet);
+
+			clear_bit(bit, lock);
+			wake_up_bit(lock, bit);
+		}
+
+		tasklet_unlock(&execlists->tasklet);
+	}
+
+	return err;
+}
+
 static enum hrtimer_restart preempt_timeout(struct hrtimer *hrtimer)
 {
 	struct intel_engine_execlists *execlists =
@@ -548,7 +575,9 @@ static enum hrtimer_restart preempt_timeout(struct hrtimer *hrtimer)
 	if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT_TIMEOUT))
 		return HRTIMER_NORESTART;
 
-	queue_work(system_highpri_wq, &execlists->preempt_reset);
+	if (try_preempt_reset(execlists))
+		queue_work(system_highpri_wq, &execlists->preempt_reset);
+
 	return HRTIMER_NORESTART;
 }
 
diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c
index af16b0a40653..fe12df163cbd 100644
--- a/drivers/gpu/drm/i915/selftests/intel_lrc.c
+++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c
@@ -546,6 +546,86 @@ static int live_preempt_timeout(void *arg)
 	return err;
 }
 
+static int live_preempt_reset(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct intel_engine_cs *engine;
+	struct i915_gem_context *ctx;
+	enum intel_engine_id id;
+	struct spinner spin;
+	int err = -ENOMEM;
+
+	if (!HAS_LOGICAL_RING_PREEMPTION(i915))
+		return 0;
+
+	mutex_lock(&i915->drm.struct_mutex);
+
+	if (spinner_init(&spin, i915))
+		goto err_unlock;
+
+	ctx= kernel_context(i915);
+	if (!ctx)
+		goto err_spin;
+
+	for_each_engine(engine, i915, id) {
+		struct i915_request *rq;
+
+		rq = spinner_create_request(&spin, ctx, engine, MI_NOOP);
+		if (IS_ERR(rq)) {
+			err = PTR_ERR(rq);
+			goto err_ctx;
+		}
+
+		i915_request_add(rq);
+		if (!wait_for_spinner(&spin, rq)) {
+			i915_gem_set_wedged(i915);
+			err = -EIO;
+			goto err_ctx;
+		}
+
+		/* Flush to improve our odds of enabling try_preempt_reset. */
+		do {
+			tasklet_schedule(&engine->execlists.tasklet);
+			tasklet_kill(&engine->execlists.tasklet);
+		} while (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted));
+		GEM_BUG_ON(i915_request_completed(rq));
+
+		local_bh_disable(); /* emulate the timer/softirq context */
+		err = try_preempt_reset(&engine->execlists);
+		local_bh_enable();
+		if (err) {
+			pr_err("Preempt reset failed on %s, irq_posted? %d, tasklet state %lx\n",
+			       engine->name,
+			       test_bit(ENGINE_IRQ_EXECLIST,
+					&engine->irq_posted),
+			       engine->execlists.tasklet.state);
+			i915_gem_set_wedged(i915);
+			goto err_ctx;
+		}
+
+		/*
+		 * In such a simple case as above; triggering a reset allows
+		 * us to save and restore the hog perfectly...
+		 */
+		spinner_end(&spin);
+
+		if (flush_test(i915, I915_WAIT_LOCKED)) {
+			err = -EIO;
+			goto err_ctx;
+		}
+	}
+
+	err = 0;
+err_ctx:
+	kernel_context_close(ctx);
+err_spin:
+	spinner_fini(&spin);
+err_unlock:
+	flush_test(i915, I915_WAIT_LOCKED);
+	mutex_unlock(&i915->drm.struct_mutex);
+	return err;
+}
+
 int intel_execlists_live_selftests(struct drm_i915_private *i915)
 {
 	static const struct i915_subtest tests[] = {
@@ -553,6 +633,7 @@ int intel_execlists_live_selftests(struct drm_i915_private *i915)
 		SUBTEST(live_preempt),
 		SUBTEST(live_late_preempt),
 		SUBTEST(live_preempt_timeout),
+		SUBTEST(live_preempt_reset),
 	};
 	return i915_subtests(tests, i915);
 }
