[RFC 07/11] drm/i915/guc: Add a second client, to be used for preemption

Michał Winiarski
2017-02-23T19:15:08Z

From: Dave Gordon <david.s.gordon@intel.com>

This second client is created with priority KMD_HIGH, and marked
as preemptive.

v2: Rebase, cleanup, use an array for the second client.

Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
drivers/gpu/drm/i915/i915_debugfs.c | 8 +--
drivers/gpu/drm/i915/i915_guc_submission.c | 86 ++++++++++++++++++++----------
drivers/gpu/drm/i915/intel_uc.h | 9 +++-
3 files changed, 71 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 1a28b52..10490bf 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2514,7 +2514,7 @@ static int i915_guc_info(struct seq_file *m, void *data)
enum intel_engine_id id;
u64 total;

- if (!guc->execbuf_client) {
+ if (!guc->client[NORMAL]) {
seq_printf(m, "GuC submission %s\n",
HAS_GUC_SCHED(dev_priv) ?
"disabled" :
@@ -2542,8 +2542,10 @@ static int i915_guc_info(struct seq_file *m, void *data)
}
seq_printf(m, "\t%s: %llu\n", "Total", total);

- seq_printf(m, "\nGuC execbuf client @ %p:\n", guc->execbuf_client);
- i915_guc_client_info(m, dev_priv, guc->execbuf_client);
+ seq_printf(m, "\nGuC execbuf client @ %p:\n", guc->client[NORMAL]);
+ i915_guc_client_info(m, dev_priv, guc->client[NORMAL]);
+ seq_printf(m, "\nGuC preempt client @ %p:\n", guc->client[PREEMPT]);
+ i915_guc_client_info(m, dev_priv, guc->client[PREEMPT]);

i915_guc_log_info(m, dev_priv);

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 3080735..2a658b9 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -247,6 +247,8 @@ static void guc_ctx_desc_init(struct intel_guc *guc,
memset(&desc, 0, sizeof(desc));

desc.attribute = GUC_CTX_DESC_ATTR_ACTIVE | GUC_CTX_DESC_ATTR_KERNEL;
+ if (client->priority <= GUC_CTX_PRIORITY_HIGH)
+ desc.attribute |= GUC_CTX_DESC_ATTR_PREEMPT;
desc.context_id = client->ctx_index;
desc.priority = client->priority;
desc.db_id = client->doorbell_id;
@@ -344,7 +346,7 @@ static void guc_ctx_desc_fini(struct intel_guc *guc,
int i915_guc_wq_reserve(struct drm_i915_gem_request *request)
{
const size_t wqi_size = sizeof(struct guc_wq_item);
- struct i915_guc_client *client = request->i915->guc.execbuf_client;
+ struct i915_guc_client *client = request->i915->guc.client[NORMAL];
struct guc_process_desc *desc = client->vaddr +
client->proc_desc_offset;
u32 freespace;
@@ -368,7 +370,7 @@ int i915_guc_wq_reserve(struct drm_i915_gem_request *request)
void i915_guc_wq_unreserve(struct drm_i915_gem_request *request)
{
const size_t wqi_size = sizeof(struct guc_wq_item);
- struct i915_guc_client *client = request->i915->guc.execbuf_client;
+ struct i915_guc_client *client = request->i915->guc.client[NORMAL];

GEM_BUG_ON(READ_ONCE(client->wq_rsvd) < wqi_size);

@@ -518,7 +520,7 @@ static void __i915_guc_submit(struct drm_i915_gem_request *rq)
struct intel_engine_cs *engine = rq->engine;
unsigned int engine_id = engine->id;
struct intel_guc *guc = &rq->i915->guc;
- struct i915_guc_client *client = guc->execbuf_client;
+ struct i915_guc_client *client = guc->client[NORMAL];
int b_ret;

spin_lock(&client->wq_lock);
@@ -747,8 +749,8 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size)
}

static void
-guc_client_free(struct drm_i915_private *dev_priv,
- struct i915_guc_client *client)
+__guc_client_free(struct drm_i915_private *dev_priv,
+ struct i915_guc_client *client)
{
struct intel_guc *guc = &dev_priv->guc;

@@ -805,7 +807,7 @@ static bool guc_doorbell_check(struct intel_guc *guc, uint16_t db_id)
*/
static void guc_init_doorbell_hw(struct intel_guc *guc)
{
- struct i915_guc_client *client = guc->execbuf_client;
+ struct i915_guc_client *client = guc->client[NORMAL];
uint16_t db_id;
int i, err;

@@ -836,7 +838,7 @@ static void guc_init_doorbell_hw(struct intel_guc *guc)
}

/**
- * guc_client_alloc() - Allocate an i915_guc_client
+ * __guc_client_alloc() - Allocate an i915_guc_client
* @dev_priv: driver private data structure
* @priority: four levels priority _CRITICAL, _HIGH, _NORMAL and _LOW
* The kernel client to replace ExecList submission is created with
@@ -845,8 +847,8 @@ static void guc_init_doorbell_hw(struct intel_guc *guc)
* Return: An i915_guc_client object if success, else NULL.
*/
static struct i915_guc_client *
-guc_client_alloc(struct drm_i915_private *dev_priv,
- uint32_t priority)
+__guc_client_alloc(struct drm_i915_private *dev_priv,
+ uint32_t priority)
{
struct i915_guc_client *client;
struct intel_guc *guc = &dev_priv->guc;
@@ -910,7 +912,7 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
guc_ctx_desc_init(guc, client);

/* For runtime client allocation we need to enable the doorbell. Not
- * required yet for the static execbuf_client as this special kernel
+ * required yet for the static client as this special kernel
* client is enabled from i915_guc_submission_enable().
*
* guc_update_doorbell_id(guc, client, db_id);
@@ -924,7 +926,7 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
return client;

err:
- guc_client_free(dev_priv, client);
+ __guc_client_free(dev_priv, client);
return NULL;
}

@@ -1021,6 +1023,45 @@ static void guc_addon_create(struct intel_guc *guc)
kunmap(page);
}

+static void guc_free_clients(struct drm_i915_private *dev_priv)
+{
+ struct intel_guc *guc = &dev_priv->guc;
+ struct i915_guc_client *client;
+
+ client = fetch_and_zero(&guc->client[NORMAL]);
+ if (client)
+ __guc_client_free(dev_priv, client);
+
+ client = fetch_and_zero(&guc->client[PREEMPT]);
+ if (client)
+ __guc_client_free(dev_priv, client);
+}
+
+static int guc_alloc_clients(struct drm_i915_private *dev_priv)
+{
+ struct intel_guc *guc = &dev_priv->guc;
+
+ guc->client[NORMAL] = __guc_client_alloc(dev_priv,
+ GUC_CTX_PRIORITY_KMD_NORMAL);
+ if (!guc->client[NORMAL]) {
+ DRM_ERROR("Failed to create GuC client for execbuf!\n");
+ goto err;
+ }
+
+ guc->client[PREEMPT] = __guc_client_alloc(dev_priv,
+ GUC_CTX_PRIORITY_KMD_HIGH);
+ if (!guc->client[PREEMPT]) {
+ DRM_ERROR("Failed to create GuC client for execbuf!\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ guc_free_clients(dev_priv);
+ return -ENOMEM;
+}
+
/*
* Set up the memory resources to be shared with the GuC. At this point,
* we require just one object that can be mapped through the GGTT.
@@ -1055,18 +1096,12 @@ int i915_guc_submission_init(struct drm_i915_private *dev_priv)
intel_guc_log_create(guc);
guc_addon_create(guc);

- guc->execbuf_client = guc_client_alloc(dev_priv,
- GUC_CTX_PRIORITY_KMD_NORMAL);
- if (!guc->execbuf_client) {
- DRM_ERROR("Failed to create GuC client for execbuf!\n");
- goto err;
+ if (guc_alloc_clients(dev_priv) != 0) {
+ i915_guc_submission_fini(dev_priv);
+ return -ENOMEM;
}

return 0;
-
-err:
- i915_guc_submission_fini(dev_priv);
- return -ENOMEM;
}

static void guc_reset_wq(struct i915_guc_client *client)
@@ -1083,7 +1118,7 @@ static void guc_reset_wq(struct i915_guc_client *client)
int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
{
struct intel_guc *guc = &dev_priv->guc;
- struct i915_guc_client *client = guc->execbuf_client;
+ struct i915_guc_client *client = guc->client[NORMAL];
struct intel_engine_cs *engine;
enum intel_engine_id id;

@@ -1129,7 +1164,7 @@ void i915_guc_submission_disable(struct drm_i915_private *dev_priv)
{
struct intel_guc *guc = &dev_priv->guc;

- if (!guc->execbuf_client)
+ if (!guc->client[NORMAL])
return;

/* Revert back to manual ELSP submission */
@@ -1139,13 +1174,8 @@ void i915_guc_submission_disable(struct drm_i915_private *dev_priv)
void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
{
struct intel_guc *guc = &dev_priv->guc;
- struct i915_guc_client *client;
-
- client = fetch_and_zero(&guc->execbuf_client);
- if (!client)
- return;

- guc_client_free(dev_priv, client);
+ guc_free_clients(dev_priv);

i915_vma_unpin_and_release(&guc->ads_vma);
i915_vma_unpin_and_release(&guc->log.vma);
diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h
index d74f4d3..9dcd8fa 100644
--- a/drivers/gpu/drm/i915/intel_uc.h
+++ b/drivers/gpu/drm/i915/intel_uc.h
@@ -146,6 +146,13 @@ struct intel_guc_log {
u32 flush_count[GUC_MAX_LOG_BUFFER];
};

+#define I915_GUC_NUM_CLIENTS 2
+
+enum i915_guc_client_id {
+ NORMAL = 0,
+ PREEMPT
+};
+
struct intel_guc {
struct intel_uc_fw fw;
struct intel_guc_log log;
@@ -157,7 +164,7 @@ struct intel_guc {
struct i915_vma *ctx_pool_vma;
struct ida ctx_ids;

- struct i915_guc_client *execbuf_client;
+ struct i915_guc_client *client[I915_GUC_NUM_CLIENTS];

DECLARE_BITMAP(doorbell_bitmap, GUC_MAX_DOORBELLS);
uint32_t db_cacheline; /* Cyclic counter mod pagesize */