[PATCH 43/43] drm/i915/gt: Move execlists submission state to the scheduling backend
Chris Wilson
chris at chris-wilson.co.uk
Tue Feb 9 21:26:39 UTC 2021
Rather than embedded the execlists state into the common
intel_engine_cs, move it to the scheduler state local the scheduling
backend.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
drivers/gpu/drm/i915/gt/intel_engine.h | 27 -
drivers/gpu/drm/i915/gt/intel_engine_cs.c | 16 -
drivers/gpu/drm/i915/gt/intel_engine_types.h | 142 +--
.../drm/i915/gt/intel_execlists_submission.c | 926 ++++++++++--------
.../gpu/drm/i915/gt/intel_ring_scheduler.c | 211 ++--
drivers/gpu/drm/i915/gt/selftest_execlists.c | 30 +-
drivers/gpu/drm/i915/gt/selftest_lrc.c | 2 +-
.../gpu/drm/i915/gt/uc/intel_guc_submission.c | 123 +--
drivers/gpu/drm/i915/i915_gpu_error.c | 60 --
drivers/gpu/drm/i915/i915_gpu_error.h | 3 -
10 files changed, 683 insertions(+), 857 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h
index 734f43d5d3dd..582f3d3a7042 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine.h
@@ -99,31 +99,6 @@ struct intel_gt;
* do the writes, and that must have qw aligned offsets, simply pretend it's 8b.
*/
-static inline unsigned int
-execlists_num_ports(const struct intel_engine_execlists * const execlists)
-{
- return execlists->port_mask + 1;
-}
-
-static inline struct i915_request *
-execlists_active(const struct intel_engine_execlists *execlists)
-{
- struct i915_request * const *cur, * const *old, *active;
-
- cur = READ_ONCE(execlists->active);
- smp_rmb(); /* pairs with overwrite protection in process_csb() */
- do {
- old = cur;
-
- active = READ_ONCE(*cur);
- cur = READ_ONCE(execlists->active);
-
- smp_rmb(); /* and complete the seqlock retry */
- } while (unlikely(cur != old));
-
- return active;
-}
-
static inline u32
intel_read_status_page(const struct intel_engine_cs *engine, int reg)
{
@@ -204,8 +179,6 @@ u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine);
void intel_engine_get_instdone(const struct intel_engine_cs *engine,
struct intel_instdone *instdone);
-void intel_engine_init_execlists(struct intel_engine_cs *engine);
-
static inline void __intel_engine_reset(struct intel_engine_cs *engine,
bool stalled)
{
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index bd5ee06e1d30..5d2803b86e83 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -568,19 +568,6 @@ int intel_engines_init_mmio(struct intel_gt *gt)
return err;
}
-void intel_engine_init_execlists(struct intel_engine_cs *engine)
-{
- struct intel_engine_execlists * const execlists = &engine->execlists;
-
- execlists->port_mask = 1;
- GEM_BUG_ON(!is_power_of_2(execlists_num_ports(execlists)));
- GEM_BUG_ON(execlists_num_ports(execlists) > EXECLIST_MAX_PORTS);
-
- memset(execlists->pending, 0, sizeof(execlists->pending));
- execlists->active =
- memset(execlists->inflight, 0, sizeof(execlists->inflight));
-}
-
static void cleanup_status_page(struct intel_engine_cs *engine)
{
struct i915_vma *vma;
@@ -1418,9 +1405,6 @@ void intel_engine_dump(struct intel_engine_cs *engine,
drm_printf(m, "Runtime: %llums\n",
ktime_to_ms(intel_engine_get_busy_time(engine,
&dummy)));
- drm_printf(m, "Forcewake: %x domains, %d active\n",
- engine->fw_domain, READ_ONCE(engine->fw_active));
-
rcu_read_lock();
rq = READ_ONCE(engine->heartbeat.systole);
if (rq)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
index 5ebf64832680..bfc6e9f96f63 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
@@ -20,7 +20,6 @@
#include "i915_gem.h"
#include "i915_pmu.h"
#include "i915_priolist_types.h"
-#include "i915_scheduler_types.h"
#include "i915_selftest.h"
#include "intel_breadcrumbs_types.h"
#include "intel_sseu.h"
@@ -59,6 +58,7 @@ struct drm_i915_gem_object;
struct drm_i915_reg_table;
struct i915_gem_context;
struct i915_request;
+struct i915_sched;
struct i915_sched_attr;
struct intel_gt;
struct intel_ring;
@@ -126,132 +126,6 @@ enum intel_engine_id {
/* A simple estimator for the round-trip latency of an engine */
DECLARE_EWMA(_engine_latency, 6, 4)
-struct st_preempt_hang {
- struct completion completion;
- unsigned int count;
-};
-
-/**
- * struct intel_engine_execlists - execlist submission queue and port state
- *
- * The struct intel_engine_execlists represents the combined logical state of
- * driver and the hardware state for execlist mode of submission.
- */
-struct intel_engine_execlists {
- /**
- * @timer: kick the current context if its timeslice expires
- */
- struct timer_list timer;
-
- /**
- * @preempt: reset the current context if it fails to give way
- */
- struct timer_list preempt;
-
- /**
- * @ccid: identifier for contexts submitted to this engine
- */
- u32 ccid;
-
- /**
- * @yield: CCID at the time of the last semaphore-wait interrupt.
- *
- * Instead of leaving a semaphore busy-spinning on an engine, we would
- * like to switch to another ready context, i.e. yielding the semaphore
- * timeslice.
- */
- u32 yield;
-
- /**
- * @error_interrupt: CS Master EIR
- *
- * The CS generates an interrupt when it detects an error. We capture
- * the first error interrupt, record the EIR and schedule the tasklet.
- * In the tasklet, we process the pending CS events to ensure we have
- * the guilty request, and then reset the engine.
- *
- * Low 16b are used by HW, with the upper 16b used as the enabling mask.
- * Reserve the upper 16b for tracking internal errors.
- */
- u32 error_interrupt;
-#define ERROR_CSB BIT(31)
-#define ERROR_PREEMPT BIT(30)
-
- /**
- * @reset_ccid: Active CCID [EXECLISTS_STATUS_HI] at the time of reset
- */
- u32 reset_ccid;
-
- /**
- * @submit_reg: gen-specific execlist submission register
- * set to the ExecList Submission Port (elsp) register pre-Gen11 and to
- * the ExecList Submission Queue Contents register array for Gen11+
- */
- u32 __iomem *submit_reg;
-
- /**
- * @ctrl_reg: the enhanced execlists control register, used to load the
- * submit queue on the HW and to request preemptions to idle
- */
- u32 __iomem *ctrl_reg;
-
-#define EXECLIST_MAX_PORTS 2
- /**
- * @active: the currently known context executing on HW
- */
- struct i915_request * const *active;
- /**
- * @inflight: the set of contexts submitted and acknowleged by HW
- *
- * The set of inflight contexts is managed by reading CS events
- * from the HW. On a context-switch event (not preemption), we
- * know the HW has transitioned from port0 to port1, and we
- * advance our inflight/active tracking accordingly.
- */
- struct i915_request *inflight[EXECLIST_MAX_PORTS + 1 /* sentinel */];
- /**
- * @pending: the next set of contexts submitted to ELSP
- *
- * We store the array of contexts that we submit to HW (via ELSP) and
- * promote them to the inflight array once HW has signaled the
- * preemption or idle-to-active event.
- */
- struct i915_request *pending[EXECLIST_MAX_PORTS + 1];
-
- /**
- * @port_mask: number of execlist ports - 1
- */
- unsigned int port_mask;
-
- struct rb_root_cached virtual;
-
- /**
- * @csb_write: control register for Context Switch buffer
- *
- * Note this register may be either mmio or HWSP shadow.
- */
- u32 *csb_write;
-
- /**
- * @csb_status: status array for Context Switch buffer
- *
- * Note these register may be either mmio or HWSP shadow.
- */
- u64 *csb_status;
-
- /**
- * @csb_size: context status buffer FIFO size
- */
- u8 csb_size;
-
- /**
- * @csb_head: context status buffer head
- */
- u8 csb_head;
-
- I915_SELFTEST_DECLARE(struct st_preempt_hang preempt_hang;)
-};
-
#define INTEL_ENGINE_CS_MAX_NAME 8
struct intel_engine_cs {
@@ -280,18 +154,6 @@ struct intel_engine_cs {
u32 context_size;
u32 mmio_base;
- /*
- * Some w/a require forcewake to be held (which prevents RC6) while
- * a particular engine is active. If so, we set fw_domain to which
- * domains need to be held for the duration of request activity,
- * and 0 if none. We try to limit the duration of the hold as much
- * as possible.
- */
- enum forcewake_domains fw_domain;
- unsigned int fw_active;
-
- unsigned long context_tag;
-
struct rb_node uabi_node;
struct intel_sseu sseu;
@@ -413,8 +275,6 @@ struct intel_engine_cs {
void (*release)(struct intel_engine_cs *engine);
- struct intel_engine_execlists execlists;
-
/*
* Keep track of completed timelines on this engine for early
* retirement with the goal of quickly enabling powersaving as
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index 45a00ec29916..7b097aad3782 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -157,6 +157,109 @@
/* Typical size of the average request (2 pipecontrols and a MI_BB) */
#define EXECLISTS_REQUEST_SIZE 64 /* bytes */
+struct st_preempt_hang {
+ struct completion completion;
+ unsigned int count;
+};
+
+struct intel_execlists {
+ struct i915_sched sched;
+
+ unsigned long flags;
+#define GEN12_CSB_PARSE BIT(0)
+
+ u32 *pause;
+
+ u32 *csb_write;
+ u64 *csb_status;
+ u8 csb_size;
+ u8 csb_head;
+ u8 port_mask;
+ u8 id;
+
+ /* tagging for contexts submitted to the engine */
+ unsigned long ccid_tags;
+ u32 ccid_engine;
+
+ /*
+ * @yield: CCID at the time of the last semaphore-wait interrupt.
+ *
+ * Instead of leaving a semaphore busy-spinning on an engine, we would
+ * like to switch to another ready context, i.e. yielding the semaphore
+ * timeslice.
+ */
+ u32 yield;
+
+ /*
+ * @error_interrupt: CS Master EIR
+ *
+ * The CS generates an interrupt when it detects an error. We capture
+ * the first error interrupt, record the EIR and schedule the tasklet.
+ * In the tasklet, we process the pending CS events to ensure we have
+ * the guilty request, and then reset the engine.
+ *
+ * Low 16b are used by HW, with the upper 16b used as the enabling mask.
+ * Reserve the upper 16b for tracking internal errors.
+ */
+ u32 error_interrupt;
+#define ERROR_CSB BIT(31)
+#define ERROR_PREEMPT BIT(30)
+
+ /**
+ * @reset_ccid: Active CCID [EXECLISTS_STATUS_HI] at the time of reset
+ */
+ u32 reset_ccid;
+
+ u32 __iomem *submit_reg;
+ u32 __iomem *ctrl_reg;
+
+ /*
+ * Some w/a require forcewake to be held (which prevents RC6) while
+ * a particular engine is active. If so, we set fw_domain to which
+ * domains need to be held for the duration of request activity,
+ * and 0 if none. We try to limit the duration of the hold as much
+ * as possible.
+ */
+ enum forcewake_domains fw_domain;
+ unsigned int fw_active;
+
+#define EXECLIST_MAX_PORTS 2
+ /*
+ * @active: the currently known context executing on HW
+ */
+ struct i915_request * const *active;
+ /*
+ * @inflight: the set of contexts submitted and acknowleged by HW
+ *
+ * The set of inflight contexts is managed by reading CS events
+ * from the HW. On a context-switch event (not preemption), we
+ * know the HW has transitioned from port0 to port1, and we
+ * advance our inflight/active tracking accordingly.
+ */
+ struct i915_request *inflight[EXECLIST_MAX_PORTS + 1 /* sentinel */];
+ /*
+ * @pending: the next set of contexts submitted to ELSP
+ *
+ * We store the array of contexts that we submit to HW (via ELSP) and
+ * promote them to the inflight array once HW has signaled the
+ * preemption or idle-to-active event.
+ */
+ struct i915_request *pending[EXECLIST_MAX_PORTS + 1];
+
+ struct rb_root_cached virtual;
+
+ struct timer_list timer;
+ struct timer_list preempt;
+
+ I915_SELFTEST_DECLARE(struct st_preempt_hang preempt_hang;)
+};
+
+static inline unsigned int
+num_ports(const struct intel_execlists * const el)
+{
+ return el->port_mask + 1;
+}
+
struct virtual_engine {
struct intel_engine_cs base;
struct intel_context context;
@@ -235,7 +338,7 @@ active_request(const struct intel_timeline * const tl, struct i915_request *rq)
return __active_request(tl, rq, 0);
}
-static void ring_set_paused(const struct intel_engine_cs *engine, int state)
+static void ring_set_paused(const struct intel_execlists *el, int state)
{
/*
* We inspect HWS_PREEMPT with a semaphore inside
@@ -243,7 +346,7 @@ static void ring_set_paused(const struct intel_engine_cs *engine, int state)
* the ring is paused as the semaphore will busywait
* until the dword is false.
*/
- engine->status_page.addr[I915_GEM_HWS_PREEMPT] = state;
+ WRITE_ONCE(*el->pause, state);
if (state)
wmb();
}
@@ -273,19 +376,19 @@ static struct i915_request *first_request(const struct i915_sched *se)
}
static struct virtual_engine *
-first_virtual_engine(const struct intel_engine_cs *engine)
+first_virtual_engine(const struct intel_execlists *el)
{
- return rb_entry_safe(rb_first_cached(&engine->execlists.virtual),
+ return rb_entry_safe(rb_first_cached(&el->virtual),
struct virtual_engine,
- nodes[engine->id].rb);
+ nodes[el->id].rb);
}
static const struct i915_request *
-first_virtual(const struct intel_engine_cs *engine)
+first_virtual(const struct intel_execlists *el)
{
struct virtual_engine *ve;
- ve = first_virtual_engine(engine);
+ ve = first_virtual_engine(el);
if (!ve)
return NULL;
@@ -307,14 +410,13 @@ dl_before(const struct i915_request *next, const struct i915_request *prev)
return !prev || (next && rq_deadline(next) < rq_deadline(prev));
}
-static bool need_preempt(const struct intel_engine_cs *engine,
+static bool need_preempt(const struct intel_execlists *el,
const struct i915_request *rq)
{
- const struct i915_sched *se = engine->sched;
const struct i915_request *first = NULL;
const struct i915_request *next;
- if (!i915_sched_use_busywait(se))
+ if (!i915_sched_use_busywait(&el->sched))
return false;
/*
@@ -332,7 +434,7 @@ static bool need_preempt(const struct intel_engine_cs *engine,
* Check against the first request in ELSP[1], it will, thanks to the
* power of PI, be the highest priority of that context.
*/
- next = next_elsp_request(se, rq);
+ next = next_elsp_request(&el->sched, rq);
if (dl_before(next, first))
first = next;
@@ -346,11 +448,11 @@ static bool need_preempt(const struct intel_engine_cs *engine,
* ELSP[0] or ELSP[1] as, thanks again to PI, if it was the same
* context, it's priority would not exceed ELSP[0] aka last_prio.
*/
- next = first_request(se);
+ next = first_request(&el->sched);
if (dl_before(next, first))
first = next;
- next = first_virtual(engine);
+ next = first_virtual(el);
if (dl_before(next, first))
first = next;
@@ -364,7 +466,7 @@ static bool need_preempt(const struct intel_engine_cs *engine,
* switching between contexts is noticeable, so we try to keep
* the deadline shuffling only to timeslice boundaries.
*/
- ENGINE_TRACE(engine,
+ ENGINE_TRACE(el->sched.priv,
"preempt for first=%llx:%llu, dl=%llu, prio=%d?\n",
first->fence.context,
first->fence.seqno,
@@ -374,7 +476,7 @@ static bool need_preempt(const struct intel_engine_cs *engine,
}
__maybe_unused static bool
-assert_priority_queue(const struct intel_engine_cs *engine,
+assert_priority_queue(const struct intel_execlists *el,
const struct i915_request *prev,
const struct i915_request *next)
{
@@ -391,7 +493,7 @@ assert_priority_queue(const struct intel_engine_cs *engine,
if (rq_deadline(prev) <= rq_deadline(next))
return true;
- ENGINE_TRACE(engine,
+ ENGINE_TRACE(el->sched.priv,
"next %llx:%lld dl %lld is before prev %llx:%lld dl %lld\n",
next->fence.context, next->fence.seqno, rq_deadline(next),
prev->fence.context, prev->fence.seqno, rq_deadline(prev));
@@ -415,9 +517,9 @@ execlists_context_status_change(struct intel_engine_cs *engine,
status, rq);
}
-static void reset_active(struct i915_request *rq,
- struct intel_engine_cs *engine)
+static void reset_active(struct i915_request *rq, struct intel_execlists *el)
{
+ struct intel_engine_cs *engine = el->sched.priv;
struct intel_context * const ce = rq->context;
u32 head;
@@ -454,8 +556,9 @@ static void reset_active(struct i915_request *rq,
}
static struct intel_engine_cs *
-__execlists_schedule_in(struct intel_engine_cs *engine, struct i915_request *rq)
+__execlists_schedule_in(struct intel_execlists *el, struct i915_request *rq)
{
+ struct intel_engine_cs *engine = el->sched.priv;
struct intel_context * const ce = rq->context;
intel_context_get(ce);
@@ -465,7 +568,7 @@ __execlists_schedule_in(struct intel_engine_cs *engine, struct i915_request *rq)
intel_context_set_banned(ce);
if (unlikely(intel_context_is_banned(ce)))
- reset_active(rq, engine);
+ reset_active(rq, el);
if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
lrc_check_regs(ce, engine, "before");
@@ -476,20 +579,20 @@ __execlists_schedule_in(struct intel_engine_cs *engine, struct i915_request *rq)
ce->lrc.ccid = ce->tag;
} else {
/* We don't need a strict matching tag, just different values */
- unsigned int tag = __ffs(engine->context_tag);
+ unsigned int tag = __ffs(el->ccid_tags);
GEM_BUG_ON(tag >= BITS_PER_LONG);
- __clear_bit(tag, &engine->context_tag);
+ __clear_bit(tag, &el->ccid_tags);
ce->lrc.ccid = (1 + tag) << (GEN11_SW_CTX_ID_SHIFT - 32);
BUILD_BUG_ON(BITS_PER_LONG > GEN12_MAX_CONTEXT_HW_ID);
}
- ce->lrc.ccid |= engine->execlists.ccid;
+ ce->lrc.ccid |= el->ccid_engine;
__intel_gt_pm_get(engine->gt);
- if (engine->fw_domain && !engine->fw_active++)
- intel_uncore_forcewake_get(engine->uncore, engine->fw_domain);
+ if (el->fw_domain && !el->fw_active++)
+ intel_uncore_forcewake_get(engine->uncore, el->fw_domain);
execlists_context_status_change(engine, rq, INTEL_CONTEXT_SCHEDULE_IN);
intel_engine_context_in(engine);
@@ -499,33 +602,34 @@ __execlists_schedule_in(struct intel_engine_cs *engine, struct i915_request *rq)
}
static void
-execlists_schedule_in(struct intel_engine_cs *engine,
+execlists_schedule_in(struct intel_execlists *el,
struct i915_request *rq,
int idx)
{
struct intel_context * const ce = rq->context;
struct intel_engine_cs *old;
- GEM_BUG_ON(!intel_engine_pm_is_awake(engine));
+ GEM_BUG_ON(!intel_engine_pm_is_awake(el->sched.priv));
trace_i915_request_in(rq, idx);
old = ce->inflight;
if (!__intel_context_inflight_count(old))
- old = __execlists_schedule_in(engine, rq);
+ old = __execlists_schedule_in(el, rq);
WRITE_ONCE(ce->inflight, ptr_inc(old));
- GEM_BUG_ON(intel_context_inflight(ce) != engine);
+ GEM_BUG_ON(intel_context_inflight(ce) != el->sched.priv);
}
static void
-resubmit_virtual_request(struct i915_request *rq, struct virtual_engine *ve)
+resubmit_virtual_request(struct intel_execlists *el,
+ struct i915_request *rq,
+ struct virtual_engine *ve)
{
struct i915_sched *se = intel_engine_get_scheduler(&ve->base);
- struct i915_sched *pv = i915_request_get_scheduler(rq);
struct i915_request *pos = rq;
struct intel_timeline *tl;
- spin_lock_irq(&pv->lock);
+ spin_lock_irq(&el->sched.lock);
if (__i915_request_is_complete(rq))
goto unlock;
@@ -551,14 +655,14 @@ resubmit_virtual_request(struct i915_request *rq, struct virtual_engine *ve)
spin_unlock(&se->lock);
unlock:
- spin_unlock_irq(&pv->lock);
+ spin_unlock_irq(&el->sched.lock);
}
-static void kick_siblings(struct intel_engine_cs *engine,
+static void kick_siblings(struct intel_execlists *el,
struct i915_request *rq,
struct intel_context *ce)
{
- struct virtual_engine *ve = container_of(ce, typeof(*ve), context);
+ struct virtual_engine *ve = to_virtual_context(ce);
/*
* This engine is now too busy to run this virtual request, so
@@ -567,17 +671,18 @@ static void kick_siblings(struct intel_engine_cs *engine,
* same as other native request.
*/
if (i915_request_in_priority_queue(rq) &&
- rq->execution_mask != engine->mask)
- resubmit_virtual_request(rq, ve);
+ rq->execution_mask != el->sched.mask)
+ resubmit_virtual_request(el, rq, ve);
if (!i915_sched_is_idle(ve->base.sched))
i915_sched_kick(ve->base.sched);
}
-static void __execlists_schedule_out(struct intel_engine_cs *engine,
+static void __execlists_schedule_out(struct intel_execlists *el,
struct i915_request * const rq,
struct intel_context * const ce)
{
+ struct intel_engine_cs *engine = el->sched.priv;
unsigned int ccid;
/*
@@ -620,13 +725,13 @@ static void __execlists_schedule_out(struct intel_engine_cs *engine,
ccid &= GEN12_MAX_CONTEXT_HW_ID;
if (ccid < BITS_PER_LONG) {
GEM_BUG_ON(ccid == 0);
- GEM_BUG_ON(test_bit(ccid - 1, &engine->context_tag));
- __set_bit(ccid - 1, &engine->context_tag);
+ GEM_BUG_ON(test_bit(ccid - 1, &el->ccid_tags));
+ __set_bit(ccid - 1, &el->ccid_tags);
}
intel_engine_context_out(engine);
execlists_context_status_change(engine, rq, INTEL_CONTEXT_SCHEDULE_OUT);
- if (engine->fw_domain && !--engine->fw_active)
- intel_uncore_forcewake_put(engine->uncore, engine->fw_domain);
+ if (el->fw_domain && !--el->fw_active)
+ intel_uncore_forcewake_put(engine->uncore, el->fw_domain);
intel_gt_pm_put_async(engine->gt);
/*
@@ -639,14 +744,14 @@ static void __execlists_schedule_out(struct intel_engine_cs *engine,
* each virtual tree and kick everyone again.
*/
if (ce->engine != engine)
- kick_siblings(engine, rq, ce);
+ kick_siblings(el, rq, ce);
WRITE_ONCE(ce->inflight, NULL);
intel_context_put(ce);
}
static inline void
-execlists_schedule_out(struct intel_engine_cs *engine, struct i915_request *rq)
+execlists_schedule_out(struct intel_execlists *el, struct i915_request *rq)
{
struct intel_context * const ce = rq->context;
@@ -655,7 +760,7 @@ execlists_schedule_out(struct intel_engine_cs *engine, struct i915_request *rq)
GEM_BUG_ON(!ce->inflight);
ce->inflight = ptr_dec(ce->inflight);
if (!__intel_context_inflight_count(ce->inflight))
- __execlists_schedule_out(engine, rq, ce);
+ __execlists_schedule_out(el, rq, ce);
i915_request_put(rq);
}
@@ -707,14 +812,14 @@ static u64 execlists_update_context(struct i915_request *rq)
return desc;
}
-static void write_desc(struct intel_engine_execlists *execlists, u64 desc, u32 port)
+static void write_desc(struct intel_execlists *el, u64 desc, u32 port)
{
- if (execlists->ctrl_reg) {
- writel(lower_32_bits(desc), execlists->submit_reg + port * 2);
- writel(upper_32_bits(desc), execlists->submit_reg + port * 2 + 1);
+ if (el->ctrl_reg) {
+ writel(lower_32_bits(desc), el->submit_reg + port * 2);
+ writel(upper_32_bits(desc), el->submit_reg + port * 2 + 1);
} else {
- writel(upper_32_bits(desc), execlists->submit_reg);
- writel(lower_32_bits(desc), execlists->submit_reg);
+ writel(upper_32_bits(desc), el->submit_reg);
+ writel(lower_32_bits(desc), el->submit_reg);
}
}
@@ -737,52 +842,48 @@ dump_port(char *buf, int buflen, const char *prefix, struct i915_request *rq)
}
static __maybe_unused noinline void
-trace_ports(const struct intel_engine_execlists *execlists,
+trace_ports(const struct intel_execlists *el,
const char *msg,
struct i915_request * const *ports)
{
- const struct intel_engine_cs *engine =
- container_of(execlists, typeof(*engine), execlists);
char __maybe_unused p0[40], p1[40];
if (!ports[0])
return;
- ENGINE_TRACE(engine, "%s { %s%s }\n", msg,
+ ENGINE_TRACE(el->sched.priv, "%s { %s%s }\n", msg,
dump_port(p0, sizeof(p0), "", ports[0]),
dump_port(p1, sizeof(p1), ", ", ports[1]));
}
static __maybe_unused noinline bool
-assert_pending_valid(const struct intel_engine_execlists *execlists,
+assert_pending_valid(const struct intel_execlists *el,
const char *msg)
{
- struct intel_engine_cs *engine =
- container_of(execlists, typeof(*engine), execlists);
struct i915_request * const *port, *rq;
struct intel_context *ce = NULL;
bool sentinel = false;
u32 ccid = -1;
- trace_ports(execlists, msg, execlists->pending);
+ trace_ports(el, msg, el->pending);
/* We may be messing around with the lists during reset, lalala */
- if (__i915_sched_tasklet_is_disabled(intel_engine_get_scheduler(engine)))
+ if (__i915_sched_tasklet_is_disabled(&el->sched))
return true;
- if (!execlists->pending[0]) {
+ if (!el->pending[0]) {
GEM_TRACE_ERR("%s: Nothing pending for promotion!\n",
- engine->name);
+ el->sched.dbg.name);
return false;
}
- if (execlists->pending[execlists_num_ports(execlists)]) {
+ if (el->pending[num_ports(el)]) {
GEM_TRACE_ERR("%s: Excess pending[%d] for promotion!\n",
- engine->name, execlists_num_ports(execlists));
+ el->sched.dbg.name, num_ports(el));
return false;
}
- for (port = execlists->pending; (rq = *port); port++) {
+ for (port = el->pending; (rq = *port); port++) {
unsigned long flags;
bool ok = true;
@@ -791,18 +892,18 @@ assert_pending_valid(const struct intel_engine_execlists *execlists,
if (ce == rq->context) {
GEM_TRACE_ERR("%s: Dup context:%llx in pending[%zd]\n",
- engine->name,
+ el->sched.dbg.name,
ce->timeline->fence_context,
- port - execlists->pending);
+ port - el->pending);
return false;
}
ce = rq->context;
if (ccid == ce->lrc.ccid) {
GEM_TRACE_ERR("%s: Dup ccid:%x context:%llx in pending[%zd]\n",
- engine->name,
+ el->sched.dbg.name,
ccid, ce->timeline->fence_context,
- port - execlists->pending);
+ port - el->pending);
return false;
}
ccid = ce->lrc.ccid;
@@ -814,9 +915,9 @@ assert_pending_valid(const struct intel_engine_execlists *execlists,
*/
if (sentinel) {
GEM_TRACE_ERR("%s: context:%llx after sentinel in pending[%zd]\n",
- engine->name,
+ el->sched.dbg.name,
ce->timeline->fence_context,
- port - execlists->pending);
+ port - el->pending);
return false;
}
sentinel = i915_request_has_sentinel(rq);
@@ -826,12 +927,12 @@ assert_pending_valid(const struct intel_engine_execlists *execlists,
* that they are never stuck behind a hog and can be immediately
* transferred onto the next idle engine.
*/
- if (rq->execution_mask != engine->mask &&
- port != execlists->pending) {
+ if (rq->execution_mask != el->sched.mask &&
+ port != el->pending) {
GEM_TRACE_ERR("%s: virtual engine:%llx not in prime position[%zd]\n",
- engine->name,
+ el->sched.dbg.name,
ce->timeline->fence_context,
- port - execlists->pending);
+ port - el->pending);
return false;
}
@@ -845,27 +946,27 @@ assert_pending_valid(const struct intel_engine_execlists *execlists,
if (i915_active_is_idle(&ce->active) &&
!intel_context_is_barrier(ce)) {
GEM_TRACE_ERR("%s: Inactive context:%llx in pending[%zd]\n",
- engine->name,
+ el->sched.dbg.name,
ce->timeline->fence_context,
- port - execlists->pending);
+ port - el->pending);
ok = false;
goto unlock;
}
if (!i915_vma_is_pinned(ce->state)) {
GEM_TRACE_ERR("%s: Unpinned context:%llx in pending[%zd]\n",
- engine->name,
+ el->sched.dbg.name,
ce->timeline->fence_context,
- port - execlists->pending);
+ port - el->pending);
ok = false;
goto unlock;
}
if (!i915_vma_is_pinned(ce->ring->vma)) {
GEM_TRACE_ERR("%s: Unpinned ring:%llx in pending[%zd]\n",
- engine->name,
+ el->sched.dbg.name,
ce->timeline->fence_context,
- port - execlists->pending);
+ port - el->pending);
ok = false;
goto unlock;
}
@@ -879,12 +980,11 @@ assert_pending_valid(const struct intel_engine_execlists *execlists,
return ce;
}
-static void execlists_submit_ports(struct intel_engine_cs *engine)
+static void execlists_submit_ports(struct intel_execlists *el)
{
- struct intel_engine_execlists *execlists = &engine->execlists;
unsigned int n;
- GEM_BUG_ON(!assert_pending_valid(execlists, "submit"));
+ GEM_BUG_ON(!assert_pending_valid(el, "submit"));
/*
* We can skip acquiring intel_runtime_pm_get() here as it was taken
@@ -894,7 +994,7 @@ static void execlists_submit_ports(struct intel_engine_cs *engine)
* that all ELSP are drained i.e. we have processed the CSB,
* before allowing ourselves to idle and calling intel_runtime_pm_put().
*/
- GEM_BUG_ON(!intel_engine_pm_is_awake(engine));
+ GEM_BUG_ON(!intel_engine_pm_is_awake(el->sched.priv));
/*
* ELSQ note: the submit queue is not cleared after being submitted
@@ -902,17 +1002,15 @@ static void execlists_submit_ports(struct intel_engine_cs *engine)
* currently ensured by the fact that we always write the same number
* of elsq entries, keep this in mind before changing the loop below.
*/
- for (n = execlists_num_ports(execlists); n--; ) {
- struct i915_request *rq = execlists->pending[n];
+ for (n = num_ports(el); n--; ) {
+ struct i915_request *rq = el->pending[n];
- write_desc(execlists,
- rq ? execlists_update_context(rq) : 0,
- n);
+ write_desc(el, rq ? execlists_update_context(rq) : 0, n);
}
/* we need to manually load the submit queue */
- if (execlists->ctrl_reg)
- writel(EL_CTRL_LOAD, execlists->ctrl_reg);
+ if (el->ctrl_reg)
+ writel(EL_CTRL_LOAD, el->ctrl_reg);
}
static bool ctx_single_port_submission(const struct intel_context *ce)
@@ -944,12 +1042,12 @@ static unsigned long i915_request_flags(const struct i915_request *rq)
return READ_ONCE(rq->fence.flags);
}
-static bool can_merge_rq(const struct intel_engine_cs *engine,
+static bool can_merge_rq(const struct intel_execlists *el,
const struct i915_request *prev,
const struct i915_request *next)
{
GEM_BUG_ON(prev == next);
- GEM_BUG_ON(!assert_priority_queue(engine, prev, next));
+ GEM_BUG_ON(!assert_priority_queue(el, prev, next));
/*
* We do not submit known completed requests. Therefore if the next
@@ -976,14 +1074,14 @@ static bool can_merge_rq(const struct intel_engine_cs *engine,
static bool virtual_matches(const struct virtual_engine *ve,
const struct i915_request *rq,
- const struct intel_engine_cs *engine)
+ const struct intel_execlists *el)
{
const struct intel_engine_cs *inflight;
if (!rq)
return false;
- if (!(rq->execution_mask & engine->mask)) /* We peeked too soon! */
+ if (!(rq->execution_mask & el->sched.mask)) /* We peeked too soon! */
return false;
/*
@@ -996,7 +1094,7 @@ static bool virtual_matches(const struct virtual_engine *ve,
* hystersis on the greedy seelction algorithm.
*/
inflight = intel_context_inflight(&ve->context);
- if (inflight && inflight != engine)
+ if (inflight && inflight != el->sched.priv)
return false;
return true;
@@ -1034,7 +1132,7 @@ static void virtual_xfer_context(struct virtual_engine *ve,
}
static bool
-timeslice_yield(const struct intel_engine_execlists *el,
+timeslice_yield(const struct intel_execlists *el,
const struct i915_request *rq)
{
/*
@@ -1052,12 +1150,10 @@ timeslice_yield(const struct intel_engine_execlists *el,
return rq->context->lrc.ccid == READ_ONCE(el->yield);
}
-static bool needs_timeslice(const struct intel_engine_cs *engine,
+static bool needs_timeslice(const struct intel_execlists *el,
const struct i915_request *rq)
{
- const struct i915_sched *se = engine->sched;
-
- if (!i915_sched_has_timeslices(se))
+ if (!i915_sched_has_timeslices(&el->sched))
return false;
/* If not currently active, or about to switch, wait for next event */
@@ -1065,23 +1161,24 @@ static bool needs_timeslice(const struct intel_engine_cs *engine,
return false;
/* We do not need to start the timeslice until after the ACK */
- if (READ_ONCE(engine->execlists.pending[0]))
+ if (READ_ONCE(el->pending[0]))
return false;
/* If ELSP[1] is occupied, always check to see if worth slicing */
- if (!i915_sched_is_last_request(se, rq)) {
- ENGINE_TRACE(engine, "timeslice required for second inflight context\n");
+ if (!i915_sched_is_last_request(&el->sched, rq)) {
+ ENGINE_TRACE(el->sched.priv,
+ "timeslice required for second inflight context\n");
return true;
}
/* Otherwise, ELSP[0] is by itself, but may be waiting in the queue */
- if (!i915_sched_is_idle(se)) {
- ENGINE_TRACE(engine, "timeslice required for queue\n");
+ if (!i915_sched_is_idle(&el->sched)) {
+ ENGINE_TRACE(el->sched.priv, "timeslice required for queue\n");
return true;
}
- if (!RB_EMPTY_ROOT(&engine->execlists.virtual.rb_root)) {
- ENGINE_TRACE(engine, "timeslice required for virtual\n");
+ if (!RB_EMPTY_ROOT(&el->virtual.rb_root)) {
+ ENGINE_TRACE(el->sched.priv, "timeslice required for virtual\n");
return true;
}
@@ -1089,14 +1186,12 @@ static bool needs_timeslice(const struct intel_engine_cs *engine,
}
static bool
-timeslice_expired(struct intel_engine_cs *engine, const struct i915_request *rq)
+timeslice_expired(struct intel_execlists *el, const struct i915_request *rq)
{
- const struct intel_engine_execlists *el = &engine->execlists;
-
if (i915_request_has_nopreempt(rq) && __i915_request_has_started(rq))
return false;
- if (!needs_timeslice(engine, rq))
+ if (!needs_timeslice(el, rq))
return false;
return timer_expired(&el->timer) || timeslice_yield(el, rq);
@@ -1107,14 +1202,13 @@ static unsigned long timeslice(const struct intel_engine_cs *engine)
return READ_ONCE(engine->props.timeslice_duration_ms);
}
-static void start_timeslice(struct intel_engine_cs *engine)
+static void start_timeslice(struct intel_execlists *el)
{
- struct intel_engine_execlists *el = &engine->execlists;
unsigned long duration;
/* Disable the timer if there is nothing to switch to */
duration = 0;
- if (needs_timeslice(engine, *el->active)) {
+ if (needs_timeslice(el, *el->active)) {
/* Avoid continually prolonging an active timeslice */
if (timer_active(&el->timer)) {
/*
@@ -1123,19 +1217,19 @@ static void start_timeslice(struct intel_engine_cs *engine)
* its timeslice, so recheck.
*/
if (!timer_pending(&el->timer))
- intel_engine_kick_scheduler(engine);
+ i915_sched_kick(&el->sched);
return;
}
- duration = timeslice(engine);
+ duration = timeslice(el->sched.priv);
}
set_timer_ms(&el->timer, duration);
}
-static void record_preemption(struct intel_engine_execlists *execlists)
+static void record_preemption(struct intel_execlists *el)
{
- (void)I915_SELFTEST_ONLY(execlists->preempt_hang.count++);
+ (void)I915_SELFTEST_ONLY(el->preempt_hang.count++);
}
static unsigned long active_preempt_timeout(struct intel_engine_cs *engine,
@@ -1151,14 +1245,13 @@ static unsigned long active_preempt_timeout(struct intel_engine_cs *engine,
return READ_ONCE(engine->props.preempt_timeout_ms);
}
-static void set_preempt_timeout(struct intel_engine_cs *engine,
+static void set_preempt_timeout(struct intel_execlists *el,
const struct i915_request *rq)
{
- if (!intel_engine_has_preempt_reset(engine))
+ if (!intel_engine_has_preempt_reset(el->sched.priv))
return;
- set_timer_ms(&engine->execlists.preempt,
- active_preempt_timeout(engine, rq));
+ set_timer_ms(&el->preempt, active_preempt_timeout(el->sched.priv, rq));
}
static bool completed(const struct i915_request *rq)
@@ -1169,25 +1262,33 @@ static bool completed(const struct i915_request *rq)
return __i915_request_is_complete(rq);
}
-static void __virtual_dequeue(struct virtual_engine *ve,
- struct intel_engine_cs *sibling)
+#define as_execlists(se) \
+ container_of(se, const struct intel_execlists, sched)
+
+static struct intel_execlists *to_execlists(struct intel_engine_cs *e)
{
- struct ve_node * const node = &ve->nodes[sibling->id];
+ return container_of(e->sched, struct intel_execlists, sched);
+}
+
+static void __virtual_dequeue(struct virtual_engine *ve,
+ struct intel_execlists *el)
+{
+ struct ve_node * const node = &ve->nodes[el->id];
struct rb_node **parent, *rb;
struct i915_request *rq;
u64 deadline;
bool first;
- rb_erase_cached(&node->rb, &sibling->execlists.virtual);
+ rb_erase_cached(&node->rb, &el->virtual);
RB_CLEAR_NODE(&node->rb);
rq = first_request(ve->base.sched);
- if (!virtual_matches(ve, rq, sibling))
+ if (!virtual_matches(ve, rq, el))
return;
rb = NULL;
first = true;
- parent = &sibling->execlists.virtual.rb_root.rb_node;
+ parent = &el->virtual.rb_root.rb_node;
deadline = rq_deadline(rq);
while (*parent) {
struct ve_node *other;
@@ -1203,24 +1304,23 @@ static void __virtual_dequeue(struct virtual_engine *ve,
}
rb_link_node(&node->rb, rb, parent);
- rb_insert_color_cached(&node->rb, &sibling->execlists.virtual, first);
+ rb_insert_color_cached(&node->rb, &el->virtual, first);
}
-static void virtual_requeue(struct intel_engine_cs *engine,
+static void virtual_requeue(struct intel_execlists *el,
struct i915_request *last)
{
- const struct i915_request * const first =
- first_request(intel_engine_get_scheduler(engine));
+ const struct i915_request * const first = first_request(&el->sched);
struct virtual_engine *ve;
- while ((ve = first_virtual_engine(engine))) {
+ while ((ve = first_virtual_engine(el))) {
struct i915_sched *se = intel_engine_get_scheduler(&ve->base);
struct i915_request *rq;
spin_lock(&se->lock);
rq = first_request(se);
- if (unlikely(!virtual_matches(ve, rq, engine)))
+ if (unlikely(!virtual_matches(ve, rq, el)))
/* lost the race to a sibling */
goto unlock;
@@ -1236,7 +1336,7 @@ static void virtual_requeue(struct intel_engine_cs *engine,
return;
}
- ENGINE_TRACE(engine,
+ ENGINE_TRACE(el->sched.priv,
"virtual rq=%llx:%lld%s, dl %lld, new engine? %s\n",
rq->fence.context,
rq->fence.seqno,
@@ -1244,10 +1344,10 @@ static void virtual_requeue(struct intel_engine_cs *engine,
__i915_request_has_started(rq) ? "*" :
"",
rq_deadline(rq),
- yesno(engine != ve->siblings[0]));
+ yesno(el->sched.priv != ve->siblings[0]));
- GEM_BUG_ON(!(rq->execution_mask & engine->mask));
- if (__i915_request_requeue(rq, engine->sched)) {
+ GEM_BUG_ON(!(rq->execution_mask & el->sched.mask));
+ if (__i915_request_requeue(rq, &el->sched)) {
/*
* Only after we confirm that we will submit
* this request (i.e. it has not already
@@ -1261,30 +1361,29 @@ static void virtual_requeue(struct intel_engine_cs *engine,
* we may be using ve->siblings[] in
* virtual_context_enter / virtual_context_exit.
*/
- virtual_xfer_context(ve, engine);
+ virtual_xfer_context(ve, el->sched.priv);
/* Bind this ve before we release the lock */
if (!ve->context.inflight)
- WRITE_ONCE(ve->context.inflight, engine);
+ WRITE_ONCE(ve->context.inflight,
+ el->sched.priv);
- GEM_BUG_ON(ve->siblings[0] != engine);
- GEM_BUG_ON(intel_context_inflight(rq->context) != engine);
+ GEM_BUG_ON(ve->siblings[0] != el->sched.priv);
+ GEM_BUG_ON(intel_context_inflight(rq->context) != el->sched.priv);
last = rq;
}
unlock:
- __virtual_dequeue(ve, engine);
+ __virtual_dequeue(ve, el);
spin_unlock(&se->lock);
}
}
-static void execlists_dequeue(struct intel_engine_cs *engine)
+static void execlists_dequeue(struct intel_execlists *el)
{
- struct intel_engine_execlists * const execlists = &engine->execlists;
- struct i915_sched *se = intel_engine_get_scheduler(engine);
- struct i915_request **port = execlists->pending;
- struct i915_request ** const last_port = port + execlists->port_mask;
+ struct i915_request **port = el->pending;
+ struct i915_request ** const last_port = port + el->port_mask;
struct i915_request *last, * const *active;
struct i915_request *rq, *rn;
struct i915_priolist *pl;
@@ -1321,28 +1420,28 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* of trouble.
*
*/
- active = execlists->active;
+ active = el->active;
while ((last = *active) && completed(last))
active++;
if (last) {
- if (need_preempt(engine, last)) {
- ENGINE_TRACE(engine,
+ if (need_preempt(el, last)) {
+ ENGINE_TRACE(el->sched.priv,
"preempting last=%llx:%llu, dl=%llu, prio=%d\n",
last->fence.context,
last->fence.seqno,
rq_deadline(last),
rq_prio(last));
- record_preemption(execlists);
+ record_preemption(el);
last = (void *)1;
- } else if (timeslice_expired(engine, last)) {
- ENGINE_TRACE(engine,
+ } else if (timeslice_expired(el, last)) {
+ ENGINE_TRACE(el->sched.priv,
"expired:%s last=%llx:%llu, deadline=%llu, now=%llu, yield?=%s\n",
- yesno(timer_expired(&execlists->timer)),
+ yesno(timer_expired(&el->timer)),
last->fence.context, last->fence.seqno,
rq_deadline(last),
i915_sched_to_ticks(ktime_get()),
- yesno(timeslice_yield(execlists, last)));
+ yesno(timeslice_yield(el, last)));
/*
* Consume this timeslice; ensure we start a new one.
@@ -1360,7 +1459,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* consumption of this timeslice, if we submit the
* same context again, grant it a full timeslice.
*/
- cancel_timer(&execlists->timer);
+ cancel_timer(&el->timer);
/*
* Unlike for preemption, if we rewind and continue
@@ -1397,7 +1496,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
}
local_irq_disable(); /* irq remains off until after ELSP write */
- spin_lock(&se->lock);
+ spin_lock(&el->sched.lock);
if ((unsigned long)last & 1) {
bool defer = (unsigned long)last & 2;
@@ -1407,7 +1506,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* as we unwind (and until we resubmit) so that we do
* not accidentally tell it to go backwards.
*/
- ring_set_paused(engine, (unsigned long)last);
+ ring_set_paused(el, (unsigned long)last);
/*
* Note that we have not stopped the GPU at this point,
@@ -1416,7 +1515,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* the preemption, some of the unwound requests may
* complete!
*/
- last = __i915_sched_rewind_requests(se);
+ last = __i915_sched_rewind_requests(&el->sched);
/*
* We want to move the interrupted request to the back of
@@ -1426,18 +1525,18 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* be run after it again.
*/
if (last && defer)
- __i915_sched_defer_request(se, last);
+ __i915_sched_defer_request(&el->sched, last);
last = NULL;
}
- if (!RB_EMPTY_ROOT(&execlists->virtual.rb_root))
- virtual_requeue(engine, last);
+ if (!RB_EMPTY_ROOT(&el->virtual.rb_root))
+ virtual_requeue(el, last);
- i915_sched_dequeue(se, pl, rq, rn) {
+ i915_sched_dequeue(&el->sched, pl, rq, rn) {
bool merge = true;
- GEM_BUG_ON(i915_request_get_scheduler(rq) != se);
+ GEM_BUG_ON(i915_request_get_scheduler(rq) != &el->sched);
/*
* Can we combine this request with the current port?
@@ -1450,7 +1549,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* second request, and so we never need to tell the
* hardware about the first.
*/
- if (last && !can_merge_rq(engine, last, rq)) {
+ if (last && !can_merge_rq(el, last, rq)) {
/*
* If we are on the second port and cannot
* combine this request with the last, then we
@@ -1476,10 +1575,10 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* the request immediately to another engine
* rather than wait for the primary request.
*/
- if (rq->execution_mask != engine->mask)
+ if (rq->execution_mask != el->sched.mask)
goto done;
- if (unlikely(dl_before(first_virtual(engine), rq)))
+ if (unlikely(dl_before(first_virtual(el), rq)))
goto done;
/*
@@ -1496,7 +1595,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
merge = false;
}
- if (__i915_request_submit(rq, engine)) {
+ if (__i915_request_submit(rq, el->sched.priv)) {
if (!merge) {
*port++ = i915_request_get(last);
last = NULL;
@@ -1515,7 +1614,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
}
done:
*port++ = i915_request_get(last);
- spin_unlock(&se->lock);
+ spin_unlock(&el->sched.lock);
/*
* We can skip poking the HW if we ended up with exactly the same set
@@ -1524,21 +1623,20 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
*/
if (submit &&
memcmp(active,
- execlists->pending,
- (port - execlists->pending) * sizeof(*port))) {
+ el->pending,
+ (port - el->pending) * sizeof(*port))) {
*port = NULL;
- while (port-- != execlists->pending)
- execlists_schedule_in(engine, *port,
- port - execlists->pending);
+ while (port-- != el->pending)
+ execlists_schedule_in(el, *port, port - el->pending);
- WRITE_ONCE(execlists->yield, -1);
- set_preempt_timeout(engine, *active);
- execlists_submit_ports(engine);
+ WRITE_ONCE(el->yield, -1);
+ set_preempt_timeout(el, *active);
+ execlists_submit_ports(el);
} else {
- ring_set_paused(engine, 0);
- while (port-- != execlists->pending)
+ ring_set_paused(el, 0);
+ while (port-- != el->pending)
i915_request_put(*port);
- *execlists->pending = NULL;
+ *el->pending = NULL;
}
local_irq_enable();
@@ -1558,27 +1656,27 @@ copy_ports(struct i915_request **dst, struct i915_request **src, int count)
}
static struct i915_request **
-cancel_port_requests(struct intel_engine_execlists * const execlists,
+cancel_port_requests(struct intel_execlists * const el,
struct i915_request **inactive)
{
struct i915_request * const *port;
- for (port = execlists->pending; *port; port++)
+ for (port = el->pending; *port; port++)
*inactive++ = *port;
- clear_ports(execlists->pending, ARRAY_SIZE(execlists->pending));
+ clear_ports(el->pending, ARRAY_SIZE(el->pending));
/* Mark the end of active before we overwrite *active */
- for (port = xchg(&execlists->active, execlists->pending); *port; port++)
+ for (port = xchg(&el->active, el->pending); *port; port++)
*inactive++ = *port;
- clear_ports(execlists->inflight, ARRAY_SIZE(execlists->inflight));
+ clear_ports(el->inflight, ARRAY_SIZE(el->inflight));
smp_wmb(); /* complete the seqlock for execlists_active() */
- WRITE_ONCE(execlists->active, execlists->inflight);
+ WRITE_ONCE(el->active, el->inflight);
/* Having cancelled all outstanding process_csb(), stop their timers */
- GEM_BUG_ON(execlists->pending[0]);
- cancel_timer(&execlists->timer);
- cancel_timer(&execlists->preempt);
+ GEM_BUG_ON(el->pending[0]);
+ cancel_timer(&el->timer);
+ cancel_timer(&el->preempt);
return inactive;
}
@@ -1648,7 +1746,7 @@ static bool gen8_csb_parse(const u64 csb)
}
static noinline u64
-wa_csb_read(const struct intel_engine_cs *engine, u64 * const csb)
+wa_csb_read(const struct intel_execlists *el, u64 * const csb)
{
u64 entry;
@@ -1663,7 +1761,8 @@ wa_csb_read(const struct intel_engine_cs *engine, u64 * const csb)
*/
preempt_disable();
if (wait_for_atomic_us((entry = READ_ONCE(*csb)) != -1, 10)) {
- int idx = csb - engine->execlists.csb_status;
+ struct intel_engine_cs *engine = el->sched.priv;
+ int idx = csb - el->csb_status;
int status;
status = GEN8_EXECLISTS_STATUS_BUF;
@@ -1681,7 +1780,7 @@ wa_csb_read(const struct intel_engine_cs *engine, u64 * const csb)
return entry;
}
-static u64 csb_read(const struct intel_engine_cs *engine, u64 * const csb)
+static u64 csb_read(const struct intel_execlists *el, u64 * const csb)
{
u64 entry = READ_ONCE(*csb);
@@ -1697,7 +1796,7 @@ static u64 csb_read(const struct intel_engine_cs *engine, u64 * const csb)
* tgl:HSDES#22011248461
*/
if (unlikely(entry == -1))
- entry = wa_csb_read(engine, csb);
+ entry = wa_csb_read(el, csb);
/* Consume this entry so that we can spot its future reuse. */
WRITE_ONCE(*csb, -1);
@@ -1706,18 +1805,22 @@ static u64 csb_read(const struct intel_engine_cs *engine, u64 * const csb)
return entry;
}
-static void new_timeslice(struct intel_engine_execlists *el)
+static void new_timeslice(struct intel_execlists *el)
{
/* By cancelling, we will start afresh in start_timeslice() */
cancel_timer(&el->timer);
}
-static struct i915_request **
-process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
+static void process_csb_delay(struct intel_engine_cs *engine)
{
- struct intel_engine_execlists * const execlists = &engine->execlists;
- u64 * const buf = execlists->csb_status;
- const u8 num_entries = execlists->csb_size;
+ ENGINE_POSTING_READ(engine, RING_CONTEXT_STATUS_PTR);
+}
+
+static struct i915_request **
+process_csb(struct intel_execlists *el, struct i915_request **inactive)
+{
+ u64 * const buf = el->csb_status;
+ const u8 num_entries = el->csb_size;
struct i915_request **prev;
u8 head, tail;
@@ -1731,8 +1834,8 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
* to use explicit shifting and masking, and probably bifurcating
* the code to handle the legacy mmio read).
*/
- head = execlists->csb_head;
- tail = READ_ONCE(*execlists->csb_write);
+ head = el->csb_head;
+ tail = READ_ONCE(*el->csb_write);
if (unlikely(head == tail))
return inactive;
@@ -1752,8 +1855,8 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
* simplest way is by stop processing the event queue and force the
* engine to reset.
*/
- execlists->csb_head = tail;
- ENGINE_TRACE(engine, "cs-irq head=%d, tail=%d\n", head, tail);
+ el->csb_head = tail;
+ ENGINE_TRACE(el->sched.priv, "cs-irq head=%d, tail=%d\n", head, tail);
/*
* Hopefully paired with a wmb() in HW!
@@ -1794,53 +1897,51 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
* status notifier.
*/
- csb = csb_read(engine, buf + head);
- ENGINE_TRACE(engine, "csb[%d]: status=0x%08x:0x%08x\n",
+ csb = csb_read(el, buf + head);
+ ENGINE_TRACE(el->sched.priv, "csb[%d]: status=0x%08x:0x%08x\n",
head, upper_32_bits(csb), lower_32_bits(csb));
- if (INTEL_GEN(engine->i915) >= 12)
+ if (el->flags & GEN12_CSB_PARSE)
promote = gen12_csb_parse(csb);
else
promote = gen8_csb_parse(csb);
if (promote) {
- struct i915_request * const *old = execlists->active;
+ struct i915_request * const *old = el->active;
- if (GEM_WARN_ON(!*execlists->pending)) {
- execlists->error_interrupt |= ERROR_CSB;
+ if (GEM_WARN_ON(!*el->pending)) {
+ el->error_interrupt |= ERROR_CSB;
break;
}
- ring_set_paused(engine, 0);
+ ring_set_paused(el, 0);
/* Point active to the new ELSP; prevent overwriting */
- WRITE_ONCE(execlists->active, execlists->pending);
+ WRITE_ONCE(el->active, el->pending);
smp_wmb(); /* notify execlists_active() */
/* cancel old inflight, prepare for switch */
- trace_ports(execlists, "preempted", old);
+ trace_ports(el, "preempted", old);
while (*old)
*inactive++ = *old++;
/* switch pending to inflight */
- GEM_BUG_ON(!assert_pending_valid(execlists, "promote"));
- copy_ports(execlists->inflight,
- execlists->pending,
- execlists_num_ports(execlists));
+ GEM_BUG_ON(!assert_pending_valid(el, "promote"));
+ copy_ports(el->inflight, el->pending, num_ports(el));
smp_wmb(); /* complete the seqlock */
- WRITE_ONCE(execlists->active, execlists->inflight);
+ WRITE_ONCE(el->active, el->inflight);
/* XXX Magic delay for tgl */
- ENGINE_POSTING_READ(engine, RING_CONTEXT_STATUS_PTR);
+ process_csb_delay(el->sched.priv);
- WRITE_ONCE(execlists->pending[0], NULL);
+ WRITE_ONCE(el->pending[0], NULL);
} else {
- if (GEM_WARN_ON(!*execlists->active)) {
- execlists->error_interrupt |= ERROR_CSB;
+ if (GEM_WARN_ON(!*el->active)) {
+ el->error_interrupt |= ERROR_CSB;
break;
}
/* port0 completed, advanced to port1 */
- trace_ports(execlists, "completed", execlists->active);
+ trace_ports(el, "completed", el->active);
/*
* We rely on the hardware being strongly
@@ -1853,10 +1954,12 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
* itself...
*/
if (GEM_SHOW_DEBUG() &&
- !__i915_request_is_complete(*execlists->active)) {
- struct i915_request *rq = *execlists->active;
+ !__i915_request_is_complete(*el->active)) {
+ struct i915_request *rq = *el->active;
const u32 *regs __maybe_unused =
rq->context->lrc_reg_state;
+ struct intel_engine_cs *engine __maybe_unused =
+ el->sched.priv;
ENGINE_TRACE(engine,
"context completed before request!\n");
@@ -1881,10 +1984,9 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
regs[CTX_RING_TAIL]);
}
- *inactive++ = *execlists->active++;
+ *inactive++ = *el->active++;
- GEM_BUG_ON(execlists->active - execlists->inflight >
- execlists_num_ports(execlists));
+ GEM_BUG_ON(el->active - el->inflight > num_ports(el));
}
} while (head != tail);
@@ -1906,7 +2008,7 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
* and merits a fresh timeslice. We reinstall the timer after
* inspecting the queue to see if we need to resumbit.
*/
- if (*prev != *execlists->active) { /* elide lite-restores */
+ if (*prev != *el->active) { /* elide lite-restores */
/*
* Note the inherent discrepancy between the HW runtime,
* recorded as part of the context switch, and the CPU
@@ -1919,20 +2021,20 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
*/
if (*prev)
lrc_runtime_stop((*prev)->context);
- if (*execlists->active)
- lrc_runtime_start((*execlists->active)->context);
- new_timeslice(execlists);
+ if (*el->active)
+ lrc_runtime_start((*el->active)->context);
+ new_timeslice(el);
}
return inactive;
}
-static void post_process_csb(struct intel_engine_cs *engine,
+static void post_process_csb(struct intel_execlists *el,
struct i915_request **port,
struct i915_request **last)
{
while (port != last)
- execlists_schedule_out(engine, *port++);
+ execlists_schedule_out(el, *port++);
}
struct execlists_capture {
@@ -2007,9 +2109,8 @@ static struct execlists_capture *capture_regs(struct intel_engine_cs *engine)
}
static struct i915_request *
-active_context(struct intel_engine_cs *engine, u32 ccid)
+active_context(struct intel_execlists *el, u32 ccid)
{
- const struct intel_engine_execlists * const el = &engine->execlists;
struct i915_request * const *port, *rq;
/*
@@ -2020,7 +2121,7 @@ active_context(struct intel_engine_cs *engine, u32 ccid)
for (port = el->active; (rq = *port); port++) {
if (rq->context->lrc.ccid == ccid) {
- ENGINE_TRACE(engine,
+ ENGINE_TRACE(el->sched.priv,
"ccid:%x found at active:%zd\n",
ccid, port - el->active);
return rq;
@@ -2029,14 +2130,14 @@ active_context(struct intel_engine_cs *engine, u32 ccid)
for (port = el->pending; (rq = *port); port++) {
if (rq->context->lrc.ccid == ccid) {
- ENGINE_TRACE(engine,
+ ENGINE_TRACE(el->sched.priv,
"ccid:%x found at pending:%zd\n",
ccid, port - el->pending);
return rq;
}
}
- ENGINE_TRACE(engine, "ccid:%x not found\n", ccid);
+ ENGINE_TRACE(el->sched.priv, "ccid:%x not found\n", ccid);
return NULL;
}
@@ -2045,7 +2146,7 @@ static u32 active_ccid(struct intel_engine_cs *engine)
return ENGINE_READ_FW(engine, RING_EXECLIST_STATUS_HI);
}
-static void execlists_capture(struct intel_engine_cs *engine)
+static void execlists_capture(struct intel_execlists *el)
{
struct execlists_capture *cap;
struct i915_request *rq;
@@ -2053,7 +2154,7 @@ static void execlists_capture(struct intel_engine_cs *engine)
if (!IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR))
return;
- rq = active_context(engine, active_ccid(engine));
+ rq = active_context(el, active_ccid(el->sched.priv));
/*
* If the context is closed or already banned, assume no one is
@@ -2071,7 +2172,7 @@ static void execlists_capture(struct intel_engine_cs *engine)
* We are inside an atomic section (softirq) here and we are delaying
* the forced preemption event.
*/
- cap = capture_regs(engine);
+ cap = capture_regs(el->sched.priv);
if (!cap)
return;
@@ -2100,7 +2201,7 @@ static void execlists_capture(struct intel_engine_cs *engine)
* simply hold that request accountable for being non-preemptible
* long enough to force the reset.
*/
- if (!i915_sched_suspend_request(engine->sched, cap->rq))
+ if (!i915_sched_suspend_request(&el->sched, cap->rq))
goto err_rq;
INIT_WORK(&cap->work, execlists_capture_work);
@@ -2114,12 +2215,12 @@ static void execlists_capture(struct intel_engine_cs *engine)
kfree(cap);
}
-static noinline void execlists_reset(struct intel_engine_cs *engine)
+static noinline void execlists_reset(struct intel_execlists *el)
{
- struct i915_sched *se = intel_engine_get_scheduler(engine);
+ struct intel_engine_cs *engine = el->sched.priv;
const unsigned int bit = I915_RESET_ENGINE + engine->id;
unsigned long *lock = &engine->gt->reset.flags;
- unsigned long eir = fetch_and_zero(&engine->execlists.error_interrupt);
+ unsigned long eir = fetch_and_zero(&el->error_interrupt);
const char *msg;
if (!intel_has_reset_engine(engine->gt))
@@ -2140,19 +2241,19 @@ static noinline void execlists_reset(struct intel_engine_cs *engine)
ENGINE_TRACE(engine, "reset for %s\n", msg);
/* Mark this tasklet as disabled to avoid waiting for it to complete */
- tasklet_disable_nosync(&se->tasklet);
+ tasklet_disable_nosync(&el->sched.tasklet);
- ring_set_paused(engine, 1); /* Freeze the current request in place */
- execlists_capture(engine);
- intel_engine_reset(engine, msg);
+ ring_set_paused(el, 1); /* Freeze the current request in place */
+ execlists_capture(el);
+ intel_engine_reset(el->sched.priv, msg);
- tasklet_enable(&se->tasklet);
+ tasklet_enable(&el->sched.tasklet);
clear_and_wake_up_bit(bit, lock);
}
-static bool preempt_timeout(const struct intel_engine_cs *const engine)
+static bool preempt_timeout(const struct intel_execlists *const el)
{
- const struct timer_list *t = &engine->execlists.preempt;
+ const struct timer_list *t = &el->preempt;
if (!CONFIG_DRM_I915_PREEMPT_TIMEOUT)
return false;
@@ -2160,7 +2261,7 @@ static bool preempt_timeout(const struct intel_engine_cs *const engine)
if (!timer_expired(t))
return false;
- return engine->execlists.pending[0];
+ return el->pending[0];
}
/*
@@ -2169,8 +2270,7 @@ static bool preempt_timeout(const struct intel_engine_cs *const engine)
*/
static void execlists_submission_tasklet(struct tasklet_struct *t)
{
- struct i915_sched * const se = from_tasklet(se, t, tasklet);
- struct intel_engine_cs *engine = se->priv;
+ struct intel_execlists *el = from_tasklet(el, t, sched.tasklet);
struct i915_request *post[2 * EXECLIST_MAX_PORTS];
struct i915_request **inactive;
@@ -2181,28 +2281,29 @@ static void execlists_submission_tasklet(struct tasklet_struct *t)
*/
rcu_read_lock();
- inactive = process_csb(engine, post);
+ inactive = process_csb(el, post);
GEM_BUG_ON(inactive - post > ARRAY_SIZE(post));
- if (unlikely(preempt_timeout(engine))) {
- cancel_timer(&engine->execlists.preempt);
- engine->execlists.error_interrupt |= ERROR_PREEMPT;
+ if (unlikely(preempt_timeout(el))) {
+ cancel_timer(&el->preempt);
+ el->error_interrupt |= ERROR_PREEMPT;
}
- if (unlikely(READ_ONCE(engine->execlists.error_interrupt)))
- execlists_reset(engine);
+ if (unlikely(READ_ONCE(el->error_interrupt)))
+ execlists_reset(el);
- if (!engine->execlists.pending[0]) {
- execlists_dequeue(engine);
- start_timeslice(engine);
+ if (!el->pending[0]) {
+ execlists_dequeue(el);
+ start_timeslice(el);
}
- post_process_csb(engine, post, inactive);
+ post_process_csb(el, post, inactive);
rcu_read_unlock();
}
static void execlists_irq_handler(struct intel_engine_cs *engine, u16 iir)
{
+ struct intel_execlists *el = to_execlists(engine);
bool tasklet = false;
if (unlikely(iir & GT_CS_MASTER_ERROR_INTERRUPT)) {
@@ -2216,17 +2317,16 @@ static void execlists_irq_handler(struct intel_engine_cs *engine, u16 iir)
if (likely(eir)) {
ENGINE_WRITE(engine, RING_EMR, ~0u);
ENGINE_WRITE(engine, RING_EIR, eir);
- WRITE_ONCE(engine->execlists.error_interrupt, eir);
+ WRITE_ONCE(el->error_interrupt, eir);
tasklet = true;
}
}
if (iir & GT_WAIT_SEMAPHORE_INTERRUPT) {
- WRITE_ONCE(engine->execlists.yield,
+ WRITE_ONCE(el->yield,
ENGINE_READ_FW(engine, RING_EXECLIST_STATUS_HI));
- ENGINE_TRACE(engine, "semaphore yield: %08x\n",
- engine->execlists.yield);
- if (del_timer(&engine->execlists.timer))
+ ENGINE_TRACE(engine, "semaphore yield: %08x\n", el->yield);
+ if (del_timer(&el->timer))
tasklet = true;
}
@@ -2237,19 +2337,17 @@ static void execlists_irq_handler(struct intel_engine_cs *engine, u16 iir)
intel_engine_signal_breadcrumbs(engine);
if (tasklet)
- intel_engine_kick_scheduler(engine);
+ i915_sched_kick(&el->sched);
}
-static void __execlists_kick(struct intel_engine_execlists *execlists)
-{
- struct intel_engine_cs *engine =
- container_of(execlists, typeof(*engine), execlists);
- intel_engine_kick_scheduler(engine);
+static void __execlists_kick(struct intel_execlists *el)
+{
+ i915_sched_kick(&el->sched);
}
#define execlists_kick(t, member) \
- __execlists_kick(container_of(t, struct intel_engine_execlists, member))
+ __execlists_kick(container_of(t, struct intel_execlists, member))
static void execlists_timeslice(struct timer_list *timer)
{
@@ -2391,12 +2489,12 @@ static const struct intel_context_ops execlists_context_ops = {
.destroy = lrc_destroy,
};
-static void reset_csb_pointers(struct intel_engine_cs *engine)
+static void reset_csb_pointers(struct intel_execlists *el)
{
- struct intel_engine_execlists * const execlists = &engine->execlists;
- const unsigned int reset_value = execlists->csb_size - 1;
+ struct intel_engine_cs *engine = el->sched.priv;
+ const unsigned int reset_value = el->csb_size - 1;
- ring_set_paused(engine, 0);
+ ring_set_paused(el, 0);
/*
* Sometimes Icelake forgets to reset its pointers on a GPU reset.
@@ -2415,21 +2513,21 @@ static void reset_csb_pointers(struct intel_engine_cs *engine)
* inline comparison of our cached head position against the last HW
* write works even before the first interrupt.
*/
- execlists->csb_head = reset_value;
- WRITE_ONCE(*execlists->csb_write, reset_value);
+ el->csb_head = reset_value;
+ WRITE_ONCE(*el->csb_write, reset_value);
wmb(); /* Make sure this is visible to HW (paranoia?) */
/* Check that the GPU does indeed update the CSB entries! */
- memset(execlists->csb_status, -1, (reset_value + 1) * sizeof(u64));
- invalidate_csb_entries(&execlists->csb_status[0],
- &execlists->csb_status[reset_value]);
+ memset(el->csb_status, -1, (reset_value + 1) * sizeof(u64));
+ invalidate_csb_entries(&el->csb_status[0],
+ &el->csb_status[reset_value]);
/* Once more for luck and our trusty paranoia */
ENGINE_WRITE(engine, RING_CONTEXT_STATUS_PTR,
0xffff << 16 | reset_value << 8 | reset_value);
ENGINE_POSTING_READ(engine, RING_CONTEXT_STATUS_PTR);
- GEM_BUG_ON(READ_ONCE(*execlists->csb_write) != reset_value);
+ GEM_BUG_ON(READ_ONCE(*el->csb_write) != reset_value);
}
static void sanitize_hwsp(struct intel_engine_cs *engine)
@@ -2442,7 +2540,7 @@ static void sanitize_hwsp(struct intel_engine_cs *engine)
static void execlists_sanitize(struct intel_engine_cs *engine)
{
- GEM_BUG_ON(*engine->execlists.active);
+ GEM_BUG_ON(*to_execlists(engine)->active);
/*
* Poison residual state on resume, in case the suspend didn't!
@@ -2456,7 +2554,7 @@ static void execlists_sanitize(struct intel_engine_cs *engine)
if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
memset(engine->status_page.addr, POISON_INUSE, PAGE_SIZE);
- reset_csb_pointers(engine);
+ reset_csb_pointers(to_execlists(engine));
/*
* The kernel_context HWSP is stored in the status_page. As above,
@@ -2475,7 +2573,7 @@ static void enable_error_interrupt(struct intel_engine_cs *engine)
/* Flush ongoing GT interrupts before touching interrupt state */
synchronize_hardirq(engine->i915->drm.irq);
- engine->execlists.error_interrupt = 0;
+ to_execlists(engine)->error_interrupt = 0;
ENGINE_WRITE(engine, RING_EMR, ~0u);
ENGINE_WRITE(engine, RING_EIR, ~0u); /* clear all existing errors */
@@ -2551,6 +2649,8 @@ static int execlists_resume(struct intel_engine_cs *engine)
static void execlists_reset_prepare(struct intel_engine_cs *engine)
{
+ struct intel_execlists *el = to_execlists(engine);
+
/*
* Prevent request submission to the hardware until we have
* completed the reset in i915_gem_reset_finish(). If a request
@@ -2560,7 +2660,7 @@ static void execlists_reset_prepare(struct intel_engine_cs *engine)
* Turning off the execlists->tasklet until the reset is over
* prevents the race.
*/
- i915_sched_disable_tasklet(intel_engine_get_scheduler(engine));
+ i915_sched_disable_tasklet(&el->sched);
/*
* We stop engines, otherwise we might get failed reset and a
@@ -2574,31 +2674,29 @@ static void execlists_reset_prepare(struct intel_engine_cs *engine)
*
* FIXME: Wa for more modern gens needs to be validated
*/
- ring_set_paused(engine, 1);
+ ring_set_paused(el, 1);
intel_engine_stop_cs(engine);
- engine->execlists.reset_ccid = active_ccid(engine);
+ el->reset_ccid = active_ccid(engine);
}
static struct i915_request **
-reset_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
+reset_csb(struct intel_execlists *el, struct i915_request **inactive)
{
- struct intel_engine_execlists * const execlists = &engine->execlists;
-
mb(); /* paranoia: read the CSB pointers from after the reset */
- clflush(execlists->csb_write);
+ clflush(el->csb_write);
mb();
- inactive = process_csb(engine, inactive); /* drain preemption events */
+ inactive = process_csb(el, inactive); /* drain preemption events */
/* Following the reset, we need to reload the CSB read/write pointers */
- reset_csb_pointers(engine);
+ reset_csb_pointers(el);
return inactive;
}
static void
-execlists_reset_active(struct intel_engine_cs *engine, bool stalled)
+execlists_reset_active(struct intel_execlists *el, bool stalled)
{
struct intel_context *ce;
struct i915_request *rq;
@@ -2609,7 +2707,7 @@ execlists_reset_active(struct intel_engine_cs *engine, bool stalled)
* its request, it was still running at the time of the
* reset and will have been clobbered.
*/
- rq = active_context(engine, engine->execlists.reset_ccid);
+ rq = active_context(el, el->reset_ccid);
if (!rq)
return;
@@ -2623,7 +2721,7 @@ execlists_reset_active(struct intel_engine_cs *engine, bool stalled)
}
/* We still have requests in-flight; the engine should be active */
- GEM_BUG_ON(!intel_engine_pm_is_awake(engine));
+ GEM_BUG_ON(!intel_engine_pm_is_awake(el->sched.priv));
/* Context has requests still in-flight; it should not be idle! */
GEM_BUG_ON(i915_active_is_idle(&ce->active));
@@ -2669,50 +2767,48 @@ execlists_reset_active(struct intel_engine_cs *engine, bool stalled)
* to recreate its own state.
*/
out_replay:
- ENGINE_TRACE(engine, "replay {head:%04x, tail:%04x}\n",
+ ENGINE_TRACE(el->sched.priv, "replay {head:%04x, tail:%04x}\n",
head, ce->ring->tail);
- lrc_reset_regs(ce, engine);
- ce->lrc.lrca = lrc_update_regs(ce, engine, head);
+ lrc_reset_regs(ce, el->sched.priv);
+ ce->lrc.lrca = lrc_update_regs(ce, el->sched.priv, head);
}
-static void execlists_reset_csb(struct intel_engine_cs *engine, bool stalled)
+static void execlists_reset_csb(struct intel_execlists *el, bool stalled)
{
- struct intel_engine_execlists * const execlists = &engine->execlists;
struct i915_request *post[2 * EXECLIST_MAX_PORTS];
struct i915_request **inactive;
rcu_read_lock();
- inactive = reset_csb(engine, post);
+ inactive = reset_csb(el, post);
- execlists_reset_active(engine, true);
+ execlists_reset_active(el, true);
- inactive = cancel_port_requests(execlists, inactive);
- post_process_csb(engine, post, inactive);
+ inactive = cancel_port_requests(el, inactive);
+ post_process_csb(el, post, inactive);
rcu_read_unlock();
}
static void execlists_reset_rewind(struct intel_engine_cs *engine, bool stalled)
{
- struct i915_sched *se = intel_engine_get_scheduler(engine);
+ struct intel_execlists *el = to_execlists(engine);
unsigned long flags;
ENGINE_TRACE(engine, "\n");
/* Process the csb, find the guilty context and throw away */
- execlists_reset_csb(engine, stalled);
+ execlists_reset_csb(el, stalled);
/* Push back any incomplete requests for replay after the reset. */
rcu_read_lock();
- spin_lock_irqsave(&se->lock, flags);
- __i915_sched_rewind_requests(se);
- spin_unlock_irqrestore(&se->lock, flags);
+ spin_lock_irqsave(&el->sched.lock, flags);
+ __i915_sched_rewind_requests(&el->sched);
+ spin_unlock_irqrestore(&el->sched.lock, flags);
rcu_read_unlock();
}
static void execlists_reset_cancel(struct intel_engine_cs *engine)
{
- struct intel_engine_execlists * const execlists = &engine->execlists;
- struct i915_sched *se = intel_engine_get_scheduler(engine);
+ struct intel_execlists * const el = to_execlists(engine);
unsigned long flags;
struct rb_node *rb;
@@ -2732,19 +2828,19 @@ static void execlists_reset_cancel(struct intel_engine_cs *engine)
* submission's irq state, we also wish to remind ourselves that
* it is irq state.)
*/
- execlists_reset_csb(engine, true);
+ execlists_reset_csb(el, true);
rcu_read_lock();
- spin_lock_irqsave(&se->lock, flags);
+ spin_lock_irqsave(&el->sched.lock, flags);
- __i915_sched_cancel_queue(se);
+ __i915_sched_cancel_queue(&el->sched);
/* Cancel all attached virtual engines */
- while ((rb = rb_first_cached(&execlists->virtual))) {
+ while ((rb = rb_first_cached(&el->virtual))) {
struct virtual_engine *ve =
rb_entry(rb, typeof(*ve), nodes[engine->id].rb);
- rb_erase_cached(rb, &execlists->virtual);
+ rb_erase_cached(rb, &el->virtual);
RB_CLEAR_NODE(rb);
spin_lock(&ve->base.sched->lock);
@@ -2752,7 +2848,7 @@ static void execlists_reset_cancel(struct intel_engine_cs *engine)
spin_unlock(&ve->base.sched->lock);
}
- spin_unlock_irqrestore(&se->lock, flags);
+ spin_unlock_irqrestore(&el->sched.lock, flags);
rcu_read_unlock();
intel_engine_signal_breadcrumbs(engine);
@@ -2788,17 +2884,38 @@ static void gen8_logical_ring_disable_irq(struct intel_engine_cs *engine)
static void execlists_park(struct intel_engine_cs *engine)
{
- cancel_timer(&engine->execlists.timer);
- cancel_timer(&engine->execlists.preempt);
+ struct intel_execlists *el = to_execlists(engine);
+
+ cancel_timer(&el->timer);
+ cancel_timer(&el->preempt);
+}
+
+static inline struct i915_request *
+execlists_active(const struct intel_execlists *el)
+{
+ struct i915_request * const *cur, * const *old, *active;
+
+ cur = READ_ONCE(el->active);
+ smp_rmb(); /* pairs with overwrite protection in process_csb() */
+ do {
+ old = cur;
+
+ active = READ_ONCE(*cur);
+ cur = READ_ONCE(el->active);
+
+ smp_rmb(); /* and complete the seqlock retry */
+ } while (unlikely(cur != old));
+
+ return active;
}
static struct i915_request *
execlists_active_request(const struct i915_sched *se)
{
- const struct intel_engine_cs *engine = se->priv;
+ const struct intel_execlists *el = as_execlists(se);
struct i915_request *rq;
- rq = execlists_active(&engine->execlists);
+ rq = execlists_active(el);
if (rq)
rq = active_request(rq->context->timeline, rq);
@@ -2863,18 +2980,18 @@ static void execlists_set_default_submission(struct intel_engine_cs *engine)
engine->sched->submit_request = i915_request_enqueue;
}
-static void execlists_shutdown(struct intel_engine_cs *engine)
+static void execlists_shutdown(struct intel_execlists *el)
{
/* Synchronise with residual timers and any softirq they raise */
- del_timer_sync(&engine->execlists.timer);
- del_timer_sync(&engine->execlists.preempt);
+ del_timer_sync(&el->timer);
+ del_timer_sync(&el->preempt);
}
static void execlists_release(struct intel_engine_cs *engine)
{
engine->sanitize = NULL; /* no longer in control, nothing to sanitize */
- execlists_shutdown(engine);
+ execlists_shutdown(to_execlists(engine));
intel_engine_cleanup_common(engine);
lrc_fini_wa_ctx(engine);
@@ -2973,71 +3090,85 @@ static void rcs_submission_override(struct intel_engine_cs *engine)
}
}
-static int init_execlists(struct intel_engine_cs *engine)
+static struct i915_sched *init_execlists(struct intel_engine_cs *engine)
{
- struct intel_engine_execlists * const execlists = &engine->execlists;
- struct drm_i915_private *i915 = engine->i915;
struct intel_uncore *uncore = engine->uncore;
+ struct drm_i915_private *i915 = engine->i915;
u32 base = engine->mmio_base;
+ struct intel_execlists *el;
- engine->sched =
- i915_sched_create(i915->drm.dev,
- engine->name,
- engine->mask,
- execlists_submission_tasklet, engine,
- ENGINE_PHYSICAL);
- if (!engine->sched)
- return -ENOMEM;
+ el = kzalloc(sizeof(*el), GFP_KERNEL);
+ if (!el)
+ return NULL;
- engine->sched->submit_request = i915_request_enqueue;
- engine->sched->active_request = execlists_active_request;
- engine->sched->revoke_context = execlists_revoke_context;
- engine->sched->show = execlists_show;
+ i915_sched_init(&el->sched,
+ i915->drm.dev,
+ engine->name,
+ engine->mask,
+ execlists_submission_tasklet, engine,
+ ENGINE_PHYSICAL);
- i915_sched_select_mode(engine->sched, I915_SCHED_MODE_DEADLINE);
+ el->sched.submit_request = i915_request_enqueue;
+ el->sched.active_request = execlists_active_request;
+ el->sched.revoke_context = execlists_revoke_context;
+ el->sched.show = execlists_show;
- intel_engine_init_execlists(engine);
-
- if (IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION) &&
- intel_engine_has_preemption(engine))
- __set_bit(I915_SCHED_TIMESLICE_BIT, &engine->sched->flags);
+ i915_sched_select_mode(&el->sched, I915_SCHED_MODE_DEADLINE);
if (intel_engine_has_preemption(engine)) {
- __set_bit(I915_SCHED_BUSYWAIT_BIT, &engine->sched->flags);
- __set_bit(I915_SCHED_PREEMPT_RESET_BIT, &engine->sched->flags);
+ __set_bit(I915_SCHED_BUSYWAIT_BIT, &el->sched.flags);
+
+ if (IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION))
+ __set_bit(I915_SCHED_TIMESLICE_BIT,
+ &el->sched.flags);
+
+ if (IS_ACTIVE(CONFIG_DRM_I915_PREEMPT_TIMEOUT))
+ __set_bit(I915_SCHED_PREEMPT_RESET_BIT,
+ &el->sched.flags);
}
- timer_setup(&engine->execlists.timer, execlists_timeslice, 0);
- timer_setup(&engine->execlists.preempt, execlists_preempt, 0);
+ if (INTEL_GEN(i915) >= 12)
+ el->flags |= GEN12_CSB_PARSE;
+
+ el->id = engine->id;
+ el->pause = &engine->status_page.addr[I915_GEM_HWS_PREEMPT];
+
+ el->port_mask = 1;
+ GEM_BUG_ON(!is_power_of_2(num_ports(el)));
+ GEM_BUG_ON(num_ports(el) > EXECLIST_MAX_PORTS);
+ el->active = el->inflight;
+
+ timer_setup(&el->timer, execlists_timeslice, 0);
+ timer_setup(&el->preempt, execlists_preempt, 0);
if (HAS_LOGICAL_RING_ELSQ(i915)) {
- execlists->submit_reg = uncore->regs +
+ el->submit_reg = uncore->regs +
i915_mmio_reg_offset(RING_EXECLIST_SQ_CONTENTS(base));
- execlists->ctrl_reg = uncore->regs +
+ el->ctrl_reg = uncore->regs +
i915_mmio_reg_offset(RING_EXECLIST_CONTROL(base));
} else {
- execlists->submit_reg = uncore->regs +
+ el->submit_reg = uncore->regs +
i915_mmio_reg_offset(RING_ELSP(base));
}
- execlists->csb_status =
+ el->csb_status =
(u64 *)&engine->status_page.addr[I915_HWS_CSB_BUF0_INDEX];
- execlists->csb_write =
+ el->csb_write =
&engine->status_page.addr[intel_hws_csb_write_index(i915)];
if (INTEL_GEN(i915) < 11)
- execlists->csb_size = GEN8_CSB_ENTRIES;
+ el->csb_size = GEN8_CSB_ENTRIES;
else
- execlists->csb_size = GEN11_CSB_ENTRIES;
+ el->csb_size = GEN11_CSB_ENTRIES;
- engine->context_tag = GENMASK(BITS_PER_LONG - 2, 0);
- if (INTEL_GEN(i915) >= 11) {
- execlists->ccid |= engine->instance << (GEN11_ENGINE_INSTANCE_SHIFT - 32);
- execlists->ccid |= engine->class << (GEN11_ENGINE_CLASS_SHIFT - 32);
- }
+ el->ccid_tags = GENMASK(BITS_PER_LONG - 2, 0);
+ if (INTEL_GEN(i915) >= 11)
+ el->ccid_engine =
+ engine->instance << (GEN11_ENGINE_INSTANCE_SHIFT - 32) |
+ engine->class << (GEN11_ENGINE_CLASS_SHIFT - 32);
- return 0;
+ return &el->sched;
}
int intel_execlists_submission_setup(struct intel_engine_cs *engine)
@@ -3048,7 +3179,8 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine)
if (engine->class == RENDER_CLASS)
rcs_submission_override(engine);
- if (init_execlists(engine))
+ engine->sched = init_execlists(engine);
+ if (!engine->sched)
return -ENOMEM;
lrc_init_wa_ctx(engine);
@@ -3062,8 +3194,7 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine)
static void rcu_virtual_context_destroy(struct work_struct *wrk)
{
- struct virtual_engine *ve =
- container_of(wrk, typeof(*ve), rcu.work);
+ struct virtual_engine *ve = container_of(wrk, typeof(*ve), rcu.work);
struct i915_sched *se = intel_engine_get_scheduler(&ve->base);
unsigned int n;
@@ -3099,7 +3230,7 @@ static void rcu_virtual_context_destroy(struct work_struct *wrk)
/* Detachment is lazily performed in the execlists tasklet */
if (!RB_EMPTY_NODE(node))
- rb_erase_cached(node, &sibling->execlists.virtual);
+ rb_erase_cached(node, &to_execlists(sibling)->virtual);
spin_unlock_irq(&sibling->sched->lock);
}
@@ -3161,7 +3292,7 @@ virtual_engine_initial_hint(struct virtual_engine *ve)
static int virtual_context_alloc(struct intel_context *ce)
{
- struct virtual_engine *ve = container_of(ce, typeof(*ve), context);
+ struct virtual_engine *ve = to_virtual_context(ce);
return lrc_alloc(ce, ve->siblings[0]);
}
@@ -3170,7 +3301,7 @@ static int virtual_context_pre_pin(struct intel_context *ce,
struct i915_gem_ww_ctx *ww,
void **vaddr)
{
- struct virtual_engine *ve = container_of(ce, typeof(*ve), context);
+ struct virtual_engine *ve = to_virtual_context(ce);
/* Note: we must use a real engine class for setting up reg state */
return lrc_pre_pin(ce, ve->siblings[0], ww, vaddr);
@@ -3178,14 +3309,14 @@ static int virtual_context_pre_pin(struct intel_context *ce,
static int virtual_context_pin(struct intel_context *ce, void *vaddr)
{
- struct virtual_engine *ve = container_of(ce, typeof(*ve), context);
+ struct virtual_engine *ve = to_virtual_context(ce);
return lrc_pin(ce, ve->siblings[0], vaddr);
}
static void virtual_context_enter(struct intel_context *ce)
{
- struct virtual_engine *ve = container_of(ce, typeof(*ve), context);
+ struct virtual_engine *ve = to_virtual_context(ce);
unsigned int n;
for (n = 0; n < ve->num_siblings; n++)
@@ -3196,7 +3327,7 @@ static void virtual_context_enter(struct intel_context *ce)
static void virtual_context_exit(struct intel_context *ce)
{
- struct virtual_engine *ve = container_of(ce, typeof(*ve), context);
+ struct virtual_engine *ve = to_virtual_context(ce);
unsigned int n;
intel_timeline_exit(ce->timeline);
@@ -3264,17 +3395,16 @@ static void virtual_submission_tasklet(struct tasklet_struct *t)
for (n = 0; n < ve->num_siblings; n++) {
struct intel_engine_cs *sibling = READ_ONCE(ve->siblings[n]);
- struct i915_sched *se = intel_engine_get_scheduler(sibling);
+ struct intel_execlists *el = to_execlists(sibling);
struct ve_node * const node = &ve->nodes[sibling->id];
struct rb_node **parent, *rb;
bool first;
- spin_lock_irq(&se->lock);
+ spin_lock_irq(&el->sched.lock);
- if (unlikely(!virtual_matches(ve, rq, sibling))) {
+ if (unlikely(!virtual_matches(ve, rq, el))) {
if (!RB_EMPTY_NODE(&node->rb)) {
- rb_erase_cached(&node->rb,
- &sibling->execlists.virtual);
+ rb_erase_cached(&node->rb, &el->virtual);
RB_CLEAR_NODE(&node->rb);
}
@@ -3286,18 +3416,17 @@ static void virtual_submission_tasklet(struct tasklet_struct *t)
* Cheat and avoid rebalancing the tree if we can
* reuse this node in situ.
*/
- first = rb_first_cached(&sibling->execlists.virtual) ==
- &node->rb;
+ first = rb_first_cached(&el->virtual) == &node->rb;
if (deadline == node->deadline ||
(deadline < node->deadline && first))
goto submit_engine;
- rb_erase_cached(&node->rb, &sibling->execlists.virtual);
+ rb_erase_cached(&node->rb, &el->virtual);
}
rb = NULL;
first = true;
- parent = &sibling->execlists.virtual.rb_root.rb_node;
+ parent = &el->virtual.rb_root.rb_node;
while (*parent) {
struct ve_node *other;
@@ -3313,17 +3442,17 @@ static void virtual_submission_tasklet(struct tasklet_struct *t)
rb_link_node(&node->rb, rb, parent);
rb_insert_color_cached(&node->rb,
- &sibling->execlists.virtual,
+ &to_execlists(sibling)->virtual,
first);
submit_engine:
GEM_BUG_ON(RB_EMPTY_NODE(&node->rb));
node->deadline = deadline;
if (first)
- i915_sched_kick(se);
+ i915_sched_kick(&el->sched);
unlock_engine:
- spin_unlock_irq(&se->lock);
+ spin_unlock_irq(&el->sched.lock);
if (intel_context_inflight(&ve->context))
break;
@@ -3399,8 +3528,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
snprintf(ve->base.name, sizeof(ve->base.name), "virtual");
- intel_engine_init_execlists(&ve->base);
-
ve->base.cops = &virtual_context_ops;
ve->base.bond_execute = virtual_bond_execute;
@@ -3605,8 +3732,8 @@ static void execlists_show(struct drm_printer *m,
int indent),
unsigned int max)
{
+ const struct intel_execlists *el = as_execlists(se);
const struct intel_engine_cs *engine = se->priv;
- const struct intel_engine_execlists *el = &engine->execlists;
const u8 num_entries = el->csb_size;
const u64 *hws = el->csb_status;
struct i915_request * const *port;
@@ -3624,7 +3751,7 @@ static void execlists_show(struct drm_printer *m,
count = 0;
for (rb = rb_first_cached(&el->virtual); rb; rb = rb_next(rb)) {
struct virtual_engine *ve =
- rb_entry(rb, typeof(*ve), nodes[engine->id].rb);
+ rb_entry(rb, typeof(*ve), nodes[el->id].rb);
struct i915_request *rq;
rq = first_request(ve->base.sched);
@@ -3701,6 +3828,9 @@ static void execlists_show(struct drm_printer *m,
repr_timer(&el->preempt),
repr_timer(&el->timer));
+ drm_printf(m, "Forcewake: %x domains, %d active\n",
+ el->fw_domain, READ_ONCE(el->fw_active));
+
rcu_read_unlock();
intel_runtime_pm_put(engine->uncore->rpm, wakeref);
}
diff --git a/drivers/gpu/drm/i915/gt/intel_ring_scheduler.c b/drivers/gpu/drm/i915/gt/intel_ring_scheduler.c
index d4c54ebdf13b..cf6207ea3b4e 100644
--- a/drivers/gpu/drm/i915/gt/intel_ring_scheduler.c
+++ b/drivers/gpu/drm/i915/gt/intel_ring_scheduler.c
@@ -31,6 +31,41 @@
*/
#define LEGACY_REQUEST_SIZE 200
+struct ring_sched {
+ struct i915_sched sched;
+
+#define MAX_PORTS 2
+ /**
+ * @active: the currently known context executing on HW
+ */
+ struct i915_request * const *active;
+ /**
+ * @inflight: the set of contexts submitted and acknowleged by HW
+ *
+ * The set of inflight contexts is managed by reading CS events
+ * from the HW. On a context-switch event (not preemption), we
+ * know the HW has transitioned from port0 to port1, and we
+ * advance our inflight/active tracking accordingly.
+ */
+ struct i915_request *inflight[MAX_PORTS + 1 /* sentinel */];
+ /**
+ * @pending: the next set of contexts submitted to ELSP
+ *
+ * We store the array of contexts that we submit to HW (via ELSP) and
+ * promote them to the inflight array once HW has signaled the
+ * preemption or idle-to-active event.
+ */
+ struct i915_request *pending[MAX_PORTS + 1];
+
+ enum forcewake_domains fw_domain;
+ unsigned int fw_active;
+};
+
+static inline struct ring_sched *to_ring_sched(struct intel_engine_cs *engine)
+{
+ return container_of(engine->sched, struct ring_sched, sched);
+}
+
static void
set_current_context(struct intel_context **ptr, struct intel_context *ce)
{
@@ -72,15 +107,15 @@ static inline void runtime_stop(struct intel_context *ce)
}
static struct intel_engine_cs *
-__schedule_in(struct intel_engine_cs *engine, struct i915_request *rq)
+__schedule_in(struct ring_sched *rs, struct intel_context *ce)
{
- struct intel_context *ce = rq->context;
+ struct intel_engine_cs *engine = rs->sched.priv;
intel_context_get(ce);
__intel_gt_pm_get(engine->gt);
- if (engine->fw_domain && !engine->fw_active++)
- intel_uncore_forcewake_get(engine->uncore, engine->fw_domain);
+ if (rs->fw_domain && !rs->fw_active++)
+ intel_uncore_forcewake_get(engine->uncore, rs->fw_domain);
intel_engine_context_in(engine);
@@ -89,25 +124,26 @@ __schedule_in(struct intel_engine_cs *engine, struct i915_request *rq)
return engine;
}
-static void schedule_in(struct intel_engine_cs *engine, struct i915_request *rq)
+static void schedule_in(struct ring_sched *rs, struct i915_request *rq)
{
struct intel_context * const ce = rq->context;
struct intel_engine_cs *old;
- GEM_BUG_ON(!intel_engine_pm_is_awake(engine));
+ GEM_BUG_ON(!intel_engine_pm_is_awake(rs->sched.priv));
old = ce->inflight;
if (!old)
- old = __schedule_in(engine, rq);
+ old = __schedule_in(rs, ce);
WRITE_ONCE(ce->inflight, ptr_inc(old));
- GEM_BUG_ON(intel_context_inflight(ce) != engine);
+ GEM_BUG_ON(intel_context_inflight(ce) != rs->sched.priv);
GEM_BUG_ON(!intel_context_inflight_count(ce));
}
static void
-__schedule_out(struct intel_engine_cs *engine, struct i915_request *rq)
+__schedule_out(struct ring_sched *rs, struct i915_request *rq)
{
+ struct intel_engine_cs *engine = rs->sched.priv;
struct intel_context *ce = rq->context;
CE_TRACE(ce, "schedule-out\n");
@@ -119,21 +155,21 @@ __schedule_out(struct intel_engine_cs *engine, struct i915_request *rq)
intel_engine_context_out(engine);
- if (engine->fw_domain && !--engine->fw_active)
- intel_uncore_forcewake_put(engine->uncore, engine->fw_domain);
+ if (rs->fw_domain && !--rs->fw_active)
+ intel_uncore_forcewake_put(engine->uncore, rs->fw_domain);
intel_gt_pm_put_async(engine->gt);
}
static void
-schedule_out(struct intel_engine_cs *engine, struct i915_request *rq)
+schedule_out(struct ring_sched *rs, struct i915_request *rq)
{
struct intel_context *ce = rq->context;
GEM_BUG_ON(!ce->inflight);
ce->inflight = ptr_dec(ce->inflight);
if (!intel_context_inflight_count(ce)) {
- GEM_BUG_ON(ce->inflight != engine);
- __schedule_out(engine, rq);
+ GEM_BUG_ON(ce->inflight != rs->sched.priv);
+ __schedule_out(rs, rq);
WRITE_ONCE(ce->inflight, NULL);
intel_context_put(ce);
}
@@ -522,24 +558,23 @@ static void wa_write_tail(const struct intel_engine_cs *engine)
_MASKED_BIT_DISABLE(PSMI_SLEEP_MSG_DISABLE));
}
-static inline void write_tail(const struct intel_engine_cs *engine)
+static inline void write_tail(const struct ring_sched *rs)
{
wmb(); /* paranoid flush of WCB before RING_TAIL write */
- if (!engine->fw_active)
- __write_tail(engine);
+ if (!rs->fw_active)
+ __write_tail(rs->sched.priv);
else
- wa_write_tail(engine);
+ wa_write_tail(rs->sched.priv);
}
-static void dequeue(struct i915_sched *se, struct intel_engine_cs *engine)
+static void dequeue(struct ring_sched *rs)
{
- struct intel_engine_execlists * const el = &engine->execlists;
- struct i915_request ** const last_port = el->pending + el->port_mask;
+ struct i915_request ** const last_port = rs->pending + MAX_PORTS - 1;
struct i915_request **port, **first, *last;
struct i915_request *rq, *rn;
struct i915_priolist *pl;
- first = copy_active(el->pending, el->active);
+ first = copy_active(rs->pending, rs->active);
if (first > last_port)
return;
@@ -547,8 +582,8 @@ static void dequeue(struct i915_sched *se, struct intel_engine_cs *engine)
last = NULL;
port = first;
- spin_lock(&se->lock);
- i915_sched_dequeue(se, pl, rq, rn) {
+ spin_lock(&rs->sched.lock);
+ i915_sched_dequeue(&rs->sched, pl, rq, rn) {
if (last && rq->context != last->context) {
if (port == last_port)
goto done;
@@ -556,55 +591,55 @@ static void dequeue(struct i915_sched *se, struct intel_engine_cs *engine)
*port++ = i915_request_get(last);
}
- last = ring_submit(engine, rq);
+ last = ring_submit(rs->sched.priv, rq);
}
done:
- spin_unlock(&se->lock);
+ spin_unlock(&rs->sched.lock);
if (last) {
*port++ = i915_request_get(last);
*port = NULL;
- if (!*el->active)
- runtime_start((*el->pending)->context);
- WRITE_ONCE(el->active, el->pending);
+ if (!*rs->active)
+ runtime_start((*rs->pending)->context);
+ WRITE_ONCE(rs->active, rs->pending);
- copy_ports(el->inflight, el->pending, port - el->pending + 1);
+ copy_ports(rs->inflight, rs->pending, port - rs->pending + 1);
while (port-- != first)
- schedule_in(engine, *port);
+ schedule_in(rs, *port);
- write_tail(engine);
+ write_tail(rs);
- WRITE_ONCE(el->active, el->inflight);
- GEM_BUG_ON(!*el->active);
+ WRITE_ONCE(rs->active, rs->inflight);
+ GEM_BUG_ON(!*rs->active);
}
- WRITE_ONCE(el->pending[0], NULL);
+ WRITE_ONCE(rs->pending[0], NULL);
local_irq_enable(); /* flush irq_work *after* RING_TAIL write */
}
-static void post_process_csb(struct intel_engine_cs *engine,
+static void post_process_csb(struct ring_sched *rs,
struct i915_request **port,
struct i915_request **last)
{
while (port != last)
- schedule_out(engine, *port++);
+ schedule_out(rs, *port++);
}
static struct i915_request **
-process_csb(struct intel_engine_execlists *el, struct i915_request **inactive)
+process_csb(struct ring_sched *rs, struct i915_request **inactive)
{
struct i915_request *rq;
- while ((rq = *el->active)) {
+ while ((rq = *rs->active)) {
if (!__i915_request_is_complete(rq)) {
runtime_start(rq->context);
break;
}
*inactive++ = rq;
- el->active++;
+ rs->active++;
runtime_stop(rq->context);
}
@@ -614,19 +649,18 @@ process_csb(struct intel_engine_execlists *el, struct i915_request **inactive)
static void submission_tasklet(struct tasklet_struct *t)
{
- struct i915_sched *se = from_tasklet(se, t, tasklet);
- struct intel_engine_cs *engine = se->priv;
- struct i915_request *post[2 * EXECLIST_MAX_PORTS];
+ struct ring_sched *rs = from_tasklet(rs, t, sched.tasklet);
+ struct i915_request *post[2 * MAX_PORTS];
struct i915_request **inactive;
rcu_read_lock();
- inactive = process_csb(&engine->execlists, post);
+ inactive = process_csb(rs, post);
GEM_BUG_ON(inactive - post > ARRAY_SIZE(post));
- if (!i915_sched_is_idle(se))
- dequeue(se, engine);
+ if (!i915_sched_is_idle(&rs->sched))
+ dequeue(rs);
- post_process_csb(engine, post, inactive);
+ post_process_csb(rs, post, inactive);
rcu_read_unlock();
}
@@ -642,71 +676,72 @@ static inline void clear_ports(struct i915_request **ports, int count)
}
static struct i915_request **
-cancel_port_requests(struct intel_engine_execlists * const el,
+cancel_port_requests(struct ring_sched * const rs,
struct i915_request **inactive)
{
struct i915_request * const *port;
- clear_ports(el->pending, ARRAY_SIZE(el->pending));
+ clear_ports(rs->pending, ARRAY_SIZE(rs->pending));
/* Mark the end of active before we overwrite *active */
- for (port = xchg(&el->active, el->pending); *port; port++)
+ for (port = xchg(&rs->active, rs->pending); *port; port++)
*inactive++ = *port;
- clear_ports(el->inflight, ARRAY_SIZE(el->inflight));
+ clear_ports(rs->inflight, ARRAY_SIZE(rs->inflight));
- smp_wmb(); /* complete the seqlock for execlists_active() */
- WRITE_ONCE(el->active, el->inflight);
+ WRITE_ONCE(rs->active, rs->inflight);
return inactive;
}
-static void __ring_rewind(struct i915_sched *se, bool stalled)
+static void __ring_rewind(struct ring_sched *rs, bool stalled)
{
struct i915_request *rq;
unsigned long flags;
rcu_read_lock();
- spin_lock_irqsave(&se->lock, flags);
- rq = __i915_sched_rewind_requests(se);
- spin_unlock_irqrestore(&se->lock, flags);
+ spin_lock_irqsave(&rs->sched.lock, flags);
+ rq = __i915_sched_rewind_requests(&rs->sched);
+ spin_unlock_irqrestore(&rs->sched.lock, flags);
if (rq && __i915_request_has_started(rq))
__i915_request_reset(rq, stalled);
rcu_read_unlock();
}
-static void ring_reset_csb(struct intel_engine_cs *engine)
+static void ring_reset_csb(struct ring_sched *rs)
{
- struct intel_engine_execlists * const el = &engine->execlists;
- struct i915_request *post[2 * EXECLIST_MAX_PORTS];
+ struct intel_engine_cs *engine = rs->sched.priv;
+ struct i915_request *post[2 * MAX_PORTS];
struct i915_request **inactive;
rcu_read_lock();
- inactive = cancel_port_requests(el, post);
+ inactive = cancel_port_requests(rs, post);
/* Clear the global submission state, we will submit from scratch */
intel_ring_reset(engine->legacy.ring, 0);
set_current_context(&engine->legacy.context, NULL);
- post_process_csb(engine, post, inactive);
+ post_process_csb(rs, post, inactive);
rcu_read_unlock();
}
static void ring_reset_rewind(struct intel_engine_cs *engine, bool stalled)
{
- ring_reset_csb(engine);
- __ring_rewind(engine->sched, stalled);
+ struct ring_sched *rs = to_ring_sched(engine);
+
+ ring_reset_csb(rs);
+ __ring_rewind(rs, stalled);
}
static void ring_reset_cancel(struct intel_engine_cs *engine)
{
- struct i915_sched *se = intel_engine_get_scheduler(engine);
+ struct ring_sched *rs = to_ring_sched(engine);
unsigned long flags;
- ring_reset_csb(engine);
+ ring_reset_csb(rs);
- spin_lock_irqsave(&se->lock, flags);
- __i915_sched_cancel_queue(se);
- spin_unlock_irqrestore(&se->lock, flags);
+ spin_lock_irqsave(&rs->sched.lock, flags);
+ __i915_sched_cancel_queue(&rs->sched);
+ spin_unlock_irqrestore(&rs->sched.lock, flags);
intel_engine_signal_breadcrumbs(engine);
}
@@ -1052,8 +1087,6 @@ static void setup_rcs(struct intel_engine_cs *engine)
static void setup_vcs(struct intel_engine_cs *engine)
{
if (INTEL_GEN(engine->i915) >= 6) {
- if (IS_GEN(engine->i915, 6))
- engine->fw_domain = FORCEWAKE_ALL;
engine->emit_flush = gen6_emit_flush_vcs;
engine->irq_enable_mask = GT_BSD_USER_INTERRUPT;
} else if (INTEL_GEN(engine->i915) >= 5) {
@@ -1086,7 +1119,7 @@ static void setup_vecs(struct intel_engine_cs *engine)
static unsigned int global_ring_size(void)
{
/* Enough space to hold 2 clients and the context switch */
- return roundup_pow_of_two(EXECLIST_MAX_PORTS * SZ_16K + SZ_4K);
+ return roundup_pow_of_two(MAX_PORTS * SZ_16K + SZ_4K);
}
static int gen7_ctx_switch_bb_init(struct intel_engine_cs *engine)
@@ -1141,6 +1174,31 @@ static int gen7_ctx_switch_bb_init(struct intel_engine_cs *engine)
return err;
}
+static struct i915_sched *create_ring_sched(struct intel_engine_cs *engine)
+{
+ struct ring_sched *rs;
+
+ rs = kzalloc(sizeof(*rs), GFP_KERNEL);
+ if (!rs)
+ return NULL;
+
+ i915_sched_init(&rs->sched,
+ engine->i915->drm.dev,
+ engine->name,
+ engine->mask,
+ submission_tasklet, engine,
+ ENGINE_PHYSICAL);
+
+ i915_sched_select_mode(&rs->sched, I915_SCHED_MODE_DEADLINE);
+
+ rs->active = rs->inflight;
+
+ if (IS_GEN(engine->i915, 6) && engine->class == VIDEO_DECODE_CLASS)
+ rs->fw_domain = FORCEWAKE_ALL;
+
+ return &rs->sched;
+}
+
int intel_ring_scheduler_setup(struct intel_engine_cs *engine)
{
struct intel_ring *ring;
@@ -1168,19 +1226,12 @@ int intel_ring_scheduler_setup(struct intel_engine_cs *engine)
return -ENODEV;
}
- engine->sched =
- i915_sched_create(engine->i915->drm.dev,
- engine->name,
- engine->mask,
- submission_tasklet, engine,
- ENGINE_PHYSICAL);
+ engine->sched = create_ring_sched(engine);
if (!engine->sched) {
err = -ENOMEM;
goto err;
}
- i915_sched_select_mode(engine->sched, I915_SCHED_MODE_DEADLINE);
-
ring = intel_engine_create_ring(engine, global_ring_size());
if (IS_ERR(ring)) {
err = PTR_ERR(ring);
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index 1fe716d9f344..f07842637121 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -54,7 +54,8 @@ static int wait_for_submit(struct intel_engine_cs *engine,
/* Wait until the HW has acknowleged the submission (or err) */
intel_engine_flush_scheduler(engine);
- if (!READ_ONCE(engine->execlists.pending[0]) && is_active(rq))
+ if (!READ_ONCE(to_execlists(engine)->pending[0]) &&
+ is_active(rq))
return 0;
if (done)
@@ -74,7 +75,7 @@ static int wait_for_reset(struct intel_engine_cs *engine,
cond_resched();
intel_engine_flush_scheduler(engine);
- if (READ_ONCE(engine->execlists.pending[0]))
+ if (READ_ONCE(to_execlists(engine)->pending[0]))
continue;
if (i915_request_completed(rq))
@@ -606,7 +607,6 @@ static int live_hold_reset(void *arg)
tasklet_disable(&se->tasklet);
se->tasklet.callback(&se->tasklet);
- GEM_BUG_ON(execlists_active(&engine->execlists) != rq);
i915_request_get(rq);
i915_sched_suspend_request(se, rq);
@@ -1180,7 +1180,7 @@ static int live_timeslice_rewind(void *arg)
ENGINE_TRACE(engine, "forcing tasklet for rewind\n");
while (i915_request_is_active(rq[A2])) { /* semaphore yield! */
/* Wait for the timeslice to kick in */
- del_timer(&engine->execlists.timer);
+ del_timer(&to_execlists(engine)->timer);
intel_engine_kick_scheduler(engine);
intel_engine_flush_scheduler(engine);
}
@@ -1356,7 +1356,7 @@ static int live_timeslice_queue(void *arg)
do {
cond_resched();
intel_engine_flush_scheduler(engine);
- } while (READ_ONCE(engine->execlists.pending[0]));
+ } while (READ_ONCE(to_execlists(engine)->pending[0]));
/* Timeslice every jiffy, so within 2 we should signal */
if (i915_request_wait(rq, 0, slice_timeout(engine)) < 0) {
@@ -1952,7 +1952,7 @@ static int live_nopreempt(void *arg)
if (!intel_engine_has_preemption(engine))
continue;
- engine->execlists.preempt_hang.count = 0;
+ to_execlists(engine)->preempt_hang.count = 0;
rq_a = spinner_create_request(&a.spin,
a.ctx, engine,
@@ -1999,9 +1999,9 @@ static int live_nopreempt(void *arg)
igt_spinner_end(&b.spin);
- if (engine->execlists.preempt_hang.count) {
+ if (to_execlists(engine)->preempt_hang.count) {
pr_err("Preemption recorded x%d; should have been suppressed!\n",
- engine->execlists.preempt_hang.count);
+ to_execlists(engine)->preempt_hang.count);
err = -EINVAL;
goto err_wedged;
}
@@ -2326,9 +2326,9 @@ static int __cancel_fail(struct live_preempt_cancel *arg)
force_reset_timeout(engine);
/* force preempt reset [failure] */
- while (!engine->execlists.pending[0])
+ while (!to_execlists(engine)->pending[0])
intel_engine_flush_scheduler(engine);
- del_timer_sync(&engine->execlists.preempt);
+ del_timer_sync(&to_execlists(engine)->preempt);
intel_engine_flush_scheduler(engine);
engine->props.preempt_timeout_ms = 0;
@@ -2447,7 +2447,7 @@ static int live_suppress_self_preempt(void *arg)
goto err_wedged;
st_engine_heartbeat_disable(engine);
- engine->execlists.preempt_hang.count = 0;
+ to_execlists(engine)->preempt_hang.count = 0;
rq_a = spinner_create_request(&a.spin,
a.ctx, engine,
@@ -2466,7 +2466,7 @@ static int live_suppress_self_preempt(void *arg)
}
/* Keep postponing the timer to avoid premature slicing */
- mod_timer(&engine->execlists.timer, jiffies + HZ);
+ mod_timer(&to_execlists(engine)->timer, jiffies + HZ);
for (depth = 0; depth < 8; depth++) {
rq_b = spinner_create_request(&b.spin,
b.ctx, engine,
@@ -2493,10 +2493,10 @@ static int live_suppress_self_preempt(void *arg)
}
igt_spinner_end(&a.spin);
- if (engine->execlists.preempt_hang.count) {
+ if (to_execlists(engine)->preempt_hang.count) {
pr_err("Preemption on %s recorded x%d, depth %d; should have been suppressed!\n",
engine->name,
- engine->execlists.preempt_hang.count,
+ to_execlists(engine)->preempt_hang.count,
depth);
st_engine_heartbeat_enable(engine);
err = -EINVAL;
@@ -3403,7 +3403,7 @@ static int live_preempt_timeout(void *arg)
}
/* Flush the previous CS ack before changing timeouts */
- while (READ_ONCE(engine->execlists.pending[0]))
+ while (READ_ONCE(to_execlists(engine)->pending[0]))
cpu_relax();
saved_timeout = engine->props.preempt_timeout_ms;
diff --git a/drivers/gpu/drm/i915/gt/selftest_lrc.c b/drivers/gpu/drm/i915/gt/selftest_lrc.c
index 391a14cc135f..fa7e7bf3cf09 100644
--- a/drivers/gpu/drm/i915/gt/selftest_lrc.c
+++ b/drivers/gpu/drm/i915/gt/selftest_lrc.c
@@ -60,7 +60,7 @@ static int wait_for_submit(struct intel_engine_cs *engine,
/* Wait until the HW has acknowleged the submission (or err) */
intel_engine_flush_scheduler(engine);
- if (!READ_ONCE(engine->execlists.pending[0]) && is_active(rq))
+ if (is_active(rq))
return 0;
if (done)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
index ac3c20a51b1a..c1ede6e8af12 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
@@ -132,126 +132,17 @@ static void flush_ggtt_writes(struct i915_vma *vma)
GUC_STATUS);
}
-static void guc_submit(struct intel_engine_cs *engine,
- struct i915_request **out,
- struct i915_request **end)
-{
- struct intel_guc *guc = &engine->gt->uc.guc;
-
- do {
- struct i915_request *rq = *out++;
-
- flush_ggtt_writes(rq->ring->vma);
- guc_add_request(guc, rq);
- } while (out != end);
-}
-
-static inline int rq_prio(const struct i915_request *rq)
-{
- return rq->sched.attr.priority;
-}
-
-static struct i915_request *
-schedule_in(struct intel_engine_cs *engine, struct i915_request *rq, int idx)
-{
- trace_i915_request_in(rq, idx);
-
- /*
- * Currently we are not tracking the rq->context being inflight
- * (ce->inflight = rq->engine). It is only used by the execlists
- * backend at the moment, a similar counting strategy would be
- * required if we generalise the inflight tracking.
- */
-
- __intel_gt_pm_get(engine->gt);
- return i915_request_get(rq);
-}
-
-static void
-schedule_out(struct intel_engine_cs *engine, struct i915_request *rq)
-{
- trace_i915_request_out(rq);
-
- i915_request_put(rq);
- intel_gt_pm_put_async(engine->gt);
-}
-
-static void __guc_dequeue(struct intel_engine_cs *engine)
-{
- struct intel_engine_execlists * const execlists = &engine->execlists;
- struct i915_sched *se = intel_engine_get_scheduler(engine);
- struct i915_request **first = execlists->inflight;
- struct i915_request ** const last_port = first + execlists->port_mask;
- struct i915_request *last = first[0];
- struct i915_request *rq, *rn;
- struct i915_request **port;
- struct i915_priolist *pl;
- bool submit = false;
-
- lockdep_assert_held(&se->lock);
-
- if (last) {
- if (*++first)
- return;
-
- last = NULL;
- }
-
- /*
- * We write directly into the execlists->inflight queue and don't use
- * the execlists->pending queue, as we don't have a distinct switch
- * event.
- */
- port = first;
- i915_sched_dequeue(se, pl, rq, rn) {
- if (last && rq->context != last->context) {
- if (port == last_port)
- goto done;
-
- *port = schedule_in(engine, last,
- port - execlists->inflight);
- port++;
- }
-
- list_del_init(&rq->sched.link);
- __i915_request_submit(rq, engine);
- submit = true;
- last = rq;
- }
-done:
- if (submit) {
- *port = schedule_in(engine, last, port - execlists->inflight);
- *++port = NULL;
- guc_submit(engine, first, port);
- }
- execlists->active = execlists->inflight;
-}
-
static void guc_submission_tasklet(struct tasklet_struct *t)
{
- struct i915_sched * const se = from_tasklet(se, t, tasklet);
- struct intel_engine_cs *engine = se->priv;
- struct intel_engine_execlists * const execlists = &engine->execlists;
- struct i915_request **port, *rq;
- unsigned long flags;
+ struct i915_sched *se = from_tasklet(se, t, tasklet);
+ struct i915_request *rq, *rn;
+ struct i915_priolist *pl;
- spin_lock_irqsave(&se->lock, flags);
-
- for (port = execlists->inflight; (rq = *port); port++) {
- if (!i915_request_completed(rq))
- break;
-
- schedule_out(engine, rq);
+ i915_sched_dequeue(se, pl, rq, rn) {
+ __i915_request_submit(rq, rq->context->engine);
+ flush_ggtt_writes(rq->context->state);
+ guc_add_request(se->priv, rq);
}
- if (port != execlists->inflight) {
- int idx = port - execlists->inflight;
- int rem = ARRAY_SIZE(execlists->inflight) - idx;
- memmove(execlists->inflight, port, rem * sizeof(*port));
- }
-
- __guc_dequeue(engine);
-
- spin_unlock_irqrestore(&se->lock, flags);
}
static void cs_irq_handler(struct intel_engine_cs *engine, u16 iir)
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 66c81f1b3bec..3122e46f0713 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -464,23 +464,6 @@ static void error_print_instdone(struct drm_i915_error_state_buf *m,
ee->instdone.slice_common_extra[1]);
}
-static void error_print_request(struct drm_i915_error_state_buf *m,
- const char *prefix,
- const struct i915_request_coredump *erq)
-{
- if (!erq->seqno)
- return;
-
- err_printf(m, "%s pid %d, seqno %8x:%08x%s%s, prio %d, head %08x, tail %08x\n",
- prefix, erq->pid, erq->context, erq->seqno,
- test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
- &erq->flags) ? "!" : "",
- test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
- &erq->flags) ? "+" : "",
- erq->sched_attr.priority,
- erq->head, erq->tail);
-}
-
static void error_print_context(struct drm_i915_error_state_buf *m,
const char *header,
const struct i915_gem_context_coredump *ctx)
@@ -513,7 +496,6 @@ static void error_print_engine(struct drm_i915_error_state_buf *m,
const struct intel_engine_coredump *ee)
{
struct i915_vma_coredump *batch;
- int n;
err_printf(m, "%s command stream:\n", ee->engine->name);
err_printf(m, " CCID: 0x%08x\n", ee->ccid);
@@ -572,11 +554,6 @@ static void error_print_engine(struct drm_i915_error_state_buf *m,
err_printf(m, " Scheduler: %s\n",
i915_sched_repr_mode(intel_engine_get_scheduler(ee->engine)));
- for (n = 0; n < ee->num_ports; n++) {
- err_printf(m, " ELSP[%d]:", n);
- error_print_request(m, " ", &ee->execlist[n]);
- }
-
error_print_context(m, " Active context: ", &ee->context);
}
@@ -1222,42 +1199,6 @@ static void engine_record_registers(struct intel_engine_coredump *ee)
}
}
-static void record_request(const struct i915_request *request,
- struct i915_request_coredump *erq)
-{
- erq->flags = request->fence.flags;
- erq->context = request->fence.context;
- erq->seqno = request->fence.seqno;
- erq->sched_attr = request->sched.attr;
- erq->head = request->head;
- erq->tail = request->tail;
-
- erq->pid = 0;
- rcu_read_lock();
- if (!intel_context_is_closed(request->context)) {
- const struct i915_gem_context *ctx;
-
- ctx = rcu_dereference(request->context->gem_context);
- if (ctx)
- erq->pid = I915_SELFTEST_ONLY(!ctx->client) ?
- 0 :
- pid_nr(i915_drm_client_pid(ctx->client));
- }
- rcu_read_unlock();
-}
-
-static void engine_record_execlists(struct intel_engine_coredump *ee)
-{
- const struct intel_engine_execlists * const el = &ee->engine->execlists;
- struct i915_request * const *port = el->active;
- unsigned int n = 0;
-
- while (*port)
- record_request(*port++, &ee->execlist[n++]);
-
- ee->num_ports = n;
-}
-
static bool record_context(struct i915_gem_context_coredump *e,
const struct i915_request *rq)
{
@@ -1357,7 +1298,6 @@ intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp)
ee->engine = engine;
engine_record_registers(ee);
- engine_record_execlists(ee);
return ee;
}
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h
index 2d8debabfe28..c31955407d18 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.h
+++ b/drivers/gpu/drm/i915/i915_gpu_error.h
@@ -101,9 +101,6 @@ struct intel_engine_coredump {
struct i915_vma_coredump *vma;
- struct i915_request_coredump execlist[EXECLIST_MAX_PORTS];
- unsigned int num_ports;
-
struct {
u32 gfx_mode;
union {
--
2.20.1
More information about the Intel-gfx-trybot
mailing list