@@ -20,6 +20,11 @@
struct __guc_ads_blob;
+enum {
+ GUC_SUBMIT_ENGINE_SINGLE_LRC,
+ GUC_SUBMIT_ENGINE_MAX
+};
+
/*
* Top level structure of GuC. It handles firmware loading and manages client
* pool. intel_guc owns a intel_guc_client to replace the legacy ExecList
@@ -30,31 +35,6 @@ struct intel_guc {
struct intel_guc_log log;
struct intel_guc_ct ct;
- /* Global engine used to submit requests to GuC */
- struct i915_sched_engine *sched_engine;
-
- /* Global state related to submission tasklet */
- struct i915_request *stalled_rq;
- struct intel_context *stalled_context;
- struct work_struct retire_worker;
- unsigned long flags;
- int total_num_rq_with_no_guc_id;
-
- /*
- * Submisson stall reason. See intel_guc_submission.c for detailed
- * description.
- */
- enum {
- STALL_NONE,
- STALL_GUC_ID_WORKQUEUE,
- STALL_GUC_ID_TASKLET,
- STALL_SCHED_DISABLE,
- STALL_REGISTER_CONTEXT,
- STALL_DEREGISTER_CONTEXT,
- STALL_MOVE_LRC_TAIL,
- STALL_ADD_REQUEST,
- } submission_stall_reason;
-
/* intel_guc_recv interrupt related state */
spinlock_t irq_lock;
unsigned int msg_enabled_mask;
@@ -68,6 +48,8 @@ struct intel_guc {
void (*disable)(struct intel_guc *guc);
} interrupts;
+ struct guc_submit_engine *gse[GUC_SUBMIT_ENGINE_MAX];
+
/*
* contexts_lock protects the pool of free guc ids and a linked list of
* guc ids available to be stolden
@@ -76,7 +58,6 @@ struct intel_guc {
struct ida guc_ids;
u32 num_guc_ids;
u32 max_guc_ids;
- atomic_t num_guc_ids_not_ready;
struct list_head guc_id_list_no_ref;
struct list_head guc_id_list_unpinned;
@@ -21,6 +21,7 @@
#include "gt/intel_ring.h"
#include "intel_guc_submission.h"
+#include "intel_guc_submission_types.h"
#include "i915_drv.h"
#include "i915_trace.h"
@@ -57,7 +58,7 @@
* WQ_TYPE_INORDER is needed to support legacy submission via GuC, which
* represents in-order queue. The kernel driver packs ring tail pointer and an
* ELSP context descriptor dword into Work Item.
- * See guc_add_request()
+ * See gse_add_request()
*
* GuC flow control state machine:
* The tasklet, workqueue (retire_worker), and the G2H handlers together more or
@@ -80,57 +81,57 @@
* context)
*/
-/* GuC Virtual Engine */
-struct guc_virtual_engine {
- struct intel_engine_cs base;
- struct intel_context context;
-};
-
static struct intel_context *
guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count);
#define GUC_REQUEST_SIZE 64 /* bytes */
+static inline struct guc_submit_engine *ce_to_gse(struct intel_context *ce)
+{
+ return container_of(ce->engine->sched_engine, struct guc_submit_engine,
+ sched_engine);
+}
+
/*
* Global GuC flags helper functions
*/
enum {
- GUC_STATE_TASKLET_BLOCKED,
- GUC_STATE_GUC_IDS_EXHAUSTED,
+ GSE_STATE_TASKLET_BLOCKED,
+ GSE_STATE_GUC_IDS_EXHAUSTED,
};
-static bool tasklet_blocked(struct intel_guc *guc)
+static bool tasklet_blocked(struct guc_submit_engine *gse)
{
- return test_bit(GUC_STATE_TASKLET_BLOCKED, &guc->flags);
+ return test_bit(GSE_STATE_TASKLET_BLOCKED, &gse->flags);
}
-static void set_tasklet_blocked(struct intel_guc *guc)
+static void set_tasklet_blocked(struct guc_submit_engine *gse)
{
- lockdep_assert_held(&guc->sched_engine->lock);
- set_bit(GUC_STATE_TASKLET_BLOCKED, &guc->flags);
+ lockdep_assert_held(&gse->sched_engine.lock);
+ set_bit(GSE_STATE_TASKLET_BLOCKED, &gse->flags);
}
-static void __clr_tasklet_blocked(struct intel_guc *guc)
+static void __clr_tasklet_blocked(struct guc_submit_engine *gse)
{
- lockdep_assert_held(&guc->sched_engine->lock);
- clear_bit(GUC_STATE_TASKLET_BLOCKED, &guc->flags);
+ lockdep_assert_held(&gse->sched_engine.lock);
+ clear_bit(GSE_STATE_TASKLET_BLOCKED, &gse->flags);
}
-static void clr_tasklet_blocked(struct intel_guc *guc)
+static void clr_tasklet_blocked(struct guc_submit_engine *gse)
{
unsigned long flags;
- spin_lock_irqsave(&guc->sched_engine->lock, flags);
- __clr_tasklet_blocked(guc);
- spin_unlock_irqrestore(&guc->sched_engine->lock, flags);
+ spin_lock_irqsave(&gse->sched_engine.lock, flags);
+ __clr_tasklet_blocked(gse);
+ spin_unlock_irqrestore(&gse->sched_engine.lock, flags);
}
-static bool guc_ids_exhausted(struct intel_guc *guc)
+static bool guc_ids_exhausted(struct guc_submit_engine *gse)
{
- return test_bit(GUC_STATE_GUC_IDS_EXHAUSTED, &guc->flags);
+ return test_bit(GSE_STATE_GUC_IDS_EXHAUSTED, &gse->flags);
}
-static bool test_and_update_guc_ids_exhausted(struct intel_guc *guc)
+static bool test_and_update_guc_ids_exhausted(struct guc_submit_engine *gse)
{
unsigned long flags;
bool ret = false;
@@ -139,33 +140,33 @@ static bool test_and_update_guc_ids_exhausted(struct intel_guc *guc)
* Strict ordering on checking if guc_ids are exhausted isn't required,
* so let's avoid grabbing the submission lock if possible.
*/
- if (guc_ids_exhausted(guc)) {
- spin_lock_irqsave(&guc->sched_engine->lock, flags);
- ret = guc_ids_exhausted(guc);
+ if (guc_ids_exhausted(gse)) {
+ spin_lock_irqsave(&gse->sched_engine.lock, flags);
+ ret = guc_ids_exhausted(gse);
if (ret)
- ++guc->total_num_rq_with_no_guc_id;
- spin_unlock_irqrestore(&guc->sched_engine->lock, flags);
+ ++gse->total_num_rq_with_no_guc_id;
+ spin_unlock_irqrestore(&gse->sched_engine.lock, flags);
}
return ret;
}
-static void set_and_update_guc_ids_exhausted(struct intel_guc *guc)
+static void set_and_update_guc_ids_exhausted(struct guc_submit_engine *gse)
{
unsigned long flags;
- spin_lock_irqsave(&guc->sched_engine->lock, flags);
- ++guc->total_num_rq_with_no_guc_id;
- set_bit(GUC_STATE_GUC_IDS_EXHAUSTED, &guc->flags);
- spin_unlock_irqrestore(&guc->sched_engine->lock, flags);
+ spin_lock_irqsave(&gse->sched_engine.lock, flags);
+ ++gse->total_num_rq_with_no_guc_id;
+ set_bit(GSE_STATE_GUC_IDS_EXHAUSTED, &gse->flags);
+ spin_unlock_irqrestore(&gse->sched_engine.lock, flags);
}
-static void clr_guc_ids_exhausted(struct intel_guc *guc)
+static void clr_guc_ids_exhausted(struct guc_submit_engine *gse)
{
- lockdep_assert_held(&guc->sched_engine->lock);
- GEM_BUG_ON(guc->total_num_rq_with_no_guc_id);
+ lockdep_assert_held(&gse->sched_engine.lock);
+ GEM_BUG_ON(gse->total_num_rq_with_no_guc_id);
- clear_bit(GUC_STATE_GUC_IDS_EXHAUSTED, &guc->flags);
+ clear_bit(GSE_STATE_GUC_IDS_EXHAUSTED, &gse->flags);
}
/*
@@ -372,6 +373,20 @@ static inline struct intel_guc *ce_to_guc(struct intel_context *ce)
return &ce->engine->gt->uc.guc;
}
+static inline struct i915_sched_engine *
+ce_to_sched_engine(struct intel_context *ce)
+{
+ return ce->engine->sched_engine;
+}
+
+static inline struct i915_sched_engine *
+guc_to_sched_engine(struct intel_guc *guc, int index)
+{
+ GEM_BUG_ON(index < 0 || index >= GUC_SUBMIT_ENGINE_MAX);
+
+ return &guc->gse[index]->sched_engine;
+}
+
static inline struct i915_priolist *to_priolist(struct rb_node *rb)
{
return rb_entry(rb, struct i915_priolist, node);
@@ -591,19 +606,20 @@ static int __guc_add_request(struct intel_guc *guc, struct i915_request *rq)
return err;
}
-static int guc_add_request(struct intel_guc *guc, struct i915_request *rq)
+static int gse_add_request(struct guc_submit_engine *gse,
+ struct i915_request *rq)
{
int ret;
- lockdep_assert_held(&guc->sched_engine->lock);
+ lockdep_assert_held(&gse->sched_engine.lock);
- ret = __guc_add_request(guc, rq);
+ ret = __guc_add_request(gse->guc, rq);
if (ret == -EBUSY) {
- guc->stalled_rq = rq;
- guc->submission_stall_reason = STALL_ADD_REQUEST;
+ gse->stalled_rq = rq;
+ gse->submission_stall_reason = STALL_ADD_REQUEST;
} else {
- guc->stalled_rq = NULL;
- guc->submission_stall_reason = STALL_NONE;
+ gse->stalled_rq = NULL;
+ gse->submission_stall_reason = STALL_NONE;
}
return ret;
@@ -611,14 +627,14 @@ static int guc_add_request(struct intel_guc *guc, struct i915_request *rq)
static int guc_lrc_desc_pin(struct intel_context *ce, bool loop);
-static int tasklet_register_context(struct intel_guc *guc,
+static int tasklet_register_context(struct guc_submit_engine *gse,
struct i915_request *rq)
{
struct intel_context *ce = rq->context;
int ret = 0;
/* Check state */
- lockdep_assert_held(&guc->sched_engine->lock);
+ lockdep_assert_held(&gse->sched_engine.lock);
GEM_BUG_ON(ce->guc_num_rq_submit_no_id);
GEM_BUG_ON(request_has_no_guc_id(rq));
GEM_BUG_ON(context_guc_id_invalid(ce));
@@ -631,7 +647,7 @@ static int tasklet_register_context(struct intel_guc *guc,
* register this context or a corner case where the GuC firwmare was
* blown away and reloaded while this context was pinned
*/
- if (unlikely((!lrc_desc_registered(guc, ce->guc_id) ||
+ if (unlikely((!lrc_desc_registered(gse->guc, ce->guc_id) ||
context_needs_register(ce)) &&
!intel_context_is_banned(ce))) {
ret = guc_lrc_desc_pin(ce, false);
@@ -640,11 +656,11 @@ static int tasklet_register_context(struct intel_guc *guc,
clr_context_needs_register(ce);
if (unlikely(ret == -EBUSY)) {
- guc->stalled_rq = rq;
- guc->submission_stall_reason = STALL_REGISTER_CONTEXT;
+ gse->stalled_rq = rq;
+ gse->submission_stall_reason = STALL_REGISTER_CONTEXT;
} else if (unlikely(ret == -EINPROGRESS)) {
- guc->stalled_rq = rq;
- guc->submission_stall_reason = STALL_DEREGISTER_CONTEXT;
+ gse->stalled_rq = rq;
+ gse->submission_stall_reason = STALL_DEREGISTER_CONTEXT;
}
}
@@ -663,28 +679,29 @@ static inline int rq_prio(const struct i915_request *rq)
return rq->sched.attr.priority;
}
-static void kick_retire_wq(struct intel_guc *guc)
+static void kick_retire_wq(struct guc_submit_engine *gse)
{
- queue_work(system_unbound_wq, &guc->retire_worker);
+ queue_work(system_unbound_wq, &gse->retire_worker);
}
-static int tasklet_pin_guc_id(struct intel_guc *guc, struct i915_request *rq);
+static int tasklet_pin_guc_id(struct guc_submit_engine *gse,
+ struct i915_request *rq);
-static int guc_dequeue_one_context(struct intel_guc *guc)
+static int gse_dequeue_one_context(struct guc_submit_engine *gse)
{
- struct i915_sched_engine * const sched_engine = guc->sched_engine;
- struct i915_request *last = guc->stalled_rq;
+ struct i915_sched_engine * const sched_engine = &gse->sched_engine;
+ struct i915_request *last = gse->stalled_rq;
bool submit = !!last;
struct rb_node *rb;
int ret;
lockdep_assert_held(&sched_engine->lock);
- GEM_BUG_ON(guc->stalled_context);
- GEM_BUG_ON(!submit && guc->submission_stall_reason);
+ GEM_BUG_ON(gse->stalled_context);
+ GEM_BUG_ON(!submit && gse->submission_stall_reason);
if (submit) {
/* Flow control conditions */
- switch (guc->submission_stall_reason) {
+ switch (gse->submission_stall_reason) {
case STALL_GUC_ID_TASKLET:
goto done;
case STALL_REGISTER_CONTEXT:
@@ -697,8 +714,8 @@ static int guc_dequeue_one_context(struct intel_guc *guc)
GEM_BUG_ON("Invalid stall state");
}
} else {
- GEM_BUG_ON(!guc->total_num_rq_with_no_guc_id &&
- guc_ids_exhausted(guc));
+ GEM_BUG_ON(!gse->total_num_rq_with_no_guc_id &&
+ guc_ids_exhausted(gse));
while ((rb = rb_first_cached(&sched_engine->queue))) {
struct i915_priolist *p = to_priolist(rb);
@@ -727,13 +744,13 @@ static int guc_dequeue_one_context(struct intel_guc *guc)
struct intel_context *ce = last->context;
if (ce->guc_num_rq_submit_no_id) {
- ret = tasklet_pin_guc_id(guc, last);
+ ret = tasklet_pin_guc_id(gse, last);
if (ret)
goto blk_tasklet_kick;
}
register_context:
- ret = tasklet_register_context(guc, last);
+ ret = tasklet_register_context(gse, last);
if (unlikely(ret == -EINPROGRESS))
goto blk_tasklet;
else if (unlikely(ret == -EDEADLK))
@@ -749,7 +766,7 @@ static int guc_dequeue_one_context(struct intel_guc *guc)
guc_set_lrc_tail(last);
add_request:
- ret = guc_add_request(guc, last);
+ ret = gse_add_request(gse, last);
if (unlikely(ret == -EDEADLK))
goto deadlk;
else if (ret == -EBUSY)
@@ -764,8 +781,8 @@ static int guc_dequeue_one_context(struct intel_guc *guc)
* No requests without a guc_id, enable guc_id allocation at request
* creation time (guc_request_alloc).
*/
- if (!guc->total_num_rq_with_no_guc_id)
- clr_guc_ids_exhausted(guc);
+ if (!gse->total_num_rq_with_no_guc_id)
+ clr_guc_ids_exhausted(gse);
return submit;
@@ -780,25 +797,26 @@ static int guc_dequeue_one_context(struct intel_guc *guc)
return false;
blk_tasklet_kick:
- kick_retire_wq(guc);
+ kick_retire_wq(gse);
blk_tasklet:
- set_tasklet_blocked(guc);
+ set_tasklet_blocked(gse);
return false;
}
-static void guc_submission_tasklet(struct tasklet_struct *t)
+static void gse_submission_tasklet(struct tasklet_struct *t)
{
struct i915_sched_engine *sched_engine =
from_tasklet(sched_engine, t, tasklet);
- struct intel_guc *guc = &sched_engine->engine->gt->uc.guc;
+ struct guc_submit_engine *gse =
+ container_of(sched_engine, typeof(*gse), sched_engine);
unsigned long flags;
bool loop;
spin_lock_irqsave(&sched_engine->lock, flags);
- if (likely(!tasklet_blocked(guc)))
+ if (likely(!tasklet_blocked(gse)))
do {
- loop = guc_dequeue_one_context(guc);
+ loop = gse_dequeue_one_context(gse);
} while (loop);
i915_sched_engine_reset_on_empty(sched_engine);
@@ -871,65 +889,92 @@ static void scrub_guc_desc_for_outstanding_g2h(struct intel_guc *guc)
static inline bool
submission_disabled(struct intel_guc *guc)
{
- struct i915_sched_engine * const sched_engine = guc->sched_engine;
+ int i;
+
+ for (i = 0; i < GUC_SUBMIT_ENGINE_MAX; ++i) {
+ struct i915_sched_engine *sched_engine =
+ guc_to_sched_engine(guc, i);
+
+ if (unlikely(!__tasklet_is_enabled(&sched_engine->tasklet)))
+ return true;
+ }
- return unlikely(!__tasklet_is_enabled(&sched_engine->tasklet));
+ return false;
}
-static void kick_tasklet(struct intel_guc *guc)
+static void kick_tasklet(struct guc_submit_engine *gse)
{
- struct i915_sched_engine * const sched_engine = guc->sched_engine;
+ struct i915_sched_engine *sched_engine = &gse->sched_engine;
- if (likely(!tasklet_blocked(guc)))
+ if (likely(!tasklet_blocked(gse)))
i915_sched_engine_hi_kick(sched_engine);
}
static void disable_submission(struct intel_guc *guc)
{
- struct i915_sched_engine * const sched_engine = guc->sched_engine;
+ int i;
- if (__tasklet_is_enabled(&sched_engine->tasklet)) {
- GEM_BUG_ON(!guc->ct.enabled);
- __tasklet_disable_sync_once(&sched_engine->tasklet);
- sched_engine->tasklet.callback = NULL;
+ for (i = 0; i < GUC_SUBMIT_ENGINE_MAX; ++i) {
+ struct i915_sched_engine *sched_engine =
+ guc_to_sched_engine(guc, i);
+
+ if (__tasklet_is_enabled(&sched_engine->tasklet)) {
+ GEM_BUG_ON(!guc->ct.enabled);
+ __tasklet_disable_sync_once(&sched_engine->tasklet);
+ sched_engine->tasklet.callback = NULL;
+ }
}
}
static void enable_submission(struct intel_guc *guc)
{
- struct i915_sched_engine * const sched_engine = guc->sched_engine;
unsigned long flags;
+ int i;
- spin_lock_irqsave(&guc->sched_engine->lock, flags);
- sched_engine->tasklet.callback = guc_submission_tasklet;
- wmb();
- if (!__tasklet_is_enabled(&sched_engine->tasklet) &&
- __tasklet_enable(&sched_engine->tasklet)) {
- GEM_BUG_ON(!guc->ct.enabled);
-
- /* Reset tasklet state */
- guc->stalled_rq = NULL;
- if (guc->stalled_context)
- intel_context_put(guc->stalled_context);
- guc->stalled_context = NULL;
- guc->submission_stall_reason = STALL_NONE;
- guc->flags = 0;
-
- /* And kick in case we missed a new request submission. */
- kick_tasklet(guc);
+ for (i = 0; i < GUC_SUBMIT_ENGINE_MAX; ++i) {
+ struct i915_sched_engine *sched_engine =
+ guc_to_sched_engine(guc, i);
+ struct guc_submit_engine *gse = guc->gse[i];
+
+ spin_lock_irqsave(&sched_engine->lock, flags);
+ sched_engine->tasklet.callback = gse_submission_tasklet;
+ wmb();
+ if (!__tasklet_is_enabled(&sched_engine->tasklet) &&
+ __tasklet_enable(&sched_engine->tasklet)) {
+ GEM_BUG_ON(!guc->ct.enabled);
+
+ /* Reset GuC submit engine state */
+ gse->stalled_rq = NULL;
+ if (gse->stalled_context)
+ intel_context_put(gse->stalled_context);
+ gse->stalled_context = NULL;
+ gse->submission_stall_reason = STALL_NONE;
+ gse->flags = 0;
+
+ /* And kick in case we missed a new request submission. */
+ kick_tasklet(gse);
+ }
+ spin_unlock_irqrestore(&sched_engine->lock, flags);
}
- spin_unlock_irqrestore(&guc->sched_engine->lock, flags);
}
-static void guc_flush_submissions(struct intel_guc *guc)
+static void gse_flush_submissions(struct guc_submit_engine *gse)
{
- struct i915_sched_engine * const sched_engine = guc->sched_engine;
+ struct i915_sched_engine * const sched_engine = &gse->sched_engine;
unsigned long flags;
spin_lock_irqsave(&sched_engine->lock, flags);
spin_unlock_irqrestore(&sched_engine->lock, flags);
}
+static void guc_flush_submissions(struct intel_guc *guc)
+{
+ int i;
+
+ for (i = 0; i < GUC_SUBMIT_ENGINE_MAX; ++i)
+ gse_flush_submissions(guc->gse[i]);
+}
+
void intel_guc_submission_reset_prepare(struct intel_guc *guc)
{
int i;
@@ -1111,13 +1156,12 @@ void intel_guc_submission_reset(struct intel_guc *guc, bool stalled)
if (intel_context_is_pinned(ce))
__guc_reset_context(ce, stalled);
- /* GuC is blown away, drop all references to contexts */
xa_destroy(&guc->context_lookup);
}
static void guc_cancel_context_requests(struct intel_context *ce)
{
- struct i915_sched_engine *sched_engine = ce_to_guc(ce)->sched_engine;
+ struct i915_sched_engine *sched_engine = ce_to_sched_engine(ce);
struct i915_request *rq;
unsigned long flags;
@@ -1132,8 +1176,9 @@ static void guc_cancel_context_requests(struct intel_context *ce)
}
static void
-guc_cancel_sched_engine_requests(struct i915_sched_engine *sched_engine)
+gse_cancel_requests(struct guc_submit_engine *gse)
{
+ struct i915_sched_engine *sched_engine = &gse->sched_engine;
struct i915_request *rq, *rn;
struct rb_node *rb;
unsigned long flags;
@@ -1190,12 +1235,14 @@ void intel_guc_submission_cancel_requests(struct intel_guc *guc)
{
struct intel_context *ce;
unsigned long index;
+ int i;
xa_for_each(&guc->context_lookup, index, ce)
if (intel_context_is_pinned(ce))
guc_cancel_context_requests(ce);
- guc_cancel_sched_engine_requests(guc->sched_engine);
+ for (i = 0; i < GUC_SUBMIT_ENGINE_MAX; ++i)
+ gse_cancel_requests(guc->gse[i]);
/* GuC is blown away, drop all references to contexts */
xa_destroy(&guc->context_lookup);
@@ -1222,13 +1269,13 @@ void intel_guc_submission_reset_finish(struct intel_guc *guc)
intel_gt_unpark_heartbeats(guc_to_gt(guc));
}
-static void retire_worker_sched_disable(struct intel_guc *guc,
+static void retire_worker_sched_disable(struct guc_submit_engine *gse,
struct intel_context *ce);
static void retire_worker_func(struct work_struct *w)
{
- struct intel_guc *guc =
- container_of(w, struct intel_guc, retire_worker);
+ struct guc_submit_engine *gse =
+ container_of(w, struct guc_submit_engine, retire_worker);
/*
* It is possible that another thread issues the schedule disable + that
@@ -1236,17 +1283,17 @@ static void retire_worker_func(struct work_struct *w)
* where nothing needs to be done here. Let's be paranoid and kick the
* tasklet in that case.
*/
- if (guc->submission_stall_reason != STALL_SCHED_DISABLE &&
- guc->submission_stall_reason != STALL_GUC_ID_WORKQUEUE) {
- kick_tasklet(guc);
+ if (gse->submission_stall_reason != STALL_SCHED_DISABLE &&
+ gse->submission_stall_reason != STALL_GUC_ID_WORKQUEUE) {
+ kick_tasklet(gse);
return;
}
- if (guc->submission_stall_reason == STALL_SCHED_DISABLE) {
- GEM_BUG_ON(!guc->stalled_context);
- GEM_BUG_ON(context_guc_id_invalid(guc->stalled_context));
+ if (gse->submission_stall_reason == STALL_SCHED_DISABLE) {
+ GEM_BUG_ON(!gse->stalled_context);
+ GEM_BUG_ON(context_guc_id_invalid(gse->stalled_context));
- retire_worker_sched_disable(guc, guc->stalled_context);
+ retire_worker_sched_disable(gse, gse->stalled_context);
}
/*
@@ -1254,16 +1301,16 @@ static void retire_worker_func(struct work_struct *w)
* albeit after possibly issuing a schedule disable as that is async
* operation.
*/
- intel_gt_retire_requests(guc_to_gt(guc));
+ intel_gt_retire_requests(guc_to_gt(gse->guc));
- if (guc->submission_stall_reason == STALL_GUC_ID_WORKQUEUE) {
- GEM_BUG_ON(guc->stalled_context);
+ if (gse->submission_stall_reason == STALL_GUC_ID_WORKQUEUE) {
+ GEM_BUG_ON(gse->stalled_context);
/* Hopefully guc_ids are now available, kick tasklet */
- guc->submission_stall_reason = STALL_GUC_ID_TASKLET;
- clr_tasklet_blocked(guc);
+ gse->submission_stall_reason = STALL_GUC_ID_TASKLET;
+ clr_tasklet_blocked(gse);
- kick_tasklet(guc);
+ kick_tasklet(gse);
}
}
@@ -1294,18 +1341,24 @@ int intel_guc_submission_init(struct intel_guc *guc)
INIT_LIST_HEAD(&guc->guc_id_list_unpinned);
ida_init(&guc->guc_ids);
- INIT_WORK(&guc->retire_worker, retire_worker_func);
-
return 0;
}
void intel_guc_submission_fini(struct intel_guc *guc)
{
+ int i;
+
if (!guc->lrc_desc_pool)
return;
guc_lrc_desc_pool_destroy(guc);
- i915_sched_engine_put(guc->sched_engine);
+
+ for (i = 0; i < GUC_SUBMIT_ENGINE_MAX; ++i) {
+ struct i915_sched_engine *sched_engine =
+ guc_to_sched_engine(guc, i);
+
+ i915_sched_engine_put(sched_engine);
+ }
}
static inline void queue_request(struct i915_sched_engine *sched_engine,
@@ -1320,22 +1373,22 @@ static inline void queue_request(struct i915_sched_engine *sched_engine,
set_bit(I915_FENCE_FLAG_PQUEUE, &rq->fence.flags);
if (empty)
- kick_tasklet(&rq->engine->gt->uc.guc);
+ kick_tasklet(ce_to_gse(rq->context));
}
/* Macro to tweak heuristic, using a simple over 50% not ready for now */
#define TOO_MANY_GUC_IDS_NOT_READY(avail, consumed) \
(consumed > avail / 2)
-static bool too_many_guc_ids_not_ready(struct intel_guc *guc,
+static bool too_many_guc_ids_not_ready(struct guc_submit_engine *gse,
struct intel_context *ce)
{
u32 available_guc_ids, guc_ids_consumed;
- available_guc_ids = guc->num_guc_ids;
- guc_ids_consumed = atomic_read(&guc->num_guc_ids_not_ready);
+ available_guc_ids = gse->guc->num_guc_ids;
+ guc_ids_consumed = atomic_read(&gse->num_guc_ids_not_ready);
if (TOO_MANY_GUC_IDS_NOT_READY(available_guc_ids, guc_ids_consumed)) {
- set_and_update_guc_ids_exhausted(guc);
+ set_and_update_guc_ids_exhausted(gse);
return true;
}
@@ -1344,34 +1397,35 @@ static bool too_many_guc_ids_not_ready(struct intel_guc *guc,
static void incr_num_rq_not_ready(struct intel_context *ce)
{
- struct intel_guc *guc = ce_to_guc(ce);
+ struct guc_submit_engine *gse = ce_to_gse(ce);
if (!atomic_fetch_add(1, &ce->guc_num_rq_not_ready))
- atomic_inc(&guc->num_guc_ids_not_ready);
+ atomic_inc(&gse->num_guc_ids_not_ready);
}
void intel_guc_decr_num_rq_not_ready(struct intel_context *ce)
{
- struct intel_guc *guc = ce_to_guc(ce);
+ struct guc_submit_engine *gse = ce_to_gse(ce);
- if (atomic_fetch_add(-1, &ce->guc_num_rq_not_ready) == 1)
- atomic_dec(&guc->num_guc_ids_not_ready);
+ if (atomic_fetch_add(-1, &ce->guc_num_rq_not_ready) == 1) {
+ GEM_BUG_ON(!atomic_read(&gse->num_guc_ids_not_ready));
+ atomic_dec(&gse->num_guc_ids_not_ready);
+ }
}
-static bool need_tasklet(struct intel_guc *guc, struct intel_context *ce)
+static bool need_tasklet(struct guc_submit_engine *gse, struct intel_context *ce)
{
- struct i915_sched_engine * const sched_engine =
- ce->engine->sched_engine;
+ struct i915_sched_engine * const sched_engine = &gse->sched_engine;
lockdep_assert_held(&sched_engine->lock);
- return guc_ids_exhausted(guc) || submission_disabled(guc) ||
- guc->stalled_rq || guc->stalled_context ||
- !lrc_desc_registered(guc, ce->guc_id) ||
+ return guc_ids_exhausted(gse) || submission_disabled(gse->guc) ||
+ gse->stalled_rq || gse->stalled_context ||
+ !lrc_desc_registered(gse->guc, ce->guc_id) ||
!i915_sched_engine_is_empty(sched_engine);
}
-static int guc_bypass_tasklet_submit(struct intel_guc *guc,
+static int gse_bypass_tasklet_submit(struct guc_submit_engine *gse,
struct i915_request *rq)
{
int ret;
@@ -1381,27 +1435,27 @@ static int guc_bypass_tasklet_submit(struct intel_guc *guc,
trace_i915_request_in(rq, 0);
guc_set_lrc_tail(rq);
- ret = guc_add_request(guc, rq);
+ ret = gse_add_request(gse, rq);
if (unlikely(ret == -EDEADLK))
- disable_submission(guc);
+ disable_submission(gse->guc);
return ret;
}
static void guc_submit_request(struct i915_request *rq)
{
+ struct guc_submit_engine *gse = ce_to_gse(rq->context);
struct i915_sched_engine *sched_engine = rq->engine->sched_engine;
- struct intel_guc *guc = &rq->engine->gt->uc.guc;
unsigned long flags;
/* Will be called from irq-context when using foreign fences. */
spin_lock_irqsave(&sched_engine->lock, flags);
- if (need_tasklet(guc, rq->context))
+ if (need_tasklet(gse, rq->context))
queue_request(sched_engine, rq, rq_prio(rq));
- else if (guc_bypass_tasklet_submit(guc, rq) == -EBUSY)
- kick_tasklet(guc);
+ else if (gse_bypass_tasklet_submit(gse, rq) == -EBUSY)
+ kick_tasklet(gse);
spin_unlock_irqrestore(&sched_engine->lock, flags);
@@ -1478,8 +1532,9 @@ static int steal_guc_id(struct intel_guc *guc, bool unpinned)
* context.
*/
if (!unpinned) {
- GEM_BUG_ON(guc->stalled_context);
- guc->stalled_context = intel_context_get(ce);
+ GEM_BUG_ON(ce_to_gse(ce)->stalled_context);
+
+ ce_to_gse(ce)->stalled_context = intel_context_get(ce);
set_context_guc_id_stolen(ce);
} else {
set_context_guc_id_invalid(ce);
@@ -1539,7 +1594,7 @@ static int pin_guc_id(struct intel_guc *guc, struct intel_context *ce,
try_again:
spin_lock_irqsave(&guc->contexts_lock, flags);
- if (!tasklet && guc_ids_exhausted(guc)) {
+ if (!tasklet && guc_ids_exhausted(ce_to_gse(ce))) {
ret = -EAGAIN;
goto out_unlock;
}
@@ -1860,7 +1915,7 @@ static void guc_context_ban(struct intel_context *ce, struct i915_request *rq)
struct intel_guc *guc = ce_to_guc(ce);
unsigned long flags;
- guc_flush_submissions(guc);
+ gse_flush_submissions(ce_to_gse(ce));
spin_lock_irqsave(&ce->guc_state.lock, flags);
set_context_banned(ce);
@@ -1936,7 +1991,7 @@ static void guc_context_sched_disable(struct intel_context *ce)
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
with_intel_runtime_pm(runtime_pm, wakeref)
- __guc_context_sched_disable(guc, ce, guc_id);
+ __guc_context_sched_disable(ce_to_guc(ce), ce, guc_id);
return;
unpin:
@@ -2077,7 +2132,7 @@ static void remove_from_context(struct i915_request *rq)
if (likely(!request_has_no_guc_id(rq)))
atomic_dec(&ce->guc_id_ref);
else
- --ce_to_guc(rq->context)->total_num_rq_with_no_guc_id;
+ --ce_to_gse(rq->context)->total_num_rq_with_no_guc_id;
unpin_guc_id(ce_to_guc(ce), ce, false);
i915_request_notify_execute_cb_imm(rq);
@@ -2136,15 +2191,15 @@ static void invalidate_guc_id_sched_disable(struct intel_context *ce)
clr_context_guc_id_stolen(ce);
}
-static void retire_worker_sched_disable(struct intel_guc *guc,
+static void retire_worker_sched_disable(struct guc_submit_engine *gse,
struct intel_context *ce)
{
unsigned long flags;
bool disabled;
- guc->stalled_context = NULL;
+ gse->stalled_context = NULL;
spin_lock_irqsave(&ce->guc_state.lock, flags);
- disabled = submission_disabled(guc);
+ disabled = submission_disabled(gse->guc);
if (!disabled && !context_pending_disable(ce) && context_enabled(ce)) {
/*
* Still enabled, issue schedule disable + configure state so
@@ -2168,7 +2223,7 @@ static void retire_worker_sched_disable(struct intel_guc *guc,
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
with_intel_runtime_pm(runtime_pm, wakeref)
- __guc_context_sched_disable(guc, ce, guc_id);
+ __guc_context_sched_disable(gse->guc, ce, guc_id);
invalidate_guc_id_sched_disable(ce);
} else if (!disabled && context_pending_disable(ce)) {
@@ -2188,10 +2243,10 @@ static void retire_worker_sched_disable(struct intel_guc *guc,
invalidate_guc_id_sched_disable(ce);
- guc->submission_stall_reason = STALL_REGISTER_CONTEXT;
- clr_tasklet_blocked(guc);
+ gse->submission_stall_reason = STALL_REGISTER_CONTEXT;
+ clr_tasklet_blocked(gse);
- kick_tasklet(ce_to_guc(ce));
+ kick_tasklet(gse);
}
intel_context_put(ce);
@@ -2204,25 +2259,26 @@ static bool context_needs_lrc_desc_pin(struct intel_context *ce, bool new_guc_id
!submission_disabled(ce_to_guc(ce));
}
-static int tasklet_pin_guc_id(struct intel_guc *guc, struct i915_request *rq)
+static int tasklet_pin_guc_id(struct guc_submit_engine *gse,
+ struct i915_request *rq)
{
struct intel_context *ce = rq->context;
int ret = 0;
- lockdep_assert_held(&guc->sched_engine->lock);
+ lockdep_assert_held(&gse->sched_engine.lock);
GEM_BUG_ON(!ce->guc_num_rq_submit_no_id);
if (atomic_add_unless(&ce->guc_id_ref, ce->guc_num_rq_submit_no_id, 0))
goto out;
- ret = pin_guc_id(guc, ce, true);
+ ret = pin_guc_id(gse->guc, ce, true);
if (unlikely(ret < 0)) {
/*
* No guc_ids available, disable the tasklet and kick the retire
* workqueue hopefully freeing up some guc_ids.
*/
- guc->stalled_rq = rq;
- guc->submission_stall_reason = STALL_GUC_ID_WORKQUEUE;
+ gse->stalled_rq = rq;
+ gse->submission_stall_reason = STALL_GUC_ID_WORKQUEUE;
return ret;
}
@@ -2234,14 +2290,14 @@ static int tasklet_pin_guc_id(struct intel_guc *guc, struct i915_request *rq)
set_context_needs_register(ce);
if (ret == NEW_GUC_ID_ENABLED) {
- guc->stalled_rq = rq;
- guc->submission_stall_reason = STALL_SCHED_DISABLE;
+ gse->stalled_rq = rq;
+ gse->submission_stall_reason = STALL_SCHED_DISABLE;
}
clear_bit(CONTEXT_LRCA_DIRTY, &ce->flags);
out:
- guc->total_num_rq_with_no_guc_id -= ce->guc_num_rq_submit_no_id;
- GEM_BUG_ON(guc->total_num_rq_with_no_guc_id < 0);
+ gse->total_num_rq_with_no_guc_id -= ce->guc_num_rq_submit_no_id;
+ GEM_BUG_ON(gse->total_num_rq_with_no_guc_id < 0);
list_for_each_entry_reverse(rq, &ce->guc_active.requests, sched.link)
if (request_has_no_guc_id(rq)) {
@@ -2259,7 +2315,7 @@ static int tasklet_pin_guc_id(struct intel_guc *guc, struct i915_request *rq)
* from a context that has scheduling enabled. We have to disable
* scheduling before deregistering the context and it isn't safe to do
* in the tasklet because of lock inversion (ce->guc_state.lock must be
- * acquired before guc->sched_engine->lock). To work around this
+ * acquired before gse->sched_engine.lock). To work around this
* we do the schedule disable in retire workqueue and block the tasklet
* until the schedule done G2H returns. Returning non-zero here kicks
* the workqueue.
@@ -2271,6 +2327,7 @@ static int guc_request_alloc(struct i915_request *rq)
{
struct intel_context *ce = rq->context;
struct intel_guc *guc = ce_to_guc(ce);
+ struct guc_submit_engine *gse = ce_to_gse(ce);
unsigned long flags;
int ret;
@@ -2282,8 +2339,8 @@ static int guc_request_alloc(struct i915_request *rq)
* ready to submit). Don't allocate one here, defer to submission in the
* tasklet.
*/
- if (test_and_update_guc_ids_exhausted(guc) ||
- too_many_guc_ids_not_ready(guc, ce)) {
+ if (test_and_update_guc_ids_exhausted(gse) ||
+ too_many_guc_ids_not_ready(gse, ce)) {
set_bit(I915_FENCE_FLAG_GUC_ID_NOT_PINNED, &rq->fence.flags);
goto out;
}
@@ -2338,7 +2395,7 @@ static int guc_request_alloc(struct i915_request *rq)
* submissions we return to allocating guc_ids in this function.
*/
set_bit(I915_FENCE_FLAG_GUC_ID_NOT_PINNED, &rq->fence.flags);
- set_and_update_guc_ids_exhausted(guc);
+ set_and_update_guc_ids_exhausted(gse);
incr_num_rq_not_ready(ce);
return 0;
@@ -2729,10 +2786,37 @@ static inline void guc_default_irqs(struct intel_engine_cs *engine)
intel_engine_set_irq_handler(engine, cs_irq_handler);
}
+static void guc_sched_engine_destroy(struct kref *kref)
+{
+ struct i915_sched_engine *sched_engine =
+ container_of(kref, typeof(*sched_engine), ref);
+ struct guc_submit_engine *gse =
+ container_of(sched_engine, typeof(*gse), sched_engine);
+
+ i915_sched_engine_kill(sched_engine); /* flush the callback */
+ kfree(gse);
+}
+
+static void guc_submit_engine_init(struct intel_guc *guc,
+ struct guc_submit_engine *gse,
+ int id)
+{
+ i915_sched_engine_init(&gse->sched_engine, ENGINE_VIRTUAL);
+ INIT_WORK(&gse->retire_worker, retire_worker_func);
+ tasklet_setup(&gse->sched_engine.tasklet, gse_submission_tasklet);
+ gse->sched_engine.schedule = i915_schedule;
+ gse->sched_engine.disabled = guc_sched_engine_disabled;
+ gse->sched_engine.destroy = guc_sched_engine_destroy;
+ gse->guc = guc;
+ gse->id = id;
+}
+
int intel_guc_submission_setup(struct intel_engine_cs *engine)
{
struct drm_i915_private *i915 = engine->i915;
struct intel_guc *guc = &engine->gt->uc.guc;
+ struct i915_sched_engine *sched_engine;
+ int ret, i;
/*
* The setup relies on several assumptions (e.g. irqs always enabled)
@@ -2740,19 +2824,20 @@ int intel_guc_submission_setup(struct intel_engine_cs *engine)
*/
GEM_BUG_ON(INTEL_GEN(i915) < 11);
- if (!guc->sched_engine) {
- guc->sched_engine = i915_sched_engine_create(ENGINE_VIRTUAL);
- if (!guc->sched_engine)
- return -ENOMEM;
-
- guc->sched_engine->schedule = i915_schedule;
- guc->sched_engine->disabled = guc_sched_engine_disabled;
- guc->sched_engine->engine = engine;
- tasklet_setup(&guc->sched_engine->tasklet,
- guc_submission_tasklet);
+ if (!guc->gse[0]) {
+ for (i = 0; i < GUC_SUBMIT_ENGINE_MAX; ++i) {
+ guc->gse[i] = kzalloc(sizeof(*guc->gse[i]), GFP_KERNEL);
+ if (!guc->gse[i]) {
+ ret = -ENOMEM;
+ goto put_sched_engine;
+ }
+ guc_submit_engine_init(guc, guc->gse[i], i);
+ }
}
+
+ sched_engine = guc_to_sched_engine(guc, GUC_SUBMIT_ENGINE_SINGLE_LRC);
i915_sched_engine_put(engine->sched_engine);
- engine->sched_engine = i915_sched_engine_get(guc->sched_engine);
+ engine->sched_engine = i915_sched_engine_get(sched_engine);
guc_default_vfuncs(engine);
guc_default_irqs(engine);
@@ -2768,6 +2853,16 @@ int intel_guc_submission_setup(struct intel_engine_cs *engine)
engine->release = guc_release;
return 0;
+
+put_sched_engine:
+ for (i = 0; i < GUC_SUBMIT_ENGINE_MAX; ++i) {
+ struct i915_sched_engine *sched_engine =
+ guc_to_sched_engine(guc, i);
+
+ if (sched_engine)
+ i915_sched_engine_put(sched_engine);
+ }
+ return ret;
}
void intel_guc_submission_enable(struct intel_guc *guc)
@@ -2863,14 +2958,16 @@ int intel_guc_deregister_done_process_msg(struct intel_guc *guc,
register_context(ce, true);
guc_signal_context_fence(ce);
if (context_block_tasklet(ce)) {
- GEM_BUG_ON(guc->submission_stall_reason !=
+ struct guc_submit_engine *gse = ce_to_gse(ce);
+
+ GEM_BUG_ON(gse->submission_stall_reason !=
STALL_DEREGISTER_CONTEXT);
clr_context_block_tasklet(ce);
- guc->submission_stall_reason = STALL_MOVE_LRC_TAIL;
- clr_tasklet_blocked(guc);
+ gse->submission_stall_reason = STALL_MOVE_LRC_TAIL;
+ clr_tasklet_blocked(gse);
- kick_tasklet(ce_to_guc(ce));
+ kick_tasklet(gse);
}
intel_context_put(ce);
} else if (context_destroyed(ce)) {
@@ -2935,11 +3032,13 @@ int intel_guc_sched_done_process_msg(struct intel_guc *guc,
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
if (context_block_tasklet(ce)) {
+ struct guc_submit_engine *gse = ce_to_gse(ce);
+
clr_context_block_tasklet(ce);
- guc->submission_stall_reason = STALL_REGISTER_CONTEXT;
- clr_tasklet_blocked(guc);
+ gse->submission_stall_reason = STALL_REGISTER_CONTEXT;
+ clr_tasklet_blocked(gse);
- kick_tasklet(ce_to_guc(ce));
+ kick_tasklet(gse);
}
if (banned) {
@@ -2971,7 +3070,7 @@ static void capture_error_state(struct intel_guc *guc,
static void guc_context_replay(struct intel_context *ce)
{
__guc_reset_context(ce, true);
- kick_tasklet(ce_to_guc(ce));
+ kick_tasklet(ce_to_gse(ce));
}
static void guc_handle_context_reset(struct intel_guc *guc,
@@ -3115,32 +3214,29 @@ void intel_guc_dump_active_requests(struct intel_engine_cs *engine,
}
}
-void intel_guc_log_submission_info(struct intel_guc *guc,
- struct drm_printer *p)
+static void gse_log_submission_info(struct guc_submit_engine *gse,
+ struct drm_printer *p, int id)
{
- struct i915_sched_engine *sched_engine = guc->sched_engine;
+ struct i915_sched_engine *sched_engine = &gse->sched_engine;
struct rb_node *rb;
unsigned long flags;
- drm_printf(p, "GuC Number Outstanding Submission G2H: %u\n",
- atomic_read(&guc->outstanding_submission_g2h));
- drm_printf(p, "GuC Number GuC IDs: %u\n", guc->num_guc_ids);
- drm_printf(p, "GuC Max GuC IDs: %u\n", guc->max_guc_ids);
- drm_printf(p, "GuC tasklet count: %u\n",
+ drm_printf(p, "GSE[%d] tasklet count: %u\n", id,
atomic_read(&sched_engine->tasklet.count));
- drm_printf(p, "GuC submit flags: 0x%04lx\n", guc->flags);
- drm_printf(p, "GuC total number request without guc_id: %d\n",
- guc->total_num_rq_with_no_guc_id);
- drm_printf(p, "GuC Number GuC IDs not ready: %d\n",
- atomic_read(&guc->num_guc_ids_not_ready));
- drm_printf(p, "GuC stall reason: %d\n", guc->submission_stall_reason);
- drm_printf(p, "GuC stalled request: %s\n",
- yesno(guc->stalled_rq));
- drm_printf(p, "GuC stalled context: %s\n\n",
- yesno(guc->stalled_context));
+ drm_printf(p, "GSE[%d] submit flags: 0x%04lx\n", id, gse->flags);
+ drm_printf(p, "GSE[%d] total number request without guc_id: %d\n",
+ id, gse->total_num_rq_with_no_guc_id);
+ drm_printf(p, "GSE[%d] Number GuC IDs not ready: %d\n",
+ id, atomic_read(&gse->num_guc_ids_not_ready));
+ drm_printf(p, "GSE[%d] stall reason: %d\n",
+ id, gse->submission_stall_reason);
+ drm_printf(p, "GSE[%d] stalled request: %s\n",
+ id, yesno(gse->stalled_rq));
+ drm_printf(p, "GSE[%d] stalled context: %s\n\n",
+ id, yesno(gse->stalled_context));
spin_lock_irqsave(&sched_engine->lock, flags);
- drm_printf(p, "Requests in GuC submit tasklet:\n");
+ drm_printf(p, "Requests in GSE[%d] submit tasklet:\n", id);
for (rb = rb_first_cached(&sched_engine->queue); rb; rb = rb_next(rb)) {
struct i915_priolist *pl = to_priolist(rb);
struct i915_request *rq;
@@ -3154,6 +3250,20 @@ void intel_guc_log_submission_info(struct intel_guc *guc,
drm_printf(p, "\n");
}
+void intel_guc_log_submission_info(struct intel_guc *guc,
+ struct drm_printer *p)
+{
+ int i;
+
+ drm_printf(p, "GuC Number Outstanding Submission G2H: %u\n",
+ atomic_read(&guc->outstanding_submission_g2h));
+ drm_printf(p, "GuC Number GuC IDs: %d\n", guc->num_guc_ids);
+ drm_printf(p, "GuC Max Number GuC IDs: %d\n\n", guc->max_guc_ids);
+
+ for (i = 0; i < GUC_SUBMIT_ENGINE_MAX; ++i)
+ gse_log_submission_info(guc->gse[i], p, i);
+}
+
void intel_guc_log_context_info(struct intel_guc *guc,
struct drm_printer *p)
{
@@ -3185,6 +3295,7 @@ guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count)
{
struct guc_virtual_engine *ve;
struct intel_guc *guc;
+ struct i915_sched_engine *sched_engine;
unsigned int n;
int err;
@@ -3193,6 +3304,7 @@ guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count)
return ERR_PTR(-ENOMEM);
guc = &siblings[0]->gt->uc.guc;
+ sched_engine = guc_to_sched_engine(guc, GUC_SUBMIT_ENGINE_SINGLE_LRC);
ve->base.i915 = siblings[0]->i915;
ve->base.gt = siblings[0]->gt;
@@ -3206,7 +3318,7 @@ guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count)
snprintf(ve->base.name, sizeof(ve->base.name), "virtual");
- ve->base.sched_engine = i915_sched_engine_get(guc->sched_engine);
+ ve->base.sched_engine = i915_sched_engine_get(sched_engine);
ve->base.cops = &virtual_guc_context_ops;
ve->base.request_alloc = guc_request_alloc;
new file mode 100644
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2014-2019 Intel Corporation
+ */
+
+#ifndef _INTEL_GUC_SUBMISSION_TYPES_H_
+#define _INTEL_GUC_SUBMISSION_TYPES_H_
+
+#include "gt/intel_engine_types.h"
+#include "gt/intel_context_types.h"
+#include "i915_scheduler_types.h"
+
+struct intel_guc;
+struct i915_request;
+
+/* GuC Virtual Engine */
+struct guc_virtual_engine {
+ struct intel_engine_cs base;
+ struct intel_context context;
+};
+
+/*
+ * Object which encapsulates the globally operated on i915_sched_engine +
+ * the GuC submission state machine described in intel_guc_submission.c.
+ */
+struct guc_submit_engine {
+ struct i915_sched_engine sched_engine;
+ struct work_struct retire_worker;
+ struct intel_guc *guc;
+ struct i915_request *stalled_rq;
+ struct intel_context *stalled_context;
+ unsigned long flags;
+ int total_num_rq_with_no_guc_id;
+ atomic_t num_guc_ids_not_ready;
+ int id;
+
+ /*
+ * Submisson stall reason. See intel_guc_submission.c for detailed
+ * description.
+ */
+ enum {
+ STALL_NONE,
+ STALL_GUC_ID_WORKQUEUE,
+ STALL_GUC_ID_TASKLET,
+ STALL_SCHED_DISABLE,
+ STALL_REGISTER_CONTEXT,
+ STALL_DEREGISTER_CONTEXT,
+ STALL_MOVE_LRC_TAIL,
+ STALL_ADD_REQUEST,
+ } submission_stall_reason;
+};
+
+#endif
@@ -431,7 +431,7 @@ void i915_request_show_with_schedule(struct drm_printer *m,
rcu_read_unlock();
}
-void i915_sched_engine_free(struct kref *kref)
+static void default_destroy(struct kref *kref)
{
struct i915_sched_engine *sched_engine =
container_of(kref, typeof(*sched_engine), ref);
@@ -445,20 +445,15 @@ static bool default_disabled(struct i915_sched_engine *sched_engine)
return false;
}
-struct i915_sched_engine *
-i915_sched_engine_create(unsigned int subclass)
+void i915_sched_engine_init(struct i915_sched_engine *sched_engine,
+ unsigned int subclass)
{
- struct i915_sched_engine *sched_engine;
-
- sched_engine = kzalloc(sizeof(*sched_engine), GFP_KERNEL);
- if (!sched_engine)
- return NULL;
-
kref_init(&sched_engine->ref);
sched_engine->queue = RB_ROOT_CACHED;
sched_engine->queue_priority_hint = INT_MIN;
sched_engine->disabled = default_disabled;
+ sched_engine->destroy = default_destroy;
INIT_LIST_HEAD(&sched_engine->requests);
INIT_LIST_HEAD(&sched_engine->hold);
@@ -477,7 +472,19 @@ i915_sched_engine_create(unsigned int subclass)
lock_map_release(&sched_engine->lock.dep_map);
local_irq_enable();
#endif
+}
+
+struct i915_sched_engine *
+i915_sched_engine_create(unsigned int subclass)
+{
+ struct i915_sched_engine *sched_engine;
+
+ sched_engine = kzalloc(sizeof(*sched_engine), GFP_KERNEL);
+ if (!sched_engine)
+ return NULL;
+ i915_sched_engine_init(sched_engine, subclass);
+
return sched_engine;
}
@@ -53,6 +53,9 @@ void i915_request_show_with_schedule(struct drm_printer *m,
const char *prefix,
int indent);
+void i915_sched_engine_init(struct i915_sched_engine *sched_engine,
+ unsigned int subclass);
+
struct i915_sched_engine *
i915_sched_engine_create(unsigned int subclass);
@@ -68,7 +71,7 @@ i915_sched_engine_get(struct i915_sched_engine *sched_engine)
static inline void
i915_sched_engine_put(struct i915_sched_engine *sched_engine)
{
- kref_put(&sched_engine->ref, i915_sched_engine_free);
+ kref_put(&sched_engine->ref, sched_engine->destroy);
}
static inline bool
@@ -141,6 +141,9 @@ struct i915_sched_engine {
/* Back pointer to engine */
struct intel_engine_cs *engine;
+ /* Destroy schedule engine */
+ void (*destroy)(struct kref *kref);
+
/* Schedule engine is disabled by backend */
bool (*disabled)(struct i915_sched_engine *sched_engine);
Move fields related to controlling the GuC submission state machine to a unique object (guc_submit_engine) rather than the global GuC state (intel_guc). This encapsulation allows multiple instances of submission objects to operate in parallel and a single instance can block if needed while another can make forward progress. This is analogous to how the execlist mode works assigning a schedule object per physical engine but rather in GuC mode we assign a schedule object based on the blocking dependencies. The guc_submit_engine object also encapsulates the i915_sched_engine object as well. Lots of find-replace. Currently only 1 guc_submit_engine instantiated, future patches will instantiate more. Signed-off-by: Matthew Brost <matthew.brost@intel.com> Cc: John Harrison <John.C.Harrison@Intel.com> --- drivers/gpu/drm/i915/gt/uc/intel_guc.h | 33 +- .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 544 +++++++++++------- .../i915/gt/uc/intel_guc_submission_types.h | 53 ++ drivers/gpu/drm/i915/i915_scheduler.c | 25 +- drivers/gpu/drm/i915/i915_scheduler.h | 5 +- drivers/gpu/drm/i915/i915_scheduler_types.h | 3 + 6 files changed, 411 insertions(+), 252 deletions(-) create mode 100644 drivers/gpu/drm/i915/gt/uc/intel_guc_submission_types.h