Some recent refactoring patches have left the doorbell creation outside
the GuC client allocation, which does not make a lot of sense (a client
without a doorbell is something useless). Move it back there, and
refactor the init_doorbell_hw consequently.

Thanks to this, we can do some other improvements, like hoisting the
check for GuC submission enabled out of the enable function.

Cc: Joonas Lahtinen <joonas.lahti...@linux.intel.com>
Cc: Michal Wajdeczko <michal.wajdec...@intel.com>
Cc: Arkadiusz Hiler <arkadiusz.hi...@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursu...@intel.com>
Cc: Chris Wilson <ch...@chris-wilson.co.uk>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospu...@intel.com>
Signed-off-by: Oscar Mateo <oscar.ma...@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.c            |   3 +-
 drivers/gpu/drm/i915/i915_guc_submission.c | 228 ++++++++++++++++-------------
 drivers/gpu/drm/i915/intel_guc_loader.c    |  22 ++-
 3 files changed, 143 insertions(+), 110 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 3329507..8f0e569 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -549,8 +549,7 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
 static void i915_gem_fini(struct drm_i915_private *dev_priv)
 {
        mutex_lock(&dev_priv->drm.struct_mutex);
-       if (i915.enable_guc_submission)
-               intel_guc_cleanup(dev_priv);
+       intel_guc_cleanup(dev_priv);
        i915_gem_cleanup_engines(dev_priv);
        i915_gem_context_fini(dev_priv);
        mutex_unlock(&dev_priv->drm.struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c 
b/drivers/gpu/drm/i915/i915_guc_submission.c
index eb677d5..a912ec4 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -163,15 +163,13 @@ static struct guc_context_desc *__get_context_desc(struct 
i915_guc_client *clien
  * client object which contains the page being used for the doorbell
  */
 
-static int __update_doorbell_desc(struct i915_guc_client *client, u16 new_id)
+static void __update_doorbell_desc(struct i915_guc_client *client, u16 new_id)
 {
        struct guc_context_desc *desc;
 
        /* Update the GuC's idea of the doorbell ID */
        desc = __get_context_desc(client);
        desc->db_id = new_id;
-
-       return 0;
 }
 
 static struct guc_doorbell_info *__get_doorbell(struct i915_guc_client *client)
@@ -225,6 +223,28 @@ static int __destroy_doorbell(struct i915_guc_client 
*client)
        return __guc_deallocate_doorbell(client->guc, client->ctx_index);
 }
 
+static int create_doorbell(struct i915_guc_client *client)
+{
+       int ret;
+
+       ret = __reserve_doorbell(client);
+       if (ret)
+               return ret;
+
+       __update_doorbell_desc(client, client->doorbell_id);
+
+       ret = __create_doorbell(client);
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       __update_doorbell_desc(client, GUC_DOORBELL_INVALID);
+       __unreserve_doorbell(client);
+       return ret;
+}
+
 static int destroy_doorbell(struct i915_guc_client *client)
 {
        int err;
@@ -495,6 +515,17 @@ static void guc_wq_item_append(struct i915_guc_client 
*client,
        wqi->fence_id = rq->global_seqno;
 }
 
+static void guc_reset_wq(struct i915_guc_client *client)
+{
+       struct guc_process_desc *desc = client->vaddr +
+                                       client->proc_desc_offset;
+
+       desc->head = 0;
+       desc->tail = 0;
+
+       client->wq_tail = 0;
+}
+
 static int guc_ring_doorbell(struct i915_guc_client *client)
 {
        struct guc_process_desc *desc;
@@ -651,19 +682,6 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc 
*guc, u32 size)
        return vma;
 }
 
-static void guc_client_free(struct i915_guc_client *client)
-{
-       /*
-        * XXX: wait for any outstanding submissions before freeing memory.
-        * Be sure to drop any locks
-        */
-       guc_ctx_desc_fini(client->guc, client);
-       i915_gem_object_unpin_map(client->vma->obj);
-       i915_vma_unpin_and_release(&client->vma);
-       ida_simple_remove(&client->guc->ctx_ids, client->ctx_index);
-       kfree(client);
-}
-
 /* Check that a doorbell register is in the expected state */
 static bool doorbell_ok(struct intel_guc *guc, u16 db_id)
 {
@@ -689,9 +707,8 @@ static int __reset_doorbell(struct i915_guc_client* client, 
u16 db_id)
 {
        int err;
 
-       err = __update_doorbell_desc(client, db_id);
-       if (!err)
-               err = __create_doorbell(client);
+       __update_doorbell_desc(client, db_id);
+       err = __create_doorbell(client);
        if (!err)
                err = __destroy_doorbell(client);
 
@@ -699,48 +716,61 @@ static int __reset_doorbell(struct i915_guc_client* 
client, u16 db_id)
 }
 
 /*
- * Borrow the first client to set up & tear down each unused doorbell
- * in turn, to ensure that all doorbell h/w is (re)initialised.
+ * Set up & tear down each unused doorbell in turn, to ensure that all doorbell
+ * HW is (re)initialised. For that end, we might have to borrow the first
+ * client. Also, tell GuC about all the doorbells in use by all clients.
+ * We do this because the KMD, the GuC and the doorbell HW can easily go out of
+ * sync (e.g. we can reset the GuC, but not the doorbel HW).
  */
 static int guc_init_doorbell_hw(struct intel_guc *guc)
 {
        struct i915_guc_client *client = guc->execbuf_client;
-       int err;
-       int i;
-
-       if (has_doorbell(client))
-               destroy_doorbell(client);
+       bool recreate_first_client = false;
+       u16 db_id;
+       int ret;
 
-       for (i = 0; i < GUC_NUM_DOORBELLS; ++i) {
-               if (doorbell_ok(guc, i))
+       /* For unused doorbells, make sure they are disabled */
+       for_each_clear_bit(db_id, guc->doorbell_bitmap, GUC_NUM_DOORBELLS) {
+               if (doorbell_ok(guc, db_id))
                        continue;
 
-               err = __reset_doorbell(client, i);
-               WARN(err, "Doorbell %d reset failed, err %d\n", i, err);
+               if (has_doorbell(client)) {
+                       /* Borrow execbuf_client (we will recreate it later) */
+                       destroy_doorbell(client);
+                       recreate_first_client = true;
+               }
+
+               ret = __reset_doorbell(client, db_id);
+               WARN(ret, "Doorbell %u reset failed, err %d\n", db_id, ret);
        }
 
-       /* Read back & verify all doorbell registers */
-       for (i = 0; i < GUC_NUM_DOORBELLS; ++i)
-               WARN_ON(!doorbell_ok(guc, i));
+       if (recreate_first_client) {
+               ret = __reserve_doorbell(client);
+               if (unlikely(ret)) {
+                       DRM_ERROR("Couldn't re-reserve first client db: %d\n", 
ret);
+                       return ret;
+               }
 
-       err = __reserve_doorbell(client);
-       if (err)
-               return err;
+               __update_doorbell_desc(client, client->doorbell_id);
+       }
 
-       err = __update_doorbell_desc(client, client->doorbell_id);
-       if (err)
-               goto err_reserve;
+       /* Now for every client (and not only execbuf_client) make sure their
+        * doorbells are known by the GuC */
+       //for (client = client_list; client != NULL; client = client->next)
+       {
+               ret = __create_doorbell(client);
+               if (ret) {
+                       DRM_ERROR("Couldn't recreate client %u doorbell: %d\n",
+                               client->ctx_index, ret);
+                       return ret;
+               }
+       }
 
-       err = __create_doorbell(client);
-       if (err)
-               goto err_update;
+       /* Read back & verify all (used & unused) doorbell registers */
+       for (db_id = 0; db_id < GUC_NUM_DOORBELLS; ++db_id)
+               WARN_ON(!doorbell_ok(guc, db_id));
 
        return 0;
-err_reserve:
-       __unreserve_doorbell(client);
-err_update:
-       __update_doorbell_desc(client, GUC_DOORBELL_INVALID);
-       return err;
 }
 
 /**
@@ -820,11 +850,9 @@ static int guc_init_doorbell_hw(struct intel_guc *guc)
        guc_proc_desc_init(guc, client);
        guc_ctx_desc_init(guc, client);
 
-       /* FIXME: Runtime client allocation (which currently we don't do) will
-        * require that the doorbell gets created now. The static execbuf_client
-        * is now getting its doorbell later (on submission enable) but maybe we
-        * also want to reorder things in the future so that we don't have to
-        * special case the doorbell creation */
+       ret = create_doorbell(client);
+       if (ret)
+               goto err_vaddr;
 
        DRM_DEBUG_DRIVER("new priority %u client %p for engine(s) 0x%x: 
ctx_index %u\n",
                         priority, client, client->engines, client->ctx_index);
@@ -832,6 +860,9 @@ static int guc_init_doorbell_hw(struct intel_guc *guc)
                         client->doorbell_id, client->doorbell_offset);
 
        return client;
+
+err_vaddr:
+       i915_gem_object_unpin_map(client->vma->obj);
 err_vma:
        i915_vma_unpin_and_release(&client->vma);
 err_id:
@@ -841,6 +872,24 @@ static int guc_init_doorbell_hw(struct intel_guc *guc)
        return ERR_PTR(ret);
 }
 
+static void guc_client_free(struct i915_guc_client *client)
+{
+       /*
+        * XXX: wait for any outstanding submissions before freeing memory.
+        * Be sure to drop any locks
+        */
+
+       /* FIXME: in many cases, by the time we get here the GuC has been
+        * reset, so we cannot destroy the doorbell properly. Ignore the
+        * error message for now */
+       destroy_doorbell(client);
+       guc_ctx_desc_fini(client->guc, client);
+       i915_gem_object_unpin_map(client->vma->obj);
+       i915_vma_unpin_and_release(&client->vma);
+       ida_simple_remove(&client->guc->ctx_ids, client->ctx_index);
+       kfree(client);
+}
+
 static void guc_policies_init(struct guc_policies *policies)
 {
        struct guc_policy *policy;
@@ -938,8 +987,8 @@ static void guc_addon_destroy(struct intel_guc *guc)
 }
 
 /*
- * 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.
+ * Set up the memory resources to be shared with the GuC (via the GGTT)
+ * at firmware loading time.
  */
 int i915_guc_submission_init(struct drm_i915_private *dev_priv)
 {
@@ -951,16 +1000,6 @@ int i915_guc_submission_init(struct drm_i915_private 
*dev_priv)
        void *vaddr;
        int ret;
 
-       if (!HAS_GUC_SCHED(dev_priv))
-               return 0;
-
-       /* Wipe bitmap & delete client in case of reinitialisation */
-       bitmap_clear(guc->doorbell_bitmap, 0, GUC_NUM_DOORBELLS);
-       i915_guc_submission_disable(dev_priv);
-
-       if (!i915.enable_guc_submission)
-               return 0;
-
        if (guc->ctx_pool)
                return 0;
 
@@ -988,20 +1027,8 @@ int i915_guc_submission_init(struct drm_i915_private 
*dev_priv)
 
        ida_init(&guc->ctx_ids);
 
-       guc->execbuf_client = guc_client_alloc(dev_priv,
-                                              INTEL_INFO(dev_priv)->ring_mask,
-                                              GUC_CTX_PRIORITY_KMD_NORMAL,
-                                              dev_priv->kernel_context);
-       if (IS_ERR(guc->execbuf_client)) {
-               DRM_ERROR("Failed to create GuC client for execbuf!\n");
-               ret = PTR_ERR(guc->execbuf_client);
-               goto err_ads;
-       }
-
        return 0;
 
-err_ads:
-       guc_addon_destroy(guc);
 err_log:
        intel_guc_log_destroy(guc);
 err_vaddr:
@@ -1015,8 +1042,6 @@ void i915_guc_submission_fini(struct drm_i915_private 
*dev_priv)
 {
        struct intel_guc *guc = &dev_priv->guc;
 
-       guc_client_free(guc->execbuf_client);
-       guc->execbuf_client = NULL;
        ida_destroy(&guc->ctx_ids);
        guc_addon_destroy(guc);
        intel_guc_log_destroy(guc);
@@ -1024,17 +1049,6 @@ void i915_guc_submission_fini(struct drm_i915_private 
*dev_priv)
        i915_vma_unpin_and_release(&guc->ctx_pool);
 }
 
-static void guc_reset_wq(struct i915_guc_client *client)
-{
-       struct guc_process_desc *desc = client->vaddr +
-                                       client->proc_desc_offset;
-
-       desc->head = 0;
-       desc->tail = 0;
-
-       client->wq_tail = 0;
-}
-
 static void guc_interrupts_capture(struct drm_i915_private *dev_priv)
 {
        struct intel_engine_cs *engine;
@@ -1063,17 +1077,28 @@ int i915_guc_submission_enable(struct drm_i915_private 
*dev_priv)
        enum intel_engine_id id;
        int err;
 
-       if (!client)
-               return -ENODEV;
+       if (!client) {
+               client = guc_client_alloc(dev_priv,
+                                         INTEL_INFO(dev_priv)->ring_mask,
+                                         GUC_CTX_PRIORITY_KMD_NORMAL,
+                                         dev_priv->kernel_context);
+               if (IS_ERR(client)) {
+                       DRM_ERROR("Failed to create GuC client for execbuf!\n");
+                       return PTR_ERR(client);
+               }
+
+               guc->execbuf_client = client;
+       }
 
        err = intel_guc_sample_forcewake(guc);
        if (err)
-               return err;
+               goto err_execbuf_client;
 
        guc_reset_wq(client);
+
        err = guc_init_doorbell_hw(guc);
        if (err)
-               return err;
+               goto err_execbuf_client;
 
        /* Take over from manual control of ELSP (execlists) */
        for_each_engine(engine, dev_priv, id) {
@@ -1097,22 +1122,22 @@ int i915_guc_submission_enable(struct drm_i915_private 
*dev_priv)
        }
 
        return 0;
+
+err_execbuf_client:
+       guc_client_free(guc->execbuf_client);
+       guc->execbuf_client = NULL;
+       return err;
 }
 
 void i915_guc_submission_disable(struct drm_i915_private *dev_priv)
 {
        struct intel_guc *guc = &dev_priv->guc;
 
-       if (!guc->execbuf_client)
-               return;
-
-       /* FIXME: in many cases, by the time we get here the GuC has been
-        * reset, so we cannot destroy the doorbell properly. Ignore the
-        * error message for now */
-       destroy_doorbell(guc->execbuf_client);
-
        /* Revert back to manual ELSP submission */
        intel_execlists_enable_submission(dev_priv);
+
+       guc_client_free(guc->execbuf_client);
+       guc->execbuf_client = NULL;
 }
 
 /**
@@ -1141,7 +1166,6 @@ int intel_guc_suspend(struct drm_i915_private *dev_priv)
        return intel_guc_send(guc, data, ARRAY_SIZE(data));
 }
 
-
 /**
  * intel_guc_resume() - notify GuC resuming from suspend state
  * @dev_priv:  i915 device private
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c 
b/drivers/gpu/drm/i915/intel_guc_loader.c
index 3c59528..649c4db 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -441,9 +441,13 @@ int intel_guc_setup(struct drm_i915_private *dev_priv)
                intel_uc_fw_status_repr(guc_fw->fetch_status),
                intel_uc_fw_status_repr(guc_fw->load_status));
 
-       err = i915_guc_submission_init(dev_priv);
-       if (err)
-               goto err_guc;
+       if (i915.enable_guc_submission) {
+               /* This is stuff we need to have available at fw load time
+                * if we are planning to enable submission later */
+               err = i915_guc_submission_init(dev_priv);
+               if (err)
+                       goto err_guc;
+       }
 
        /*
         * WaEnableuKernelHeaderValidFix:skl,bxt
@@ -495,7 +499,8 @@ int intel_guc_setup(struct drm_i915_private *dev_priv)
 err_interrupts:
        gen9_disable_guc_interrupts(dev_priv);
 err_submission:
-       i915_guc_submission_fini(dev_priv);
+       if (i915.enable_guc_submission)
+               i915_guc_submission_fini(dev_priv);
 err_guc:
        i915_ggtt_disable_guc(dev_priv);
 fail:
@@ -543,8 +548,13 @@ int intel_guc_setup(struct drm_i915_private *dev_priv)
 
 void intel_guc_cleanup(struct drm_i915_private *dev_priv)
 {
-       gen9_disable_guc_interrupts(dev_priv);
-       i915_guc_submission_fini(dev_priv);
+       if (i915.enable_guc_submission) {
+               guc_interrupts_release(dev_priv);
+               i915_guc_submission_disable(dev_priv);
+               gen9_disable_guc_interrupts(dev_priv);
+               i915_guc_submission_fini(dev_priv);
+       }
+
        i915_ggtt_disable_guc(dev_priv);
 }
 
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to