diff mbox

drm/i915: Break workaround register emission into batches of 15

Message ID 20180615080030.6014-1-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson June 15, 2018, 8 a.m. UTC
We are restricted to the number of registers we can rewrite into a
single command by the packet length. If we have more registers than can
be fitted into a single packet, we therefore need to split the writes
into multiple packets.

Reported-by: Kenneth Graunke <kenneth@whitecape.org>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Oscar Mateo <oscar.mateo@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Kenneth Graunke <kenneth@whitecape.org>
---
 drivers/gpu/drm/i915/intel_workarounds.c | 31 ++++++++++++++++--------
 1 file changed, 21 insertions(+), 10 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c
index f8bb32e974f6..d82e08af6a60 100644
--- a/drivers/gpu/drm/i915/intel_workarounds.c
+++ b/drivers/gpu/drm/i915/intel_workarounds.c
@@ -553,6 +553,8 @@  int intel_ctx_workarounds_init(struct drm_i915_private *dev_priv)
 int intel_ctx_workarounds_emit(struct i915_request *rq)
 {
 	struct i915_workarounds *w = &rq->i915->workarounds;
+	struct i915_wa_reg *reg = w->reg;
+	unsigned int remain;
 	u32 *cs;
 	int ret, i;
 
@@ -563,18 +565,27 @@  int intel_ctx_workarounds_emit(struct i915_request *rq)
 	if (ret)
 		return ret;
 
-	cs = intel_ring_begin(rq, (w->count * 2 + 2));
-	if (IS_ERR(cs))
-		return PTR_ERR(cs);
+	remain = w->count;
+	do {
+		unsigned int count;
 
-	*cs++ = MI_LOAD_REGISTER_IMM(w->count);
-	for (i = 0; i < w->count; i++) {
-		*cs++ = w->reg[i].addr;
-		*cs++ = w->reg[i].value;
-	}
-	*cs++ = MI_NOOP;
+		count = min(remain, 15u);
+		remain -= count;
+
+		cs = intel_ring_begin(rq, 2 * count + 2);
+		if (IS_ERR(cs))
+			return PTR_ERR(cs);
+
+		*cs++ = MI_LOAD_REGISTER_IMM(count);
+		for (i = 0; i < count; i++) {
+			*cs++ = reg->addr;
+			*cs++ = reg->value;
+			reg++;
+		}
+		*cs++ = MI_NOOP;
 
-	intel_ring_advance(rq, cs);
+		intel_ring_advance(rq, cs);
+	} while (remain);
 
 	ret = rq->engine->emit_flush(rq, EMIT_BARRIER);
 	if (ret)