Since fw version 25.161, GuC lets us know when an engine had to be reset
due to a hang in another dependent engine, by setting BIT(engine_class) in
the queue_engine_error field. GuC will ignore any other wq item until this
flag is cleared.

To restart the workqueue processing for that engine, we must insert a
special wq item called resume-parsing and wait until the queue_engine_error
field is updated.

Co-Developed-by: Michel Thierry <michel.thie...@intel.com>
Co-Developed-by: Michal Wajdeczko <michal.wajdec...@intel.com>
Signed-off-by: Michel Thierry <michel.thie...@intel.com>
Signed-off-by: Michal Wajdeczko <michal.wajdec...@intel.com>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospu...@intel.com>
Cc: Vinay Belgaumkar <vinay.belgaum...@intel.com>
Cc: Michal Winiarski <michal.winiar...@intel.com>
Cc: Tomasz Lis <tomasz....@intel.com>
---
 drivers/gpu/drm/i915/intel_guc_submission.c | 92 +++++++++++++++++++--
 1 file changed, 86 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c 
b/drivers/gpu/drm/i915/intel_guc_submission.c
index 1a27352b73a9..b0b10cac9b9b 100644
--- a/drivers/gpu/drm/i915/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/intel_guc_submission.c
@@ -427,6 +427,76 @@ static void guc_proxy_stage_desc_fini(struct 
intel_guc_client *client)
        memset(desc, 0, sizeof(*desc));
 }
 
+static u32 get_wq_offset(struct guc_process_desc *desc)
+{
+       const size_t wqi_size = sizeof(struct guc_wq_item);
+       u32 wq_off;
+
+       /*
+        * Free space is guaranteed, either by normal port submission or
+        * because we waited for the wq_resume to be processed.
+        */
+       wq_off = READ_ONCE(desc->tail);
+       GEM_BUG_ON(CIRC_SPACE(wq_off, READ_ONCE(desc->head),
+                             GUC_WQ_SIZE) < wqi_size);
+       GEM_BUG_ON(wq_off & (wqi_size - 1));
+
+       return wq_off;
+}
+
+static void write_wqi(struct guc_process_desc *desc, u32 wq_off)
+{
+       const size_t wqi_size = sizeof(struct guc_wq_item);
+
+       WRITE_ONCE(desc->tail, (wq_off + wqi_size) & (GUC_WQ_SIZE - 1));
+}
+
+static void guc_append_wq_resume_parsing_item(struct intel_guc_client *client,
+                                             struct intel_engine_cs *engine)
+{
+       struct guc_process_desc *desc = __get_process_desc(client);
+       const u32 target_engine = engine->guc_id;
+       const u32 wqi_resume = WQ_TYPE_RESUME |
+                              (target_engine << WQ_TARGET_SHIFT) |
+                              (0 << WQ_LEN_SHIFT);
+       const u32 wqi_noop = WQ_TYPE_NOOP |
+                           (target_engine << WQ_TARGET_SHIFT) |
+                           (0 << WQ_LEN_SHIFT);
+       struct guc_wq_item *wqi;
+       u32 wq_off;
+
+       lockdep_assert_held(&client->wq_lock);
+
+       wq_off = get_wq_offset(desc);
+       wqi = client->vaddr + wq_off + GUC_DB_SIZE;
+
+       /*
+        * Submit 4 wq_items (1 RESUME_WQ_PARSING followed by 3 NOOPs) in
+        * order to keep it the same size as a 'normal' wq_item.
+        */
+       wqi->header = wqi_resume;
+       wqi->context_desc = wqi_noop;
+       wqi->submit_element_info = wqi_noop;
+       wqi->fence_id = wqi_noop;
+
+       write_wqi(desc, wq_off);
+}
+
+#define GUC_WAIT_FOR_ENGINE_ERROR_CLEANED_MS 10
+
+static void guc_wait_wq_resumed(struct intel_guc_client *client,
+                               struct intel_engine_cs *engine)
+{
+       struct guc_process_desc *desc = __get_process_desc(client);
+       u8 guc_class = engine->class;
+
+       lockdep_assert_held(&client->wq_lock);
+
+       /* must wait for the flag to be cleared */
+       WARN_ON(wait_for_atomic(!(desc->queue_engine_error & BIT(guc_class)),
+                               GUC_WAIT_FOR_ENGINE_ERROR_CLEANED_MS));
+}
+
 /* Construct a Work Item and append it to the GuC's Work Queue */
 static void guc_wq_item_append(struct intel_guc_client *client,
                               struct intel_context *ce,
@@ -454,11 +524,7 @@ static void guc_wq_item_append(struct intel_guc_client 
*client,
        /* We expect the WQ to be active if we're appending items to it */
        GEM_BUG_ON(desc->wq_status != WQ_STATUS_ACTIVE);
 
-       /* Free space is guaranteed. */
-       wq_off = READ_ONCE(desc->tail);
-       GEM_BUG_ON(CIRC_SPACE(wq_off, READ_ONCE(desc->head),
-                             GUC_WQ_SIZE) < wqi_size);
-       GEM_BUG_ON(wq_off & (wqi_size - 1));
+       wq_off = get_wq_offset(desc);
 
        /* WQ starts from the page after doorbell / process_desc */
        wqi = client->vaddr + wq_off + GUC_DB_SIZE;
@@ -481,7 +547,7 @@ static void guc_wq_item_append(struct intel_guc_client 
*client,
        }
 
        /* Make the update visible to GuC */
-       WRITE_ONCE(desc->tail, (wq_off + wqi_size) & (GUC_WQ_SIZE - 1));
+       write_wqi(desc, wq_off);
 }
 
 static void guc_ring_doorbell(struct intel_guc_client *client)
@@ -505,6 +571,14 @@ static void guc_ring_doorbell(struct intel_guc_client 
*client)
        GEM_BUG_ON(db->db_status != GUC_DOORBELL_ENABLED);
 }
 
+static bool guc_needs_wq_resume_parsing_item(struct intel_guc_client *client,
+                                            u32 target_engine_class)
+{
+       struct guc_process_desc *desc = __get_process_desc(client);
+
+       return desc->queue_engine_error & BIT(target_engine_class);
+}
+
 static void guc_add_request(struct intel_guc *guc, struct i915_request *rq)
 {
        struct intel_guc_client *client = guc->execbuf_client;
@@ -512,9 +586,15 @@ static void guc_add_request(struct intel_guc *guc, struct 
i915_request *rq)
        struct intel_context *ce = rq->hw_context;
        u32 ctx_desc = lower_32_bits(rq->hw_context->lrc_desc);
        u32 ring_tail = intel_ring_set_tail(rq->ring, rq->tail) / sizeof(u64);
+       u8 guc_class = engine->class;
 
        spin_lock(&client->wq_lock);
 
+       if (guc_needs_wq_resume_parsing_item(client, guc_class)) {
+               guc_append_wq_resume_parsing_item(client, engine);
+               guc_wait_wq_resumed(client, engine);
+       }
+
        guc_wq_item_append(client, ce, engine->guc_id, ctx_desc,
                           ring_tail, rq->fence.seqno);
        guc_ring_doorbell(client);
-- 
2.19.2

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

Reply via email to