[PATCH 3/4] drm/exynos: added userptr feature.

Inki Dae inki.dae at samsung.com
Wed May 16 03:30:33 PDT 2012



> -----Original Message-----
> From: robdclark at gmail.com [mailto:robdclark at gmail.com] On Behalf Of Rob
> Clark
> Sent: Wednesday, May 16, 2012 5:43 PM
> To: Inki Dae
> Cc: InKi Dae; kyungmin.park at samsung.com; sw0312.kim at samsung.com; dri-
> devel at lists.freedesktop.org
> Subject: Re: [PATCH 3/4] drm/exynos: added userptr feature.
> 
> On Wed, May 16, 2012 at 12:04 AM, Inki Dae <inki.dae at samsung.com> wrote:
> >
> >
> >> -----Original Message-----
> >> From: robdclark at gmail.com [mailto:robdclark at gmail.com] On Behalf Of Rob
> >> Clark
> >> Sent: Tuesday, May 15, 2012 11:29 PM
> >> To: InKi Dae
> >> Cc: Inki Dae; kyungmin.park at samsung.com; sw0312.kim at samsung.com; dri-
> >> devel at lists.freedesktop.org
> >> Subject: Re: [PATCH 3/4] drm/exynos: added userptr feature.
> >>
> >> On Tue, May 15, 2012 at 7:40 AM, InKi Dae <daeinki at gmail.com> wrote:
> >> > 2012/5/15 Rob Clark <rob.clark at linaro.org>:
> >> >> On Tue, May 15, 2012 at 2:17 AM, Inki Dae <inki.dae at samsung.com>
> wrote:
> >> >>> Hi Rob,
> >> >>>
> >> >>>> -----Original Message-----
> >> >>>> From: robdclark at gmail.com [mailto:robdclark at gmail.com] On Behalf
> Of
> >> Rob
> >> >>>> Clark
> >> >>>> Sent: Tuesday, May 15, 2012 4:35 PM
> >> >>>> To: Inki Dae
> >> >>>> Cc: airlied at linux.ie; dri-devel at lists.freedesktop.org;
> >> >>>> kyungmin.park at samsung.com; sw0312.kim at samsung.com
> >> >>>> Subject: Re: [PATCH 3/4] drm/exynos: added userptr feature.
> >> >>>>
> >> >>>> On Mon, Apr 23, 2012 at 7:43 AM, Inki Dae <inki.dae at samsung.com>
> >> wrote:
> >> >>>> > this feature could be used to use memory region allocated by
> >> malloc() in
> >> >>>> user
> >> >>>> > mode and mmaped memory region allocated by other memory
> allocators.
> >> >>>> userptr
> >> >>>> > interface can identify memory type through vm_flags value and
> would
> >> get
> >> >>>> > pages or page frame numbers to user space appropriately.
> >> >>>>
> >> >>>> I apologize for being a little late to jump in on this thread,
> but...
> >> >>>>
> >> >>>> I must confess to not being a huge fan of userptr.  It really is
> >> >>>> opening a can of worms, and seems best avoided if at all possible.
> >> >>>> I'm not entirely sure the use-case for which you require this, but
> I
> >> >>>> wonder if there isn't an alternative way?   I mean, the main case
> I
> >> >>>> could think of for mapping userspace memory would be something
> like
> >> >>>> texture upload.  But could that be handled in an alternative way,
> >> >>>> something like a pwrite or texture_upload API, which could
> >> temporarily
> >> >>>> pin the userspace memory, kick off a dma from that user buffer to
> a
> >> >>>> proper GEM buffer, and then unpin the user buffer when the DMA
> >> >>>> completes?
> >> >>>>
> >> >>>
> >> >>> This feature have being discussed with drm and linux-mm guys and I
> >> have
> >> >>> posted this patch four times.
> >> >>> So please, see below e-mail threads.
> >> >>> http://www.spinics.net/lists/dri-devel/msg22729.html
> >> >>>
> >> >>> and then please, give me your opinions.
> >> >>
> >> >>
> >> >> Yeah, I read that and understand that the purpose is to support
> >> >> malloc()'d memory (and btw, all the other changes like limits to the
> >> >> amount of userptr buffers are good if we do decide to support
> userptr
> >> >> buffers).  But my question was more about why do you need to support
> >> >> malloc'd buffers... other than "just because v4l2 does" ;-)
> >> >>
> >> >> I don't really like the userptr feature in v4l2 either, and view it
> as
> >> >> a necessary evil because at the time there was nothing like dmabuf.
> >> >> But now that we have dmabuf to share buffers with zero copy between
> >> >> two devices, to we *really* still need userptr?
> >> >>
> >> >
> >> > Definitely no, as I mentioned on this email thread, we are using the
> >> > userptr feature for pixman and evas
> >> > backend to use gpu acceleration directly(zero-copy). as you may know,
> >> > Evas is part of the Enlightenment Foundation Libraries(EFL) and
> >> > Elementary for pixman. all the applicaions based on them uses user
> >> > address to draw something so the backends(such as gpu accelerators)
> >> > can refer to only the user address to the buffer rendered. do you
> >> > think we can avoid memory copy to use those GPUs without such userptr
> >> > feature? I think there is no way and only the way that the gpu uses
> >> > the user address to render without memory copy. and as mentioned on
> >> > this thread, this feature had been tried by i915 in the desktop
world.
> >> > for this, you can refer to Daniel's comments.
> >>
> >> oh, yeah, for something like pixman it is hard to accelerate.  But I
> >> wonder if there is still some benefit.  I don't know as much about
> >> evas, but pixman is assumed to be a synchronous API, so you must
> >> always block until the operation completes which looses a lot of the
> >> potential benefit of a blitter.  And also I think you have no control
> >> over when the client free()'s a buffer.  So you end up having to
> >> map/unmap the buffer to the gpu/blitter/whatever every single
> >> operation.  Not to mention possible need for cache operations, etc.  I
> >> wonder if trying to accel it in hw really brings any benefit vs just
> >> using NEON?
> >>
> >
> > Yes, actually, we are using NEON backend of PIXMAN for best performance
> > also. like this, PIXMAN's NEON backend for small image and 2D GPU
> backend of
> > EXA for large image because NEON is faster than 2d gpu for small image
> but
> > not for large image.
> >
> >> I thought EFL has a GLES backend..  I could be wrong about that, but
> >> if it does probably you'd get better performance by using the GLES
> >> backend vs trying to accelerate what is intended as a sw path..
> >>
> > Right, EFL has a GLES backend and also PIXMAN for software path.
> application
> > using Elementary can use PIXMAN for software path and also GLES for
> hardware
> > acceleration. so the purpose of using userptr feature is for buffer
> drawn by
> > any user using Evas to be rendered by gpu hardware.
> 
> 
> hmm, I don't suppose it is primarily a one-way transfer (ie. like one
> time blit from sw rendered surface to texture)?  I'd be more
> comfortable w/ an API that somehow just created a temporary mapping
> that unpins the pages before the syscall returns, ie. like a
> EXYNOS_IOCTL_BLIT_FROM_USERPTR type interface, which does some blit
> from a user ptr to a GEM bo.
> 

