GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT));
 
        execlists_cancel_port_requests(execlists);
-       execlists_unwind_incomplete_requests(execlists);
+       __unwind_incomplete_requests(container_of(execlists,
+                                                 struct intel_engine_cs,
+                                                 execlists));
 
        execlists_clear_active(execlists, EXECLISTS_ACTIVE_PREEMPT);
 }
 
-static void __execlists_dequeue(struct intel_engine_cs *engine)
+static void execlists_dequeue(struct intel_engine_cs *engine)
 {
        struct intel_engine_execlists * const execlists = &engine->execlists;
        struct execlist_port *port = execlists->port;
        struct rb_node *rb;
        bool submit = false;
 
-       lockdep_assert_held(&engine->timeline.lock);
-
-       /* Hardware submission is through 2 ports. Conceptually each port
+       /*
+        * Hardware submission is through 2 ports. Conceptually each port
         * has a (RING_START, RING_HEAD, RING_TAIL) tuple. RING_START is
         * static for a context, and unique to each, so we only execute
         * requests belonging to a single context from each ring. RING_HEAD
                   !port_isset(engine->execlists.port));
 }
 
-static void execlists_dequeue(struct intel_engine_cs *engine)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&engine->timeline.lock, flags);
-       __execlists_dequeue(engine);
-       spin_unlock_irqrestore(&engine->timeline.lock, flags);
-}
-
 void
 execlists_cancel_port_requests(struct intel_engine_execlists * const execlists)
 {
        spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
+static inline bool
+reset_in_progress(const struct intel_engine_execlists *execlists)
+{
+       return unlikely(!__tasklet_is_enabled(&execlists->tasklet));
+}
+
 static void process_csb(struct intel_engine_cs *engine)
 {
        struct intel_engine_execlists * const execlists = &engine->execlists;
        execlists->csb_head = head;
 }
 
-/*
- * Check the unread Context Status Buffers and manage the submission of new
- * contexts to the ELSP accordingly.
- */
-static void execlists_submission_tasklet(unsigned long data)
+static void __execlists_submission_tasklet(struct intel_engine_cs *const engine)
 {
-       struct intel_engine_cs * const engine = (struct intel_engine_cs *)data;
-
-       GEM_TRACE("%s awake?=%d, active=%x\n",
-                 engine->name,
-                 engine->i915->gt.awake,
-                 engine->execlists.active);
+       lockdep_assert_held(&engine->timeline.lock);
 
        /*
         * We can skip acquiring intel_runtime_pm_get() here as it was taken
                execlists_dequeue(engine);
 }
 
+/*
+ * Check the unread Context Status Buffers and manage the submission of new
+ * contexts to the ELSP accordingly.
+ */
+static void execlists_submission_tasklet(unsigned long data)
+{
+       struct intel_engine_cs * const engine = (struct intel_engine_cs *)data;
+       unsigned long flags;
+
+       GEM_TRACE("%s awake?=%d, active=%x\n",
+                 engine->name,
+                 engine->i915->gt.awake,
+                 engine->execlists.active);
+
+       spin_lock_irqsave(&engine->timeline.lock, flags);
+
+       if (engine->i915->gt.awake) /* we may be delayed until after we idle! */
+               __execlists_submission_tasklet(engine);
+
+       spin_unlock_irqrestore(&engine->timeline.lock, flags);
+}
+
 static void queue_request(struct intel_engine_cs *engine,
                          struct i915_sched_node *node,
                          int prio)
                      &lookup_priolist(engine, prio)->requests);
 }
 
-static void __submit_queue(struct intel_engine_cs *engine, int prio)
+static void __update_queue(struct intel_engine_cs *engine, int prio)
 {
        engine->execlists.queue_priority = prio;
-       tasklet_hi_schedule(&engine->execlists.tasklet);
+}
+
+static void __submit_queue_imm(struct intel_engine_cs *engine)
+{
+       struct intel_engine_execlists * const execlists = &engine->execlists;
+
+       if (reset_in_progress(execlists))
+               return; /* defer until we restart the engine following reset */
+
+       if (execlists->tasklet.func == execlists_submission_tasklet)
+               __execlists_submission_tasklet(engine);
+       else
+               tasklet_hi_schedule(&execlists->tasklet);
 }
 
 static void submit_queue(struct intel_engine_cs *engine, int prio)
 {
-       if (prio > engine->execlists.queue_priority)
-               __submit_queue(engine, prio);
+       if (prio > engine->execlists.queue_priority) {
+               __update_queue(engine, prio);
+               __submit_queue_imm(engine);
+       }
 }
 
 static void execlists_submit_request(struct i915_request *request)
        spin_lock_irqsave(&engine->timeline.lock, flags);
 
        queue_request(engine, &request->sched, rq_prio(request));
-       submit_queue(engine, rq_prio(request));
 
        GEM_BUG_ON(!engine->execlists.first);
        GEM_BUG_ON(list_empty(&request->sched.link));
 
+       submit_queue(engine, rq_prio(request));
+
        spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
                }
 
                if (prio > engine->execlists.queue_priority &&
-                   i915_sw_fence_done(&sched_to_request(node)->submit))
-                       __submit_queue(engine, prio);
+                   i915_sw_fence_done(&sched_to_request(node)->submit)) {
+                       /* defer submission until after all of our updates */
+                       __update_queue(engine, prio);
+                       tasklet_hi_schedule(&engine->execlists.tasklet);
+               }
        }
 
        spin_unlock_irq(&engine->timeline.lock);
 {
        struct intel_engine_execlists * const execlists = &engine->execlists;
        struct i915_request *request, *active;
+       unsigned long flags;
 
        GEM_TRACE("%s\n", engine->name);
 
         */
        __tasklet_disable_sync_once(&execlists->tasklet);
 
+       spin_lock_irqsave(&engine->timeline.lock, flags);
+
        /*
         * We want to flush the pending context switches, having disabled
         * the tasklet above, we can assume exclusive access to the execlists.
        active = NULL;
        request = port_request(execlists->port);
        if (request) {
-               unsigned long flags;
-
                /*
                 * Prevent the breadcrumb from advancing before we decide
                 * which request is currently active.
                 */
                intel_engine_stop_cs(engine);
 
-               spin_lock_irqsave(&engine->timeline.lock, flags);
                list_for_each_entry_from_reverse(request,
                                                 &engine->timeline.requests,
                                                 link) {
 
                        active = request;
                }
-               spin_unlock_irqrestore(&engine->timeline.lock, flags);
        }
 
+       spin_unlock_irqrestore(&engine->timeline.lock, flags);
+
        return active;
 }