diff mbox series

[RFC,1/1] drm/i915/guc: Provide mmio list to be saved/restored on engine reset

Message ID 20190925230032.23676-2-fernando.pacheco@intel.com (mailing list archive)
State New, archived
Headers show
Series GuC engine reset support | expand

Commit Message

Fernando Pacheco Sept. 25, 2019, 11 p.m. UTC
The driver must provide GuC with a list of mmio registers
that should be saved/restored during a GuC-based engine reset.
We provide a minimal set of registers that should get things
working and extend as needed.

Signed-off-by: Fernando Pacheco <fernando.pacheco@intel.com>
---
 drivers/gpu/drm/i915/gt/intel_workarounds.c   | 23 +++--
 .../gpu/drm/i915/gt/intel_workarounds_types.h |  1 +
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c    | 87 +++++++++++++++++++
 3 files changed, 105 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c
index ba65e5018978..694e6c82425d 100644
--- a/drivers/gpu/drm/i915/gt/intel_workarounds.c
+++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c
@@ -146,23 +146,31 @@  static void _wa_add(struct i915_wa_list *wal, const struct i915_wa *wa)
 }
 
 static void
-wa_write_masked_or(struct i915_wa_list *wal, i915_reg_t reg, u32 mask,
-		   u32 val)
+__wa_write_masked_or(struct i915_wa_list *wal, i915_reg_t reg, u32 mask,
+		     u32 val, bool masked_bits)
 {
 	struct i915_wa wa = {
 		.reg  = reg,
 		.mask = mask,
 		.val  = val,
 		.read = mask,
+		.masked_bits = masked_bits,
 	};
 
 	_wa_add(wal, &wa);
 }
 
+static void
+wa_write_masked_or(struct i915_wa_list *wal, i915_reg_t reg, u32 mask,
+		   u32 val)
+{
+	__wa_write_masked_or(wal, reg, mask, val, false);
+}
+
 static void
 wa_masked_en(struct i915_wa_list *wal, i915_reg_t reg, u32 val)
 {
-	wa_write_masked_or(wal, reg, val, _MASKED_BIT_ENABLE(val));
+	__wa_write_masked_or(wal, reg, val, _MASKED_BIT_ENABLE(val), true);
 }
 
 static void
@@ -178,13 +186,16 @@  wa_write_or(struct i915_wa_list *wal, i915_reg_t reg, u32 val)
 }
 
 #define WA_SET_BIT_MASKED(addr, mask) \
-	wa_write_masked_or(wal, (addr), (mask), _MASKED_BIT_ENABLE(mask))
+	__wa_write_masked_or(wal, (addr), (mask), \
+			     _MASKED_BIT_ENABLE(mask), true)
 
 #define WA_CLR_BIT_MASKED(addr, mask) \
-	wa_write_masked_or(wal, (addr), (mask), _MASKED_BIT_DISABLE(mask))
+	__wa_write_masked_or(wal, (addr), (mask), \
+			     _MASKED_BIT_DISABLE(mask), true)
 
 #define WA_SET_FIELD_MASKED(addr, mask, value) \
-	wa_write_masked_or(wal, (addr), (mask), _MASKED_FIELD((mask), (value)))
+	__wa_write_masked_or(wal, (addr), (mask), \
+			     _MASKED_FIELD((mask), (value)), true)
 
 static void gen8_ctx_workarounds_init(struct intel_engine_cs *engine,
 				      struct i915_wa_list *wal)
diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h
index e27ab1b710b3..a43d5f968f2d 100644
--- a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h
@@ -16,6 +16,7 @@  struct i915_wa {
 	u32		mask;
 	u32		val;
 	u32		read;
+	bool		masked_bits;
 };
 
 struct i915_wa_list {
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index ca6674b8e00c..ba75a5ea3a4b 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -3,6 +3,8 @@ 
  * Copyright © 2014-2019 Intel Corporation
  */
 
+#include <linux/bsearch.h>
+
 #include "gt/intel_gt.h"
 #include "intel_guc_ads.h"
 #include "intel_uc.h"
@@ -16,6 +18,9 @@ 
  * its internal state for sleep.
  */
 
+static void guc_mmio_reg_state_init(struct guc_mmio_reg_state *reg_state,
+				    struct intel_engine_cs *engine);
+
 static void guc_policy_init(struct guc_policy *policy)
 {
 	policy->execution_quantum = POLICY_DEFAULT_EXECUTION_QUANTUM_US;
@@ -70,9 +75,15 @@  static void __guc_ads_init(struct intel_guc *guc)
 	struct drm_i915_private *dev_priv = guc_to_gt(guc)->i915;
 	struct __guc_ads_blob *blob = guc->ads_blob;
 	const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE;
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
 	u32 base;
 	u8 engine_class;
 
+	/* GuC mmio save/restore list */
+	for_each_engine(engine, dev_priv, id)
+		guc_mmio_reg_state_init(&blob->reg_state, engine);
+
 	/* GuC scheduling policies */
 	guc_policies_init(&blob->policies);
 
@@ -182,3 +193,79 @@  void intel_guc_ads_reset(struct intel_guc *guc)
 		return;
 	__guc_ads_init(guc);
 }
+
+static int guc_mmio_reg_cmp(const void *a, const void *b)
+{
+	const struct guc_mmio_reg *ra = a;
+	const struct guc_mmio_reg *rb = b;
+
+	return (int)ra->offset - (int)rb->offset;
+}
+
+static void guc_mmio_reg_add(struct guc_mmio_regset *regset,
+			     u32 offset, u32 flags)
+{
+	u32 count = regset->number_of_registers;
+	struct guc_mmio_reg reg = {
+		.offset = offset,
+		.flags = flags,
+	};
+	struct guc_mmio_reg *slot;
+
+	GEM_BUG_ON(count >= GUC_REGSET_MAX_REGISTERS);
+
+	if (bsearch(&reg, regset->registers, count,
+		    sizeof(reg), guc_mmio_reg_cmp))
+		return;
+
+	slot = &regset->registers[count];
+	regset->number_of_registers++;
+	*slot = reg;
+
+	while (slot-- > regset->registers) {
+		GEM_BUG_ON(slot[0].offset == slot[1].offset);
+		if (slot[1].offset > slot[0].offset)
+			break;
+
+		swap(slot[1], slot[0]);
+	}
+}
+
+#define GUC_MMIO_REG_ADD(regset, reg, masked) \
+	guc_mmio_reg_add(regset, \
+			 i915_mmio_reg_offset((reg)), \
+			 (masked) ? GUC_REGSET_MASKED : 0)
+
+static void guc_mmio_regset_init(struct guc_mmio_regset *regset,
+				 struct intel_engine_cs *engine)
+{
+	const u32 base = engine->mmio_base;
+	struct i915_wa_list *wal = &engine->wa_list;
+	struct i915_wa *wa;
+	unsigned int i;
+
+	GUC_MMIO_REG_ADD(regset, RING_MODE_GEN7(base), true);
+	GUC_MMIO_REG_ADD(regset, RING_HWS_PGA(base), false);
+	GUC_MMIO_REG_ADD(regset, RING_IMR(base), false);
+
+	for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
+		GUC_MMIO_REG_ADD(regset, wa->reg, wa->masked_bits);
+
+	/* Be extra paranoid and include all whitelist registers. */
+	for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++)
+		GUC_MMIO_REG_ADD(regset,
+				 RING_FORCE_TO_NONPRIV(base, i),
+				 false);
+}
+
+static void guc_mmio_reg_state_init(struct guc_mmio_reg_state *reg_state,
+				    struct intel_engine_cs *engine)
+{
+	struct guc_mmio_regset *regset;
+
+	GEM_BUG_ON(engine->class >= GUC_MAX_ENGINE_CLASSES);
+	GEM_BUG_ON(engine->instance >= GUC_MAX_INSTANCES_PER_CLASS);
+	regset = &reg_state->engine_reg[engine->class][engine->instance];
+
+	guc_mmio_regset_init(regset, engine);
+}