Skip to content

Commit

Permalink
drm/i915: Flush logical context image out to memory upon suspend
Browse files Browse the repository at this point in the history
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=96526
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Tested-by: Ville 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
  • Loading branch information
Chris Wilson committed Jul 15, 2016
1 parent 945657b commit 5ab57c7
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 3 deletions.
4 changes: 1 addition & 3 deletions drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1590,9 +1590,7 @@ static int i915_drm_resume(struct drm_device *dev)

intel_csr_ucode_resume(dev_priv);

mutex_lock(&dev->struct_mutex);
i915_gem_restore_gtt_mappings(dev);
mutex_unlock(&dev->struct_mutex);
i915_gem_resume(dev);

i915_restore_state(dev);
intel_opregion_setup(dev_priv);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -3384,6 +3384,7 @@ void i915_gem_init_swizzling(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_suspend(struct drm_device *dev);
void i915_gem_resume(struct drm_device *dev);
void __i915_add_request(struct drm_i915_gem_request *req,
struct drm_i915_gem_object *batch_obj,
bool flush_caches);
Expand Down
35 changes: 35 additions & 0 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -4983,12 +4983,30 @@ i915_gem_suspend(struct drm_device *dev)
intel_suspend_gt_powersave(dev_priv);

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);
if (ret)
goto err;

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_context_lost(dev_priv);
mutex_unlock(&dev->struct_mutex);
Expand All @@ -5009,6 +5027,23 @@ i915_gem_suspend(struct drm_device *dev)
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)
{
struct drm_i915_private *dev_priv = to_i915(dev);
Expand Down

0 comments on commit 5ab57c7

Please sign in to comment.