[Intel-gfx] [PATCH v4 06/16] drm/i915/gt: Clear compress metadata for Xe_HP platforms

Robert Beckett bob.beckett at collabora.com
Wed Dec 15 16:59:22 UTC 2021


The fixes below fix gem_lmem_swapping at basic igt test

On 09/12/2021 15:45, Ramalingam C wrote:
> From: Ayaz A Siddiqui <ayaz.siddiqui at intel.com>
> 
> Xe-HP and latest devices support Flat CCS which reserved a portion of
> the device memory to store compression metadata, during the clearing of
> device memory buffer object we also need to clear the associated
> CCS buffer.
> 
> Flat CCS memory can not be directly accessed by S/W.
> Address of CCS buffer associated main BO is automatically calculated
> by device itself. KMD/UMD can only access this buffer indirectly using
> XY_CTRL_SURF_COPY_BLT cmd via the address of device memory buffer.
> 
> v2: Fixed issues with platform naming [Lucas]
> 
> Cc: CQ Tang <cq.tang at intel.com>
> Signed-off-by: Ayaz A Siddiqui <ayaz.siddiqui at intel.com>
> Signed-off-by: Ramalingam C <ramalingam.c at intel.com>
> ---
>   drivers/gpu/drm/i915/gt/intel_gpu_commands.h |  14 +++
>   drivers/gpu/drm/i915/gt/intel_migrate.c      | 120 ++++++++++++++++++-
>   2 files changed, 131 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h
> index f8253012d166..07bf5a1753bd 100644
> --- a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h
> +++ b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h
> @@ -203,6 +203,20 @@
>   #define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
>   #define GFX_OP_DRAWRECT_INFO_I965  ((0x7900<<16)|0x2)
>   
> +#define XY_CTRL_SURF_INSTR_SIZE	5
> +#define MI_FLUSH_DW_SIZE		3
> +#define XY_CTRL_SURF_COPY_BLT		((2 << 29) | (0x48 << 22) | 3)
> +#define   SRC_ACCESS_TYPE_SHIFT	21
> +#define   DST_ACCESS_TYPE_SHIFT	20
> +#define   CCS_SIZE_SHIFT		8
> +#define   XY_CTRL_SURF_MOCS_SHIFT	25
> +#define   NUM_CCS_BYTES_PER_BLOCK	256
> +#define   NUM_CCS_BLKS_PER_XFER	1024
> +#define   INDIRECT_ACCESS		0
> +#define   DIRECT_ACCESS		1
> +#define  MI_FLUSH_LLC			BIT(9)
> +#define  MI_FLUSH_CCS			BIT(16)
> +
>   #define COLOR_BLT_CMD			(2 << 29 | 0x40 << 22 | (5 - 2))
>   #define XY_COLOR_BLT_CMD		(2 << 29 | 0x50 << 22)
>   #define SRC_COPY_BLT_CMD		(2 << 29 | 0x43 << 22)
> diff --git a/drivers/gpu/drm/i915/gt/intel_migrate.c b/drivers/gpu/drm/i915/gt/intel_migrate.c
> index 19a01878fee3..64ffaacac1e0 100644
> --- a/drivers/gpu/drm/i915/gt/intel_migrate.c
> +++ b/drivers/gpu/drm/i915/gt/intel_migrate.c
> @@ -16,6 +16,7 @@ struct insert_pte_data {
>   };
>   
>   #define CHUNK_SZ SZ_8M /* ~1ms at 8GiB/s preemption delay */
> +#define GET_CCS_SIZE(i915, size)	(HAS_FLAT_CCS(i915) ? (size) >> 8 : 0)

do the rounding here. Don't manually round, use kernel macros:

-#define GET_CCS_SIZE(i915, size)       (HAS_FLAT_CCS(i915) ? (size) >> 
8 : 0)

+#define GET_CCS_SIZE(i915, size)       (HAS_FLAT_CCS(i915) ? 
DIV_ROUND_UP(size, NUM_CCS_BYTES_PER_BLOCK ) : 0)


