drm/i915/execlists: Track inflight CCID
authorChris Wilson <chris@chris-wilson.co.uk>
Tue, 28 Apr 2020 18:47:50 +0000 (19:47 +0100)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Wed, 6 May 2020 22:37:59 +0000 (15:37 -0700)
The presumption is that by using a circular counter that is twice as
large as the maximum ELSP submission, we would never reuse the same CCID
for two inflight contexts.

However, if we continually preempt an active context such that it always
remains inflight, it can be resubmitted with an arbitrary number of
paired contexts. As each of its paired contexts will use a new CCID,
eventually it will wrap and submit two ELSP with the same CCID.

Rather than use a simple circular counter, switch over to a small bitmap
of inflight ids so we can avoid reusing one that is still potentially
active.

Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/1796
Fixes: 2935ed5339c4 ("drm/i915: Remove logical HW ID")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Cc: <stable@vger.kernel.org> # v5.5+
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200428184751.11257-2-chris@chris-wilson.co.uk
(cherry picked from commit 5c4a53e3b1cbc38d0906e382f1037290658759bb)
(cherry picked from commit 134711240307d5586ae8e828d2699db70a8b74f2)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/i915/gt/intel_engine_types.h
drivers/gpu/drm/i915/gt/intel_lrc.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/selftests/i915_vma.c

index 8dd210a2c340aa3151894f96280137212740c123..0be674ae1cf63ff4a2adf665696dca8f8b9b74a1 100644 (file)
@@ -309,8 +309,7 @@ struct intel_engine_cs {
        u32 context_size;
        u32 mmio_base;
 
-       unsigned int context_tag;
-#define NUM_CONTEXT_TAG roundup_pow_of_two(2 * EXECLIST_MAX_PORTS)
+       unsigned long context_tag;
 
        struct rb_node uabi_node;
 
index e8b02f84aa3d06b0f2352a315c13bc7889fad01f..77420372d8134000af049fef478c4f0c209ba35d 100644 (file)
@@ -1239,13 +1239,17 @@ __execlists_schedule_in(struct i915_request *rq)
 
        if (ce->tag) {
                /* Use a fixed tag for OA and friends */
+               GEM_BUG_ON(ce->tag <= BITS_PER_LONG);
                ce->lrc.ccid = ce->tag;
        } else {
                /* We don't need a strict matching tag, just different values */
-               ce->lrc.ccid =
-                       (++engine->context_tag % NUM_CONTEXT_TAG) <<
-                       (GEN11_SW_CTX_ID_SHIFT - 32);
-               BUILD_BUG_ON(NUM_CONTEXT_TAG > GEN12_MAX_CONTEXT_HW_ID);
+               unsigned int tag = ffs(engine->context_tag);
+
+               GEM_BUG_ON(tag == 0 || tag >= BITS_PER_LONG);
+               clear_bit(tag - 1, &engine->context_tag);
+               ce->lrc.ccid = tag << (GEN11_SW_CTX_ID_SHIFT - 32);
+
+               BUILD_BUG_ON(BITS_PER_LONG > GEN12_MAX_CONTEXT_HW_ID);
        }
 
        ce->lrc.ccid |= engine->execlists.ccid;
@@ -1289,7 +1293,8 @@ static void kick_siblings(struct i915_request *rq, struct intel_context *ce)
 
 static inline void
 __execlists_schedule_out(struct i915_request *rq,
-                        struct intel_engine_cs * const engine)
+                        struct intel_engine_cs * const engine,
+                        unsigned int ccid)
 {
        struct intel_context * const ce = rq->context;
 
@@ -1307,6 +1312,14 @@ __execlists_schedule_out(struct i915_request *rq,
            i915_request_completed(rq))
                intel_engine_add_retire(engine, ce->timeline);
 
+       ccid >>= GEN11_SW_CTX_ID_SHIFT - 32;
+       ccid &= GEN12_MAX_CONTEXT_HW_ID;
+       if (ccid < BITS_PER_LONG) {
+               GEM_BUG_ON(ccid == 0);
+               GEM_BUG_ON(test_bit(ccid - 1, &engine->context_tag));
+               set_bit(ccid - 1, &engine->context_tag);
+       }
+
        intel_context_update_runtime(ce);
        intel_engine_context_out(engine);
        execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT);
@@ -1332,15 +1345,17 @@ execlists_schedule_out(struct i915_request *rq)
 {
        struct intel_context * const ce = rq->context;
        struct intel_engine_cs *cur, *old;
+       u32 ccid;
 
        trace_i915_request_out(rq);
 
+       ccid = rq->context->lrc.ccid;
        old = READ_ONCE(ce->inflight);
        do
                cur = ptr_unmask_bits(old, 2) ? ptr_dec(old) : NULL;
        while (!try_cmpxchg(&ce->inflight, &old, cur));
        if (!cur)
-               __execlists_schedule_out(rq, old);
+               __execlists_schedule_out(rq, old, ccid);
 
        i915_request_put(rq);
 }
@@ -3556,7 +3571,7 @@ static void enable_execlists(struct intel_engine_cs *engine)
 
        enable_error_interrupt(engine);
 
-       engine->context_tag = 0;
+       engine->context_tag = GENMASK(BITS_PER_LONG - 2, 0);
 }
 
 static bool unexpected_starting_state(struct intel_engine_cs *engine)
index b5030192be3ef6b9db29708530221e33d9874ce4..cf2c01f17da837235dd8f79e1614cf896e814299 100644 (file)
@@ -1327,11 +1327,10 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream)
                        ((1U << GEN11_SW_CTX_ID_WIDTH) - 1) << (GEN11_SW_CTX_ID_SHIFT - 32);
                /*
                 * Pick an unused context id
-                * 0 - (NUM_CONTEXT_TAG - 1) are used by other contexts
+                * 0 - BITS_PER_LONG are used by other contexts
                 * GEN12_MAX_CONTEXT_HW_ID (0x7ff) is used by idle context
                 */
                stream->specific_ctx_id = (GEN12_MAX_CONTEXT_HW_ID - 1) << (GEN11_SW_CTX_ID_SHIFT - 32);
-               BUILD_BUG_ON((GEN12_MAX_CONTEXT_HW_ID - 1) < NUM_CONTEXT_TAG);
                break;
        }
 
index 58b5f40a07dd6be16eedab36d8c52d9ff9e2e914..af89c7fc8f59340bad9d38628b0c6f751caed521 100644 (file)
@@ -173,7 +173,7 @@ static int igt_vma_create(void *arg)
                }
 
                nc = 0;
-               for_each_prime_number(num_ctx, 2 * NUM_CONTEXT_TAG) {
+               for_each_prime_number(num_ctx, 2 * BITS_PER_LONG) {
                        for (; nc < num_ctx; nc++) {
                                ctx = mock_context(i915, "mock");
                                if (!ctx)