[PATCH 20/22] drm/i915/uc: Support resume from sleep w/ and w/o GuC/HuC load

Sagar Arun Kamble sagar.a.kamble at intel.com
Tue Oct 17 08:03:43 UTC 2017


GuC/HuC resume from sleep depends on whether they are loaded. We defined
function guc_loaded() to know GuC load status in earlier patch.

If GuC is not available then we need to first load the GuC/HuC and then
do all resume tasks. Currently on resume from sleep, GuC/HuC are not
loaded as GPU is reset at the end of suspend/early resume. So we will have
to load the firmware and send action to resume. Resume will be done
through uC init during GEM init based on newly introduced state
"guc->suspended".
This approach is verified by not doing the GPU reset from gem sanitize.
During GEM init, firmware load will be skipped based on load status which
is updated during intel_uc_resume_prepare. uc_runtime_resume path will be
updated with similar functionality in the next patch.

v2: Updated commit message. Removed skip_load_on_resume and reset_on_load
state variables. Reusing guc_mia_in_reset(). Updated return from uc_init.
Rebase. (Michal Wajdeczko)

v3: Refactored patch as resume_prepare functionality is moved to earlier
patch.

Signed-off-by: Sagar Arun Kamble <sagar.a.kamble at intel.com>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Michal Wajdeczko <michal.wajdeczko at intel.com>
Cc: MichaƂ Winiarski <michal.winiarski at intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
---
 drivers/gpu/drm/i915/intel_guc.c | 52 +++++++++++++++++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_guc.h |  2 ++
 drivers/gpu/drm/i915/intel_uc.c  | 23 ++++++++++++++++++
 3 files changed, 68 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c
index 21c93ff..b5539e4 100644
--- a/drivers/gpu/drm/i915/intel_guc.c
+++ b/drivers/gpu/drm/i915/intel_guc.c
@@ -65,6 +65,7 @@ void intel_guc_init_early(struct intel_guc *guc)
 	mutex_init(&guc->send_mutex);
 	guc->send = intel_guc_send_nop;
 	guc->notify = gen8_guc_raise_irq;
+	guc->suspended = false;
 }
 
 static u32 get_gt_type(struct drm_i915_private *dev_priv)
@@ -290,11 +291,17 @@ int intel_guc_suspend(struct intel_guc *guc)
 	struct i915_gem_context *ctx;
 	u32 data[3];
 
+	/*
+	 * FIXME: Suspend flow needs to updated to ensure all doorbells
+	 * are evicted prior to sending sleep action to GuC.
+	 */
 	if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
 		return 0;
 
 	intel_suspend_guc_interrupts(guc);
 
+	guc->suspended = true;
+
 	ctx = dev_priv->kernel_context;
 
 	data[0] = INTEL_GUC_ACTION_ENTER_S_STATE;
@@ -332,20 +339,47 @@ int intel_guc_resume(struct intel_guc *guc)
 	struct i915_gem_context *ctx;
 	u32 data[3];
 
-	if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
+	if (!guc->suspended) {
+		DRM_ERROR("GuC not suspended. Resume skipped\n");
 		return 0;
+	}
 
-	intel_restore_guc_interrupts(guc);
+	/*
+	 * Function uc_resume_prepare would have determined GuC/HuC load status.
+	 * If not loaded, it is similar to fresh boot and we need load the
+	 * GuC/HuC firmwares and enable other GuC related mechanisms. Post
+	 * loading GuC, we need to send action to resume from sleep for GuC to
+	 * restore its state prior to suspend.
+	 * If loaded, we need to restore GuC interrupts, invoke GuC action to
+	 * resume from sleep.
+	 */
+	if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS) {
+		/*
+		 * FIXME: Load and resume during Runtime resume need to be
+		 * supported.
+		 */
+		DRM_DEBUG_DRIVER("GuC not available. Load and resume will be "
+				 "done during GEM Init if in DRM resume.\n");
+	} else {
+		/*
+		 * FIXME: Resume flow needs to updated to ensure all valid
+		 * doorbells are acquired post sending resume action to GuC.
+		 */
 
-	ctx = dev_priv->kernel_context;
+		intel_restore_guc_interrupts(guc);
 
-	data[0] = INTEL_GUC_ACTION_EXIT_S_STATE;
-	data[1] = GUC_POWER_D0;
-	/* first page is shared data with GuC */
-	data[2] = guc_ggtt_offset(ctx->engine[RCS].state) +
-		  LRC_GUCSHR_PN * PAGE_SIZE;
+		ctx = dev_priv->kernel_context;
 
-	return intel_guc_send(guc, data, ARRAY_SIZE(data));
+		data[0] = INTEL_GUC_ACTION_EXIT_S_STATE;
+		data[1] = GUC_POWER_D0;
+		/* first page is shared data with GuC */
+		data[2] = guc_ggtt_offset(ctx->engine[RCS].state) +
+			  LRC_GUCSHR_PN * PAGE_SIZE;
+
+		return intel_guc_send(guc, data, ARRAY_SIZE(data));
+	}
+
+	return 0;
 }
 
 /**
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 610a2d5..480c039 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -49,6 +49,8 @@ struct intel_guc {
 	struct intel_guc_log log;
 	struct intel_guc_ct ct;
 
+	bool suspended:1;
+
 	/* Log snapshot if GuC errors during load */
 	struct drm_i915_gem_object *load_err_log;
 
diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c
index 500b38b..54a6487c 100644
--- a/drivers/gpu/drm/i915/intel_uc.c
+++ b/drivers/gpu/drm/i915/intel_uc.c
@@ -184,6 +184,13 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv)
 	if (!i915_modparams.enable_guc_loading)
 		return 0;
 
+	/*
+	 * If on resume from sleep, GuC was available we resumed GuC during
+	 * i915_gem_resume. We need to skip load here.
+	 */
+	if (guc->fw.load_status == INTEL_UC_FIRMWARE_SUCCESS)
+		return 0;
+
 	guc_disable_communication(guc);
 	intel_reset_guc_interrupts(guc);
 
@@ -242,6 +249,22 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv)
 	if (ret)
 		goto err_interrupts;
 
+	/*
+	 * If GuC/HuC were not available after suspend cycle, they need to
+	 * be loaded. For this we are using intel_uc_init_hw path as we want
+	 * to handle HuC/GuC load, GuC resume, HuC authentication and
+	 * submission enabling etc. all here.
+	 */
+	if (guc->suspended) {
+		ret = intel_guc_resume(guc);
+		if (ret) {
+			DRM_ERROR("GuC resume failed (%d)\n", ret);
+			goto err_comm;
+		}
+
+		guc->suspended = false;
+	}
+
 	intel_huc_auth(&dev_priv->huc);
 	if (i915_modparams.enable_guc_submission) {
 		ret = i915_guc_submission_enable(dev_priv);
-- 
1.9.1



More information about the Intel-gfx-trybot mailing list