diff mbox series

[v10,22/23] drm/i915/vm_bind: Properly build persistent map sg table

Message ID 20230118071609.17572-23-niranjana.vishwanathapura@intel.com (mailing list archive)
State New, archived
Headers show
Series drm/i915/vm_bind: Add VM_BIND functionality | expand

Commit Message

Niranjana Vishwanathapura Jan. 18, 2023, 7:16 a.m. UTC
Properly build the sg table for persistent mapping which can
be partial map of the underlying object. Ensure the sg pages
are properly set for page backed regions. The dump capture
support requires this for page backed regions.

v2: Remove redundant sg_mark_end() call

Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
---
 drivers/gpu/drm/i915/i915_vma.c | 113 +++++++++++++++++++++++++++++++-
 1 file changed, 112 insertions(+), 1 deletion(-)

Comments

Matthew Auld Jan. 18, 2023, 12:49 p.m. UTC | #1
On 18/01/2023 07:16, Niranjana Vishwanathapura wrote:
> Properly build the sg table for persistent mapping which can
> be partial map of the underlying object. Ensure the sg pages
> are properly set for page backed regions. The dump capture
> support requires this for page backed regions.
> 
> v2: Remove redundant sg_mark_end() call
> 
> Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_vma.c | 113 +++++++++++++++++++++++++++++++-
>   1 file changed, 112 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
> index 5b9ae5ebf55c..2f0994f0ed42 100644
> --- a/drivers/gpu/drm/i915/i915_vma.c
> +++ b/drivers/gpu/drm/i915/i915_vma.c
> @@ -1328,6 +1328,113 @@ intel_partial_pages(const struct i915_gtt_view *view,
>   	return ERR_PTR(ret);
>   }
>   
> +static unsigned int
> +intel_copy_dma_sg(struct sg_table *src_st, struct sg_table *dst_st,
> +		  u64 offset, u64 length, bool dry_run)
> +{
> +	struct scatterlist *dst_sg, *src_sg;
> +	unsigned int i, len, nents = 0;
> +
> +	dst_sg = dst_st->sgl;
> +	for_each_sgtable_dma_sg(src_st, src_sg, i) {
> +		if (sg_dma_len(src_sg) <= offset) {
> +			offset -= sg_dma_len(src_sg);
> +			continue;
> +		}
> +
> +		nents++;
> +		len = min(sg_dma_len(src_sg) - offset, length);
> +		if (!dry_run) {
> +			sg_dma_address(dst_sg) = sg_dma_address(src_sg) + offset;
> +			sg_dma_len(dst_sg) = len;
> +			dst_sg = sg_next(dst_sg);
> +		}
> +
> +		length -= len;
> +		offset = 0;
> +		if (!length)
> +			break;
> +	}
> +	WARN_ON_ONCE(length);
> +
> +	return nents;
> +}
> +
> +static unsigned int
> +intel_copy_sg(struct sg_table *src_st, struct sg_table *dst_st,
> +	      u64 offset, u64 length, bool dry_run)
> +{
> +	struct scatterlist *dst_sg, *src_sg;
> +	unsigned int i, len, nents = 0;
> +
> +	dst_sg = dst_st->sgl;
> +	for_each_sgtable_sg(src_st, src_sg, i) {
> +		if (src_sg->length <= offset) {
> +			offset -= src_sg->length;
> +			continue;
> +		}
> +
> +		nents++;
> +		len = min(src_sg->length - offset, length);
> +		if (!dry_run) {
> +			unsigned long pfn;
> +
> +			pfn = page_to_pfn(sg_page(src_sg)) + offset / PAGE_SIZE;
> +			sg_set_page(dst_sg, pfn_to_page(pfn), len, 0);
> +			dst_sg = sg_next(dst_sg);
> +		}
> +
> +		length -= len;
> +		offset = 0;
> +		if (!length)
> +			break;
> +	}
> +	WARN_ON_ONCE(length);
> +
> +	return nents;
> +}
> +
> +static noinline struct sg_table *

Not sure why this noinline is needed here?

Reviewed-by: Matthew Auld <matthew.auld@intel.com>

> +intel_persistent_partial_pages(const struct i915_gtt_view *view,
> +			       struct drm_i915_gem_object *obj)
> +{
> +	u64 offset = view->partial.offset << PAGE_SHIFT;
> +	struct sg_table *st, *obj_st = obj->mm.pages;
> +	u64 length = view->partial.size << PAGE_SHIFT;
> +	unsigned int nents;
> +	int ret = -ENOMEM;
> +
> +	st = kmalloc(sizeof(*st), GFP_KERNEL);
> +	if (!st)
> +		goto err_st_alloc;
> +
> +	/* Get required sg_table size */
> +	nents = intel_copy_dma_sg(obj_st, st, offset, length, true);
> +	if (i915_gem_object_has_struct_page(obj)) {
> +		unsigned int pg_nents;
> +
> +		pg_nents = intel_copy_sg(obj_st, st, offset, length, true);
> +		if (nents < pg_nents)
> +			nents = pg_nents;
> +	}
> +
> +	ret = sg_alloc_table(st, nents, GFP_KERNEL);
> +	if (ret)
> +		goto err_sg_alloc;
> +
> +	/* Build sg_table for specified <offset, length> section */
> +	intel_copy_dma_sg(obj_st, st, offset, length, false);
> +	if (i915_gem_object_has_struct_page(obj))
> +		intel_copy_sg(obj_st, st, offset, length, false);
> +
> +	return st;
> +
> +err_sg_alloc:
> +	kfree(st);
> +err_st_alloc:
> +	return ERR_PTR(ret);
> +}
> +
>   static int
>   __i915_vma_get_pages(struct i915_vma *vma)
>   {
> @@ -1360,7 +1467,11 @@ __i915_vma_get_pages(struct i915_vma *vma)
>   		break;
>   
>   	case I915_GTT_VIEW_PARTIAL:
> -		pages = intel_partial_pages(&vma->gtt_view, vma->obj);
> +		if (i915_vma_is_persistent(vma))
> +			pages = intel_persistent_partial_pages(&vma->gtt_view,
> +							       vma->obj);
> +		else
> +			pages = intel_partial_pages(&vma->gtt_view, vma->obj);
>   		break;
>   	}
>
Andi Shyti Feb. 2, 2023, 4:51 p.m. UTC | #2
Hi Niranjana,

