Commit 5ab57c70 authored by Chris Wilson's avatar Chris Wilson

drm/i915: Flush logical context image out to memory upon suspend

Before suspend, and especially before building the hibernation image, we
need to context image to be coherent in memory. To do this we require
that we perform a context switch to a disposable context (i.e. the
dev_priv->kernel_context) - when that switch is complete, all other
context images will be complete. This leaves the kernel_context image as
incomplete, but fortunately that is disposable and we can do a quick
fixup of the logical state after resuming.

v2: Share the nearly identical code to switch to the kernel context with
eviction.
v3: Explain why we need the switch and reset.

Testcase: igt/gem_exec_suspend # bsw
References: https://bugs.freedesktop.org/show_bug.cgi?id=96526Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Tested-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1468590980-6186-2-git-send-email-chris@chris-wilson.co.uk
parent 945657b4
...@@ -1590,9 +1590,7 @@ static int i915_drm_resume(struct drm_device *dev) ...@@ -1590,9 +1590,7 @@ static int i915_drm_resume(struct drm_device *dev)
intel_csr_ucode_resume(dev_priv); intel_csr_ucode_resume(dev_priv);
mutex_lock(&dev->struct_mutex); i915_gem_resume(dev);
i915_gem_restore_gtt_mappings(dev);
mutex_unlock(&dev->struct_mutex);
i915_restore_state(dev); i915_restore_state(dev);
intel_opregion_setup(dev_priv); intel_opregion_setup(dev_priv);
......
...@@ -3384,6 +3384,7 @@ void i915_gem_init_swizzling(struct drm_device *dev); ...@@ -3384,6 +3384,7 @@ void i915_gem_init_swizzling(struct drm_device *dev);
void i915_gem_cleanup_engines(struct drm_device *dev); void i915_gem_cleanup_engines(struct drm_device *dev);
int __must_check i915_gem_wait_for_idle(struct drm_i915_private *dev_priv); int __must_check i915_gem_wait_for_idle(struct drm_i915_private *dev_priv);
int __must_check i915_gem_suspend(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev);
void i915_gem_resume(struct drm_device *dev);
void __i915_add_request(struct drm_i915_gem_request *req, void __i915_add_request(struct drm_i915_gem_request *req,
struct drm_i915_gem_object *batch_obj, struct drm_i915_gem_object *batch_obj,
bool flush_caches); bool flush_caches);
......
...@@ -4983,12 +4983,30 @@ i915_gem_suspend(struct drm_device *dev) ...@@ -4983,12 +4983,30 @@ i915_gem_suspend(struct drm_device *dev)
intel_suspend_gt_powersave(dev_priv); intel_suspend_gt_powersave(dev_priv);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
/* We have to flush all the executing contexts to main memory so
* that they can saved in the hibernation image. To ensure the last
* context image is coherent, we have to switch away from it. That
* leaves the dev_priv->kernel_context still active when
* we actually suspend, and its image in memory may not match the GPU
* state. Fortunately, the kernel_context is disposable and we do
* not rely on its state.
*/
ret = i915_gem_switch_to_kernel_context(dev_priv);
if (ret)
goto err;
ret = i915_gem_wait_for_idle(dev_priv); ret = i915_gem_wait_for_idle(dev_priv);
if (ret) if (ret)
goto err; goto err;
i915_gem_retire_requests(dev_priv); i915_gem_retire_requests(dev_priv);
/* Note that rather than stopping the engines, all we have to do
* is assert that every RING_HEAD == RING_TAIL (all execution complete)
* and similar for all logical context images (to ensure they are
* all ready for hibernation).
*/
i915_gem_stop_engines(dev); i915_gem_stop_engines(dev);
i915_gem_context_lost(dev_priv); i915_gem_context_lost(dev_priv);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
...@@ -5009,6 +5027,23 @@ i915_gem_suspend(struct drm_device *dev) ...@@ -5009,6 +5027,23 @@ i915_gem_suspend(struct drm_device *dev)
return ret; return ret;
} }
void i915_gem_resume(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = to_i915(dev);
mutex_lock(&dev->struct_mutex);
i915_gem_restore_gtt_mappings(dev);
/* As we didn't flush the kernel context before suspend, we cannot
* guarantee that the context image is complete. So let's just reset
* it and start again.
*/
if (i915.enable_execlists)
intel_lr_context_reset(dev_priv, dev_priv->kernel_context);
mutex_unlock(&dev->struct_mutex);
}
void i915_gem_init_swizzling(struct drm_device *dev) void i915_gem_init_swizzling(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = to_i915(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment