drm/i915/gt: Prevent timeslicing into unpreemptable requests
We have a I915_REQUEST_NOPREEMPT flag that we set when we must prevent the HW from preempting during the course of this request. We need to honour this flag and protect the HW even if we have a heartbeat request, or other maximum priority barrier, pending. As such, restrict the timeslicing check to avoid preempting into the topmost priority band, leaving the unpreemptable requests in blissful peace running uninterrupted on the HW. v2: Set the I915_PRIORITY_BARRIER to be less than I915_PRIORITY_UNPREEMPTABLE so that we never submit a request (heartbeat or barrier) that can legitimately preempt the current non-premptable request. Fixes:2a98f4e65b
("drm/i915: add infrastructure to hold off preemption on a request") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20200527162418.24755-1-chris@chris-wilson.co.uk (cherry picked from commitb72f02d78e
) Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
This commit is contained in:
parent
3ffbe35321
commit
4178b5a60c
|
@ -1925,6 +1925,7 @@ need_timeslice(const struct intel_engine_cs *engine,
|
|||
if (!list_is_last(&rq->sched.link, &engine->active.requests))
|
||||
hint = max(hint, rq_prio(list_next_entry(rq, sched.link)));
|
||||
|
||||
GEM_BUG_ON(hint >= I915_PRIORITY_UNPREEMPTABLE);
|
||||
return hint >= effective_prio(rq);
|
||||
}
|
||||
|
||||
|
|
|
@ -823,7 +823,7 @@ slice_semaphore_queue(struct intel_engine_cs *outer,
|
|||
}
|
||||
}
|
||||
|
||||
err = release_queue(outer, vma, n, INT_MAX);
|
||||
err = release_queue(outer, vma, n, I915_PRIORITY_BARRIER);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -1289,6 +1289,121 @@ err_obj:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int live_timeslice_nopreempt(void *arg)
|
||||
{
|
||||
struct intel_gt *gt = arg;
|
||||
struct intel_engine_cs *engine;
|
||||
enum intel_engine_id id;
|
||||
struct igt_spinner spin;
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* We should not timeslice into a request that is marked with
|
||||
* I915_REQUEST_NOPREEMPT.
|
||||
*/
|
||||
if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION))
|
||||
return 0;
|
||||
|
||||
if (igt_spinner_init(&spin, gt))
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_engine(engine, gt, id) {
|
||||
struct intel_context *ce;
|
||||
struct i915_request *rq;
|
||||
unsigned long timeslice;
|
||||
|
||||
if (!intel_engine_has_preemption(engine))
|
||||
continue;
|
||||
|
||||
ce = intel_context_create(engine);
|
||||
if (IS_ERR(ce)) {
|
||||
err = PTR_ERR(ce);
|
||||
break;
|
||||
}
|
||||
|
||||
engine_heartbeat_disable(engine);
|
||||
timeslice = xchg(&engine->props.timeslice_duration_ms, 1);
|
||||
|
||||
/* Create an unpreemptible spinner */
|
||||
|
||||
rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
|
||||
intel_context_put(ce);
|
||||
if (IS_ERR(rq)) {
|
||||
err = PTR_ERR(rq);
|
||||
goto out_heartbeat;
|
||||
}
|
||||
|
||||
i915_request_get(rq);
|
||||
i915_request_add(rq);
|
||||
|
||||
if (!igt_wait_for_spinner(&spin, rq)) {
|
||||
i915_request_put(rq);
|
||||
err = -ETIME;
|
||||
goto out_spin;
|
||||
}
|
||||
|
||||
set_bit(I915_FENCE_FLAG_NOPREEMPT, &rq->fence.flags);
|
||||
i915_request_put(rq);
|
||||
|
||||
/* Followed by a maximum priority barrier (heartbeat) */
|
||||
|
||||
ce = intel_context_create(engine);
|
||||
if (IS_ERR(ce)) {
|
||||
err = PTR_ERR(rq);
|
||||
goto out_spin;
|
||||
}
|
||||
|
||||
rq = intel_context_create_request(ce);
|
||||
intel_context_put(ce);
|
||||
if (IS_ERR(rq)) {
|
||||
err = PTR_ERR(rq);
|
||||
goto out_spin;
|
||||
}
|
||||
|
||||
rq->sched.attr.priority = I915_PRIORITY_BARRIER;
|
||||
i915_request_get(rq);
|
||||
i915_request_add(rq);
|
||||
|
||||
/*
|
||||
* Wait until the barrier is in ELSP, and we know timeslicing
|
||||
* will have been activated.
|
||||
*/
|
||||
if (wait_for_submit(engine, rq, HZ / 2)) {
|
||||
i915_request_put(rq);
|
||||
err = -ETIME;
|
||||
goto out_spin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since the ELSP[0] request is unpreemptible, it should not
|
||||
* allow the maximum priority barrier through. Wait long
|
||||
* enough to see if it is timesliced in by mistake.
|
||||
*/
|
||||
if (i915_request_wait(rq, 0, timeslice_threshold(engine)) >= 0) {
|
||||
pr_err("%s: I915_PRIORITY_BARRIER request completed, bypassing no-preempt request\n",
|
||||
engine->name);
|
||||
err = -EINVAL;
|
||||
}
|
||||
i915_request_put(rq);
|
||||
|
||||
out_spin:
|
||||
igt_spinner_end(&spin);
|
||||
out_heartbeat:
|
||||
xchg(&engine->props.timeslice_duration_ms, timeslice);
|
||||
engine_heartbeat_enable(engine);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
if (igt_flush_test(gt->i915)) {
|
||||
err = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
igt_spinner_fini(&spin);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int live_busywait_preempt(void *arg)
|
||||
{
|
||||
struct intel_gt *gt = arg;
|
||||
|
@ -4296,6 +4411,7 @@ int intel_execlists_live_selftests(struct drm_i915_private *i915)
|
|||
SUBTEST(live_timeslice_preempt),
|
||||
SUBTEST(live_timeslice_rewind),
|
||||
SUBTEST(live_timeslice_queue),
|
||||
SUBTEST(live_timeslice_nopreempt),
|
||||
SUBTEST(live_busywait_preempt),
|
||||
SUBTEST(live_preempt),
|
||||
SUBTEST(live_late_preempt),
|
||||
|
|
|
@ -42,7 +42,7 @@ enum {
|
|||
* active request.
|
||||
*/
|
||||
#define I915_PRIORITY_UNPREEMPTABLE INT_MAX
|
||||
#define I915_PRIORITY_BARRIER INT_MAX
|
||||
#define I915_PRIORITY_BARRIER (I915_PRIORITY_UNPREEMPTABLE - 1)
|
||||
|
||||
struct i915_priolist {
|
||||
struct list_head requests[I915_PRIORITY_COUNT];
|
||||
|
|
Loading…
Reference in New Issue