diff mbox series

[v3] drm/i915/ttm: fix sg_table construction

Message ID 20220711085859.24198-1-matthew.auld@intel.com (mailing list archive)
State New, archived
Headers show
Series [v3] drm/i915/ttm: fix sg_table construction | expand

Commit Message

Matthew Auld July 11, 2022, 8:58 a.m. UTC
If we encounter some monster sized local-memory page that exceeds the
maximum sg length (UINT32_MAX), ensure that don't end up with some
misaligned address in the entry that follows, leading to fireworks
later. Also ensure we have some coverage of this in the selftests.

v2(Chris):
  - Use round_down consistently to avoid udiv errors
v3(Nirmoy):
  - Also update the max_segment in the selftest

Fixes: f701b16d4cc5 ("drm/i915/ttm: add i915_sg_from_buddy_resource")
Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6379
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Nirmoy Das <nirmoy.das@linux.intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 11 ++++++++--
 drivers/gpu/drm/i915/i915_scatterlist.c       | 19 +++++++++++++----
 drivers/gpu/drm/i915/i915_scatterlist.h       |  6 ++++--
 drivers/gpu/drm/i915/intel_region_ttm.c       | 10 ++++++---
 drivers/gpu/drm/i915/intel_region_ttm.h       |  3 ++-
 .../drm/i915/selftests/intel_memory_region.c  | 21 +++++++++++++++++--
 drivers/gpu/drm/i915/selftests/mock_region.c  |  3 ++-
 7 files changed, 58 insertions(+), 15 deletions(-)

Comments

Nirmoy Das July 11, 2022, 9:53 a.m. UTC | #1
On 7/11/2022 10:58 AM, Matthew Auld wrote:
> If we encounter some monster sized local-memory page that exceeds the
> maximum sg length (UINT32_MAX), ensure that don't end up with some
> misaligned address in the entry that follows, leading to fireworks
> later. Also ensure we have some coverage of this in the selftests.
>
> v2(Chris):
>    - Use round_down consistently to avoid udiv errors
> v3(Nirmoy):
>    - Also update the max_segment in the selftest
>
> Fixes: f701b16d4cc5 ("drm/i915/ttm: add i915_sg_from_buddy_resource")
> Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6379
> Signed-off-by: Matthew Auld <matthew.auld@intel.com>


Reviewed-by: Nirmoy Das <nirmoy.das@intel.com>

> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Nirmoy Das <nirmoy.das@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/gem/i915_gem_ttm.c       | 11 ++++++++--
>   drivers/gpu/drm/i915/i915_scatterlist.c       | 19 +++++++++++++----
>   drivers/gpu/drm/i915/i915_scatterlist.h       |  6 ++++--
>   drivers/gpu/drm/i915/intel_region_ttm.c       | 10 ++++++---
>   drivers/gpu/drm/i915/intel_region_ttm.h       |  3 ++-
>   .../drm/i915/selftests/intel_memory_region.c  | 21 +++++++++++++++++--
>   drivers/gpu/drm/i915/selftests/mock_region.c  |  3 ++-
>   7 files changed, 58 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> index 7e1f8b83077f..c5c8aa1f8558 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> @@ -602,10 +602,15 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
>   			 struct ttm_resource *res)
>   {
>   	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
> +	u64 page_alignment;
>   
>   	if (!i915_ttm_gtt_binds_lmem(res))
>   		return i915_ttm_tt_get_st(bo->ttm);
>   
> +	page_alignment = bo->page_alignment << PAGE_SHIFT;
> +	if (!page_alignment)
> +		page_alignment = obj->mm.region->min_page_size;
> +
>   	/*
>   	 * If CPU mapping differs, we need to add the ttm_tt pages to
>   	 * the resulting st. Might make sense for GGTT.
> @@ -616,7 +621,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
>   			struct i915_refct_sgt *rsgt;
>   
>   			rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
> -								 res);
> +								 res,
> +								 page_alignment);
>   			if (IS_ERR(rsgt))
>   				return rsgt;
>   
> @@ -625,7 +631,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
>   		return i915_refct_sgt_get(obj->ttm.cached_io_rsgt);
>   	}
>   
> -	return intel_region_ttm_resource_to_rsgt(obj->mm.region, res);
> +	return intel_region_ttm_resource_to_rsgt(obj->mm.region, res,
> +						 page_alignment);
>   }
>   
>   static int i915_ttm_truncate(struct drm_i915_gem_object *obj)
> diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c
> index 159571b9bd24..f63b50b71e10 100644
> --- a/drivers/gpu/drm/i915/i915_scatterlist.c
> +++ b/drivers/gpu/drm/i915/i915_scatterlist.c
> @@ -68,6 +68,7 @@ void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
>    * drm_mm_node
>    * @node: The drm_mm_node.
>    * @region_start: An offset to add to the dma addresses of the sg list.
> + * @page_alignment: Required page alignment for each sg entry. Power of two.
>    *
>    * Create a struct sg_table, initializing it from a struct drm_mm_node,
>    * taking a maximum segment length into account, splitting into segments
> @@ -77,15 +78,18 @@ void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
>    * error code cast to an error pointer on failure.
>    */
>   struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
> -					      u64 region_start)
> +					      u64 region_start,
> +					      u64 page_alignment)
>   {
> -	const u64 max_segment = SZ_1G; /* Do we have a limit on this? */
> +	const u64 max_segment = round_down(UINT_MAX, page_alignment);
>   	u64 segment_pages = max_segment >> PAGE_SHIFT;
>   	u64 block_size, offset, prev_end;
>   	struct i915_refct_sgt *rsgt;
>   	struct sg_table *st;
>   	struct scatterlist *sg;
>   
> +	GEM_BUG_ON(!max_segment);
> +
>   	rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
>   	if (!rsgt)
>   		return ERR_PTR(-ENOMEM);
> @@ -112,6 +116,8 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
>   				sg = __sg_next(sg);
>   
>   			sg_dma_address(sg) = region_start + offset;
> +			GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
> +					       page_alignment));
>   			sg_dma_len(sg) = 0;
>   			sg->length = 0;
>   			st->nents++;
> @@ -138,6 +144,7 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
>    * i915_buddy_block list
>    * @res: The struct i915_ttm_buddy_resource.
>    * @region_start: An offset to add to the dma addresses of the sg list.
> + * @page_alignment: Required page alignment for each sg entry. Power of two.
>    *
>    * Create a struct sg_table, initializing it from struct i915_buddy_block list,
>    * taking a maximum segment length into account, splitting into segments
> @@ -147,11 +154,12 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
>    * error code cast to an error pointer on failure.
>    */
>   struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
> -						     u64 region_start)
> +						     u64 region_start,
> +						     u64 page_alignment)
>   {
>   	struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
>   	const u64 size = res->num_pages << PAGE_SHIFT;
> -	const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE);
> +	const u64 max_segment = round_down(UINT_MAX, page_alignment);
>   	struct drm_buddy *mm = bman_res->mm;
>   	struct list_head *blocks = &bman_res->blocks;
>   	struct drm_buddy_block *block;
> @@ -161,6 +169,7 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
>   	resource_size_t prev_end;
>   
>   	GEM_BUG_ON(list_empty(blocks));
> +	GEM_BUG_ON(!max_segment);
>   
>   	rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
>   	if (!rsgt)
> @@ -191,6 +200,8 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
>   					sg = __sg_next(sg);
>   
>   				sg_dma_address(sg) = region_start + offset;
> +				GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
> +						       page_alignment));
>   				sg_dma_len(sg) = 0;
>   				sg->length = 0;
>   				st->nents++;
> diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h
> index 12c6a1684081..b13e4cdea923 100644
> --- a/drivers/gpu/drm/i915/i915_scatterlist.h
> +++ b/drivers/gpu/drm/i915/i915_scatterlist.h
> @@ -213,9 +213,11 @@ static inline void __i915_refct_sgt_init(struct i915_refct_sgt *rsgt,
>   void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size);
>   
>   struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
> -					      u64 region_start);
> +					      u64 region_start,
> +					      u64 page_alignment);
>   
>   struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
> -						     u64 region_start);
> +						     u64 region_start,
> +						     u64 page_alignment);
>   
>   #endif
> diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
> index 62ff77445b01..6873808a7015 100644
> --- a/drivers/gpu/drm/i915/intel_region_ttm.c
> +++ b/drivers/gpu/drm/i915/intel_region_ttm.c
> @@ -152,6 +152,7 @@ int intel_region_ttm_fini(struct intel_memory_region *mem)
>    * Convert an opaque TTM resource manager resource to a refcounted sg_table.
>    * @mem: The memory region.
>    * @res: The resource manager resource obtained from the TTM resource manager.
> + * @page_alignment: Required page alignment for each sg entry. Power of two.
>    *
>    * The gem backends typically use sg-tables for operations on the underlying
>    * io_memory. So provide a way for the backends to translate the
> @@ -161,16 +162,19 @@ int intel_region_ttm_fini(struct intel_memory_region *mem)
>    */
>   struct i915_refct_sgt *
>   intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
> -				  struct ttm_resource *res)
> +				  struct ttm_resource *res,
> +				  u64 page_alignment)
>   {
>   	if (mem->is_range_manager) {
>   		struct ttm_range_mgr_node *range_node =
>   			to_ttm_range_mgr_node(res);
>   
>   		return i915_rsgt_from_mm_node(&range_node->mm_nodes[0],
> -					      mem->region.start);
> +					      mem->region.start,
> +					      page_alignment);
>   	} else {
> -		return i915_rsgt_from_buddy_resource(res, mem->region.start);
> +		return i915_rsgt_from_buddy_resource(res, mem->region.start,
> +						     page_alignment);
>   	}
>   }
>   
> diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
> index cf9d86dcf409..98fba5155619 100644
> --- a/drivers/gpu/drm/i915/intel_region_ttm.h
> +++ b/drivers/gpu/drm/i915/intel_region_ttm.h
> @@ -24,7 +24,8 @@ int intel_region_ttm_fini(struct intel_memory_region *mem);
>   
>   struct i915_refct_sgt *
>   intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
> -				  struct ttm_resource *res);
> +				  struct ttm_resource *res,
> +				  u64 page_alignment);
>   
>   void intel_region_ttm_resource_free(struct intel_memory_region *mem,
>   				    struct ttm_resource *res);
> diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
> index 73eb53edb8de..3b18e5905c86 100644
> --- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
> +++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
> @@ -451,7 +451,6 @@ static int igt_mock_splintered_region(void *arg)
>   
>   static int igt_mock_max_segment(void *arg)
>   {
> -	const unsigned int max_segment = rounddown(UINT_MAX, PAGE_SIZE);
>   	struct intel_memory_region *mem = arg;
>   	struct drm_i915_private *i915 = mem->i915;
>   	struct i915_ttm_buddy_resource *res;
> @@ -460,7 +459,10 @@ static int igt_mock_max_segment(void *arg)
>   	struct drm_buddy *mm;
>   	struct list_head *blocks;
>   	struct scatterlist *sg;
> +	I915_RND_STATE(prng);
>   	LIST_HEAD(objects);
> +	unsigned int max_segment;
> +	unsigned int ps;
>   	u64 size;
>   	int err = 0;
>   
> @@ -472,7 +474,13 @@ static int igt_mock_max_segment(void *arg)
>   	 */
>   
>   	size = SZ_8G;
> -	mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0, 0);
> +	ps = PAGE_SIZE;
> +	if (i915_prandom_u64_state(&prng) & 1)
> +		ps = SZ_64K; /* For something like DG2 */
> +
> +	max_segment = round_down(UINT_MAX, ps);
> +
> +	mem = mock_region_create(i915, 0, size, ps, 0, 0);
>   	if (IS_ERR(mem))
>   		return PTR_ERR(mem);
>   
> @@ -498,12 +506,21 @@ static int igt_mock_max_segment(void *arg)
>   	}
>   
>   	for (sg = obj->mm.pages->sgl; sg; sg = sg_next(sg)) {
> +		dma_addr_t daddr = sg_dma_address(sg);
> +
>   		if (sg->length > max_segment) {
>   			pr_err("%s: Created an oversized scatterlist entry, %u > %u\n",
>   			       __func__, sg->length, max_segment);
>   			err = -EINVAL;
>   			goto out_close;
>   		}
> +
> +		if (!IS_ALIGNED(daddr, ps)) {
> +			pr_err("%s: Created an unaligned scatterlist entry, addr=%pa, ps=%u\n",
> +			       __func__,  &daddr, ps);
> +			err = -EINVAL;
> +			goto out_close;
> +		}
>   	}
>   
>   out_close:
> diff --git a/drivers/gpu/drm/i915/selftests/mock_region.c b/drivers/gpu/drm/i915/selftests/mock_region.c
> index 670557ce1024..bac21fe84ca5 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_region.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_region.c
> @@ -33,7 +33,8 @@ static int mock_region_get_pages(struct drm_i915_gem_object *obj)
>   		return PTR_ERR(obj->mm.res);
>   
>   	obj->mm.rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
> -							 obj->mm.res);
> +							 obj->mm.res,
> +							 obj->mm.region->min_page_size);
>   	if (IS_ERR(obj->mm.rsgt)) {
>   		err = PTR_ERR(obj->mm.rsgt);
>   		goto err_free_resource;
Guenter Roeck July 16, 2022, 3:38 p.m. UTC | #2
On Mon, Jul 11, 2022 at 09:58:59AM +0100, Matthew Auld wrote:
> If we encounter some monster sized local-memory page that exceeds the
> maximum sg length (UINT32_MAX), ensure that don't end up with some
> misaligned address in the entry that follows, leading to fireworks
> later. Also ensure we have some coverage of this in the selftests.
> 
> v2(Chris):
>   - Use round_down consistently to avoid udiv errors
> v3(Nirmoy):
>   - Also update the max_segment in the selftest
> 
> Fixes: f701b16d4cc5 ("drm/i915/ttm: add i915_sg_from_buddy_resource")
> Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6379
> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Nirmoy Das <nirmoy.das@linux.intel.com>
> Reviewed-by: Nirmoy Das <nirmoy.das@intel.com>

Building i386:defconfig ... failed
--------------
Error log:
x86_64-linux-ld: drivers/gpu/drm/i915/i915_scatterlist.o: in function `i915_rsgt_from_mm_node':
i915_scatterlist.c:(.text+0x196): undefined reference to `__udivdi3'

Bisect log attached.

Guenter

---
# bad: [9b59ec8d50a1f28747ceff9a4f39af5deba9540e] Merge tag 'riscv-for-linus-5.19-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux
# good: [e5d523f1ae8f2cef01f8e071aeee432654166708] ubsan: disable UBSAN_DIV_ZERO for clang
git bisect start 'HEAD' 'e5d523f1ae8f'
# bad: [2a347a06ebb1b186a5cb919c9f5ab6e040554be7] Merge tag 'platform-drivers-x86-v5.19-4' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
git bisect bad 2a347a06ebb1b186a5cb919c9f5ab6e040554be7
# bad: [093f8d8f10aa22935bc8bf7100700f714ebaba9c] Merge tag 'amd-drm-fixes-5.19-2022-07-13' of https://gitlab.freedesktop.org/agd5f/linux into drm-fixes
git bisect bad 093f8d8f10aa22935bc8bf7100700f714ebaba9c
# bad: [ad765fae792e16ce3c1d0b69ce939e3f7dba40ab] drm/i915/gem: Look for waitboosting across the whole object prior to individual waits
git bisect bad ad765fae792e16ce3c1d0b69ce939e3f7dba40ab
# good: [f99546298a4537965b75d518c210742f641be389] Merge tag 'gvt-fixes-2022-07-11' of https://github.com/intel/gvt-linux into drm-intel-fixes
git bisect good f99546298a4537965b75d518c210742f641be389
# bad: [aff1e0b09b54b64944b7fe32997229552737b9e9] drm/i915/ttm: fix sg_table construction
git bisect bad aff1e0b09b54b64944b7fe32997229552737b9e9
# good: [896dcabd1f8f613c533d948df17408c41f8929f5] drm/i915/selftests: fix a couple IS_ERR() vs NULL tests
git bisect good 896dcabd1f8f613c533d948df17408c41f8929f5
# first bad commit: [aff1e0b09b54b64944b7fe32997229552737b9e9] drm/i915/ttm: fix sg_table construction
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
index 7e1f8b83077f..c5c8aa1f8558 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -602,10 +602,15 @@  i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
 			 struct ttm_resource *res)
 {
 	struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+	u64 page_alignment;
 
 	if (!i915_ttm_gtt_binds_lmem(res))
 		return i915_ttm_tt_get_st(bo->ttm);
 
+	page_alignment = bo->page_alignment << PAGE_SHIFT;
+	if (!page_alignment)
+		page_alignment = obj->mm.region->min_page_size;
+
 	/*
 	 * If CPU mapping differs, we need to add the ttm_tt pages to
 	 * the resulting st. Might make sense for GGTT.
@@ -616,7 +621,8 @@  i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
 			struct i915_refct_sgt *rsgt;
 
 			rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
-								 res);
+								 res,
+								 page_alignment);
 			if (IS_ERR(rsgt))
 				return rsgt;
 
@@ -625,7 +631,8 @@  i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
 		return i915_refct_sgt_get(obj->ttm.cached_io_rsgt);
 	}
 
-	return intel_region_ttm_resource_to_rsgt(obj->mm.region, res);
+	return intel_region_ttm_resource_to_rsgt(obj->mm.region, res,
+						 page_alignment);
 }
 
 static int i915_ttm_truncate(struct drm_i915_gem_object *obj)
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c
index 159571b9bd24..f63b50b71e10 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.c
+++ b/drivers/gpu/drm/i915/i915_scatterlist.c
@@ -68,6 +68,7 @@  void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
  * drm_mm_node
  * @node: The drm_mm_node.
  * @region_start: An offset to add to the dma addresses of the sg list.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * Create a struct sg_table, initializing it from a struct drm_mm_node,
  * taking a maximum segment length into account, splitting into segments
@@ -77,15 +78,18 @@  void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
  * error code cast to an error pointer on failure.
  */
 struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
-					      u64 region_start)
+					      u64 region_start,
+					      u64 page_alignment)
 {
-	const u64 max_segment = SZ_1G; /* Do we have a limit on this? */
+	const u64 max_segment = round_down(UINT_MAX, page_alignment);
 	u64 segment_pages = max_segment >> PAGE_SHIFT;
 	u64 block_size, offset, prev_end;
 	struct i915_refct_sgt *rsgt;
 	struct sg_table *st;
 	struct scatterlist *sg;
 
+	GEM_BUG_ON(!max_segment);
+
 	rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
 	if (!rsgt)
 		return ERR_PTR(-ENOMEM);
@@ -112,6 +116,8 @@  struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
 				sg = __sg_next(sg);
 
 			sg_dma_address(sg) = region_start + offset;
+			GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
+					       page_alignment));
 			sg_dma_len(sg) = 0;
 			sg->length = 0;
 			st->nents++;
