diff mbox series

drm/i915: RFC: Introduce Wa_14011282866

Message ID 20230510215811.650160-1-matthew.s.atwood@intel.com (mailing list archive)
State New, archived
Headers show
Series drm/i915: RFC: Introduce Wa_14011282866 | expand

Commit Message

Matt Atwood May 10, 2023, 9:58 p.m. UTC
From: Tilak Tangudu <tilak.tangudu@intel.com>

Wa_14011282866 applies to RKL, ADL-S, ADL-P and TGL.

Allocate buffer pinned to GGTT and add WA to restore sampler power
context.

Bspec: 46247

Signed-off-by: Matt Atwood <matthew.s.atwood@intel.com>
Signed-off-by: Tilak Tangudu <tilak.tangudu@intel.com>
---
 drivers/gpu/drm/i915/gt/intel_gt_regs.h   |  5 ++
 drivers/gpu/drm/i915/gt/intel_rc6.c       | 88 +++++++++++++++++++++++
 drivers/gpu/drm/i915/gt/intel_rc6_types.h |  3 +
 3 files changed, 96 insertions(+)

Comments

Matt Roper May 12, 2023, 10:47 p.m. UTC | #1
On Wed, May 10, 2023 at 02:58:11PM -0700, Matt Atwood wrote:
> From: Tilak Tangudu <tilak.tangudu@intel.com>
> 
> Wa_14011282866 applies to RKL, ADL-S, ADL-P and TGL.

Wa_14011282866 isn't a valid workaround number.

> 
> Allocate buffer pinned to GGTT and add WA to restore sampler power
> context.
> 
> Bspec: 46247
> 
> Signed-off-by: Matt Atwood <matthew.s.atwood@intel.com>
> Signed-off-by: Tilak Tangudu <tilak.tangudu@intel.com>

These lines are backward if Tilak is the original author as shown above.
From Documentation/process/submitting-patches.rst:

        "Any further SoBs (Signed-off-by:'s) following the author's SoB
        are from people handling and transporting the patch, but were
        not involved in its development. SoB chains should reflect the
        **real** route a patch took as it was propagated to the
        maintainers and ultimately to Linus, with the first SoB entry
        signalling primary authorship of a single author."

> ---
>  drivers/gpu/drm/i915/gt/intel_gt_regs.h   |  5 ++
>  drivers/gpu/drm/i915/gt/intel_rc6.c       | 88 +++++++++++++++++++++++
>  drivers/gpu/drm/i915/gt/intel_rc6_types.h |  3 +
>  3 files changed, 96 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
> index b8a39c219b60..91cbdd24572f 100644
> --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h
> +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
> @@ -48,6 +48,11 @@
>  /* RCP unit config (Gen8+) */
>  #define RCP_CONFIG				_MMIO(0xd08)
>  
> +#define CTX_WA_PTR				_MMIO(0x2058)
> +#define CTX_WA_PTR_ADDR_MASK			REG_GENMASK(31, 12)
> +#define CTX_WA_TYPE_MASK			REG_GENMASK(4, 3)
> +#define CTX_WA_VALID				REG_BIT(0)

This register isn't at the right place.  Also the bit definitions are
missing a couple spaces before the bitfield names.

> +
>  #define RC6_LOCATION				_MMIO(0xd40)
>  #define   RC6_CTX_IN_DRAM			(1 << 0)
>  #define RC6_CTX_BASE				_MMIO(0xd48)
> diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c
> index 908a3d0f2343..9589af2e8ca3 100644
> --- a/drivers/gpu/drm/i915/gt/intel_rc6.c
> +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c
> @@ -12,6 +12,7 @@
>  #include "i915_vgpu.h"
>  #include "intel_engine_regs.h"
>  #include "intel_gt.h"
> +#include "intel_gpu_commands.h"
>  #include "intel_gt_pm.h"
>  #include "intel_gt_regs.h"
>  #include "intel_pcode.h"
> @@ -38,6 +39,7 @@
>   * require higher latency to switch to and wake up.
>   */
>  
> +#define RC6_CTX_WA_BB_SIZE (PAGE_SIZE)

