diff mbox

[4/5] drm/i915: Add a partial GGTT view type

Message ID 1429877392.19506.9.camel@jlahtine-mobl1 (mailing list archive)
State New, archived
Headers show

Commit Message

Joonas Lahtinen April 24, 2015, 12:09 p.m. UTC
Partial view type allows manipulating parts of huge BOs through the GGTT,
which was not previously possible due to constraint that whole object had
to be mapped for any access to it through GGTT.

Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_gem_gtt.c |   46 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_gem_gtt.h |   15 ++++++++++--
 2 files changed, 59 insertions(+), 2 deletions(-)

Comments

Tvrtko Ursulin April 27, 2015, 2:50 p.m. UTC | #1
Hi,

On 04/24/2015 01:09 PM, Joonas Lahtinen wrote:
>
> Partial view type allows manipulating parts of huge BOs through the GGTT,
> which was not previously possible due to constraint that whole object had
> to be mapped for any access to it through GGTT.
>
> Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/i915_gem_gtt.c |   46 +++++++++++++++++++++++++++++++++++
>   drivers/gpu/drm/i915/i915_gem_gtt.h |   15 ++++++++++--
>   2 files changed, 59 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index 5babbd3..5937d3d 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -2764,6 +2764,47 @@ err_st_alloc:
>   	return ERR_PTR(ret);
>   }
>
> +static struct sg_table *
> +intel_partial_pages(const struct i915_ggtt_view *view,
> +		    struct drm_i915_gem_object *obj)
> +{
> +	struct sg_table *st;
> +	struct scatterlist *sg;
> +	struct sg_page_iter obj_sg_iter;
> +	int ret;
> +
> +	st = kmalloc(sizeof(*st), GFP_KERNEL);
> +	if (!st)
> +		goto err_st_alloc;
> +
> +	ret = sg_alloc_table(st, view->params.partial.size, GFP_KERNEL);
> +	if (ret)
> +		goto err_sg_alloc;
> +
> +	sg = st->sgl;
> +	st->nents = 0;

sg_alloc_table configures the sg_table so not needed I think. Although I 
do see I am also doing it. :)

> +	for_each_sg_page(obj->pages->sgl, &obj_sg_iter, obj->pages->nents,
> +		view->params.partial.offset)
> +	{
> +		if (st->nents >= view->params.partial.size)
> +			break;
> +
> +		sg_set_page(sg, NULL, PAGE_SIZE, 0);
> +		sg_dma_address(sg) = sg_page_iter_dma_address(&obj_sg_iter);
> +		sg_dma_len(sg) = PAGE_SIZE;
> +
> +		sg = sg_next(sg);
> +		st->nents++;
> +	}

I suppose in this case (as opposed to rotated view) using 
sg_alloc_table_from_pages() could produce a more compact table. With the 
caveat of that it doesn't always work (see i915_gem_userptr.c/st_set_pages).

So maybe promote to driver public st_set_pages and call in on an array 
of pages?

> +
> +	return st;
> +
> +err_sg_alloc:
> +	kfree(st);

Here you lose ret from sg_alloc_table.

