drm/i915: Emit even number of dwords when emitting LRIs
authorArun Siluvery <arun.siluvery@linux.intel.com>
Wed, 22 Oct 2014 17:59:52 +0000 (18:59 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 24 Oct 2014 14:34:15 +0000 (16:34 +0200)
The number of DWords should be even when doing ring emits as
command sequences require QWord alignment.

There was some discussion about the maximum length of the MI_LRI
command. Quoting Mika

"I did some test with bdw:

"The maximum is 128 writes, resulting the 8 bit length
field of the command being 0xff, thus following the spec.
The 128'th write went through.

"Perhaps the max command length is then less in older gens?

"Perhaps WARN_ON(x > 128) in MI_LOAD_REGISTER_IMM would be in place
but one needs minor tweak to command parser a bit also then.

#define I915_MAX_WA_REGS 16

keeps us safe for now atleast."

Ville commented that on pre-gen6 the length field seems to be
restricted to 0x3f though. So for all cases we should be ok.

v2: user LRI variant that can write multiple regs in one go (Damien).
We can simply insert one NOP at the end instead of one per register write.

Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Arun Siluvery <arun.siluvery@linux.intel.com>
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
[danvet: Add a summary of the MI_LRI length discussion.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/intel_ringbuffer.c

index 5f935d4dfb6a96f4b2c58497d6a89bee31ae54bd..603148e6dbc39b034371c92e0b52c0d782f42ef7 100644 (file)
@@ -680,15 +680,16 @@ static int intel_ring_workarounds_emit(struct intel_engine_cs *ring)
        if (ret)
                return ret;
 
-       ret = intel_ring_begin(ring, w->count * 3);
+       ret = intel_ring_begin(ring, (w->count * 2 + 2));
        if (ret)
                return ret;
 
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(w->count));
        for (i = 0; i < w->count; i++) {
-               intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
                intel_ring_emit(ring, w->reg[i].addr);
                intel_ring_emit(ring, w->reg[i].value);
        }
+       intel_ring_emit(ring, MI_NOOP);
 
        intel_ring_advance(ring);