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

Rob Clark rob.clark at linaro.org
Wed May 16 01:42:42 PDT 2012


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.

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