Commit 23902e49 authored by Chris Wilson's avatar Chris Wilson

drm/i915: Split request submit/execute phase into two

In order to support deferred scheduling, we need to differentiate
between when the request is ready to run (i.e. the submit fence is
signaled) and when the request is actually run (a new execute fence).
This is typically split between the request itself wanting to wait upon
others (for which we use the submit fence) and the CPU wanting to wait
upon the request, for which we use the execute fence to be sure the
hardware is ready to signal completion.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161114204105.29171-3-chris@chris-wilson.co.uk
parent bb89485e
...@@ -350,11 +350,19 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) ...@@ -350,11 +350,19 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
list_move_tail(&request->link, &timeline->requests); list_move_tail(&request->link, &timeline->requests);
spin_unlock(&request->timeline->lock); spin_unlock(&request->timeline->lock);
i915_sw_fence_commit(&request->execute);
spin_unlock_irqrestore(&timeline->lock, flags); spin_unlock_irqrestore(&timeline->lock, flags);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static int __i915_sw_fence_call
execute_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
{
return NOTIFY_DONE;
}
/** /**
* i915_gem_request_alloc - allocate a request structure * i915_gem_request_alloc - allocate a request structure
* *
...@@ -440,6 +448,12 @@ i915_gem_request_alloc(struct intel_engine_cs *engine, ...@@ -440,6 +448,12 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
__timeline_get_seqno(req->timeline->common)); __timeline_get_seqno(req->timeline->common));
i915_sw_fence_init(&req->submit, submit_notify); i915_sw_fence_init(&req->submit, submit_notify);
i915_sw_fence_init(&req->execute, execute_notify);
/* Ensure that the execute fence completes after the submit fence -
* as we complete the execute fence from within the submit fence
* callback, its completion would otherwise be visible first.
*/
i915_sw_fence_await_sw_fence(&req->execute, &req->submit, &req->execq);
INIT_LIST_HEAD(&req->active_list); INIT_LIST_HEAD(&req->active_list);
req->i915 = dev_priv; req->i915 = dev_priv;
...@@ -816,9 +830,9 @@ bool __i915_spin_request(const struct drm_i915_gem_request *req, ...@@ -816,9 +830,9 @@ bool __i915_spin_request(const struct drm_i915_gem_request *req,
} }
static long static long
__i915_request_wait_for_submit(struct drm_i915_gem_request *request, __i915_request_wait_for_execute(struct drm_i915_gem_request *request,
unsigned int flags, unsigned int flags,
long timeout) long timeout)
{ {
const int state = flags & I915_WAIT_INTERRUPTIBLE ? const int state = flags & I915_WAIT_INTERRUPTIBLE ?
TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE; TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
...@@ -830,9 +844,9 @@ __i915_request_wait_for_submit(struct drm_i915_gem_request *request, ...@@ -830,9 +844,9 @@ __i915_request_wait_for_submit(struct drm_i915_gem_request *request,
add_wait_queue(q, &reset); add_wait_queue(q, &reset);
do { do {
prepare_to_wait(&request->submit.wait, &wait, state); prepare_to_wait(&request->execute.wait, &wait, state);
if (i915_sw_fence_done(&request->submit)) if (i915_sw_fence_done(&request->execute))
break; break;
if (flags & I915_WAIT_LOCKED && if (flags & I915_WAIT_LOCKED &&
...@@ -850,7 +864,7 @@ __i915_request_wait_for_submit(struct drm_i915_gem_request *request, ...@@ -850,7 +864,7 @@ __i915_request_wait_for_submit(struct drm_i915_gem_request *request,
timeout = io_schedule_timeout(timeout); timeout = io_schedule_timeout(timeout);
} while (timeout); } while (timeout);
finish_wait(&request->submit.wait, &wait); finish_wait(&request->execute.wait, &wait);
if (flags & I915_WAIT_LOCKED) if (flags & I915_WAIT_LOCKED)
remove_wait_queue(q, &reset); remove_wait_queue(q, &reset);
...@@ -902,13 +916,14 @@ long i915_wait_request(struct drm_i915_gem_request *req, ...@@ -902,13 +916,14 @@ long i915_wait_request(struct drm_i915_gem_request *req,
trace_i915_gem_request_wait_begin(req); trace_i915_gem_request_wait_begin(req);
if (!i915_sw_fence_done(&req->submit)) { if (!i915_sw_fence_done(&req->execute)) {
timeout = __i915_request_wait_for_submit(req, flags, timeout); timeout = __i915_request_wait_for_execute(req, flags, timeout);
if (timeout < 0) if (timeout < 0)
goto complete; goto complete;
GEM_BUG_ON(!i915_sw_fence_done(&req->submit)); GEM_BUG_ON(!i915_sw_fence_done(&req->execute));
} }
GEM_BUG_ON(!i915_sw_fence_done(&req->submit));
GEM_BUG_ON(!req->global_seqno); GEM_BUG_ON(!req->global_seqno);
/* Optimistic short spin before touching IRQs */ /* Optimistic short spin before touching IRQs */
......
...@@ -87,8 +87,23 @@ struct drm_i915_gem_request { ...@@ -87,8 +87,23 @@ struct drm_i915_gem_request {
struct intel_timeline *timeline; struct intel_timeline *timeline;
struct intel_signal_node signaling; struct intel_signal_node signaling;
/* Fences for the various phases in the request's lifetime.
*
* The submit fence is used to await upon all of the request's
* dependencies. When it is signaled, the request is ready to run.
* It is used by the driver to then queue the request for execution.
*
* The execute fence is used to signal when the request has been
* sent to hardware.
*
* It is illegal for the submit fence of one request to wait upon the
* execute fence of an earlier request. It should be sufficient to
* wait upon the submit fence of the earlier request.
*/
struct i915_sw_fence submit; struct i915_sw_fence submit;
struct i915_sw_fence execute;
wait_queue_t submitq; wait_queue_t submitq;
wait_queue_t execq;
u32 global_seqno; u32 global_seqno;
......
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