Do we really need this?  It's unlikely that we'll wind up needing more
than a page (and we're not even trying to check in the code below either).

>  static struct intel_gt *rc6_to_gt(struct intel_rc6 *rc6)
>  {
>  	return container_of(rc6, struct intel_gt, rc6);
> @@ -53,8 +55,86 @@ static struct drm_i915_private *rc6_to_i915(struct intel_rc6 *rc)
>  	return rc6_to_gt(rc)->i915;
>  }
>  
> +static int rc6_wa_bb_ctx_init(struct intel_rc6 *rc6)
> +{
> +	struct drm_i915_private *i915 = rc6_to_i915(rc6);
> +	struct intel_gt *gt = rc6_to_gt(rc6);
> +	struct drm_i915_gem_object *obj;
> +	struct i915_vma *vma;
> +	void *batch;
> +	struct i915_gem_ww_ctx ww;
> +	int err;
> +
> +	obj = i915_gem_object_create_shmem(i915, RC6_CTX_WA_BB_SIZE);
> +	if (IS_ERR(obj))
> +		return PTR_ERR(obj);
> +
> +	vma = i915_vma_instance(obj, &gt->ggtt->vm, NULL);
> +	if (IS_ERR(vma)) {
> +		err = PTR_ERR(vma);
> +		goto err;
> +	}
> +	rc6->vma = vma;
> +	i915_gem_ww_ctx_init(&ww, true);
> +retry:
> +	err = i915_gem_object_lock(rc6->vma->obj, &ww);

Nitpick:  Can't we just use the shorter local variable 'obj' here and in
the pin_map?

> +	if (!err)
> +		err = i915_ggtt_pin(rc6->vma, &ww, 0, PIN_HIGH);
> +	if (err)
> +		goto err_ww_fini;
> +
> +	batch = i915_gem_object_pin_map(rc6->vma->obj, I915_MAP_WB);
> +	if (IS_ERR(batch)) {
> +		err = PTR_ERR(batch);
> +		goto err_unpin;
> +	}
> +	rc6->rc6_wa_bb = batch;
> +	return 0;
> +err_unpin:
> +	if (err)
> +		i915_vma_unpin(rc6->vma);
> +err_ww_fini:
> +	if (err == -EDEADLK) {
> +		err = i915_gem_ww_ctx_backoff(&ww);
> +		if (!err)
> +			goto retry;
> +	}
> +	i915_gem_ww_ctx_fini(&ww);
> +
> +	if (err)
> +		i915_vma_put(rc6->vma);
> +err:
> +	i915_gem_object_put(obj);
> +	return err;
> +}

Where do we clean up all the stuff done in this function?

> +
> +static void rc6_wa_bb_restore_sampler_power_ctx(struct intel_rc6 *rc6)
> +{
> +	struct intel_uncore *uncore = rc6_to_uncore(rc6);
> +	u32 *rc6_wa_bb;
> +
> +	if (!rc6->vma->obj)
> +		return;
> +
> +	rc6_wa_bb = rc6->rc6_wa_bb;
> +	*rc6_wa_bb++ = MI_NOOP;
> +	*rc6_wa_bb++ = MI_LOAD_REGISTER_IMM(1) | MI_LRI_FORCE_POSTED;
> +	*rc6_wa_bb++ = i915_mmio_reg_offset(GEN10_SAMPLER_MODE);
> +	*rc6_wa_bb++ = _MASKED_BIT_ENABLE(ENABLE_SMALLPL);

This isn't the only register/bit that we're attempting to program
(unsuccessfully) today; we need to handle all of the programming that
targets the affected TDL registers such as Wa_1406941453.

Rather than including specific register values here (with no explanation
of why we're even programming these), it would be better if we could
just place these in the usual locations where workarounds and tuning
settings are applied.  Then have the code here walk the workaround list
looking for any entries that write to a broken register; if any are
found, add them to the power context batchbuffer here to restore them
manually.  That way the registers/values are clear because they're
implemented in the same place they are for every other platform, and the
code here is future-proof to catch any other uses of these registers in
the future.  You may need to adjust where this batch buffer gets built
to do that (since I think the GT PM init happens before the WAL init).


> +	*rc6_wa_bb++ = MI_NOOP;
> +	*rc6_wa_bb++ = MI_BATCH_BUFFER_END;
> +
> +	i915_gem_object_flush_map(rc6->vma->obj);
> +
> +	intel_uncore_write(uncore, CTX_WA_PTR,
> +			   REG_FIELD_PREP(CTX_WA_PTR_ADDR_MASK,
> +					  i915_vma_offset(rc6->vma) & GENMASK(19, 0)) |

This isn't what we want here; note the "Format:" label on the register
bitfield...the value that you pack into bits 31:12 of the register is
supposed to be bits 31:12 of the address.  I.e., the entire register
should effectively be the address, with the valid bit OR'd into bit 0 at
the end.

> +			   CTX_WA_VALID);
> +}
> +
>  static void gen11_rc6_enable(struct intel_rc6 *rc6)
>  {
> +	struct drm_i915_private *i915 = rc6_to_i915(rc6);
>  	struct intel_gt *gt = rc6_to_gt(rc6);
>  	struct intel_uncore *uncore = gt->uncore;
>  	struct intel_engine_cs *engine;
> @@ -103,6 +183,11 @@ static void gen11_rc6_enable(struct intel_rc6 *rc6)
>  	intel_uncore_write_fw(uncore, GEN9_MEDIA_PG_IDLE_HYSTERESIS, 60);
>  	intel_uncore_write_fw(uncore, GEN9_RENDER_PG_IDLE_HYSTERESIS, 60);
>  
> +	/* Wa_14011282866 Restore sampler power context */

We're inserting this into the middle of a numbered sequence.  I'm not
sure where that sequence comes from, but putting it here makes it look
as if this was part of step "2c: Program Coarse Power Gating Policies."

> +	if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915) ||
> +	    IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915))

