Commit 3033acab authored by Chris Wilson's avatar Chris Wilson

drm/i915: Queue the idling context switch after all other timelines

Before suspend, we wait for the switch to the kernel context. In order
for all the other context images to be complete upon suspend, that
switch must be the last operation by the GPU (i.e. this idling request
must not overtake any pending requests). To make this request execute last,
we make it depend on every other inflight request.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161028125858.23563-24-chris@chris-wilson.co.uk
parent 73cb9701
...@@ -4362,6 +4362,15 @@ void __i915_gem_object_release_unless_active(struct drm_i915_gem_object *obj) ...@@ -4362,6 +4362,15 @@ void __i915_gem_object_release_unless_active(struct drm_i915_gem_object *obj)
i915_gem_object_put(obj); i915_gem_object_put(obj);
} }
static void assert_kernel_context_is_current(struct drm_i915_private *dev_priv)
{
struct intel_engine_cs *engine;
enum intel_engine_id id;
for_each_engine(engine, dev_priv, id)
GEM_BUG_ON(engine->last_context != dev_priv->kernel_context);
}
int i915_gem_suspend(struct drm_device *dev) int i915_gem_suspend(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = to_i915(dev);
...@@ -4391,6 +4400,7 @@ int i915_gem_suspend(struct drm_device *dev) ...@@ -4391,6 +4400,7 @@ int i915_gem_suspend(struct drm_device *dev)
i915_gem_retire_requests(dev_priv); i915_gem_retire_requests(dev_priv);
assert_kernel_context_is_current(dev_priv);
i915_gem_context_lost(dev_priv); i915_gem_context_lost(dev_priv);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
......
...@@ -931,22 +931,33 @@ int i915_switch_context(struct drm_i915_gem_request *req) ...@@ -931,22 +931,33 @@ int i915_switch_context(struct drm_i915_gem_request *req)
int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv) int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
{ {
struct intel_engine_cs *engine; struct intel_engine_cs *engine;
struct i915_gem_timeline *timeline;
enum intel_engine_id id; enum intel_engine_id id;
lockdep_assert_held(&dev_priv->drm.struct_mutex);
for_each_engine(engine, dev_priv, id) { for_each_engine(engine, dev_priv, id) {
struct drm_i915_gem_request *req; struct drm_i915_gem_request *req;
int ret; int ret;
if (engine->last_context == NULL)
continue;
if (engine->last_context == dev_priv->kernel_context)
continue;
req = i915_gem_request_alloc(engine, dev_priv->kernel_context); req = i915_gem_request_alloc(engine, dev_priv->kernel_context);
if (IS_ERR(req)) if (IS_ERR(req))
return PTR_ERR(req); return PTR_ERR(req);
/* Queue this switch after all other activity */
list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
struct drm_i915_gem_request *prev;
struct intel_timeline *tl;
tl = &timeline->engine[engine->id];
prev = i915_gem_active_raw(&tl->last_request,
&dev_priv->drm.struct_mutex);
if (prev)
i915_sw_fence_await_sw_fence_gfp(&req->submit,
&prev->submit,
GFP_KERNEL);
}
ret = i915_switch_context(req); ret = i915_switch_context(req);
i915_add_request_no_flush(req); i915_add_request_no_flush(req);
if (ret) if (ret)
......
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