Commit a70a9e99 authored by Chris Wilson's avatar Chris Wilson Committed by Joonas Lahtinen
Browse files

drm/i915: Defer rc6 shutdown to suspend_late

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: c1132367 ("drm/i915: Extract GT render sleep (rc6) management")
Testcase: igt/gem_exec_suspend/power-S0
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Andi Shyti <andi.shyti@intel.com>
Acked-by: default avatarAndi Shyti <andi.shyti@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191101141009.15581-4-chris@chris-wilson.co.uk


(cherry picked from commit c601cb21)
Signed-off-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
parent d4033a9b
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -27,7 +27,7 @@ void i915_gem_suspend(struct drm_i915_private *i915)
	 * state. Fortunately, the kernel_context is disposable and we do
	 * state. Fortunately, the kernel_context is disposable and we do
	 * not rely on its state.
	 * not rely on its state.
	 */
	 */
	intel_gt_suspend(&i915->gt);
	intel_gt_suspend_prepare(&i915->gt);


	i915_gem_drain_freed_objects(i915);
	i915_gem_drain_freed_objects(i915);
}
}
@@ -69,6 +69,8 @@ void i915_gem_suspend_late(struct drm_i915_private *i915)
	 * machine in an unusable condition.
	 * machine in an unusable condition.
	 */
	 */


	intel_gt_suspend_late(&i915->gt);

	spin_lock_irqsave(&i915->mm.obj_lock, flags);
	spin_lock_irqsave(&i915->mm.obj_lock, flags);
	for (phase = phases; *phase; phase++) {
	for (phase = phases; *phase; phase++) {
		LIST_HEAD(keep);
		LIST_HEAD(keep);
+38 −6
Original line number Original line Diff line number Diff line
@@ -4,6 +4,8 @@
 * Copyright © 2019 Intel Corporation
 * Copyright © 2019 Intel Corporation
 */
 */


#include <linux/suspend.h>

#include "i915_drv.h"
#include "i915_drv.h"
#include "i915_globals.h"
#include "i915_globals.h"
#include "i915_params.h"
#include "i915_params.h"
@@ -236,8 +238,11 @@ int intel_gt_resume(struct intel_gt *gt)
	return err;
	return err;
}
}


static void wait_for_idle(struct intel_gt *gt)
static void wait_for_suspend(struct intel_gt *gt)
{
{
	if (!intel_gt_pm_is_awake(gt))
		return;

	if (intel_gt_wait_for_idle(gt, I915_GEM_IDLE_TIMEOUT) == -ETIME) {
	if (intel_gt_wait_for_idle(gt, I915_GEM_IDLE_TIMEOUT) == -ETIME) {
		/*
		/*
		 * Forcibly cancel outstanding work and leave
		 * Forcibly cancel outstanding work and leave
@@ -246,19 +251,46 @@ static void wait_for_idle(struct intel_gt *gt)
		intel_gt_set_wedged(gt);
		intel_gt_set_wedged(gt);
	}
	}


	GEM_BUG_ON(atomic_read(&gt->user_wakeref));
	intel_gt_pm_wait_for_idle(gt);
	intel_gt_pm_wait_for_idle(gt);
}
}


void intel_gt_suspend(struct intel_gt *gt)
void intel_gt_suspend_prepare(struct intel_gt *gt)
{
{
	intel_wakeref_t wakeref;

	user_forcewake(gt, true);
	user_forcewake(gt, true);
	wait_for_suspend(gt);

	intel_uc_suspend(&gt->uc);
}

static suspend_state_t pm_suspend_target(void)
{
#if IS_ENABLED(CONFIG_PM_SLEEP)
	return pm_suspend_target_state;
#else
	return PM_SUSPEND_TO_IDLE;
#endif
}

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 */
	/* We expect to be idle already; but also want to be independent */
	wait_for_idle(gt);
	wait_for_suspend(gt);


	intel_uc_suspend(&gt->uc);
	/*
	 * 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() == PM_SUSPEND_TO_IDLE)
		return;


	with_intel_runtime_pm(gt->uncore->rpm, wakeref) {
	with_intel_runtime_pm(gt->uncore->rpm, wakeref) {
		intel_rps_disable(&gt->rps);
		intel_rps_disable(&gt->rps);
+2 −1
Original line number Original line Diff line number Diff line
@@ -43,8 +43,9 @@ void intel_gt_pm_fini(struct intel_gt *gt);


void intel_gt_sanitize(struct intel_gt *gt, bool force);
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);
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);
void intel_gt_runtime_suspend(struct intel_gt *gt);
int intel_gt_runtime_resume(struct intel_gt *gt);
int intel_gt_runtime_resume(struct intel_gt *gt);
+5 −0
Original line number Original line Diff line number Diff line
@@ -525,6 +525,11 @@ void intel_rc6_init(struct intel_rc6 *rc6)


void intel_rc6_sanitize(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)
	if (rc6->supported)
		__intel_rc6_disable(rc6);
		__intel_rc6_disable(rc6);
}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -15,7 +15,7 @@ static int live_gt_resume(void *arg)


	/* Do several suspend/resume cycles to check we don't explode! */
	/* Do several suspend/resume cycles to check we don't explode! */
	do {
	do {
		intel_gt_suspend(gt);
		intel_gt_suspend_late(gt);


		if (gt->rc6.enabled) {
		if (gt->rc6.enabled) {
			pr_err("rc6 still enabled after suspend!\n");
			pr_err("rc6 still enabled after suspend!\n");