[PATCH] drm/i915: Defer rc6 shutdown to suspend_late

Chris Wilson chris at chris-wilson.co.uk
Sun Oct 13 14:45:32 UTC 2019


Currently we shutdown rc6 during i915_gem_resume() but this is called
during the preparation phase (i915_drm_prepare) for all suspend paths,
but we only want to shutdown rc6 for S3+. Move the actual shutdown to
i915_gem_suspend_late().

We then need to differentiate between suspend targets, to distinguish S0
(s2idle) where the device is kept awake but needs to be in a low power
mode (the same as runtime suspend) from the device suspend levels where
we lose control of HW and so must disable any HW access to dangling
memory.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=111909
Fixes: c113236718e8 ("drm/i915: Extract GT render sleep (rc6) management")
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Andi Shyti <andi.shyti at intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_pm.c   |  7 ++---
 drivers/gpu/drm/i915/gt/intel_gt_pm.c    | 37 +++++++++++++++++++-----
 drivers/gpu/drm/i915/gt/intel_gt_pm.h    |  3 +-
 drivers/gpu/drm/i915/gt/intel_rc6.c      |  5 ++++
 drivers/gpu/drm/i915/gt/selftest_gt_pm.c |  2 +-
 5 files changed, 41 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c
index 7987b54fb1f5..f09684b96656 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_pm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.c
@@ -97,8 +97,7 @@ void i915_gem_suspend(struct drm_i915_private *i915)
 	 * state. Fortunately, the kernel_context is disposable and we do
 	 * not rely on its state.
 	 */
-	intel_gt_suspend(&i915->gt);
-	intel_uc_suspend(&i915->gt.uc);
+	intel_gt_suspend_prepare(&i915->gt);
 
 	cancel_delayed_work_sync(&i915->gt.hangcheck.work);
 
@@ -142,6 +141,8 @@ void i915_gem_suspend_late(struct drm_i915_private *i915)
 	 * machine in an unusable condition.
 	 */
 
+	intel_gt_suspend_late(&i915->gt);
+
 	spin_lock_irqsave(&i915->mm.obj_lock, flags);
 	for (phase = phases; *phase; phase++) {
 		LIST_HEAD(keep);
@@ -187,8 +188,6 @@ void i915_gem_resume(struct drm_i915_private *i915)
 	if (intel_gt_resume(&i915->gt))
 		goto err_wedged;
 
-	intel_uc_resume(&i915->gt.uc);
-
 	/* Always reload a context for powersaving. */
 	if (!i915_gem_load_power_context(i915))
 		goto err_wedged;
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
index 87e34e0b6427..cb2b559783d1 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
@@ -4,6 +4,8 @@
  * Copyright © 2019 Intel Corporation
  */
 
+#include <linux/suspend.h>
+
 #include "i915_drv.h"
 #include "i915_globals.h"
 #include "i915_params.h"
@@ -168,6 +170,7 @@ int intel_gt_resume(struct intel_gt *gt)
 	 */
 	intel_gt_pm_get(gt);
 	intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);
+
 	intel_rc6_sanitize(&gt->rc6);
 
 	for_each_engine(engine, gt->i915, id) {
@@ -195,15 +198,21 @@ int intel_gt_resume(struct intel_gt *gt)
 		}
 	}
 
+	intel_uc_resume(&gt->uc);
+
 	intel_rc6_enable(&gt->rc6);
+
 	intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL);
 	intel_gt_pm_put(gt);
 
 	return err;
 }
 
-static void wait_for_idle(struct intel_gt *gt)
+void intel_gt_suspend_prepare(struct intel_gt *gt)
 {
+	if (!intel_gt_pm_is_awake(gt))
+		return;
+
 	if (intel_gt_wait_for_idle(gt, I915_GEM_IDLE_TIMEOUT) == -ETIME) {
 		/*
 		 * Forcibly cancel outstanding work and leave
@@ -215,15 +224,29 @@ static void wait_for_idle(struct intel_gt *gt)
 	intel_gt_pm_wait_for_idle(gt);
 }
 
-void intel_gt_suspend(struct intel_gt *gt)
+void intel_gt_suspend_late(struct intel_gt *gt)
 {
-	intel_wakeref_t wakeref;
-
 	/* We expect to be idle already; but also want to be independent */
-	wait_for_idle(gt);
+	intel_gt_suspend_prepare(gt);
+
+	/*
+	 * On disabling the device, we want to turn off HW access to memory
+	 * that we no longer own.
+	 *
+	 * However, not all suspend-states disable the device. S0 (s2idle)
+	 * is effectively runtime-suspend, the device is left powered on
+	 * but needs to be put into a low power state. We need to keep
+	 * powermanagement enabled, but we also retain system state and so
+	 * it remains safe to keep on using our allocated memory.
+	 */
+	if (pm_suspend_target_state != PM_SUSPEND_TO_IDLE) {
+		intel_wakeref_t wakeref;
+
+		with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+			intel_rc6_disable(&gt->rc6);
+	}
 
-	with_intel_runtime_pm(gt->uncore->rpm, wakeref)
-		intel_rc6_disable(&gt->rc6);
+	intel_uc_suspend(&gt->uc);
 }
 
 void intel_gt_runtime_suspend(struct intel_gt *gt)
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h b/drivers/gpu/drm/i915/gt/intel_gt_pm.h
index 997770d3a968..9967f94b512f 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h
@@ -49,8 +49,9 @@ void intel_gt_pm_fini(struct intel_gt *gt);
 
 void intel_gt_sanitize(struct intel_gt *gt, bool force);
 
+void intel_gt_suspend_prepare(struct intel_gt *gt);
+void intel_gt_suspend_late(struct intel_gt *gt);
 int intel_gt_resume(struct intel_gt *gt);
-void intel_gt_suspend(struct intel_gt *gt);
 
 void intel_gt_runtime_suspend(struct intel_gt *gt);
 int intel_gt_runtime_resume(struct intel_gt *gt);
diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c
index 71184aa72896..b9d743f6adfe 100644
--- a/drivers/gpu/drm/i915/gt/intel_rc6.c
+++ b/drivers/gpu/drm/i915/gt/intel_rc6.c
@@ -525,6 +525,11 @@ void intel_rc6_init(struct intel_rc6 *rc6)
 
 void intel_rc6_sanitize(struct intel_rc6 *rc6)
 {
+	if (rc6->enabled) { /* unbalanced suspend/resume */
+		rpm_get(rc6);
+		rc6->enabled = false;
+	}
+
 	if (rc6->supported)
 		__intel_rc6_disable(rc6);
 }
diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
index 87985bd46423..909d117db98f 100644
--- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
+++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
@@ -13,7 +13,7 @@ static int live_gt_resume(void *arg)
 
 	/* Do several suspend/resume cycles to check we don't explode! */
 	do {
-		intel_gt_suspend(gt);
+		intel_gt_suspend_late(gt);
 
 		if (gt->rc6.enabled) {
 			pr_err("rc6 still enabled after suspend!\n");
-- 
2.23.0



More information about the Intel-gfx-trybot mailing list