[PATCH v14 22/25] 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 10:37:11 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.

v4: Rebase with changed GuC suspend/resume. Updated comments. (Sagar)

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 |  1 +
 drivers/gpu/drm/i915/intel_guc.h |  2 ++
 drivers/gpu/drm/i915/intel_uc.c  | 59 ++++++++++++++++++++++++++++++++++------
 3 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c
index 0e9b2e6..980be5a 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)
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 7bb7667..4b6894f 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 then 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. After
+	 * firmware is loaded we send action to resume to GuC to restore its
+	 * suspended state.
+	 */
+	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);
@@ -348,6 +371,8 @@ int intel_uc_suspend(struct drm_i915_private *dev_priv)
 
 	intel_suspend_guc_interrupts(guc);
 
+	guc->suspended = true;
+
 out:
 	return ret;
 }
@@ -368,20 +393,36 @@ void intel_uc_resume(struct drm_i915_private *dev_priv)
 	if (!i915_modparams.enable_guc_loading)
 		return;
 
-	if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS) {
-		DRM_ERROR("GuC not loaded. Resume skipped\n");
+	if (!guc->suspended) {
+		DRM_ERROR("GuC not suspended. Resume skipped\n");
 		return;
 	}
 
-	intel_restore_guc_interrupts(guc);
+	/*
+	 * Function uc_resume_prepare would have determined GuC/HuC load status.
+	 * If loaded, we need to restore GuC interrupts, invoke GuC action to
+	 * resume from sleep.
+	 * 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 (guc->fw.load_status == INTEL_UC_FIRMWARE_SUCCESS) {
+		intel_restore_guc_interrupts(guc);
 
-	ret = intel_guc_resume(guc);
-	if (ret) {
-		DRM_ERROR("GuC resume failed (%d)\n", ret);
-		intel_suspend_guc_interrupts(guc);
-	}
+		ret = intel_guc_resume(guc);
+		if (ret) {
+			DRM_ERROR("GuC resume failed (%d)\n", ret);
+			intel_suspend_guc_interrupts(guc);
+		}
 
-	/* TODO: Need to restore doorbells for all GuC clients. */
+		/* TODO: Need to restore doorbells for all GuC clients. */
+
+		guc->suspended = false;
+	} else {
+		DRM_DEBUG_DRIVER("GuC not available. Load and resume will be "
+				 "done during GEM Init\n");
+	}
 }
 
 /**
-- 
1.9.1



More information about the Intel-gfx-trybot mailing list