[PATCH 5/7] drm/i915/guc: Don't give up on WOPCM partitioning regs mismatch

Michał Winiarski michal.winiarski at intel.com
Thu Mar 22 19:57:08 UTC 2018


It's possible that when we're being loaded, the write-once registers were
already programmed. It's also possible, that values present in those registers
match our FW size and HW restrictions.
Rather than failing the module load when we detect any differences from our
preferred values, let's replace them with what's present in the registers,
failing the load only if we're unable to satisfy the constraints.

Signed-off-by: Michał Winiarski <michal.winiarski at intel.com>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Jackie Li <yaodong.li at intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko at intel.com>
---
 drivers/gpu/drm/i915/i915_gem.c    |   6 +--
 drivers/gpu/drm/i915/intel_wopcm.c | 105 ++++++++++++++++++-------------------
 drivers/gpu/drm/i915/intel_wopcm.h |   6 ++-
 3 files changed, 58 insertions(+), 59 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 802df8e1a544..1b25eadc5940 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -5154,11 +5154,7 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv)
 		goto out;
 	}
 
-	ret = intel_wopcm_init_hw(&dev_priv->wopcm);
-	if (ret) {
-		DRM_ERROR("Enabling WOPCM failed (%d)\n", ret);
-		goto out;
-	}
+	intel_wopcm_init_hw(&dev_priv->wopcm);
 
 	/* We can't enable contexts until all firmware is loaded */
 	ret = intel_uc_init_hw(dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c
index 61b97d74f631..10d8e30c6291 100644
--- a/drivers/gpu/drm/i915/intel_wopcm.c
+++ b/drivers/gpu/drm/i915/intel_wopcm.c
@@ -179,7 +179,7 @@ __guc_region_grow(struct intel_wopcm *wopcm, u32 size)
 	wopcm->guc.size += size;
 }
 
-static void wopcm_adjust_for_hw_restrictions(struct intel_wopcm *wopcm)
+static int wopcm_adjust_for_hw_restrictions(struct intel_wopcm *wopcm)
 {
 	struct drm_i915_private *i915 = wopcm_to_i915(wopcm);
 	u32 huc_fw_size = intel_uc_fw_get_upload_size(&i915->huc.fw);
@@ -188,19 +188,29 @@ static void wopcm_adjust_for_hw_restrictions(struct intel_wopcm *wopcm)
 	if (IS_GEN9(i915) || IS_CNL_REVID(i915, CNL_REVID_A0, CNL_REVID_A0)) {
 		size = gen9_size_for_dword_gap_restriction(wopcm->guc.base,
 							   wopcm->guc.size);
-		if (size)
+		if (size) {
+			if (wopcm->guc.base_locked || wopcm->guc.size_locked)
+				return -E2BIG;
+
 			__guc_region_grow(wopcm, size);
+		}
 
 		size = gen9_size_for_huc_restriction(wopcm->guc.size,
 						     huc_fw_size);
-		if (size)
+		if (size) {
+			if (wopcm->guc.base_locked || wopcm->guc.size_locked)
+				return -E2BIG;
+
 			__guc_region_grow(wopcm, size);
+		}
 
 		GEM_BUG_ON(gen9_size_for_dword_gap_restriction(wopcm->guc.base,
 							       wopcm->guc.size));
 		GEM_BUG_ON(gen9_size_for_huc_restriction(wopcm->guc.size,
 							 huc_fw_size));
 	}
+
+	return 0;
 }
 
 static bool wopcm_check_components_fit(struct intel_wopcm *wopcm)
@@ -230,12 +240,30 @@ static int wopcm_guc_region_init(struct intel_wopcm *wopcm)
 {
 	struct drm_i915_private *dev_priv = wopcm_to_i915(wopcm);
 	u32 guc_fw_size = intel_uc_fw_get_upload_size(&dev_priv->guc.fw);
+	u32 huc_fw_size = intel_uc_fw_get_upload_size(&dev_priv->huc.fw);
 	u32 ctx_rsvd = context_reserved_size(dev_priv);
+	u32 reg_val;
 
-	wopcm->guc.size = guc_fw_size_in_wopcm(guc_fw_size);
+	reg_val = I915_READ(GUC_WOPCM_SIZE);
+	if (reg_val & GUC_WOPCM_SIZE_LOCKED) {
+		wopcm->guc.size = (reg_val & GUC_WOPCM_SIZE_MASK);
+		wopcm->guc.size_locked = true;
+	} else {
+		wopcm->guc.size = guc_fw_size_in_wopcm(guc_fw_size);
+	}
 
-	wopcm->guc.base = ALIGN_DOWN(wopcm->size - ctx_rsvd - wopcm->guc.size,
-				     GUC_WOPCM_OFFSET_ALIGNMENT);
+	reg_val = I915_READ(DMA_GUC_WOPCM_OFFSET);
+	if (reg_val & GUC_WOPCM_OFFSET_VALID) {
+		if (huc_fw_size && !(reg_val & HUC_LOADING_AGENT_GUC))
+			return -EIO;
+
+		wopcm->guc.base = (reg_val & GUC_WOPCM_OFFSET_MASK);
+		wopcm->guc.base_locked = true;
+	} else {
+		wopcm->guc.base = ALIGN_DOWN(wopcm->size - wopcm->guc.size -
+					     ctx_rsvd,
+					     GUC_WOPCM_OFFSET_ALIGNMENT);
+	}
 
 	return 0;
 }