>   
>   static bool engine_supports_migration(struct intel_engine_cs *engine)
>   {
> @@ -488,15 +489,104 @@ intel_context_migrate_copy(struct intel_context *ce,
>   	return err;
>   }
>   
> -static int emit_clear(struct i915_request *rq, int size, u32 value)
> +static inline u32 *i915_flush_dw(u32 *cmd, u64 dst, u32 flags)
> +{
> +	/* Mask the 3 LSB to use the PPGTT address space */
> +	*cmd++ = MI_FLUSH_DW | flags;
> +	*cmd++ = lower_32_bits(dst);
> +	*cmd++ = upper_32_bits(dst);
> +
> +	return cmd;
> +}
> +
> +static u32 calc_ctrl_surf_instr_size(struct drm_i915_private *i915, int size)
> +{
> +	u32 num_cmds, num_blks, total_size;
> +
> +	if (!GET_CCS_SIZE(i915, size))
> +		return 0;
> +
> +	/*
> +	 * XY_CTRL_SURF_COPY_BLT transfers CCS in 256 byte
> +	 * blocks. one XY_CTRL_SURF_COPY_BLT command can
> +	 * trnasfer upto 1024 blocks.
> +	 */
> +	num_blks = (GET_CCS_SIZE(i915, size) +
> +			   (NUM_CCS_BYTES_PER_BLOCK - 1)) >> 8;

-       num_blks = (GET_CCS_SIZE(i915, size) +

-                          (NUM_CCS_BYTES_PER_BLOCK - 1)) >> 8;

+       num_blks = GET_CCS_SIZE(i915, size);



> +	num_cmds = (num_blks + (NUM_CCS_BLKS_PER_XFER - 1)) >> 10;
> +	total_size = (XY_CTRL_SURF_INSTR_SIZE) * num_cmds;
> +
> +	/*
> +	 * We need to add a flush before and after
> +	 * XY_CTRL_SURF_COPY_BLT
> +	 */
> +	total_size += 2 * MI_FLUSH_DW_SIZE;
> +	return total_size;
> +}
> +
> +static u32 *_i915_ctrl_surf_copy_blt(u32 *cmd, u64 src_addr, u64 dst_addr,
> +				     u8 src_mem_access, u8 dst_mem_access,
> +				     int src_mocs, int dst_mocs,
> +				     u16 num_ccs_blocks)
> +{
> +	int i = num_ccs_blocks;
> +
> +	/*
> +	 * The XY_CTRL_SURF_COPY_BLT instruction is used to copy the CCS
> +	 * data in and out of the CCS region.
> +	 *
> +	 * We can copy at most 1024 blocks of 256 bytes using one
> +	 * XY_CTRL_SURF_COPY_BLT instruction.
> +	 *
> +	 * In case we need to copy more than 1024 blocks, we need to add
> +	 * another instruction to the same batch buffer.
> +	 *
> +	 * 1024 blocks of 256 bytes of CCS represent a total 256KB of CCS.
> +	 *
> +	 * 256 KB of CCS represents 256 * 256 KB = 64 MB of LMEM.
> +	 */
> +	do {
> +		/*
> +		 * We use logical AND with 1023 since the size field
> +		 * takes values which is in the range of 0 - 1023
> +		 */
> +		*cmd++ = ((XY_CTRL_SURF_COPY_BLT) |
> +			  (src_mem_access << SRC_ACCESS_TYPE_SHIFT) |
> +			  (dst_mem_access << DST_ACCESS_TYPE_SHIFT) |
> +			  (((i - 1) & 1023) << CCS_SIZE_SHIFT));
> +		*cmd++ = lower_32_bits(src_addr);
> +		*cmd++ = ((upper_32_bits(src_addr) & 0xFFFF) |
> +			  (src_mocs << XY_CTRL_SURF_MOCS_SHIFT));
> +		*cmd++ = lower_32_bits(dst_addr);
> +		*cmd++ = ((upper_32_bits(dst_addr) & 0xFFFF) |
> +			  (dst_mocs << XY_CTRL_SURF_MOCS_SHIFT));
> +		src_addr += SZ_64M;
> +		dst_addr += SZ_64M;
> +		i -= NUM_CCS_BLKS_PER_XFER;
> +	} while (i > 0);
> +
> +	return cmd;
> +}
> +
> +static int emit_clear(struct i915_request *rq,
> +		      int size,
> +		      u32 value,
> +		      bool is_lmem)
>   {
>   	const int ver = GRAPHICS_VER(rq->engine->i915);
>   	u32 instance = rq->engine->instance;
>   	u32 *cs;
> +	struct drm_i915_private *i915 = rq->engine->i915;
> +	u32 num_ccs_blks, ccs_ring_size;
>   
>   	GEM_BUG_ON(size >> PAGE_SHIFT > S16_MAX);
>   
> -	cs = intel_ring_begin(rq, ver >= 8 ? 8 : 6);
> +	/* Clear flat css only when value is 0 */
> +	ccs_ring_size = (is_lmem && !value) ?
> +			 calc_ctrl_surf_instr_size(i915, size)
> +			 : 0;
> +
> +	cs = intel_ring_begin(rq, ver >= 8 ? 8 + ccs_ring_size : 6);

round up to qword:

-       cs = intel_ring_begin(rq, ver >= 8 ? 8 + ccs_ring_size : 6);

+       cs = intel_ring_begin(rq, round_up(ver >= 8 ? 8 + ccs_ring_size 
: 6, 2));



>   	if (IS_ERR(cs))
>   		return PTR_ERR(cs);
>   
> @@ -519,6 +609,30 @@ static int emit_clear(struct i915_request *rq, int size, u32 value)
>   		*cs++ = value;
>   	}
>   
> +	if (is_lmem && HAS_FLAT_CCS(i915) && !value) {
> +		num_ccs_blks = (GET_CCS_SIZE(i915, size) +
> +				NUM_CCS_BYTES_PER_BLOCK - 1) >> 8;

-               num_ccs_blks = (GET_CCS_SIZE(i915, size) +

-                               NUM_CCS_BYTES_PER_BLOCK - 1) >> 8;

+               num_ccs_blks = GET_CCS_SIZE(i915, size);


> +		/*
> +		 * Flat CCS surface can only be accessed via
> +		 * XY_CTRL_SURF_COPY_BLT CMD and using indirect
> +		 * mapping of associated LMEM.
> +		 * We can clear ccs surface by writing all 0s,
> +		 * so we will flush the previously cleared buffer
> +		 * and use it as a source.
> +		 */
> +
> +		cs = i915_flush_dw(cs, (u64)instance << 32,
> +				   MI_FLUSH_LLC | MI_FLUSH_CCS);
> +		cs = _i915_ctrl_surf_copy_blt(cs,
> +					      (u64)instance << 32,
> +					      (u64)instance << 32,
> +					      DIRECT_ACCESS,
> +					      INDIRECT_ACCESS,
> +					      1, 1,
> +					      num_ccs_blks);
> +		cs = i915_flush_dw(cs, (u64)instance << 32,
> +				   MI_FLUSH_LLC | MI_FLUSH_CCS);

pad to qword:

+               if (ccs_ring_size & 1)

+                       *cs++ = MI_NOOP;



> +	}
>   	intel_ring_advance(rq, cs);
>   	return 0;
>   }
> @@ -579,7 +693,7 @@ intel_context_migrate_clear(struct intel_context *ce,
>   		if (err)
>   			goto out_rq;
>   
> -		err = emit_clear(rq, len, value);
> +		err = emit_clear(rq, len, value, is_lmem);
>   
>   		/* Arbitration is re-enabled between requests. */
>   out_rq:
> 


More information about the Intel-gfx mailing list