> +err_st_alloc:
> +	return ERR_PTR(-ENOMEM);
> +}
> +
>   static int
>   i915_get_ggtt_vma_pages(struct i915_vma *vma)
>   {
> @@ -2777,6 +2818,9 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
>   	else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
>   		vma->ggtt_view.pages =
>   			intel_rotate_fb_obj_pages(&vma->ggtt_view, vma->obj);
> +	else if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL)
> +		vma->ggtt_view.pages =
> +			intel_partial_pages(&vma->ggtt_view, vma->obj);
>   	else
>   		WARN_ONCE(1, "GGTT view %u not implemented!\n",
>   			  vma->ggtt_view.type);
> @@ -2859,6 +2903,8 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj,
>   	if (view->type == I915_GGTT_VIEW_NORMAL ||
>   	    view->type == I915_GGTT_VIEW_ROTATED) {
>   		return obj->base.size;
> +	} else if (view->type == I915_GGTT_VIEW_PARTIAL) {
> +		return view->params.partial.size << PAGE_SHIFT;
>   	} else {
>   		WARN_ONCE(1, "GGTT view %u not implemented!\n", view->type);
>   		return obj->base.size;
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
> index 34b7cca..ab1ad8a 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.h
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
> @@ -117,7 +117,8 @@ typedef uint64_t gen8_pde_t;
>
>   enum i915_ggtt_view_type {
>   	I915_GGTT_VIEW_NORMAL = 0,
> -	I915_GGTT_VIEW_ROTATED
> +	I915_GGTT_VIEW_ROTATED,
> +	I915_GGTT_VIEW_PARTIAL,
>   };
>
>   struct intel_rotation_info {
> @@ -130,6 +131,13 @@ struct intel_rotation_info {
>   struct i915_ggtt_view {
>   	enum i915_ggtt_view_type type;
>
> +	union {
> +		struct {
> +			pgoff_t offset;
> +			size_t size;

Size is in pages right? Maybe it would be more self-documenting to use 
some basic type like unsigned int or long since size_t, to me at least, 
suggests bytes.

> +		} partial;
> +	} params;
> +
>   	struct sg_table *pages;
>
>   	union {
> @@ -495,7 +503,10 @@ i915_ggtt_view_equal(const struct i915_ggtt_view *a,
>   	if (WARN_ON(!a || !b))
>   		return false;
>
> -	return a->type == b->type;
> +	if (a->type != b->type)
> +		return false;
> +
> +	return !memcmp(&a->params, &b->params, sizeof(a->params));

So for rotated views it would still do memcmp. OK structure is zeroed on 
alloc, but it is pointless to do so.

Regards,

Tvrtko
Tvrtko Ursulin April 28, 2015, 8:38 a.m. UTC | #2
On 04/27/2015 03:50 PM, Tvrtko Ursulin wrote:
>> +    for_each_sg_page(obj->pages->sgl, &obj_sg_iter, obj->pages->nents,
>> +        view->params.partial.offset)
>> +    {
>> +        if (st->nents >= view->params.partial.size)
>> +            break;
>> +
>> +        sg_set_page(sg, NULL, PAGE_SIZE, 0);
>> +        sg_dma_address(sg) = sg_page_iter_dma_address(&obj_sg_iter);
>> +        sg_dma_len(sg) = PAGE_SIZE;
>> +
>> +        sg = sg_next(sg);
>> +        st->nents++;
>> +    }
>
> I suppose in this case (as opposed to rotated view) using
> sg_alloc_table_from_pages() could produce a more compact table. With the
> caveat of that it doesn't always work (see
> i915_gem_userptr.c/st_set_pages).
>
> So maybe promote to driver public st_set_pages and call in on an array
> of pages?

Scratch this, on second thought it makes no sense.

Only if we had a smarter helper like sg_alloc_table_from_table_range() 
but no one cared about coalescing in the past.

Regards,

Tvrtko
Joonas Lahtinen April 30, 2015, 11:02 a.m. UTC | #3
On ma, 2015-04-27 at 15:50 +0100, Tvrtko Ursulin wrote:
> Hi,
> 
> On 04/24/2015 01:09 PM, Joonas Lahtinen wrote:
> >
> > Partial view type allows manipulating parts of huge BOs through the GGTT,
> > which was not previously possible due to constraint that whole object had
> > to be mapped for any access to it through GGTT.
> >
> > Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> > ---
> >   drivers/gpu/drm/i915/i915_gem_gtt.c |   46 +++++++++++++++++++++++++++++++++++
> >   drivers/gpu/drm/i915/i915_gem_gtt.h |   15 ++++++++++--
> >   2 files changed, 59 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > index 5babbd3..5937d3d 100644
> > --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > @@ -2764,6 +2764,47 @@ err_st_alloc:
> >   	return ERR_PTR(ret);
> >   }
> >
> > +static struct sg_table *
> > +intel_partial_pages(const struct i915_ggtt_view *view,
> > +		    struct drm_i915_gem_object *obj)
> > +{
> > +	struct sg_table *st;
> > +	struct scatterlist *sg;
> > +	struct sg_page_iter obj_sg_iter;
> > +	int ret;
> > +
> > +	st = kmalloc(sizeof(*st), GFP_KERNEL);
> > +	if (!st)
> > +		goto err_st_alloc;
> > +
> > +	ret = sg_alloc_table(st, view->params.partial.size, GFP_KERNEL);
> > +	if (ret)
> > +		goto err_sg_alloc;
> > +
> > +	sg = st->sgl;
> > +	st->nents = 0;
> 
> sg_alloc_table configures the sg_table so not needed I think. Although I 
> do see I am also doing it. :)
> 

I initially stripped it w/r your code, but I was so desperate debugging
the for_each_sg_page interface I tried everything ;)

Removed it.

> > +	for_each_sg_page(obj->pages->sgl, &obj_sg_iter, obj->pages->nents,
> > +		view->params.partial.offset)
> > +	{
> > +		if (st->nents >= view->params.partial.size)
> > +			break;
> > +
> > +		sg_set_page(sg, NULL, PAGE_SIZE, 0);
> > +		sg_dma_address(sg) = sg_page_iter_dma_address(&obj_sg_iter);
> > +		sg_dma_len(sg) = PAGE_SIZE;
> > +
> > +		sg = sg_next(sg);
> > +		st->nents++;
> > +	}
> 
> I suppose in this case (as opposed to rotated view) using 
> sg_alloc_table_from_pages() could produce a more compact table. With the 
> caveat of that it doesn't always work (see i915_gem_userptr.c/st_set_pages).
> 
> So maybe promote to driver public st_set_pages and call in on an array 
> of pages?
> 

Disregarded regards to your later mail.

> > +
> > +	return st;
> > +
> > +err_sg_alloc:
> > +	kfree(st);
> 
> Here you lose ret from sg_alloc_table.
> 

Good catch.

> > +err_st_alloc:
> > +	return ERR_PTR(-ENOMEM);
> > +}
> > +
> >   static int
> >   i915_get_ggtt_vma_pages(struct i915_vma *vma)
> >   {
> > @@ -2777,6 +2818,9 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
> >   	else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
> >   		vma->ggtt_view.pages =
> >   			intel_rotate_fb_obj_pages(&vma->ggtt_view, vma->obj);
> > +	else if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL)
> > +		vma->ggtt_view.pages =
> > +			intel_partial_pages(&vma->ggtt_view, vma->obj);
> >   	else
> >   		WARN_ONCE(1, "GGTT view %u not implemented!\n",
> >   			  vma->ggtt_view.type);
> > @@ -2859,6 +2903,8 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj,
> >   	if (view->type == I915_GGTT_VIEW_NORMAL ||
> >   	    view->type == I915_GGTT_VIEW_ROTATED) {
> >   		return obj->base.size;
> > +	} else if (view->type == I915_GGTT_VIEW_PARTIAL) {
> > +		return view->params.partial.size << PAGE_SHIFT;
> >   	} else {
> >   		WARN_ONCE(1, "GGTT view %u not implemented!\n", view->type);
> >   		return obj->base.size;
> > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
> > index 34b7cca..ab1ad8a 100644
> > --- a/drivers/gpu/drm/i915/i915_gem_gtt.h
> > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
> > @@ -117,7 +117,8 @@ typedef uint64_t gen8_pde_t;
> >
> >   enum i915_ggtt_view_type {
> >   	I915_GGTT_VIEW_NORMAL = 0,
> > -	I915_GGTT_VIEW_ROTATED
> > +	I915_GGTT_VIEW_ROTATED,
> > +	I915_GGTT_VIEW_PARTIAL,
> >   };
> >
> >   struct intel_rotation_info {
> > @@ -130,6 +131,13 @@ struct intel_rotation_info {
> >   struct i915_ggtt_view {
> >   	enum i915_ggtt_view_type type;
> >
> > +	union {
> > +		struct {
> > +			pgoff_t offset;
> > +			size_t size;
> 
> Size is in pages right? Maybe it would be more self-documenting to use 
> some basic type like unsigned int or long since size_t, to me at least, 
> suggests bytes.
> 

Yeah, using unsigned long for offset and unsigned int for size, maps
more directly to the functions they're used with.

> > +		} partial;
> > +	} params;
> > +
> >   	struct sg_table *pages;
> >
> >   	union {
> > @@ -495,7 +503,10 @@ i915_ggtt_view_equal(const struct i915_ggtt_view *a,
> >   	if (WARN_ON(!a || !b))
> >   		return false;
> >
> > -	return a->type == b->type;
> > +	if (a->type != b->type)
> > +		return false;
> > +
> > +	return !memcmp(&a->params, &b->params, sizeof(a->params));
> 
> So for rotated views it would still do memcmp. OK structure is zeroed on 
> alloc, but it is pointless to do so.
> 

I'd rather not have special cases for each view type all around the
code, as I think even the current ones that there are should be reduced.

Regards, Joonas

> Regards,
> 
> Tvrtko
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 5babbd3..5937d3d 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -2764,6 +2764,47 @@  err_st_alloc:
 	return ERR_PTR(ret);
 }
 
+static struct sg_table *
+intel_partial_pages(const struct i915_ggtt_view *view,
+		    struct drm_i915_gem_object *obj)
+{
+	struct sg_table *st;
+	struct scatterlist *sg;
+	struct sg_page_iter obj_sg_iter;
+	int ret;
+
+	st = kmalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		goto err_st_alloc;
+
+	ret = sg_alloc_table(st, view->params.partial.size, GFP_KERNEL);
+	if (ret)
+		goto err_sg_alloc;
+
+	sg = st->sgl;
+	st->nents = 0;
+	for_each_sg_page(obj->pages->sgl, &obj_sg_iter, obj->pages->nents,
+		view->params.partial.offset)
+	{
+		if (st->nents >= view->params.partial.size)
+			break;
+
+		sg_set_page(sg, NULL, PAGE_SIZE, 0);
+		sg_dma_address(sg) = sg_page_iter_dma_address(&obj_sg_iter);
+		sg_dma_len(sg) = PAGE_SIZE;
+
+		sg = sg_next(sg);
+		st->nents++;
+	}
+
+	return st;
+
+err_sg_alloc:
+	kfree(st);
+err_st_alloc:
+	return ERR_PTR(-ENOMEM);
+}
+
 static int
 i915_get_ggtt_vma_pages(struct i915_vma *vma)
 {
@@ -2777,6 +2818,9 @@  i915_get_ggtt_vma_pages(struct i915_vma *vma)
 	else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
 		vma->ggtt_view.pages =
 			intel_rotate_fb_obj_pages(&vma->ggtt_view, vma->obj);
+	else if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL)
+		vma->ggtt_view.pages =
+			intel_partial_pages(&vma->ggtt_view, vma->obj);
 	else
 		WARN_ONCE(1, "GGTT view %u not implemented!\n",
 			  vma->ggtt_view.type);
@@ -2859,6 +2903,8 @@  i915_ggtt_view_size(struct drm_i915_gem_object *obj,
 	if (view->type == I915_GGTT_VIEW_NORMAL ||
 	    view->type == I915_GGTT_VIEW_ROTATED) {
 		return obj->base.size;
+	} else if (view->type == I915_GGTT_VIEW_PARTIAL) {
+		return view->params.partial.size << PAGE_SHIFT;
 	} else {
 		WARN_ONCE(1, "GGTT view %u not implemented!\n", view->type);
 		return obj->base.size;
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 34b7cca..ab1ad8a 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -117,7 +117,8 @@  typedef uint64_t gen8_pde_t;
 
 enum i915_ggtt_view_type {
 	I915_GGTT_VIEW_NORMAL = 0,
-	I915_GGTT_VIEW_ROTATED
+	I915_GGTT_VIEW_ROTATED,
+	I915_GGTT_VIEW_PARTIAL,
 };
 
 struct intel_rotation_info {
@@ -130,6 +131,13 @@  struct intel_rotation_info {
 struct i915_ggtt_view {
 	enum i915_ggtt_view_type type;
 
+	union {
+		struct {
+			pgoff_t offset;
+			size_t size;
+		} partial;
+	} params;
+
 	struct sg_table *pages;
 
 	union {
@@ -495,7 +503,10 @@  i915_ggtt_view_equal(const struct i915_ggtt_view *a,
 	if (WARN_ON(!a || !b))
 		return false;
 
-	return a->type == b->type;
+	if (a->type != b->type)
+		return false;
+
+	return !memcmp(&a->params, &b->params, sizeof(a->params));
 }
 
 size_t