@@ -262,7 +290,9 @@ int intel_wopcm_init(struct intel_wopcm *wopcm)
 	if (err)
 		return err;
 
-	wopcm_adjust_for_hw_restrictions(wopcm);
+	err = wopcm_adjust_for_hw_restrictions(wopcm);
+	if (err)
+		return err;
 
 	err = wopcm_check_components_fit(wopcm);
 	if (err)
@@ -275,66 +305,35 @@ int intel_wopcm_init(struct intel_wopcm *wopcm)
 	return 0;
 }
 
-static inline int write_and_verify(struct drm_i915_private *dev_priv,
-				   i915_reg_t reg, u32 val, u32 mask,
-				   u32 locked_bit)
-{
-	u32 reg_val;
-
-	GEM_BUG_ON(val & ~mask);
-
-	I915_WRITE(reg, val);
-
-	reg_val = I915_READ(reg);
-
-	return (reg_val & mask) != (val | locked_bit) ? -EIO : 0;
-}
-
 /**
  * intel_wopcm_init_hw() - Setup GuC WOPCM registers.
  * @wopcm: pointer to intel_wopcm.
  *
- * Setup the GuC WOPCM size and offset registers with the calculated values. It
- * will verify the register values to make sure the registers are locked with
- * correct values.
+ * Setup the GuC WOPCM size and offset registers with the calculated values.
  *
- * Return: 0 on success. -EIO if registers were locked with incorrect values.
  */
-int intel_wopcm_init_hw(struct intel_wopcm *wopcm)
+void intel_wopcm_init_hw(struct intel_wopcm *wopcm)
 {
 	struct drm_i915_private *dev_priv = wopcm_to_i915(wopcm);
-	u32 huc_agent;
-	u32 mask;
-	int err;
 
 	if (!USES_GUC(dev_priv))
-		return 0;
+		return;
 
 	GEM_BUG_ON(!HAS_GUC(dev_priv));
 	GEM_BUG_ON(!wopcm->guc.size);
 	GEM_BUG_ON(!wopcm->guc.base);
 
-	err = write_and_verify(dev_priv, GUC_WOPCM_SIZE, wopcm->guc.size,
-			       GUC_WOPCM_SIZE_MASK | GUC_WOPCM_SIZE_LOCKED,
-			       GUC_WOPCM_SIZE_LOCKED);
-	if (err)
-		goto err_out;
-
-	huc_agent = USES_HUC(dev_priv) ? HUC_LOADING_AGENT_GUC : 0;
-	mask = GUC_WOPCM_OFFSET_MASK | GUC_WOPCM_OFFSET_VALID | huc_agent;
-	err = write_and_verify(dev_priv, DMA_GUC_WOPCM_OFFSET,
-			       wopcm->guc.base | huc_agent, mask,
-			       GUC_WOPCM_OFFSET_VALID);
-	if (err)
-		goto err_out;
-
-	return 0;
-
-err_out:
-	DRM_ERROR("Failed to init WOPCM registers:\n");
-	DRM_ERROR("DMA_GUC_WOPCM_OFFSET=%#x\n",
-		  I915_READ(DMA_GUC_WOPCM_OFFSET));
-	DRM_ERROR("GUC_WOPCM_SIZE=%#x\n", I915_READ(GUC_WOPCM_SIZE));
+	if (!wopcm->guc.size_locked) {
+		I915_WRITE(GUC_WOPCM_SIZE, wopcm->guc.size &
+					   GUC_WOPCM_SIZE_MASK);
+		GEM_BUG_ON(!I915_READ(GUC_WOPCM_SIZE) & GUC_WOPCM_SIZE_LOCKED);
+	}
 
-	return err;
+	if (!wopcm->guc.base_locked) {
+		I915_WRITE(DMA_GUC_WOPCM_OFFSET,
+			   (GUC_WOPCM_OFFSET_MASK & wopcm->guc.base) |
+			   HUC_LOADING_AGENT_GUC);
+		GEM_BUG_ON(!I915_READ(DMA_GUC_WOPCM_OFFSET) &
+			   GUC_WOPCM_OFFSET_VALID);
+	}
 }
diff --git a/drivers/gpu/drm/i915/intel_wopcm.h b/drivers/gpu/drm/i915/intel_wopcm.h
index 6298910a384c..144232999bfe 100644
--- a/drivers/gpu/drm/i915/intel_wopcm.h
+++ b/drivers/gpu/drm/i915/intel_wopcm.h
@@ -14,18 +14,22 @@
  * @size: Size of overall WOPCM.
  * @guc: GuC WOPCM Region info.
  * @guc.base: GuC WOPCM base which is offset from WOPCM base.
+ * @guc.base_locked: True if base register was locked during partitioning.
  * @guc.size: Size of the GuC WOPCM region.
+ * @guc.size_locked: True if size register was locked during partitioning.
  */
 struct intel_wopcm {
 	u32 size;
 	struct {
 		u32 base;
+		bool base_locked;
 		u32 size;
+		bool size_locked;
 	} guc;
 };
 
 void intel_wopcm_init_early(struct intel_wopcm *wopcm);
 int intel_wopcm_init(struct intel_wopcm *wopcm);
-int intel_wopcm_init_hw(struct intel_wopcm *wopcm);
+void intel_wopcm_init_hw(struct intel_wopcm *wopcm);
 
 #endif
-- 
2.14.3



More information about the Intel-gfx-trybot mailing list