If we're using a long platform list like this in multiple places to
implement a single workaround, it's generally best to make a dedicated
function for it so that any future changes to the workaround bounds can
be adjusted in just one place.


Matt

> +		rc6_wa_bb_restore_sampler_power_ctx(rc6);
> +
>  	/* 3a: Enable RC6
>  	 *
>  	 * With GuCRC, we do not enable bit 31 of RC_CTL,
> @@ -610,6 +695,9 @@ void intel_rc6_init(struct intel_rc6 *rc6)
>  		err = chv_rc6_init(rc6);
>  	else if (IS_VALLEYVIEW(i915))
>  		err = vlv_rc6_init(rc6);
> +	else if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915) ||
> +		 IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915))
> +		err = rc6_wa_bb_ctx_init(rc6);
>  	else
>  		err = 0;
>  
> diff --git a/drivers/gpu/drm/i915/gt/intel_rc6_types.h b/drivers/gpu/drm/i915/gt/intel_rc6_types.h
> index cd4587098162..643fd4e839ad 100644
> --- a/drivers/gpu/drm/i915/gt/intel_rc6_types.h
> +++ b/drivers/gpu/drm/i915/gt/intel_rc6_types.h
> @@ -33,6 +33,9 @@ struct intel_rc6 {
>  
>  	struct drm_i915_gem_object *pctx;
>  
> +	u32 *rc6_wa_bb;
> +	struct i915_vma *vma;
> +
>  	bool supported : 1;
>  	bool enabled : 1;
>  	bool manual : 1;
> -- 
> 2.40.0
>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
index b8a39c219b60..91cbdd24572f 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
@@ -48,6 +48,11 @@ 
 /* RCP unit config (Gen8+) */
 #define RCP_CONFIG				_MMIO(0xd08)
 
+#define CTX_WA_PTR				_MMIO(0x2058)
+#define CTX_WA_PTR_ADDR_MASK			REG_GENMASK(31, 12)
+#define CTX_WA_TYPE_MASK			REG_GENMASK(4, 3)
+#define CTX_WA_VALID				REG_BIT(0)
+
 #define RC6_LOCATION				_MMIO(0xd40)
 #define   RC6_CTX_IN_DRAM			(1 << 0)
 #define RC6_CTX_BASE				_MMIO(0xd48)
diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c
index 908a3d0f2343..9589af2e8ca3 100644
--- a/drivers/gpu/drm/i915/gt/intel_rc6.c
+++ b/drivers/gpu/drm/i915/gt/intel_rc6.c
@@ -12,6 +12,7 @@ 
 #include "i915_vgpu.h"
 #include "intel_engine_regs.h"
 #include "intel_gt.h"
+#include "intel_gpu_commands.h"
 #include "intel_gt_pm.h"
 #include "intel_gt_regs.h"
 #include "intel_pcode.h"
@@ -38,6 +39,7 @@ 
  * require higher latency to switch to and wake up.
  */
 
+#define RC6_CTX_WA_BB_SIZE (PAGE_SIZE)
 static struct intel_gt *rc6_to_gt(struct intel_rc6 *rc6)
 {
 	return container_of(rc6, struct intel_gt, rc6);
@@ -53,8 +55,86 @@  static struct drm_i915_private *rc6_to_i915(struct intel_rc6 *rc)
 	return rc6_to_gt(rc)->i915;
 }
 
