diff mbox series

[3/7] drm/i915/gem: Unify user object creation

Message ID 20210715223900.1840576-4-jason@jlekstrand.net (mailing list archive)
State New, archived
Headers show
Series drm/i915: Migrate memory to SMEM when imported cross-device | expand

Commit Message

Jason Ekstrand July 15, 2021, 10:38 p.m. UTC
Instead of hand-rolling the same three calls in each function, pull them
into an i915_gem_object_create_user helper.  Apart from re-ordering of
the placements array ENOMEM check, the only functional change here
should be that i915_gem_dumb_create now calls i915_gem_flush_free_objects
which it probably should have been calling all along.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_create.c | 106 +++++++++------------
 1 file changed, 43 insertions(+), 63 deletions(-)

Comments

Matthew Auld July 16, 2021, 11:20 a.m. UTC | #1
On Thu, 15 Jul 2021 at 23:39, Jason Ekstrand <jason@jlekstrand.net> wrote:
>
> Instead of hand-rolling the same three calls in each function, pull them
> into an i915_gem_object_create_user helper.  Apart from re-ordering of
> the placements array ENOMEM check, the only functional change here
> should be that i915_gem_dumb_create now calls i915_gem_flush_free_objects
> which it probably should have been calling all along.
>
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_create.c | 106 +++++++++------------
>  1 file changed, 43 insertions(+), 63 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> index 391c8c4a12172..69bf9ec777642 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_create.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> @@ -11,13 +11,14 @@
>  #include "i915_trace.h"
>  #include "i915_user_extensions.h"
>
> -static u32 object_max_page_size(struct drm_i915_gem_object *obj)
> +static u32 object_max_page_size(struct intel_memory_region **placements,
> +                               unsigned int n_placements)
>  {
>         u32 max_page_size = 0;
>         int i;
>
> -       for (i = 0; i < obj->mm.n_placements; i++) {
> -               struct intel_memory_region *mr = obj->mm.placements[i];
> +       for (i = 0; i < n_placements; i++) {
> +               struct intel_memory_region *mr = placements[i];
>
>                 GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
>                 max_page_size = max_t(u32, max_page_size, mr->min_page_size);
> @@ -81,22 +82,35 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj,
>         return 0;
>  }
>
> -static int
> -i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
> +static struct drm_i915_gem_object *
> +i915_gem_object_create_user(struct drm_i915_private *i915, u64 size,

create_user sounds nice.

> +                           struct intel_memory_region **placements,
> +                           unsigned int n_placements)
>  {
> -       struct intel_memory_region *mr = obj->mm.placements[0];
> +       struct intel_memory_region *mr = placements[0];
> +       struct drm_i915_gem_object *obj;
>         unsigned int flags;
>         int ret;
>
> -       size = round_up(size, object_max_page_size(obj));
> +       i915_gem_flush_free_objects(i915);

Needs to be a separate patch.

> +
> +       obj = i915_gem_object_alloc();
> +       if (!obj)
> +               return ERR_PTR(-ENOMEM);

Should move this way down, so we don't accidently leak it.
Jason Ekstrand July 16, 2021, 2:02 p.m. UTC | #2
On Fri, Jul 16, 2021 at 6:21 AM Matthew Auld
<matthew.william.auld@gmail.com> wrote:
>
> On Thu, 15 Jul 2021 at 23:39, Jason Ekstrand <jason@jlekstrand.net> wrote:
> >
> > Instead of hand-rolling the same three calls in each function, pull them
> > into an i915_gem_object_create_user helper.  Apart from re-ordering of
> > the placements array ENOMEM check, the only functional change here
> > should be that i915_gem_dumb_create now calls i915_gem_flush_free_objects
> > which it probably should have been calling all along.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_create.c | 106 +++++++++------------
> >  1 file changed, 43 insertions(+), 63 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > index 391c8c4a12172..69bf9ec777642 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > @@ -11,13 +11,14 @@
> >  #include "i915_trace.h"
> >  #include "i915_user_extensions.h"
> >
> > -static u32 object_max_page_size(struct drm_i915_gem_object *obj)
> > +static u32 object_max_page_size(struct intel_memory_region **placements,
> > +                               unsigned int n_placements)
> >  {
> >         u32 max_page_size = 0;
> >         int i;
> >
> > -       for (i = 0; i < obj->mm.n_placements; i++) {
> > -               struct intel_memory_region *mr = obj->mm.placements[i];
> > +       for (i = 0; i < n_placements; i++) {
> > +               struct intel_memory_region *mr = placements[i];
> >
> >                 GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
> >                 max_page_size = max_t(u32, max_page_size, mr->min_page_size);
> > @@ -81,22 +82,35 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj,
> >         return 0;
> >  }
> >
> > -static int
> > -i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
> > +static struct drm_i915_gem_object *
> > +i915_gem_object_create_user(struct drm_i915_private *i915, u64 size,
>
> create_user sounds nice.
>
> > +                           struct intel_memory_region **placements,
> > +                           unsigned int n_placements)
> >  {
> > -       struct intel_memory_region *mr = obj->mm.placements[0];
> > +       struct intel_memory_region *mr = placements[0];
> > +       struct drm_i915_gem_object *obj;
> >         unsigned int flags;
> >         int ret;
> >
> > -       size = round_up(size, object_max_page_size(obj));
> > +       i915_gem_flush_free_objects(i915);
>
> Needs to be a separate patch.

Done.

> > +
> > +       obj = i915_gem_object_alloc();
> > +       if (!obj)
> > +               return ERR_PTR(-ENOMEM);
>
> Should move this way down, so we don't accidently leak it.

Done.

--Jason
Matthew Auld July 20, 2021, 9:34 a.m. UTC | #3
On Thu, 15 Jul 2021 at 23:39, Jason Ekstrand <jason@jlekstrand.net> wrote:
>
> Instead of hand-rolling the same three calls in each function, pull them
> into an i915_gem_object_create_user helper.  Apart from re-ordering of
> the placements array ENOMEM check, the only functional change here
> should be that i915_gem_dumb_create now calls i915_gem_flush_free_objects
> which it probably should have been calling all along.
>
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_create.c | 106 +++++++++------------
>  1 file changed, 43 insertions(+), 63 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> index 391c8c4a12172..69bf9ec777642 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_create.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> @@ -11,13 +11,14 @@
>  #include "i915_trace.h"
>  #include "i915_user_extensions.h"
>
> -static u32 object_max_page_size(struct drm_i915_gem_object *obj)
> +static u32 object_max_page_size(struct intel_memory_region **placements,
> +                               unsigned int n_placements)
>  {
>         u32 max_page_size = 0;
>         int i;
>
> -       for (i = 0; i < obj->mm.n_placements; i++) {
> -               struct intel_memory_region *mr = obj->mm.placements[i];
> +       for (i = 0; i < n_placements; i++) {
> +               struct intel_memory_region *mr = placements[i];
>
>                 GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
>                 max_page_size = max_t(u32, max_page_size, mr->min_page_size);
> @@ -81,22 +82,35 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj,
>         return 0;
>  }
>
> -static int
> -i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
> +static struct drm_i915_gem_object *
> +i915_gem_object_create_user(struct drm_i915_private *i915, u64 size,
> +                           struct intel_memory_region **placements,
> +                           unsigned int n_placements)
>  {
> -       struct intel_memory_region *mr = obj->mm.placements[0];
> +       struct intel_memory_region *mr = placements[0];
> +       struct drm_i915_gem_object *obj;
>         unsigned int flags;
>         int ret;
>
> -       size = round_up(size, object_max_page_size(obj));
> +       i915_gem_flush_free_objects(i915);
> +
> +       obj = i915_gem_object_alloc();
> +       if (!obj)
> +               return ERR_PTR(-ENOMEM);
> +
> +       size = round_up(size, object_max_page_size(placements, n_placements));
>         if (size == 0)
> -               return -EINVAL;
> +               return ERR_PTR(-EINVAL);
>
>         /* For most of the ABI (e.g. mmap) we think in system pages */
>         GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
>
>         if (i915_gem_object_size_2big(size))
> -               return -E2BIG;
> +               return ERR_PTR(-E2BIG);
> +
> +       ret = object_set_placements(obj, placements, n_placements);
> +       if (ret)
> +               goto object_free;

Thinking on this again, it might be way too thorny to expose
create_user as-is to other parts of i915, like we do in the last
patch. Since the caller will be expected to manually validate the
placements, otherwise we might crash and burn in weird ways as new
users pop up. i.e it needs the same validation that happens as part of
the extension. Also as new extensions arrive, like with PXP, that also
has to get bolted onto create_user, which might have its own hidden
constraints.
Jason Ekstrand July 20, 2021, 10:04 p.m. UTC | #4
On Tue, Jul 20, 2021 at 4:35 AM Matthew Auld
<matthew.william.auld@gmail.com> wrote:
>
> On Thu, 15 Jul 2021 at 23:39, Jason Ekstrand <jason@jlekstrand.net> wrote:
> >
> > Instead of hand-rolling the same three calls in each function, pull them
> > into an i915_gem_object_create_user helper.  Apart from re-ordering of
> > the placements array ENOMEM check, the only functional change here
> > should be that i915_gem_dumb_create now calls i915_gem_flush_free_objects
> > which it probably should have been calling all along.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_create.c | 106 +++++++++------------
> >  1 file changed, 43 insertions(+), 63 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > index 391c8c4a12172..69bf9ec777642 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > @@ -11,13 +11,14 @@
> >  #include "i915_trace.h"
> >  #include "i915_user_extensions.h"
> >
> > -static u32 object_max_page_size(struct drm_i915_gem_object *obj)
> > +static u32 object_max_page_size(struct intel_memory_region **placements,
> > +                               unsigned int n_placements)
> >  {
> >         u32 max_page_size = 0;
> >         int i;
> >
> > -       for (i = 0; i < obj->mm.n_placements; i++) {
> > -               struct intel_memory_region *mr = obj->mm.placements[i];
> > +       for (i = 0; i < n_placements; i++) {
> > +               struct intel_memory_region *mr = placements[i];
> >
> >                 GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
> >                 max_page_size = max_t(u32, max_page_size, mr->min_page_size);
> > @@ -81,22 +82,35 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj,
> >         return 0;
> >  }
> >
> > -static int
> > -i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
> > +static struct drm_i915_gem_object *
> > +i915_gem_object_create_user(struct drm_i915_private *i915, u64 size,
> > +                           struct intel_memory_region **placements,
> > +                           unsigned int n_placements)
> >  {
> > -       struct intel_memory_region *mr = obj->mm.placements[0];
> > +       struct intel_memory_region *mr = placements[0];
> > +       struct drm_i915_gem_object *obj;
> >         unsigned int flags;
> >         int ret;
> >
> > -       size = round_up(size, object_max_page_size(obj));
> > +       i915_gem_flush_free_objects(i915);
> > +
> > +       obj = i915_gem_object_alloc();
> > +       if (!obj)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       size = round_up(size, object_max_page_size(placements, n_placements));
> >         if (size == 0)
> > -               return -EINVAL;
> > +               return ERR_PTR(-EINVAL);
> >
> >         /* For most of the ABI (e.g. mmap) we think in system pages */
> >         GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
> >
> >         if (i915_gem_object_size_2big(size))
> > -               return -E2BIG;
> > +               return ERR_PTR(-E2BIG);
> > +
> > +       ret = object_set_placements(obj, placements, n_placements);
> > +       if (ret)
> > +               goto object_free;
>
> Thinking on this again, it might be way too thorny to expose
> create_user as-is to other parts of i915, like we do in the last
> patch. Since the caller will be expected to manually validate the
> placements, otherwise we might crash and burn in weird ways as new
> users pop up. i.e it needs the same validation that happens as part of
> the extension. Also as new extensions arrive, like with PXP, that also
> has to get bolted onto create_user, which might have its own hidden
> constraints.

Perhaps.  Do you have a suggestion for how to make it available to
selftests without exposing it to "the rest of i915"?  If you want, I
can make create_user duplicate the placements uniqueness check.
That's really the only validation currently in the ioctl besides all
the stuff for making sure that the class/instance provided by the user
isn't bogus.  But if we've got real i915_memory_region pointers, we
don't need that.

--Jason
Matthew Auld July 21, 2021, 8:24 a.m. UTC | #5
On Tue, 20 Jul 2021 at 23:04, Jason Ekstrand <jason@jlekstrand.net> wrote:
>
> On Tue, Jul 20, 2021 at 4:35 AM Matthew Auld
> <matthew.william.auld@gmail.com> wrote:
> >
> > On Thu, 15 Jul 2021 at 23:39, Jason Ekstrand <jason@jlekstrand.net> wrote:
> > >
> > > Instead of hand-rolling the same three calls in each function, pull them
> > > into an i915_gem_object_create_user helper.  Apart from re-ordering of
> > > the placements array ENOMEM check, the only functional change here
> > > should be that i915_gem_dumb_create now calls i915_gem_flush_free_objects
> > > which it probably should have been calling all along.
> > >
> > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > > ---
> > >  drivers/gpu/drm/i915/gem/i915_gem_create.c | 106 +++++++++------------
> > >  1 file changed, 43 insertions(+), 63 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > > index 391c8c4a12172..69bf9ec777642 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > > @@ -11,13 +11,14 @@
> > >  #include "i915_trace.h"
> > >  #include "i915_user_extensions.h"
> > >
> > > -static u32 object_max_page_size(struct drm_i915_gem_object *obj)
> > > +static u32 object_max_page_size(struct intel_memory_region **placements,
> > > +                               unsigned int n_placements)
> > >  {
> > >         u32 max_page_size = 0;
> > >         int i;
> > >
> > > -       for (i = 0; i < obj->mm.n_placements; i++) {
> > > -               struct intel_memory_region *mr = obj->mm.placements[i];
> > > +       for (i = 0; i < n_placements; i++) {
> > > +               struct intel_memory_region *mr = placements[i];
> > >
> > >                 GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
> > >                 max_page_size = max_t(u32, max_page_size, mr->min_page_size);
> > > @@ -81,22 +82,35 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj,
> > >         return 0;
> > >  }
> > >
> > > -static int
> > > -i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
> > > +static struct drm_i915_gem_object *
> > > +i915_gem_object_create_user(struct drm_i915_private *i915, u64 size,
> > > +                           struct intel_memory_region **placements,
> > > +                           unsigned int n_placements)
> > >  {
> > > -       struct intel_memory_region *mr = obj->mm.placements[0];
> > > +       struct intel_memory_region *mr = placements[0];
> > > +       struct drm_i915_gem_object *obj;
> > >         unsigned int flags;
> > >         int ret;
> > >
> > > -       size = round_up(size, object_max_page_size(obj));
> > > +       i915_gem_flush_free_objects(i915);
> > > +
> > > +       obj = i915_gem_object_alloc();
> > > +       if (!obj)
> > > +               return ERR_PTR(-ENOMEM);
> > > +
> > > +       size = round_up(size, object_max_page_size(placements, n_placements));
> > >         if (size == 0)
> > > -               return -EINVAL;
> > > +               return ERR_PTR(-EINVAL);
> > >
> > >         /* For most of the ABI (e.g. mmap) we think in system pages */
> > >         GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
> > >
> > >         if (i915_gem_object_size_2big(size))
> > > -               return -E2BIG;
> > > +               return ERR_PTR(-E2BIG);
> > > +
> > > +       ret = object_set_placements(obj, placements, n_placements);
> > > +       if (ret)
> > > +               goto object_free;
> >
> > Thinking on this again, it might be way too thorny to expose
> > create_user as-is to other parts of i915, like we do in the last
> > patch. Since the caller will be expected to manually validate the
> > placements, otherwise we might crash and burn in weird ways as new
> > users pop up. i.e it needs the same validation that happens as part of
> > the extension. Also as new extensions arrive, like with PXP, that also
> > has to get bolted onto create_user, which might have its own hidden
> > constraints.
>
> Perhaps.  Do you have a suggestion for how to make it available to
> selftests without exposing it to "the rest of i915"?  If you want, I
> can make create_user duplicate the placements uniqueness check.
> That's really the only validation currently in the ioctl besides all
> the stuff for making sure that the class/instance provided by the user
> isn't bogus.  But if we've got real i915_memory_region pointers, we
> don't need that.

Yeah, I guess the concern here was duplicated placements(that would
change the meaning of n_placements > 1), and then ofc regions not
supported by the device. Also maybe stolen which doesn't have a TTM
backend yet.

If this is just for the selftests, doing what the mman selftests do
with create_region + set_placements would be one option. Otherwise
maybe just add  __two_underscores and a big comment, for why you
should be careful when using this?

>
> --Jason
Jason Ekstrand July 21, 2021, 3:47 p.m. UTC | #6
On Wed, Jul 21, 2021 at 3:25 AM Matthew Auld
<matthew.william.auld@gmail.com> wrote:
>
> On Tue, 20 Jul 2021 at 23:04, Jason Ekstrand <jason@jlekstrand.net> wrote:
> >
> > On Tue, Jul 20, 2021 at 4:35 AM Matthew Auld
> > <matthew.william.auld@gmail.com> wrote:
> > >
> > > On Thu, 15 Jul 2021 at 23:39, Jason Ekstrand <jason@jlekstrand.net> wrote:
> > > >
> > > > Instead of hand-rolling the same three calls in each function, pull them
> > > > into an i915_gem_object_create_user helper.  Apart from re-ordering of
> > > > the placements array ENOMEM check, the only functional change here
> > > > should be that i915_gem_dumb_create now calls i915_gem_flush_free_objects
> > > > which it probably should have been calling all along.
> > > >
> > > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > > > ---
> > > >  drivers/gpu/drm/i915/gem/i915_gem_create.c | 106 +++++++++------------
> > > >  1 file changed, 43 insertions(+), 63 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > > > index 391c8c4a12172..69bf9ec777642 100644
> > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > > > @@ -11,13 +11,14 @@
> > > >  #include "i915_trace.h"
> > > >  #include "i915_user_extensions.h"
> > > >
> > > > -static u32 object_max_page_size(struct drm_i915_gem_object *obj)
> > > > +static u32 object_max_page_size(struct intel_memory_region **placements,
> > > > +                               unsigned int n_placements)
> > > >  {
> > > >         u32 max_page_size = 0;
> > > >         int i;
> > > >
> > > > -       for (i = 0; i < obj->mm.n_placements; i++) {
> > > > -               struct intel_memory_region *mr = obj->mm.placements[i];
> > > > +       for (i = 0; i < n_placements; i++) {
> > > > +               struct intel_memory_region *mr = placements[i];
> > > >
> > > >                 GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
> > > >                 max_page_size = max_t(u32, max_page_size, mr->min_page_size);
> > > > @@ -81,22 +82,35 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj,
> > > >         return 0;
> > > >  }
> > > >
> > > > -static int
> > > > -i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
> > > > +static struct drm_i915_gem_object *
> > > > +i915_gem_object_create_user(struct drm_i915_private *i915, u64 size,
> > > > +                           struct intel_memory_region **placements,
> > > > +                           unsigned int n_placements)
> > > >  {
> > > > -       struct intel_memory_region *mr = obj->mm.placements[0];
> > > > +       struct intel_memory_region *mr = placements[0];
> > > > +       struct drm_i915_gem_object *obj;
> > > >         unsigned int flags;
> > > >         int ret;
> > > >
> > > > -       size = round_up(size, object_max_page_size(obj));
> > > > +       i915_gem_flush_free_objects(i915);
> > > > +
> > > > +       obj = i915_gem_object_alloc();
> > > > +       if (!obj)
> > > > +               return ERR_PTR(-ENOMEM);
> > > > +
> > > > +       size = round_up(size, object_max_page_size(placements, n_placements));
> > > >         if (size == 0)
> > > > -               return -EINVAL;
> > > > +               return ERR_PTR(-EINVAL);
> > > >
> > > >         /* For most of the ABI (e.g. mmap) we think in system pages */
> > > >         GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
> > > >
> > > >         if (i915_gem_object_size_2big(size))
> > > > -               return -E2BIG;
> > > > +               return ERR_PTR(-E2BIG);
> > > > +
> > > > +       ret = object_set_placements(obj, placements, n_placements);
> > > > +       if (ret)
> > > > +               goto object_free;
> > >
> > > Thinking on this again, it might be way too thorny to expose
> > > create_user as-is to other parts of i915, like we do in the last
> > > patch. Since the caller will be expected to manually validate the
> > > placements, otherwise we might crash and burn in weird ways as new
> > > users pop up. i.e it needs the same validation that happens as part of
> > > the extension. Also as new extensions arrive, like with PXP, that also
> > > has to get bolted onto create_user, which might have its own hidden
> > > constraints.
> >
> > Perhaps.  Do you have a suggestion for how to make it available to
> > selftests without exposing it to "the rest of i915"?  If you want, I
> > can make create_user duplicate the placements uniqueness check.
> > That's really the only validation currently in the ioctl besides all
> > the stuff for making sure that the class/instance provided by the user
> > isn't bogus.  But if we've got real i915_memory_region pointers, we
> > don't need that.
>
> Yeah, I guess the concern here was duplicated placements(that would
> change the meaning of n_placements > 1), and then ofc regions not
> supported by the device. Also maybe stolen which doesn't have a TTM
> backend yet.
>
> If this is just for the selftests, doing what the mman selftests do
> with create_region + set_placements would be one option. Otherwise
> maybe just add  __two_underscores and a big comment, for why you
> should be careful when using this?

I've added __two_underscores and some kerneldoc.  I also looked at
adding some validation to that function.  I'm happy to do so if you'd
like but didn't want to add overhead if you thought __ and a big fat
warning were enough.

--Jason
Matthew Auld July 21, 2021, 4:29 p.m. UTC | #7
On Wed, 21 Jul 2021 at 16:47, Jason Ekstrand <jason@jlekstrand.net> wrote:
>
> On Wed, Jul 21, 2021 at 3:25 AM Matthew Auld
> <matthew.william.auld@gmail.com> wrote:
> >
> > On Tue, 20 Jul 2021 at 23:04, Jason Ekstrand <jason@jlekstrand.net> wrote:
> > >
> > > On Tue, Jul 20, 2021 at 4:35 AM Matthew Auld
> > > <matthew.william.auld@gmail.com> wrote:
> > > >
> > > > On Thu, 15 Jul 2021 at 23:39, Jason Ekstrand <jason@jlekstrand.net> wrote:
> > > > >
> > > > > Instead of hand-rolling the same three calls in each function, pull them
> > > > > into an i915_gem_object_create_user helper.  Apart from re-ordering of
> > > > > the placements array ENOMEM check, the only functional change here
> > > > > should be that i915_gem_dumb_create now calls i915_gem_flush_free_objects
> > > > > which it probably should have been calling all along.
> > > > >
> > > > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > > > > ---
> > > > >  drivers/gpu/drm/i915/gem/i915_gem_create.c | 106 +++++++++------------
> > > > >  1 file changed, 43 insertions(+), 63 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > > > > index 391c8c4a12172..69bf9ec777642 100644
> > > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c
> > > > > @@ -11,13 +11,14 @@
> > > > >  #include "i915_trace.h"
> > > > >  #include "i915_user_extensions.h"
> > > > >
> > > > > -static u32 object_max_page_size(struct drm_i915_gem_object *obj)
> > > > > +static u32 object_max_page_size(struct intel_memory_region **placements,
> > > > > +                               unsigned int n_placements)
> > > > >  {
> > > > >         u32 max_page_size = 0;
> > > > >         int i;
> > > > >
> > > > > -       for (i = 0; i < obj->mm.n_placements; i++) {
> > > > > -               struct intel_memory_region *mr = obj->mm.placements[i];
> > > > > +       for (i = 0; i < n_placements; i++) {
> > > > > +               struct intel_memory_region *mr = placements[i];
> > > > >
> > > > >                 GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
> > > > >                 max_page_size = max_t(u32, max_page_size, mr->min_page_size);
> > > > > @@ -81,22 +82,35 @@ static int i915_gem_publish(struct drm_i915_gem_object *obj,
> > > > >         return 0;
> > > > >  }
> > > > >
> > > > > -static int
> > > > > -i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
> > > > > +static struct drm_i915_gem_object *
> > > > > +i915_gem_object_create_user(struct drm_i915_private *i915, u64 size,
> > > > > +                           struct intel_memory_region **placements,
> > > > > +                           unsigned int n_placements)
> > > > >  {
> > > > > -       struct intel_memory_region *mr = obj->mm.placements[0];
> > > > > +       struct intel_memory_region *mr = placements[0];
> > > > > +       struct drm_i915_gem_object *obj;
> > > > >         unsigned int flags;
> > > > >         int ret;
> > > > >
> > > > > -       size = round_up(size, object_max_page_size(obj));
> > > > > +       i915_gem_flush_free_objects(i915);
> > > > > +
> > > > > +       obj = i915_gem_object_alloc();
> > > > > +       if (!obj)
> > > > > +               return ERR_PTR(-ENOMEM);
> > > > > +
> > > > > +       size = round_up(size, object_max_page_size(placements, n_placements));
> > > > >         if (size == 0)
> > > > > -               return -EINVAL;
> > > > > +               return ERR_PTR(-EINVAL);
> > > > >
> > > > >         /* For most of the ABI (e.g. mmap) we think in system pages */
> > > > >         GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
> > > > >
> > > > >         if (i915_gem_object_size_2big(size))
> > > > > -               return -E2BIG;
> > > > > +               return ERR_PTR(-E2BIG);
> > > > > +
> > > > > +       ret = object_set_placements(obj, placements, n_placements);
> > > > > +       if (ret)
> > > > > +               goto object_free;
> > > >
> > > > Thinking on this again, it might be way too thorny to expose
> > > > create_user as-is to other parts of i915, like we do in the last
> > > > patch. Since the caller will be expected to manually validate the
> > > > placements, otherwise we might crash and burn in weird ways as new
> > > > users pop up. i.e it needs the same validation that happens as part of
> > > > the extension. Also as new extensions arrive, like with PXP, that also
> > > > has to get bolted onto create_user, which might have its own hidden
> > > > constraints.
> > >
> > > Perhaps.  Do you have a suggestion for how to make it available to
> > > selftests without exposing it to "the rest of i915"?  If you want, I
> > > can make create_user duplicate the placements uniqueness check.
> > > That's really the only validation currently in the ioctl besides all
> > > the stuff for making sure that the class/instance provided by the user
> > > isn't bogus.  But if we've got real i915_memory_region pointers, we
> > > don't need that.
> >
> > Yeah, I guess the concern here was duplicated placements(that would
> > change the meaning of n_placements > 1), and then ofc regions not
> > supported by the device. Also maybe stolen which doesn't have a TTM
> > backend yet.
> >
> > If this is just for the selftests, doing what the mman selftests do
> > with create_region + set_placements would be one option. Otherwise
> > maybe just add  __two_underscores and a big comment, for why you
> > should be careful when using this?
>
> I've added __two_underscores and some kerneldoc.  I also looked at
> adding some validation to that function.  I'm happy to do so if you'd
> like but didn't want to add overhead if you thought __ and a big fat
> warning were enough.

__two_underscores and a comment should be fine for now.

>
> --Jason
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c
index 391c8c4a12172..69bf9ec777642 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_create.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c
@@ -11,13 +11,14 @@ 
 #include "i915_trace.h"
 #include "i915_user_extensions.h"
 
-static u32 object_max_page_size(struct drm_i915_gem_object *obj)
+static u32 object_max_page_size(struct intel_memory_region **placements,
+				unsigned int n_placements)
 {
 	u32 max_page_size = 0;
 	int i;
 
-	for (i = 0; i < obj->mm.n_placements; i++) {
-		struct intel_memory_region *mr = obj->mm.placements[i];
+	for (i = 0; i < n_placements; i++) {
+		struct intel_memory_region *mr = placements[i];
 
 		GEM_BUG_ON(!is_power_of_2(mr->min_page_size));
 		max_page_size = max_t(u32, max_page_size, mr->min_page_size);
@@ -81,22 +82,35 @@  static int i915_gem_publish(struct drm_i915_gem_object *obj,
 	return 0;
 }
 
-static int
-i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
+static struct drm_i915_gem_object *
+i915_gem_object_create_user(struct drm_i915_private *i915, u64 size,
+			    struct intel_memory_region **placements,
+			    unsigned int n_placements)
 {
-	struct intel_memory_region *mr = obj->mm.placements[0];
+	struct intel_memory_region *mr = placements[0];
+	struct drm_i915_gem_object *obj;
 	unsigned int flags;
 	int ret;
 
-	size = round_up(size, object_max_page_size(obj));
+	i915_gem_flush_free_objects(i915);
+
+	obj = i915_gem_object_alloc();
+	if (!obj)
+		return ERR_PTR(-ENOMEM);
+
+	size = round_up(size, object_max_page_size(placements, n_placements));
 	if (size == 0)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	/* For most of the ABI (e.g. mmap) we think in system pages */
 	GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
 
 	if (i915_gem_object_size_2big(size))
-		return -E2BIG;
+		return ERR_PTR(-E2BIG);
+
+	ret = object_set_placements(obj, placements, n_placements);
+	if (ret)
+		goto object_free;
 
 	/*
 	 * I915_BO_ALLOC_USER will make sure the object is cleared before
@@ -106,12 +120,18 @@  i915_gem_setup(struct drm_i915_gem_object *obj, u64 size)
 
 	ret = mr->ops->init_object(mr, obj, size, 0, flags);
 	if (ret)
-		return ret;
+		goto object_free;
 
 	GEM_BUG_ON(size != obj->base.size);
 
 	trace_i915_gem_object_create(obj);
-	return 0;
+	return obj;
+
+object_free:
+	if (obj->mm.n_placements > 1)
+		kfree(obj->mm.placements);
+	i915_gem_object_free(obj);
+	return ERR_PTR(ret);
 }
 
 int
@@ -124,7 +144,6 @@  i915_gem_dumb_create(struct drm_file *file,
 	enum intel_memory_type mem_type;
 	int cpp = DIV_ROUND_UP(args->bpp, 8);
 	u32 format;
-	int ret;
 
 	switch (cpp) {
 	case 1:
@@ -157,24 +176,13 @@  i915_gem_dumb_create(struct drm_file *file,
 	if (HAS_LMEM(to_i915(dev)))
 		mem_type = INTEL_MEMORY_LOCAL;
 
-	obj = i915_gem_object_alloc();
-	if (!obj)
-		return -ENOMEM;
-
 	mr = intel_memory_region_by_type(to_i915(dev), mem_type);
-	ret = object_set_placements(obj, &mr, 1);
-	if (ret)
-		goto object_free;
 
-	ret = i915_gem_setup(obj, args->size);
-	if (ret)
-		goto object_free;
+	obj = i915_gem_object_create_user(to_i915(dev), args->size, &mr, 1);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
 
 	return i915_gem_publish(obj, file, &args->size, &args->handle);
-
-object_free:
-	i915_gem_object_free(obj);
-	return ret;
 }
 
 /**
@@ -191,28 +199,14 @@  i915_gem_create_ioctl(struct drm_device *dev, void *data,
 	struct drm_i915_gem_create *args = data;
 	struct drm_i915_gem_object *obj;
 	struct intel_memory_region *mr;
-	int ret;
-
-	i915_gem_flush_free_objects(i915);
-
-	obj = i915_gem_object_alloc();
-	if (!obj)
-		return -ENOMEM;
 
 	mr = intel_memory_region_by_type(i915, INTEL_MEMORY_SYSTEM);
-	ret = object_set_placements(obj, &mr, 1);
-	if (ret)
-		goto object_free;
 
-	ret = i915_gem_setup(obj, args->size);
-	if (ret)
-		goto object_free;
+	obj = i915_gem_object_create_user(i915, args->size, &mr, 1);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
 
 	return i915_gem_publish(obj, file, &args->size, &args->handle);
-
-object_free:
-	i915_gem_object_free(obj);
-	return ret;
 }
 
 #define MAX_N_PLACEMENTS = (INTEL_REGION_UNKNOWN + 1)
@@ -379,38 +373,24 @@  i915_gem_create_ext_ioctl(struct drm_device *dev, void *data,
 	if (args->flags)
 		return -EINVAL;
 
-	i915_gem_flush_free_objects(i915);
-
-	obj = i915_gem_object_alloc();
-	if (!obj)
-		return -ENOMEM;
-
 	ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
 				   create_extensions,
 				   ARRAY_SIZE(create_extensions),
 				   &ext_data);
 	if (ret)
-		goto object_free;
+		return ret;
 
 	if (!ext_data.n_placements) {
 		ext_data.placements[0] =
 			intel_memory_region_by_type(i915, INTEL_MEMORY_SYSTEM);
 		ext_data.n_placements = 1;
 	}
-	ret = object_set_placements(obj, ext_data.placements,
-				    ext_data.n_placements);
-	if (ret)
-		goto object_free;
 
-	ret = i915_gem_setup(obj, args->size);
-	if (ret)
-		goto object_free;
+	obj = i915_gem_object_create_user(i915, args->size,
+					  ext_data.placements,
+					  ext_data.n_placements);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
 
 	return i915_gem_publish(obj, file, &args->size, &args->handle);
-
-object_free:
-	if (obj->mm.n_placements > 1)
-		kfree(obj->mm.placements);
-	i915_gem_object_free(obj);
-	return ret;
 }