@@ -138,6 +144,7 @@  struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
  * i915_buddy_block list
  * @res: The struct i915_ttm_buddy_resource.
  * @region_start: An offset to add to the dma addresses of the sg list.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * Create a struct sg_table, initializing it from struct i915_buddy_block list,
  * taking a maximum segment length into account, splitting into segments
@@ -147,11 +154,12 @@  struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
  * error code cast to an error pointer on failure.
  */
 struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
-						     u64 region_start)
+						     u64 region_start,
+						     u64 page_alignment)
 {
 	struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
 	const u64 size = res->num_pages << PAGE_SHIFT;
-	const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE);
+	const u64 max_segment = round_down(UINT_MAX, page_alignment);
 	struct drm_buddy *mm = bman_res->mm;
 	struct list_head *blocks = &bman_res->blocks;
 	struct drm_buddy_block *block;
@@ -161,6 +169,7 @@  struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
 	resource_size_t prev_end;
 
 	GEM_BUG_ON(list_empty(blocks));
+	GEM_BUG_ON(!max_segment);
 
 	rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
 	if (!rsgt)
@@ -191,6 +200,8 @@  struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
 					sg = __sg_next(sg);
 
 				sg_dma_address(sg) = region_start + offset;
+				GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
+						       page_alignment));
 				sg_dma_len(sg) = 0;
 				sg->length = 0;
 				st->nents++;
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h
index 12c6a1684081..b13e4cdea923 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.h
+++ b/drivers/gpu/drm/i915/i915_scatterlist.h
@@ -213,9 +213,11 @@  static inline void __i915_refct_sgt_init(struct i915_refct_sgt *rsgt,
 void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size);
 
 struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
-					      u64 region_start);
+					      u64 region_start,
+					      u64 page_alignment);
 
 struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
-						     u64 region_start);
+						     u64 region_start,
+						     u64 page_alignment);
 
 #endif
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
index 62ff77445b01..6873808a7015 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.c
+++ b/drivers/gpu/drm/i915/intel_region_ttm.c
@@ -152,6 +152,7 @@  int intel_region_ttm_fini(struct intel_memory_region *mem)
  * Convert an opaque TTM resource manager resource to a refcounted sg_table.
  * @mem: The memory region.
  * @res: The resource manager resource obtained from the TTM resource manager.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * The gem backends typically use sg-tables for operations on the underlying
  * io_memory. So provide a way for the backends to translate the
@@ -161,16 +162,19 @@  int intel_region_ttm_fini(struct intel_memory_region *mem)
  */
 struct i915_refct_sgt *
 intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
-				  struct ttm_resource *res)
+				  struct ttm_resource *res,
+				  u64 page_alignment)
 {
 	if (mem->is_range_manager) {
 		struct ttm_range_mgr_node *range_node =
 			to_ttm_range_mgr_node(res);
 
 		return i915_rsgt_from_mm_node(&range_node->mm_nodes[0],
-					      mem->region.start);
+					      mem->region.start,
+					      page_alignment);
 	} else {
-		return i915_rsgt_from_buddy_resource(res, mem->region.start);
+		return i915_rsgt_from_buddy_resource(res, mem->region.start,
+						     page_alignment);
 	}
 }
 
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h
index cf9d86dcf409..98fba5155619 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.h
+++ b/drivers/gpu/drm/i915/intel_region_ttm.h
@@ -24,7 +24,8 @@  int intel_region_ttm_fini(struct intel_memory_region *mem);
 
 struct i915_refct_sgt *
 intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
-				  struct ttm_resource *res);
+				  struct ttm_resource *res,
+				  u64 page_alignment);
 
 void intel_region_ttm_resource_free(struct intel_memory_region *mem,
 				    struct ttm_resource *res);
diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
index 73eb53edb8de..3b18e5905c86 100644
--- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
@@ -451,7 +451,6 @@  static int igt_mock_splintered_region(void *arg)
 
 static int igt_mock_max_segment(void *arg)
 {
-	const unsigned int max_segment = rounddown(UINT_MAX, PAGE_SIZE);
 	struct intel_memory_region *mem = arg;
 	struct drm_i915_private *i915 = mem->i915;
 	struct i915_ttm_buddy_resource *res;
@@ -460,7 +459,10 @@  static int igt_mock_max_segment(void *arg)
 	struct drm_buddy *mm;
 	struct list_head *blocks;
 	struct scatterlist *sg;
+	I915_RND_STATE(prng);
 	LIST_HEAD(objects);
+	unsigned int max_segment;
+	unsigned int ps;
 	u64 size;
 	int err = 0;
 
@@ -472,7 +474,13 @@  static int igt_mock_max_segment(void *arg)
 	 */
 
 	size = SZ_8G;
-	mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0, 0);
+	ps = PAGE_SIZE;
+	if (i915_prandom_u64_state(&prng) & 1)
+		ps = SZ_64K; /* For something like DG2 */
+
+	max_segment = round_down(UINT_MAX, ps);
+
+	mem = mock_region_create(i915, 0, size, ps, 0, 0);
 	if (IS_ERR(mem))
 		return PTR_ERR(mem);
 
@@ -498,12 +506,21 @@  static int igt_mock_max_segment(void *arg)
 	}
 
 	for (sg = obj->mm.pages->sgl; sg; sg = sg_next(sg)) {
+		dma_addr_t daddr = sg_dma_address(sg);
+
 		if (sg->length > max_segment) {
 			pr_err("%s: Created an oversized scatterlist entry, %u > %u\n",
 			       __func__, sg->length, max_segment);
 			err = -EINVAL;
 			goto out_close;
 		}
+
+		if (!IS_ALIGNED(daddr, ps)) {
+			pr_err("%s: Created an unaligned scatterlist entry, addr=%pa, ps=%u\n",
+			       __func__,  &daddr, ps);
+			err = -EINVAL;
+			goto out_close;
+		}
 	}
 
 out_close:
diff --git a/drivers/gpu/drm/i915/selftests/mock_region.c b/drivers/gpu/drm/i915/selftests/mock_region.c
index 670557ce1024..bac21fe84ca5 100644
--- a/drivers/gpu/drm/i915/selftests/mock_region.c
+++ b/drivers/gpu/drm/i915/selftests/mock_region.c
@@ -33,7 +33,8 @@  static int mock_region_get_pages(struct drm_i915_gem_object *obj)
 		return PTR_ERR(obj->mm.res);
 
 	obj->mm.rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
-							 obj->mm.res);
+							 obj->mm.res,
+							 obj->mm.region->min_page_size);
 	if (IS_ERR(obj->mm.rsgt)) {
 		err = PTR_ERR(obj->mm.rsgt);
 		goto err_free_resource;