+static int rc6_wa_bb_ctx_init(struct intel_rc6 *rc6)
+{
+	struct drm_i915_private *i915 = rc6_to_i915(rc6);
+	struct intel_gt *gt = rc6_to_gt(rc6);
+	struct drm_i915_gem_object *obj;
+	struct i915_vma *vma;
+	void *batch;
+	struct i915_gem_ww_ctx ww;
+	int err;
+
+	obj = i915_gem_object_create_shmem(i915, RC6_CTX_WA_BB_SIZE);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	vma = i915_vma_instance(obj, &gt->ggtt->vm, NULL);
+	if (IS_ERR(vma)) {
+		err = PTR_ERR(vma);
+		goto err;
+	}
+	rc6->vma = vma;
+	i915_gem_ww_ctx_init(&ww, true);
+retry:
+	err = i915_gem_object_lock(rc6->vma->obj, &ww);
+	if (!err)
+		err = i915_ggtt_pin(rc6->vma, &ww, 0, PIN_HIGH);
+	if (err)
+		goto err_ww_fini;
+
+	batch = i915_gem_object_pin_map(rc6->vma->obj, I915_MAP_WB);
+	if (IS_ERR(batch)) {
+		err = PTR_ERR(batch);
+		goto err_unpin;
+	}
+	rc6->rc6_wa_bb = batch;
+	return 0;
+err_unpin:
+	if (err)
+		i915_vma_unpin(rc6->vma);
+err_ww_fini:
+	if (err == -EDEADLK) {
+		err = i915_gem_ww_ctx_backoff(&ww);
+		if (!err)
+			goto retry;
+	}
+	i915_gem_ww_ctx_fini(&ww);
+
+	if (err)
+		i915_vma_put(rc6->vma);
+err:
+	i915_gem_object_put(obj);
+	return err;
+}
+
+static void rc6_wa_bb_restore_sampler_power_ctx(struct intel_rc6 *rc6)
+{
+	struct intel_uncore *uncore = rc6_to_uncore(rc6);
+	u32 *rc6_wa_bb;
+
+	if (!rc6->vma->obj)
+		return;
+
+	rc6_wa_bb = rc6->rc6_wa_bb;
+	*rc6_wa_bb++ = MI_NOOP;
+	*rc6_wa_bb++ = MI_LOAD_REGISTER_IMM(1) | MI_LRI_FORCE_POSTED;
+	*rc6_wa_bb++ = i915_mmio_reg_offset(GEN10_SAMPLER_MODE);
+	*rc6_wa_bb++ = _MASKED_BIT_ENABLE(ENABLE_SMALLPL);
+	*rc6_wa_bb++ = MI_NOOP;
+	*rc6_wa_bb++ = MI_BATCH_BUFFER_END;
+
+	i915_gem_object_flush_map(rc6->vma->obj);
+
+	intel_uncore_write(uncore, CTX_WA_PTR,
+			   REG_FIELD_PREP(CTX_WA_PTR_ADDR_MASK,
+					  i915_vma_offset(rc6->vma) & GENMASK(19, 0)) |
+			   CTX_WA_VALID);
+}
+
 static void gen11_rc6_enable(struct intel_rc6 *rc6)
 {
+	struct drm_i915_private *i915 = rc6_to_i915(rc6);
 	struct intel_gt *gt = rc6_to_gt(rc6);
 	struct intel_uncore *uncore = gt->uncore;
 	struct intel_engine_cs *engine;
@@ -103,6 +183,11 @@  static void gen11_rc6_enable(struct intel_rc6 *rc6)
 	intel_uncore_write_fw(uncore, GEN9_MEDIA_PG_IDLE_HYSTERESIS, 60);
 	intel_uncore_write_fw(uncore, GEN9_RENDER_PG_IDLE_HYSTERESIS, 60);
 
+	/* Wa_14011282866 Restore sampler power context */
+	if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915) ||
+	    IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915))
+		rc6_wa_bb_restore_sampler_power_ctx(rc6);
+
 	/* 3a: Enable RC6
 	 *
 	 * With GuCRC, we do not enable bit 31 of RC_CTL,
@@ -610,6 +695,9 @@  void intel_rc6_init(struct intel_rc6 *rc6)
 		err = chv_rc6_init(rc6);
 	else if (IS_VALLEYVIEW(i915))
 		err = vlv_rc6_init(rc6);
+	else if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915) ||
+		 IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915))
+		err = rc6_wa_bb_ctx_init(rc6);
 	else
 		err = 0;
 
diff --git a/drivers/gpu/drm/i915/gt/intel_rc6_types.h b/drivers/gpu/drm/i915/gt/intel_rc6_types.h
index cd4587098162..643fd4e839ad 100644
--- a/drivers/gpu/drm/i915/gt/intel_rc6_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_rc6_types.h
@@ -33,6 +33,9 @@  struct intel_rc6 {
 
 	struct drm_i915_gem_object *pctx;
 
+	u32 *rc6_wa_bb;
+	struct i915_vma *vma;
+
 	bool supported : 1;
 	bool enabled : 1;
 	bool manual : 1;