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.thierry@xxxxxxxxx> Co-Developed-by: Michal Wajdeczko <michal.wajdeczko@xxxxxxxxx> Signed-off-by: Michel Thierry <michel.thierry@xxxxxxxxx> Signed-off-by: Michal Wajdeczko <michal.wajdeczko@xxxxxxxxx> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@xxxxxxxxx> Cc: Vinay Belgaumkar <vinay.belgaumkar@xxxxxxxxx> Cc: Michal Winiarski <michal.winiarski@xxxxxxxxx> Cc: Tomasz Lis <tomasz.lis@xxxxxxxxx> --- 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@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx