diff mbox series

[1/2] drm/i915/gem: Limit lmem scatterlist elements to UINT_MAX

Message ID 20201201235847.1860-1-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show
Series [1/2] drm/i915/gem: Limit lmem scatterlist elements to UINT_MAX | expand

Commit Message

Chris Wilson Dec. 1, 2020, 11:58 p.m. UTC
Adhere to the i915_sg_max_segment() limit on the lengths of individual
scatterlist elements, and in doing so split up very large chunks of lmem
into managable pieces for the dma-mapping backend.

Reported-by: Venkata Sandeep Dhanalakota <venkata.s.dhanalakota@intel.com>
Suggested-by: Matthew Auld <matthew.auld@intel.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Venkata Sandeep Dhanalakota <venkata.s.dhanalakota@intel.com>
Cc: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_region.c | 42 ++++++++++++----------
 1 file changed, 24 insertions(+), 18 deletions(-)

Comments

Matthew Auld Dec. 2, 2020, 10:37 a.m. UTC | #1
On 01/12/2020 23:58, Chris Wilson wrote:
> Adhere to the i915_sg_max_segment() limit on the lengths of individual
> scatterlist elements, and in doing so split up very large chunks of lmem
> into managable pieces for the dma-mapping backend.
> 
> Reported-by: Venkata Sandeep Dhanalakota <venkata.s.dhanalakota@intel.com>
> Suggested-by: Matthew Auld <matthew.auld@intel.com>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Venkata Sandeep Dhanalakota <venkata.s.dhanalakota@intel.com>
> Cc: Matthew Auld <matthew.auld@intel.com>
> ---
>   drivers/gpu/drm/i915/gem/i915_gem_region.c | 42 ++++++++++++----------
>   1 file changed, 24 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c
> index e72d78074c9e..edb84072f979 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_region.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c
> @@ -22,6 +22,7 @@ i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj,
>   int
>   i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
>   {
> +	const u64 max_segment = i915_sg_segment_size();

I think we just need to add:

@@ -150,8 +150,8 @@ static int igt_mock_contiguous(void *arg)
         if (IS_ERR(obj))
                 return PTR_ERR(obj);

-       if (obj->mm.pages->nents != 1) {
-               pr_err("%s min object spans multiple sg entries\n", 
__func__);
+       if (!list_is_singular(&obj->mm.blocks)) {
+               pr_err("%s min object spans multiple blocks\n", __func__);
                 err = -EINVAL;
                 goto err_close_objects;
         }
@@ -163,8 +163,8 @@ static int igt_mock_contiguous(void *arg)
         if (IS_ERR(obj))
                 return PTR_ERR(obj);

-       if (obj->mm.pages->nents != 1) {
-               pr_err("%s max object spans multiple sg entries\n", 
__func__);
+       if (!list_is_singular(&obj->mm.blocks)) {
+               pr_err("%s max object spans multiple blocks\n", __func__);
                 err = -EINVAL;
                 goto err_close_objects;
         }
@@ -189,8 +189,8 @@ static int igt_mock_contiguous(void *arg)
                 goto err_close_objects;
         }

-       if (obj->mm.pages->nents != 1) {
-               pr_err("%s object spans multiple sg entries\n", __func__);
+       if (!list_is_singular(&obj->mm.blocks)) {
+               pr_err("%s object spans multiple blocks\n", __func__);
                 err = -EINVAL;
                 goto err_close_objects;
         }


Thanks for fixing this,
Reviewed-by: Matthew Auld <matthew.auld@intel.com>


>   	struct intel_memory_region *mem = obj->mm.region;
>   	struct list_head *blocks = &obj->mm.blocks;
>   	resource_size_t size = obj->base.size;
> @@ -37,7 +38,7 @@ i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
>   	if (!st)
>   		return -ENOMEM;
>   
> -	if (sg_alloc_table(st, size >> ilog2(mem->mm.chunk_size), GFP_KERNEL)) {
> +	if (sg_alloc_table(st, size >> PAGE_SHIFT, GFP_KERNEL)) {
>   		kfree(st);
>   		return -ENOMEM;
>   	}
> @@ -58,33 +59,38 @@ i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
>   	prev_end = (resource_size_t)-1;
>   
>   	list_for_each_entry(block, blocks, link) {
> -		u64 block_size, offset;
> +		u64 block_size, offset, len;
>   
>   		block_size = min_t(u64, size,
>   				   i915_buddy_block_size(&mem->mm, block));
>   		offset = i915_buddy_block_offset(block);
>   
> -		GEM_BUG_ON(overflows_type(block_size, sg->length));
> +		while (block_size) {
> +			if (offset != prev_end || sg->length >= max_segment) {
> +				if (st->nents) {
> +					sg_page_sizes |= sg->length;
> +					sg = __sg_next(sg);
> +				}
>   
> -		if (offset != prev_end ||
> -		    add_overflows_t(typeof(sg->length), sg->length, block_size)) {
> -			if (st->nents) {
> -				sg_page_sizes |= sg->length;
> -				sg = __sg_next(sg);
> -			}
> +				len = min(block_size, max_segment);
>   
> -			sg_dma_address(sg) = mem->region.start + offset;
> -			sg_dma_len(sg) = block_size;
> +				sg_dma_address(sg) = mem->region.start + offset;
> +				sg_dma_len(sg) = len;
>   
> -			sg->length = block_size;
> +				sg->length = len;
>   
> -			st->nents++;
> -		} else {
> -			sg->length += block_size;
> -			sg_dma_len(sg) += block_size;
> -		}
> +				st->nents++;
> +			} else {
> +				len = min(block_size, max_segment - sg->length);
> +				sg->length += len;
> +				sg_dma_len(sg) += len;
> +			}
>   
> -		prev_end = offset + block_size;
> +			offset += len;
> +			block_size -= len;
> +
> +			prev_end = offset;
> +		}
>   	}
>   
>   	sg_page_sizes |= sg->length;
>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c
index e72d78074c9e..edb84072f979 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_region.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c
@@ -22,6 +22,7 @@  i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj,
 int
 i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
 {
+	const u64 max_segment = i915_sg_segment_size();
 	struct intel_memory_region *mem = obj->mm.region;
 	struct list_head *blocks = &obj->mm.blocks;
 	resource_size_t size = obj->base.size;
@@ -37,7 +38,7 @@  i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
 	if (!st)
 		return -ENOMEM;
 
-	if (sg_alloc_table(st, size >> ilog2(mem->mm.chunk_size), GFP_KERNEL)) {
+	if (sg_alloc_table(st, size >> PAGE_SHIFT, GFP_KERNEL)) {
 		kfree(st);
 		return -ENOMEM;
 	}
@@ -58,33 +59,38 @@  i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
 	prev_end = (resource_size_t)-1;
 
 	list_for_each_entry(block, blocks, link) {
-		u64 block_size, offset;
+		u64 block_size, offset, len;
 
 		block_size = min_t(u64, size,
 				   i915_buddy_block_size(&mem->mm, block));
 		offset = i915_buddy_block_offset(block);
 
-		GEM_BUG_ON(overflows_type(block_size, sg->length));
+		while (block_size) {
+			if (offset != prev_end || sg->length >= max_segment) {
+				if (st->nents) {
+					sg_page_sizes |= sg->length;
+					sg = __sg_next(sg);
+				}
 
-		if (offset != prev_end ||
-		    add_overflows_t(typeof(sg->length), sg->length, block_size)) {
-			if (st->nents) {
-				sg_page_sizes |= sg->length;
-				sg = __sg_next(sg);
-			}
+				len = min(block_size, max_segment);
 
-			sg_dma_address(sg) = mem->region.start + offset;
-			sg_dma_len(sg) = block_size;
+				sg_dma_address(sg) = mem->region.start + offset;
+				sg_dma_len(sg) = len;
 
-			sg->length = block_size;
+				sg->length = len;
 
-			st->nents++;
-		} else {
-			sg->length += block_size;
-			sg_dma_len(sg) += block_size;
-		}
+				st->nents++;
+			} else {
+				len = min(block_size, max_segment - sg->length);
+				sg->length += len;
+				sg_dma_len(sg) += len;
+			}
 
-		prev_end = offset + block_size;
+			offset += len;
+			block_size -= len;
+
+			prev_end = offset;
+		}
 	}
 
 	sg_page_sizes |= sg->length;