@@ -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);
@@ -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);
@@ -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 */