You mean use such interface to do BitBLIT instead of using userptr? via
driver also uses this way.

> BR,
> -R
> 
> >
> > Thanks,
> > Inki Dae
> >
> >> > and as you know, note that we are already using dmabuf to share a
> >> > buffer between device drivers or v4l2 and drm framework. for this, we
> >> > also tested drm prime feature with v4l2 world and we applied umm
> >> > concept to ump for 3d gpu(known as mali) also.
> >> >
> >> > Anyway, this userptr feature is different from your thought. and
> maybe
> >> > you also need such feature for performance enhancement. Please give
> me
> >> > any idea if you have any good way instead of this userptr fearure.
> >> > there may be any good idea I don't know.
> >>
> >> well, I just try and point people to APIs that are actually designed
> >> with hw acceleration in mind in the first place (x11/EXA, GLES, etc)
> >> ;-)
> >>
> >> There missing really an API for client side 2d accel.  Well, I guess
> >> there is OpenVG, although I'm not sure if anyone actually ever used
> >> it.. maybe we do need something for better supporting 2d blitters in
> >> weston compositor, for example.
> >>
> >> BR,
> >> -R
> >>
> >>
> >> > Thanks,
> >> > Inki Dae
> >> >
> >> >> I guess if I understood better the use-case, maybe I could try to
> >> >> think of some alternatives.
> >> >>
> >> >> BR,
> >> >> -R
> >> >>
> >> >>> Thanks,
> >> >>> Inki Dae
> >> >>>
> >> >>>> BR,
> >> >>>> -R
> >> >>>>
> >> >>>> > Signed-off-by: Inki Dae <inki.dae at samsung.com>
> >> >>>> > Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
> >> >>>> > ---
> >> >>>> >  drivers/gpu/drm/exynos/exynos_drm_drv.c |    2 +
> >> >>>> >  drivers/gpu/drm/exynos/exynos_drm_gem.c |  258
> >> >>>> +++++++++++++++++++++++++++++++
> >> >>>> >  drivers/gpu/drm/exynos/exynos_drm_gem.h |   13 ++-
> >> >>>> >  include/drm/exynos_drm.h                |   25 +++-
> >> >>>> >  4 files changed, 296 insertions(+), 2 deletions(-)
> >> >>>> >
> >> >>>> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c
> >> >>>> b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> >> >>>> > index f58a487..5bb0361 100644
> >> >>>> > --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
> >> >>>> > +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> >> >>>> > @@ -211,6 +211,8 @@ static struct drm_ioctl_desc exynos_ioctls[]
> =
> >> {
> >> >>>> >                        DRM_AUTH),
> >> >>>> >        DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP,
> >> >>>> >                        exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED |
> >> >>> DRM_AUTH),
> >> >>>> > +       DRM_IOCTL_DEF_DRV(EXYNOS_GEM_USERPTR,
> >> >>>> > +                       exynos_drm_gem_userptr_ioctl,
> > DRM_UNLOCKED),
> >> >>>> >        DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS,
> >> >>>> exynos_plane_set_zpos_ioctl,
> >> >>>> >                        DRM_UNLOCKED | DRM_AUTH),
> >> >>>> >        DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
> >> >>>> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c
> >> >>>> b/drivers/gpu/drm/exynos/exynos_drm_gem.c
> >> >>>> > index afd0cd4..b68d4ea 100644
> >> >>>> > --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
> >> >>>> > +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
> >> >>>> > @@ -66,6 +66,43 @@ static int check_gem_flags(unsigned int
flags)
> >> >>>> >        return 0;
> >> >>>> >  }
> >> >>>> >
> >> >>>> > +static struct vm_area_struct *get_vma(struct vm_area_struct
> *vma)
> >> >>>> > +{
> >> >>>> > +       struct vm_area_struct *vma_copy;
> >> >>>> > +
> >> >>>> > +       vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
> >> >>>> > +       if (!vma_copy)
> >> >>>> > +               return NULL;
> >> >>>> > +
> >> >>>> > +       if (vma->vm_ops && vma->vm_ops->open)
> >> >>>> > +               vma->vm_ops->open(vma);
> >> >>>> > +
> >> >>>> > +       if (vma->vm_file)
> >> >>>> > +               get_file(vma->vm_file);
> >> >>>> > +
> >> >>>> > +       memcpy(vma_copy, vma, sizeof(*vma));
> >> >>>> > +
> >> >>>> > +       vma_copy->vm_mm = NULL;
> >> >>>> > +       vma_copy->vm_next = NULL;
> >> >>>> > +       vma_copy->vm_prev = NULL;
> >> >>>> > +
> >> >>>> > +       return vma_copy;
> >> >>>> > +}
> >> >>>> > +
> >> >>>> > +static void put_vma(struct vm_area_struct *vma)
> >> >>>> > +{
> >> >>>> > +       if (!vma)
> >> >>>> > +               return;
> >> >>>> > +
> >> >>>> > +       if (vma->vm_ops && vma->vm_ops->close)
> >> >>>> > +               vma->vm_ops->close(vma);
> >> >>>> > +
> >> >>>> > +       if (vma->vm_file)
> >> >>>> > +               fput(vma->vm_file);
> >> >>>> > +
> >> >>>> > +       kfree(vma);
> >> >>>> > +}
> >> >>>> > +
> >> >>>> >  static void update_vm_cache_attr(struct exynos_drm_gem_obj
*obj,
> >> >>>> >                                        struct vm_area_struct
*vma)
> >> >>>> >  {
> >> >>>> > @@ -254,6 +291,41 @@ static void exynos_drm_gem_put_pages(struct
> >> >>>> drm_gem_object *obj)
> >> >>>> >        /* add some codes for UNCACHED type here. TODO */
> >> >>>> >  }
> >> >>>> >
> >> >>>> > +static void exynos_drm_put_userptr(struct drm_gem_object *obj)
> >> >>>> > +{
> >> >>>> > +       struct exynos_drm_gem_obj *exynos_gem_obj;
> >> >>>> > +       struct exynos_drm_gem_buf *buf;
> >> >>>> > +       struct vm_area_struct *vma;
> >> >>>> > +       int npages;
> >> >>>> > +
> >> >>>> > +       exynos_gem_obj = to_exynos_gem_obj(obj);
> >> >>>> > +       buf = exynos_gem_obj->buffer;
> >> >>>> > +       vma = exynos_gem_obj->vma;
> >> >>>> > +
> >> >>>> > +       if (vma && (vma->vm_flags & VM_PFNMAP) &&
(vma->vm_pgoff))
> > {
> >> >>>> > +               put_vma(exynos_gem_obj->vma);
> >> >>>> > +               goto out;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       npages = buf->size >> PAGE_SHIFT;
> >> >>>> > +
> >> >>>> > +       npages--;
> >> >>>> > +       while (npages >= 0) {
> >> >>>> > +               if (buf->write)
> >> >>>> > +                       set_page_dirty_lock(buf->pages[npages]);
> >> >>>> > +
> >> >>>> > +               put_page(buf->pages[npages]);
> >> >>>> > +               npages--;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +out:
> >> >>>> > +       kfree(buf->pages);
> >> >>>> > +       buf->pages = NULL;
> >> >>>> > +
> >> >>>> > +       kfree(buf->sgt);
> >> >>>> > +       buf->sgt = NULL;
> >> >>>> > +}
> >> >>>> > +
> >> >>>> >  static int exynos_drm_gem_handle_create(struct drm_gem_object
> > *obj,
> >> >>>> >                                        struct drm_file
*file_priv,
> >> >>>> >                                        unsigned int *handle)
> >> >>>> > @@ -293,6 +365,8 @@ void exynos_drm_gem_destroy(struct
> >> >>>> exynos_drm_gem_obj *exynos_gem_obj)
> >> >>>> >
> >> >>>> >        if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG)
> >> >>>> >                exynos_drm_gem_put_pages(obj);
> >> >>>> > +       else if (exynos_gem_obj->flags & EXYNOS_BO_USERPTR)
> >> >>>> > +               exynos_drm_put_userptr(obj);
> >> >>>> >        else
> >> >>>> >                exynos_drm_free_buf(obj->dev,
exynos_gem_obj->flags,
> >> >>> buf);
> >> >>>> >
> >> >>>> > @@ -606,6 +680,190 @@ int exynos_drm_gem_mmap_ioctl(struct
> >> drm_device
> >> >>>> *dev, void *data,
> >> >>>> >        return 0;
> >> >>>> >  }
> >> >>>> >
> >> >>>> > +static int exynos_drm_get_userptr(struct drm_device *dev,
> >> >>>> > +                               struct exynos_drm_gem_obj *obj,
> >> >>>> > +                               unsigned long userptr,
> >> >>>> > +                               unsigned int write)
> >> >>>> > +{
> >> >>>> > +       unsigned int get_npages;
> >> >>>> > +       unsigned long npages = 0;
> >> >>>> > +       struct vm_area_struct *vma;
> >> >>>> > +       struct exynos_drm_gem_buf *buf = obj->buffer;
> >> >>>> > +
> >> >>>> > +       vma = find_vma(current->mm, userptr);
> >> >>>> > +
> >> >>>> > +       /* the memory region mmaped with VM_PFNMAP. */
> >> >>>> > +       if (vma && (vma->vm_flags & VM_PFNMAP) &&
(vma->vm_pgoff))
> > {
> >> >>>> > +               unsigned long this_pfn, prev_pfn, pa;
> >> >>>> > +               unsigned long start, end, offset;
> >> >>>> > +               struct scatterlist *sgl;
> >> >>>> > +
> >> >>>> > +               start = userptr;
> >> >>>> > +               offset = userptr & ~PAGE_MASK;
> >> >>>> > +               end = start + buf->size;
> >> >>>> > +               sgl = buf->sgt->sgl;
> >> >>>> > +
> >> >>>> > +               for (prev_pfn = 0; start < end; start +=
PAGE_SIZE)
> > {
> >> >>>> > +                       int ret = follow_pfn(vma, start,
> > &this_pfn);
> >> >>>> > +                       if (ret)
> >> >>>> > +                               return ret;
> >> >>>> > +
> >> >>>> > +                       if (prev_pfn == 0)
> >> >>>> > +                               pa = this_pfn << PAGE_SHIFT;
> >> >>>> > +                       else if (this_pfn != prev_pfn + 1)
> >> >>>> > +                               return -EFAULT;
> >> >>>> > +
> >> >>>> > +                       sg_dma_address(sgl) = (pa + offset);
> >> >>>> > +                       sg_dma_len(sgl) = PAGE_SIZE;
> >> >>>> > +                       prev_pfn = this_pfn;
> >> >>>> > +                       pa += PAGE_SIZE;
> >> >>>> > +                       npages++;
> >> >>>> > +                       sgl = sg_next(sgl);
> >> >>>> > +               }
> >> >>>> > +
> >> >>>> > +               buf->dma_addr = pa + offset;
> >> >>>> > +
> >> >>>> > +               obj->vma = get_vma(vma);
> >> >>>> > +               if (!obj->vma)
> >> >>>> > +                       return -ENOMEM;
> >> >>>> > +
> >> >>>> > +               buf->pfnmap = true;
> >> >>>> > +
> >> >>>> > +               return npages;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       buf->write = write;
> >> >>>> > +       npages = buf->size >> PAGE_SHIFT;
> >> >>>> > +
> >> >>>> > +       down_read(&current->mm->mmap_sem);
> >> >>>> > +       get_npages = get_user_pages(current, current->mm,
userptr,
> >> >>>> > +                                       npages, write, 1,
> > buf->pages,
> >> >>> NULL);
> >> >>>> > +       up_read(&current->mm->mmap_sem);
> >> >>>> > +       if (get_npages != npages)
> >> >>>> > +               DRM_ERROR("failed to get user_pages.\n");
> >> >>>> > +
> >> >>>> > +       buf->pfnmap = false;
> >> >>>> > +
> >> >>>> > +       return get_npages;
> >> >>>> > +}
> >> >>>> > +
> >> >>>> > +int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void
> >> *data,
> >> >>>> > +                                     struct drm_file
*file_priv)
> >> >>>> > +{
> >> >>>> > +       struct exynos_drm_gem_obj *exynos_gem_obj;
> >> >>>> > +       struct drm_exynos_gem_userptr *args = data;
> >> >>>> > +       struct exynos_drm_gem_buf *buf;
> >> >>>> > +       struct scatterlist *sgl;
> >> >>>> > +       unsigned long size, userptr;
> >> >>>> > +       unsigned int npages;
> >> >>>> > +       int ret, get_npages;
> >> >>>> > +
> >> >>>> > +       DRM_DEBUG_KMS("%s\n", __FILE__);
> >> >>>> > +
> >> >>>> > +       if (!args->size) {
> >> >>>> > +               DRM_ERROR("invalid size.\n");
> >> >>>> > +               return -EINVAL;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       ret = check_gem_flags(args->flags);
> >> >>>> > +       if (ret)
> >> >>>> > +               return ret;
> >> >>>> > +
> >> >>>> > +       size = roundup_gem_size(args->size, EXYNOS_BO_USERPTR);
> >> >>>> > +       userptr = args->userptr;
> >> >>>> > +
> >> >>>> > +       buf = exynos_drm_init_buf(dev, size);
> >> >>>> > +       if (!buf)
> >> >>>> > +               return -ENOMEM;
> >> >>>> > +
> >> >>>> > +       exynos_gem_obj = exynos_drm_gem_init(dev, size);
> >> >>>> > +       if (!exynos_gem_obj) {
> >> >>>> > +               ret = -ENOMEM;
> >> >>>> > +               goto err_free_buffer;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
> >> >>>> > +       if (!buf->sgt) {
> >> >>>> > +               DRM_ERROR("failed to allocate buf->sgt.\n");
> >> >>>> > +               ret = -ENOMEM;
> >> >>>> > +               goto err_release_gem;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       npages = size >> PAGE_SHIFT;
> >> >>>> > +
> >> >>>> > +       ret = sg_alloc_table(buf->sgt, npages, GFP_KERNEL);
> >> >>>> > +       if (ret < 0) {
> >> >>>> > +               DRM_ERROR("failed to initailize sg table.\n");
> >> >>>> > +               goto err_free_sgt;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       buf->pages = kzalloc(npages * sizeof(struct page *),
> >> >>> GFP_KERNEL);
> >> >>>> > +       if (!buf->pages) {
> >> >>>> > +               DRM_ERROR("failed to allocate buf->pages\n");
> >> >>>> > +               ret = -ENOMEM;
> >> >>>> > +               goto err_free_table;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       exynos_gem_obj->buffer = buf;
> >> >>>> > +
> >> >>>> > +       get_npages = exynos_drm_get_userptr(dev, exynos_gem_obj,
> >> >>> userptr,
> >> >>>> 1);
> >> >>>> > +       if (get_npages != npages) {
> >> >>>> > +               DRM_ERROR("failed to get user_pages.\n");
> >> >>>> > +               ret = get_npages;
> >> >>>> > +               goto err_release_userptr;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       ret =
exynos_drm_gem_handle_create(&exynos_gem_obj->base,
> >> >>>> file_priv,
> >> >>>> > +                                               &args->handle);
> >> >>>> > +       if (ret < 0) {
> >> >>>> > +               DRM_ERROR("failed to create gem handle.\n");
> >> >>>> > +               goto err_release_userptr;
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       sgl = buf->sgt->sgl;
> >> >>>> > +
> >> >>>> > +       /*
> >> >>>> > +        * if buf->pfnmap is true then update sgl of sgt with
> pages
> >> but
> >> >>>> > +        * if buf->pfnmap is false then it means the sgl was
> > updated
> >> >>>> already
> >> >>>> > +        * so it doesn't need to update the sgl.
> >> >>>> > +        */
> >> >>>> > +       if (!buf->pfnmap) {
> >> >>>> > +               unsigned int i = 0;
> >> >>>> > +
> >> >>>> > +               /* set all pages to sg list. */
> >> >>>> > +               while (i < npages) {
> >> >>>> > +                       sg_set_page(sgl, buf->pages[i],
PAGE_SIZE,
> > 0);
> >> >>>> > +                       sg_dma_address(sgl) =
> >> >>> page_to_phys(buf->pages[i]);
> >> >>>> > +                       i++;
> >> >>>> > +                       sgl = sg_next(sgl);
> >> >>>> > +               }
> >> >>>> > +       }
> >> >>>> > +
> >> >>>> > +       /* always use EXYNOS_BO_USERPTR as memory type for
> userptr.
> >> */
> >> >>>> > +       exynos_gem_obj->flags |= EXYNOS_BO_USERPTR;
> >> >>>> > +
> >> >>>> > +       return 0;
> >> >>>> > +
> >> >>>> > +err_release_userptr:
> >> >>>> > +       get_npages--;
> >> >>>> > +       while (get_npages >= 0)
> >> >>>> > +               put_page(buf->pages[get_npages--]);
> >> >>>> > +       kfree(buf->pages);
> >> >>>> > +       buf->pages = NULL;
> >> >>>> > +err_free_table:
> >> >>>> > +       sg_free_table(buf->sgt);
> >> >>>> > +err_free_sgt:
> >> >>>> > +       kfree(buf->sgt);
> >> >>>> > +       buf->sgt = NULL;
> >> >>>> > +err_release_gem:
> >> >>>> > +       drm_gem_object_release(&exynos_gem_obj->base);
> >> >>>> > +       kfree(exynos_gem_obj);
> >> >>>> > +       exynos_gem_obj = NULL;
> >> >>>> > +err_free_buffer:
> >> >>>> > +       exynos_drm_free_buf(dev, 0, buf);
> >> >>>> > +       return ret;
> >> >>>> > +}
> >> >>>> > +
> >> >>>> >  int exynos_drm_gem_init_object(struct drm_gem_object *obj)
> >> >>>> >  {
> >> >>>> >        DRM_DEBUG_KMS("%s\n", __FILE__);
> >> >>>> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h
> >> >>>> b/drivers/gpu/drm/exynos/exynos_drm_gem.h
> >> >>>> > index efc8252..1de2241 100644
> >> >>>> > --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
> >> >>>> > +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
> >> >>>> > @@ -29,7 +29,8 @@
> >> >>>> >  #define to_exynos_gem_obj(x)   container_of(x,\
> >> >>>> >                        struct exynos_drm_gem_obj, base)
> >> >>>> >
> >> >>>> > -#define IS_NONCONTIG_BUFFER(f)         (f &
EXYNOS_BO_NONCONTIG)
> >> >>>> > +#define IS_NONCONTIG_BUFFER(f)         ((f &
EXYNOS_BO_NONCONTIG)
> >> ||\
> >> >>>> > +                                       (f & EXYNOS_BO_USERPTR))
> >> >>>> >
> >> >>>> >  /*
> >> >>>> >  * exynos drm gem buffer structure.
> >> >>>> > @@ -38,18 +39,23 @@
> >> >>>> >  * @dma_addr: bus address(accessed by dma) to allocated memory
> >> region.
> >> >>>> >  *     - this address could be physical address without IOMMU
and
> >> >>>> >  *     device address with IOMMU.
> >> >>>> > + * @write: whether pages will be written to by the caller.
> >> >>>> >  * @sgt: sg table to transfer page data.
> >> >>>> >  * @pages: contain all pages to allocated memory region.
> >> >>>> >  * @page_size: could be 4K, 64K or 1MB.
> >> >>>> >  * @size: size of allocated memory region.
> >> >>>> > + * @pfnmap: indicate whether memory region from userptr is
> mmaped
> >> with
> >> >>>> > + *     VM_PFNMAP or not.
> >> >>>> >  */
> >> >>>> >  struct exynos_drm_gem_buf {
> >> >>>> >        void __iomem            *kvaddr;
> >> >>>> >        dma_addr_t              dma_addr;
> >> >>>> > +       unsigned int            write;
> >> >>>> >        struct sg_table         *sgt;
> >> >>>> >        struct page             **pages;
> >> >>>> >        unsigned long           page_size;
> >> >>>> >        unsigned long           size;
> >> >>>> > +       bool                    pfnmap;
> >> >>>> >  };
> >> >>>> >
> >> >>>> >  /*
> >> >>>> > @@ -73,6 +79,7 @@ struct exynos_drm_gem_obj {
> >> >>>> >        struct drm_gem_object           base;
> >> >>>> >        struct exynos_drm_gem_buf       *buffer;
> >> >>>> >        unsigned long                   size;
> >> >>>> > +       struct vm_area_struct           *vma;
> >> >>>> >        unsigned int                    flags;
> >> >>>> >  };
> >> >>>> >
> >> >>>> > @@ -127,6 +134,10 @@ int exynos_drm_gem_map_offset_ioctl(struct
> >> >>>> drm_device *dev, void *data,
> >> >>>> >  int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void
> *data,
> >> >>>> >                              struct drm_file *file_priv);
> >> >>>> >
> >> >>>> > +/* map user space allocated by malloc to pages. */
> >> >>>> > +int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void
> >> *data,
> >> >>>> > +                                     struct drm_file
*file_priv);
> >> >>>> > +
> >> >>>> >  /* initialize gem object. */
> >> >>>> >  int exynos_drm_gem_init_object(struct drm_gem_object *obj);
> >> >>>> >
> >> >>>> > diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
> >> >>>> > index 2d6eb06..48eda6e 100644
> >> >>>> > --- a/include/drm/exynos_drm.h
> >> >>>> > +++ b/include/drm/exynos_drm.h
> >> >>>> > @@ -75,6 +75,23 @@ struct drm_exynos_gem_mmap {
> >> >>>> >  };
> >> >>>> >
> >> >>>> >  /**
> >> >>>> > + * User-requested user space importing structure
> >> >>>> > + *
> >> >>>> > + * @userptr: user space address allocated by malloc.
> >> >>>> > + * @size: size to the buffer allocated by malloc.
> >> >>>> > + * @flags: indicate user-desired cache attribute to map the
> >> allocated
> >> >>>> buffer
> >> >>>> > + *     to kernel space.
> >> >>>> > + * @handle: a returned handle to created gem object.
> >> >>>> > + *     - this handle will be set by gem module of kernel side.
> >> >>>> > + */
> >> >>>> > +struct drm_exynos_gem_userptr {
> >> >>>> > +       uint64_t userptr;
> >> >>>> > +       uint64_t size;
> >> >>>> > +       unsigned int flags;
> >> >>>> > +       unsigned int handle;
> >> >>>> > +};
> >> >>>> > +
> >> >>>> > +/**
> >> >>>> >  * A structure for user connection request of virtual display.
> >> >>>> >  *
> >> >>>> >  * @connection: indicate whether doing connetion or not by user.
> >> >>>> > @@ -105,13 +122,16 @@ enum e_drm_exynos_gem_mem_type {
> >> >>>> >        EXYNOS_BO_CACHABLE      = 1 << 1,
> >> >>>> >        /* write-combine mapping. */
> >> >>>> >        EXYNOS_BO_WC            = 1 << 2,
> >> >>>> > +       /* user space memory allocated by malloc. */
> >> >>>> > +       EXYNOS_BO_USERPTR       = 1 << 3,
> >> >>>> >        EXYNOS_BO_MASK          = EXYNOS_BO_NONCONTIG |
> >> >>> EXYNOS_BO_CACHABLE
> >> >>>> |
> >> >>>> > -                                       EXYNOS_BO_WC
> >> >>>> > +                                       EXYNOS_BO_WC |
> > EXYNOS_BO_USERPTR
> >> >>>> >  };
> >> >>>> >
> >> >>>> >  #define DRM_EXYNOS_GEM_CREATE          0x00
> >> >>>> >  #define DRM_EXYNOS_GEM_MAP_OFFSET      0x01
> >> >>>> >  #define DRM_EXYNOS_GEM_MMAP            0x02
> >> >>>> > +#define DRM_EXYNOS_GEM_USERPTR         0x03
> >> >>>> >  /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
> >> >>>> >  #define DRM_EXYNOS_PLANE_SET_ZPOS      0x06
> >> >>>> >  #define DRM_EXYNOS_VIDI_CONNECTION     0x07
> >> >>>> > @@ -125,6 +145,9 @@ enum e_drm_exynos_gem_mem_type {
> >> >>>> >  #define DRM_IOCTL_EXYNOS_GEM_MMAP    
 DRM_IOWR(DRM_COMMAND_BASE
> +
> >> \
> >> >>>> >                DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap)
> >> >>>> >
> >> >>>> > +#define
> DRM_IOCTL_EXYNOS_GEM_USERPTR   DRM_IOWR(DRM_COMMAND_BASE +
> >> \
> >> >>>> > +               DRM_EXYNOS_GEM_USERPTR, struct
> > drm_exynos_gem_userptr)
> >> >>>> > +
> >> >>>> >  #define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS
> >> >>>  DRM_IOWR(DRM_COMMAND_BASE
> >> >>>> + \
> >> >>>> >                DRM_EXYNOS_PLANE_SET_ZPOS, struct
> >> >>> drm_exynos_plane_set_zpos)
> >> >>>> >
> >> >>>> > --
> >> >>>> > 1.7.4.1
> >> >>>> >
> >> >>>> > _______________________________________________
> >> >>>> > dri-devel mailing list
> >> >>>> > dri-devel at lists.freedesktop.org
> >> >>>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >> >>>
> >> >>> _______________________________________________
> >> >>> dri-devel mailing list
> >> >>> dri-devel at lists.freedesktop.org
> >> >>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >> >> _______________________________________________
> >> >> dri-devel mailing list
> >> >> dri-devel at lists.freedesktop.org
> >> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >> > _______________________________________________
> >> > dri-devel mailing list
> >> > dri-devel at lists.freedesktop.org
> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel



More information about the dri-devel mailing list