On Tue, Jan 17, 2023 at 11:16:08PM -0800, Niranjana Vishwanathapura wrote:
> Properly build the sg table for persistent mapping which can
> be partial map of the underlying object. Ensure the sg pages
> are properly set for page backed regions. The dump capture
> support requires this for page backed regions.
> 
> v2: Remove redundant sg_mark_end() call
> 
> Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>

Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>

Andi
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 5b9ae5ebf55c..2f0994f0ed42 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -1328,6 +1328,113 @@  intel_partial_pages(const struct i915_gtt_view *view,
 	return ERR_PTR(ret);
 }
 
+static unsigned int
+intel_copy_dma_sg(struct sg_table *src_st, struct sg_table *dst_st,
+		  u64 offset, u64 length, bool dry_run)
+{
+	struct scatterlist *dst_sg, *src_sg;
+	unsigned int i, len, nents = 0;
+
+	dst_sg = dst_st->sgl;
+	for_each_sgtable_dma_sg(src_st, src_sg, i) {
+		if (sg_dma_len(src_sg) <= offset) {
+			offset -= sg_dma_len(src_sg);
+			continue;
+		}
+
+		nents++;
+		len = min(sg_dma_len(src_sg) - offset, length);
+		if (!dry_run) {
+			sg_dma_address(dst_sg) = sg_dma_address(src_sg) + offset;
+			sg_dma_len(dst_sg) = len;
+			dst_sg = sg_next(dst_sg);
+		}
+
+		length -= len;
+		offset = 0;
+		if (!length)
+			break;
+	}
+	WARN_ON_ONCE(length);
+
+	return nents;
+}
+
+static unsigned int
+intel_copy_sg(struct sg_table *src_st, struct sg_table *dst_st,
+	      u64 offset, u64 length, bool dry_run)
+{
+	struct scatterlist *dst_sg, *src_sg;
+	unsigned int i, len, nents = 0;
+
+	dst_sg = dst_st->sgl;
+	for_each_sgtable_sg(src_st, src_sg, i) {
+		if (src_sg->length <= offset) {
+			offset -= src_sg->length;
+			continue;
+		}
+
+		nents++;
+		len = min(src_sg->length - offset, length);
+		if (!dry_run) {
+			unsigned long pfn;
+
+			pfn = page_to_pfn(sg_page(src_sg)) + offset / PAGE_SIZE;
+			sg_set_page(dst_sg, pfn_to_page(pfn), len, 0);
+			dst_sg = sg_next(dst_sg);
+		}
+
+		length -= len;
+		offset = 0;
+		if (!length)
+			break;
+	}
+	WARN_ON_ONCE(length);
+
+	return nents;
+}
+
+static noinline struct sg_table *
+intel_persistent_partial_pages(const struct i915_gtt_view *view,
+			       struct drm_i915_gem_object *obj)
+{
+	u64 offset = view->partial.offset << PAGE_SHIFT;
+	struct sg_table *st, *obj_st = obj->mm.pages;
+	u64 length = view->partial.size << PAGE_SHIFT;
+	unsigned int nents;
+	int ret = -ENOMEM;
+
+	st = kmalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		goto err_st_alloc;
+
+	/* Get required sg_table size */
+	nents = intel_copy_dma_sg(obj_st, st, offset, length, true);
+	if (i915_gem_object_has_struct_page(obj)) {
+		unsigned int pg_nents;
+
+		pg_nents = intel_copy_sg(obj_st, st, offset, length, true);
+		if (nents < pg_nents)
+			nents = pg_nents;
+	}
+
+	ret = sg_alloc_table(st, nents, GFP_KERNEL);
+	if (ret)
+		goto err_sg_alloc;
+
+	/* Build sg_table for specified <offset, length> section */
+	intel_copy_dma_sg(obj_st, st, offset, length, false);
+	if (i915_gem_object_has_struct_page(obj))
+		intel_copy_sg(obj_st, st, offset, length, false);
+
+	return st;
+
+err_sg_alloc:
+	kfree(st);
+err_st_alloc:
+	return ERR_PTR(ret);
+}
+
 static int
 __i915_vma_get_pages(struct i915_vma *vma)
 {
@@ -1360,7 +1467,11 @@  __i915_vma_get_pages(struct i915_vma *vma)
 		break;
 
 	case I915_GTT_VIEW_PARTIAL:
-		pages = intel_partial_pages(&vma->gtt_view, vma->obj);
+		if (i915_vma_is_persistent(vma))
+			pages = intel_persistent_partial_pages(&vma->gtt_view,
+							       vma->obj);
+		else
+			pages = intel_partial_pages(&vma->gtt_view, vma->obj);
 		break;
 	}