diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 207cda0626268769d00fa38e21951132a1f57b76..749f27916a02b91f86e93ad0add0c198c693ed86 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -728,7 +728,7 @@ static void guc_dequeue(struct intel_engine_cs *engine) execlists->first = rb; if (submit) { port_assign(port, last); - execlists_set_active(execlists, EXECLISTS_ACTIVE_USER); + execlists_user_begin(execlists, execlists->port); guc_submit(engine); } @@ -748,17 +748,20 @@ static void guc_submission_tasklet(unsigned long data) struct execlist_port *port = execlists->port; struct i915_request *rq; - rq = port_request(&port[0]); + rq = port_request(port); while (rq && i915_request_completed(rq)) { trace_i915_request_out(rq); i915_request_put(rq); - execlists_port_complete(execlists, port); - - rq = port_request(&port[0]); + port = execlists_port_complete(execlists, port); + if (port_isset(port)) { + execlists_user_begin(execlists, port); + rq = port_request(port); + } else { + execlists_user_end(execlists); + rq = NULL; + } } - if (!rq) - execlists_clear_active(execlists, EXECLISTS_ACTIVE_USER); if (execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT) && intel_read_status_page(engine, I915_GEM_HWS_PREEMPT_INDEX) == diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index f60b61bf8b3bb9ec4e41f350ae1c8cf8e631063f..4d08875422b6338613db406b70053b7fc0524ad0 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -374,6 +374,19 @@ execlists_context_status_change(struct i915_request *rq, unsigned long status) status, rq); } +inline void +execlists_user_begin(struct intel_engine_execlists *execlists, + const struct execlist_port *port) +{ + execlists_set_active_once(execlists, EXECLISTS_ACTIVE_USER); +} + +inline void +execlists_user_end(struct intel_engine_execlists *execlists) +{ + execlists_clear_active(execlists, EXECLISTS_ACTIVE_USER); +} + static inline void execlists_context_schedule_in(struct i915_request *rq) { @@ -711,7 +724,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) spin_unlock_irq(&engine->timeline->lock); if (submit) { - execlists_set_active(execlists, EXECLISTS_ACTIVE_USER); + execlists_user_begin(execlists, execlists->port); execlists_submit_ports(engine); } @@ -742,7 +755,7 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists) port++; } - execlists_clear_active(execlists, EXECLISTS_ACTIVE_USER); + execlists_user_end(execlists); } static void clear_gtiir(struct intel_engine_cs *engine) @@ -873,7 +886,7 @@ static void execlists_submission_tasklet(unsigned long data) { struct intel_engine_cs * const engine = (struct intel_engine_cs *)data; struct intel_engine_execlists * const execlists = &engine->execlists; - struct execlist_port * const port = execlists->port; + struct execlist_port *port = execlists->port; struct drm_i915_private *dev_priv = engine->i915; bool fw = false; @@ -1012,10 +1025,28 @@ static void execlists_submission_tasklet(unsigned long data) GEM_BUG_ON(count == 0); if (--count == 0) { + /* + * On the final event corresponding to the + * submission of this context, we expect either + * an element-switch event or a completion + * event (and on completion, the active-idle + * marker). No more preemptions, lite-restore + * or otherwise. + */ GEM_BUG_ON(status & GEN8_CTX_STATUS_PREEMPTED); GEM_BUG_ON(port_isset(&port[1]) && !(status & GEN8_CTX_STATUS_ELEMENT_SWITCH)); + GEM_BUG_ON(!port_isset(&port[1]) && + !(status & GEN8_CTX_STATUS_ACTIVE_IDLE)); + + /* + * We rely on the hardware being strongly + * ordered, that the breadcrumb write is + * coherent (visible from the CPU) before the + * user interrupt and CSB is processed. + */ GEM_BUG_ON(!i915_request_completed(rq)); + execlists_context_schedule_out(rq); trace_i915_request_out(rq); i915_request_put(rq); @@ -1023,17 +1054,14 @@ static void execlists_submission_tasklet(unsigned long data) GEM_TRACE("%s completed ctx=%d\n", engine->name, port->context_id); - execlists_port_complete(execlists, port); + port = execlists_port_complete(execlists, port); + if (port_isset(port)) + execlists_user_begin(execlists, port); + else + execlists_user_end(execlists); } else { port_set(port, port_pack(rq, count)); } - - /* After the final element, the hw should be idle */ - GEM_BUG_ON(port_count(port) == 0 && - !(status & GEN8_CTX_STATUS_ACTIVE_IDLE)); - if (port_count(port) == 0) - execlists_clear_active(execlists, - EXECLISTS_ACTIVE_USER); } if (head != execlists->csb_head) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index a02c7b3b9d55456b0957f962f39d03fad2c30bce..40461e29cdabe1661313442364a5cbb5702f0c47 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -638,6 +638,13 @@ execlists_set_active(struct intel_engine_execlists *execlists, __set_bit(bit, (unsigned long *)&execlists->active); } +static inline bool +execlists_set_active_once(struct intel_engine_execlists *execlists, + unsigned int bit) +{ + return !__test_and_set_bit(bit, (unsigned long *)&execlists->active); +} + static inline void execlists_clear_active(struct intel_engine_execlists *execlists, unsigned int bit) @@ -652,6 +659,10 @@ execlists_is_active(const struct intel_engine_execlists *execlists, return test_bit(bit, (unsigned long *)&execlists->active); } +void execlists_user_begin(struct intel_engine_execlists *execlists, + const struct execlist_port *port); +void execlists_user_end(struct intel_engine_execlists *execlists); + void execlists_cancel_port_requests(struct intel_engine_execlists * const execlists); @@ -664,7 +675,7 @@ execlists_num_ports(const struct intel_engine_execlists * const execlists) return execlists->port_mask + 1; } -static inline void +static inline struct execlist_port * execlists_port_complete(struct intel_engine_execlists * const execlists, struct execlist_port * const port) { @@ -675,6 +686,8 @@ execlists_port_complete(struct intel_engine_execlists * const execlists, memmove(port, port + 1, m * sizeof(struct execlist_port)); memset(port + m, 0, sizeof(struct execlist_port)); + + return port; } static inline unsigned int