[PATCH v3] drm/msm: Add syncobj support.

Jordan Crouse jcrouse at codeaurora.org
Fri Feb 7 17:36:02 UTC 2020


On Thu, Feb 06, 2020 at 05:43:52PM +0100, Bas Nieuwenhuizen wrote:
> Hi,
> 
> I'd appreciate if you could take a look at this patch. I believe I
> have accommodated the earlier review comments.

Sorry, it was sitting on my todo list. Looks good.

> Thank you,
> Bas
> 
> On Fri, Jan 24, 2020 at 12:58 AM Bas Nieuwenhuizen
> <bas at basnieuwenhuizen.nl> wrote:
> >
> > This
> >
> > 1) Enables core DRM syncobj support.
> > 2) Adds options to the submission ioctl to wait/signal syncobjs.
> >
> > Just like the wait fence fd, this does inline waits. Using the
> > scheduler would be nice but I believe it is out of scope for
> > this work.
> >
> > Support for timeline syncobjs is implemented and the interface
> > is ready for it, but I'm not enabling it yet until there is
> > some code for turnip to use it.
> >
> > The reset is mostly in there because in the presence of waiting
> > and signalling the same semaphores, resetting them after
> > signalling can become very annoying.
> >
> > v2:
> >   - Fixed style issues
> >   - Removed a cleanup issue in a failure case
> >   - Moved to a copy_from_user per syncobj
> >
> > v3:
> >  - Fixed a missing declaration introduced in v2
> >  - Reworked to use ERR_PTR/PTR_ERR
> >  - Simplified failure gotos.
> >
> > Signed-off-by: Bas Nieuwenhuizen <bas at basnieuwenhuizen.nl>
> > ---
> >  drivers/gpu/drm/msm/msm_drv.c        |   6 +-
> >  drivers/gpu/drm/msm/msm_gem_submit.c | 232 ++++++++++++++++++++++++++-
> >  include/uapi/drm/msm_drm.h           |  24 ++-
> >  3 files changed, 258 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
> > index c84f0a8b3f2c..5246b41798df 100644
> > --- a/drivers/gpu/drm/msm/msm_drv.c
> > +++ b/drivers/gpu/drm/msm/msm_drv.c
> > @@ -37,9 +37,10 @@
> >   * - 1.4.0 - softpin, MSM_RELOC_BO_DUMP, and GEM_INFO support to set/get
> >   *           GEM object's debug name
> >   * - 1.5.0 - Add SUBMITQUERY_QUERY ioctl
> > + * - 1.6.0 - Syncobj support
> >   */
> >  #define MSM_VERSION_MAJOR      1
> > -#define MSM_VERSION_MINOR      5
> > +#define MSM_VERSION_MINOR      6
> >  #define MSM_VERSION_PATCHLEVEL 0
> >
> >  static const struct drm_mode_config_funcs mode_config_funcs = {
> > @@ -988,7 +989,8 @@ static struct drm_driver msm_driver = {
> >         .driver_features    = DRIVER_GEM |
> >                                 DRIVER_RENDER |
> >                                 DRIVER_ATOMIC |
> > -                               DRIVER_MODESET,
> > +                               DRIVER_MODESET |
> > +                               DRIVER_SYNCOBJ,
> >         .open               = msm_open,
> >         .postclose           = msm_postclose,
> >         .lastclose          = drm_fb_helper_lastclose,
> > diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
> > index be5327af16fa..11045f56b815 100644
> > --- a/drivers/gpu/drm/msm/msm_gem_submit.c
> > +++ b/drivers/gpu/drm/msm/msm_gem_submit.c
> > @@ -8,7 +8,9 @@
> >  #include <linux/sync_file.h>
> >  #include <linux/uaccess.h>
> >
> > +#include <drm/drm_drv.h>
> >  #include <drm/drm_file.h>
> > +#include <drm/drm_syncobj.h>
> >
> >  #include "msm_drv.h"
> >  #include "msm_gpu.h"
> > @@ -394,6 +396,186 @@ static void submit_cleanup(struct msm_gem_submit *submit)
> >         ww_acquire_fini(&submit->ticket);
> >  }
> >
> > +
> > +struct msm_submit_post_dep {
> > +       struct drm_syncobj *syncobj;
> > +       uint64_t point;
> > +       struct dma_fence_chain *chain;
> > +};
> > +
> > +static struct drm_syncobj **msm_wait_deps(struct drm_device *dev,
> > +                                          struct drm_file *file,
> > +                                          uint64_t in_syncobjs_addr,
> > +                                          uint32_t nr_in_syncobjs,
> > +                                          size_t syncobj_stride,
> > +                                          struct msm_ringbuffer *ring)
> > +{
> > +       struct drm_syncobj **syncobjs = NULL;
> > +       struct drm_msm_gem_submit_syncobj syncobj_desc = {0};
> > +       int ret = 0;
> > +       uint32_t i, j;
> > +
> > +       syncobjs = kcalloc(nr_in_syncobjs, sizeof(*syncobjs),
> > +                          GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
> > +       if (!syncobjs)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       for (i = 0; i < nr_in_syncobjs; ++i) {
> > +               uint64_t address = in_syncobjs_addr + i * syncobj_stride;
> > +               struct dma_fence *fence;
> > +
> > +               if (copy_from_user(&syncobj_desc,
> > +                                  u64_to_user_ptr(address),
> > +                                  min(syncobj_stride, sizeof(syncobj_desc)))) {
> > +                       ret = -EFAULT;
> > +                       break;
> > +               }
> > +
> > +               if (syncobj_desc.point &&
> > +                   !drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) {
> > +                       ret = -EOPNOTSUPP;
> > +                       break;
> > +               }
> > +
> > +               if (syncobj_desc.flags & ~MSM_SUBMIT_SYNCOBJ_FLAGS) {
> > +                       ret = -EINVAL;
> > +                       break;
> > +               }
> > +
> > +               ret = drm_syncobj_find_fence(file, syncobj_desc.handle,
> > +                                            syncobj_desc.point, 0, &fence);
> > +               if (ret)
> > +                       break;
> > +
> > +               if (!dma_fence_match_context(fence, ring->fctx->context))
> > +                       ret = dma_fence_wait(fence, true);
> > +
> > +               dma_fence_put(fence);
> > +               if (ret)
> > +                       break;
> > +
> > +               if (syncobj_desc.flags & MSM_SUBMIT_SYNCOBJ_RESET) {
> > +                       syncobjs[i] =
> > +                               drm_syncobj_find(file, syncobj_desc.handle);
> > +                       if (!syncobjs[i]) {
> > +                               ret = -EINVAL;
> > +                               break;
> > +                       }
> > +               }
> > +       }
> > +
> > +       if (ret) {
> > +               for (j = 0; j <= i; ++j) {
> > +                       if (syncobjs[j])
> > +                               drm_syncobj_put(syncobjs[j]);
> > +               }
> > +               kfree(syncobjs);
> > +               return ERR_PTR(ret);
> > +       }
> > +       return syncobjs;
> > +}
> > +
> > +static void msm_reset_syncobjs(struct drm_syncobj **syncobjs,
> > +                               uint32_t nr_syncobjs)
> > +{
> > +       uint32_t i;
> > +
> > +       for (i = 0; syncobjs && i < nr_syncobjs; ++i) {
> > +               if (syncobjs[i])
> > +                       drm_syncobj_replace_fence(syncobjs[i], NULL);
> > +       }
> > +}
> > +
> > +static struct msm_submit_post_dep *msm_parse_post_deps(struct drm_device *dev,
> > +                                                       struct drm_file *file,
> > +                                                       uint64_t syncobjs_addr,
> > +                                                       uint32_t nr_syncobjs,
> > +                                                       size_t syncobj_stride)
> > +{
> > +       struct msm_submit_post_dep *post_deps;
> > +       struct drm_msm_gem_submit_syncobj syncobj_desc = {0};
> > +       int ret = 0;
> > +       uint32_t i, j;
> > +
> > +       post_deps = kmalloc_array(nr_syncobjs, sizeof(*post_deps),
> > +                                 GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
> > +       if (!post_deps)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       for (i = 0; i < nr_syncobjs; ++i) {
> > +               uint64_t address = syncobjs_addr + i * syncobj_stride;
> > +
> > +               if (copy_from_user(&syncobj_desc,
> > +                                  u64_to_user_ptr(address),
> > +                                  min(syncobj_stride, sizeof(syncobj_desc)))) {
> > +                       ret = -EFAULT;
> > +                       break;
> > +               }
> > +
> > +               post_deps[i].point = syncobj_desc.point;
> > +               post_deps[i].chain = NULL;
> > +
> > +               if (syncobj_desc.flags) {
> > +                       ret = -EINVAL;
> > +                       break;
> > +               }
> > +
> > +               if (syncobj_desc.point) {
> > +                       if (!drm_core_check_feature(dev,
> > +                                                   DRIVER_SYNCOBJ_TIMELINE)) {
> > +                               ret = -EOPNOTSUPP;
> > +                               break;
> > +                       }
> > +
> > +                       post_deps[i].chain =
> > +                               kmalloc(sizeof(*post_deps[i].chain),
> > +                                       GFP_KERNEL);
> > +                       if (!post_deps[i].chain) {
> > +                               ret = -ENOMEM;
> > +                               break;
> > +                       }
> > +               }
> > +
> > +               post_deps[i].syncobj =
> > +                       drm_syncobj_find(file, syncobj_desc.handle);
> > +               if (!post_deps[i].syncobj) {
> > +                       ret = -EINVAL;
> > +                       break;
> > +               }
> > +       }
> > +
> > +       if (ret) {
> > +               for (j = 0; j <= i; ++j) {
> > +                       kfree(post_deps[j].chain);
> > +                       if (post_deps[j].syncobj)
> > +                               drm_syncobj_put(post_deps[j].syncobj);
> > +               }
> > +
> > +               kfree(post_deps);
> > +               return ERR_PTR(ret);
> > +       }
> > +
> > +       return post_deps;
> > +}
> > +
> > +static void msm_process_post_deps(struct msm_submit_post_dep *post_deps,
> > +                                  uint32_t count, struct dma_fence *fence)
> > +{
> > +       uint32_t i;
> > +
> > +       for (i = 0; post_deps && i < count; ++i) {
> > +               if (post_deps[i].chain) {
> > +                       drm_syncobj_add_point(post_deps[i].syncobj,
> > +                                             post_deps[i].chain,
> > +                                             fence, post_deps[i].point);
> > +                       post_deps[i].chain = NULL;
> > +               } else {
> > +                       drm_syncobj_replace_fence(post_deps[i].syncobj,
> > +                                                 fence);
> > +               }
> > +       }
> > +}
> > +
> >  int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
> >                 struct drm_file *file)
> >  {
> > @@ -406,6 +588,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
> >         struct sync_file *sync_file = NULL;
> >         struct msm_gpu_submitqueue *queue;
> >         struct msm_ringbuffer *ring;
> > +       struct msm_submit_post_dep *post_deps = NULL;
> > +       struct drm_syncobj **syncobjs_to_reset = NULL;
> >         int out_fence_fd = -1;
> >         struct pid *pid = get_pid(task_pid(current));
> >         unsigned i;
> > @@ -413,6 +597,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
> >         if (!gpu)
> >                 return -ENXIO;
> >
> > +       if (args->pad)
> > +               return -EINVAL;
> > +
> >         /* for now, we just have 3d pipe.. eventually this would need to
> >          * be more clever to dispatch to appropriate gpu module:
> >          */
> > @@ -460,9 +647,29 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
> >                         return ret;
> >         }
> >
> > +       if (args->flags & MSM_SUBMIT_SYNCOBJ_IN) {
> > +               syncobjs_to_reset = msm_wait_deps(dev, file,
> > +                                                 args->in_syncobjs,
> > +                                                 args->nr_in_syncobjs,
> > +                                                 args->syncobj_stride, ring);
> > +               if (IS_ERR(syncobjs_to_reset))
> > +                       return PTR_ERR(syncobjs_to_reset);
> > +       }
> > +
> > +       if (args->flags & MSM_SUBMIT_SYNCOBJ_OUT) {
> > +               post_deps = msm_parse_post_deps(dev, file,
> > +                                               args->out_syncobjs,
> > +                                               args->nr_out_syncobjs,
> > +                                               args->syncobj_stride);
> > +               if (IS_ERR(post_deps)) {
> > +                       ret = PTR_ERR(post_deps);
> > +                       goto out_post_unlock;
> > +               }
> > +       }
> > +
> >         ret = mutex_lock_interruptible(&dev->struct_mutex);
> >         if (ret)
> > -               return ret;
> > +               goto out_post_unlock;
> >
> >         if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
> >                 out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
> > @@ -586,6 +793,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
> >                 args->fence_fd = out_fence_fd;
> >         }
> >
> > +       msm_reset_syncobjs(syncobjs_to_reset, args->nr_in_syncobjs);
> > +       msm_process_post_deps(post_deps, args->nr_out_syncobjs,
> > +                             submit->fence);
> > +
> > +
> >  out:
> >         submit_cleanup(submit);
> >         if (ret)
> > @@ -594,5 +806,23 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
> >         if (ret && (out_fence_fd >= 0))
> >                 put_unused_fd(out_fence_fd);
> >         mutex_unlock(&dev->struct_mutex);
> > +
> > +out_post_unlock:
> > +       if (!IS_ERR_OR_NULL(post_deps)) {
> > +               for (i = 0; i < args->nr_out_syncobjs; ++i) {
> > +                       kfree(post_deps[i].chain);
> > +                       drm_syncobj_put(post_deps[i].syncobj);
> > +               }
> > +               kfree(post_deps);
> > +       }
> > +
> > +       if (!IS_ERR_OR_NULL(syncobjs_to_reset)) {
> > +               for (i = 0; i < args->nr_in_syncobjs; ++i) {
> > +                       if (syncobjs_to_reset[i])
> > +                               drm_syncobj_put(syncobjs_to_reset[i]);
> > +               }
> > +               kfree(syncobjs_to_reset);
> > +       }
> > +
> >         return ret;
> >  }
> > diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
> > index 0b85ed6a3710..19806eb3a8e8 100644
> > --- a/include/uapi/drm/msm_drm.h
> > +++ b/include/uapi/drm/msm_drm.h
> > @@ -217,13 +217,28 @@ struct drm_msm_gem_submit_bo {
> >  #define MSM_SUBMIT_FENCE_FD_IN   0x40000000 /* enable input fence_fd */
> >  #define MSM_SUBMIT_FENCE_FD_OUT  0x20000000 /* enable output fence_fd */
> >  #define MSM_SUBMIT_SUDO          0x10000000 /* run submitted cmds from RB */
> > +#define MSM_SUBMIT_SYNCOBJ_IN    0x08000000 /* enable input syncobj */
> > +#define MSM_SUBMIT_SYNCOBJ_OUT   0x04000000 /* enable output syncobj */
> >  #define MSM_SUBMIT_FLAGS                ( \
> >                 MSM_SUBMIT_NO_IMPLICIT   | \
> >                 MSM_SUBMIT_FENCE_FD_IN   | \
> >                 MSM_SUBMIT_FENCE_FD_OUT  | \
> >                 MSM_SUBMIT_SUDO          | \
> > +               MSM_SUBMIT_SYNCOBJ_IN    | \
> > +               MSM_SUBMIT_SYNCOBJ_OUT   | \
> >                 0)
> >
> > +#define MSM_SUBMIT_SYNCOBJ_RESET 0x00000001 /* Reset syncobj after wait. */
> > +#define MSM_SUBMIT_SYNCOBJ_FLAGS        ( \
> > +               MSM_SUBMIT_SYNCOBJ_RESET | \
> > +               0)
> > +
> > +struct drm_msm_gem_submit_syncobj {
> > +       __u32 handle;     /* in, syncobj handle. */
> > +       __u32 flags;      /* in, from MSM_SUBMIT_SYNCOBJ_FLAGS */
> > +       __u64 point;      /* in, timepoint for timeline syncobjs. */
> > +};
> > +
> >  /* Each cmdstream submit consists of a table of buffers involved, and
> >   * one or more cmdstream buffers.  This allows for conditional execution
> >   * (context-restore), and IB buffers needed for per tile/bin draw cmds.
> > @@ -236,7 +251,14 @@ struct drm_msm_gem_submit {
> >         __u64 bos;            /* in, ptr to array of submit_bo's */
> >         __u64 cmds;           /* in, ptr to array of submit_cmd's */
> >         __s32 fence_fd;       /* in/out fence fd (see MSM_SUBMIT_FENCE_FD_IN/OUT) */
> > -       __u32 queueid;         /* in, submitqueue id */
> > +       __u32 queueid;        /* in, submitqueue id */
> > +       __u64 in_syncobjs;    /* in, ptr to to array of drm_msm_gem_submit_syncobj */
> > +       __u64 out_syncobjs;   /* in, ptr to to array of drm_msm_gem_submit_syncobj */
> > +       __u32 nr_in_syncobjs; /* in, number of entries in in_syncobj */
> > +       __u32 nr_out_syncobjs; /* in, number of entries in out_syncobj. */
> > +       __u32 syncobj_stride; /* in, stride of syncobj arrays. */
> > +       __u32 pad;            /*in, reserved for future use, always 0. */
> > +
> >  };
> >
> >  /* The normal way to synchronize with the GPU is just to CPU_PREP on
> > --
> > 2.25.0
> >

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


More information about the dri-devel mailing list