On Tue, May 15, 2012 at 7:40 AM, InKi Dae <daeinki@xxxxxxxxx> wrote: > 2012/5/15 Rob Clark <rob.clark@xxxxxxxxxx>: >> On Tue, May 15, 2012 at 2:17 AM, Inki Dae <inki.dae@xxxxxxxxxxx> wrote: >>> Hi Rob, >>> >>>> -----Original Message----- >>>> From: robdclark@xxxxxxxxx [mailto:robdclark@xxxxxxxxx] On Behalf Of Rob >>>> Clark >>>> Sent: Tuesday, May 15, 2012 4:35 PM >>>> To: Inki Dae >>>> Cc: airlied@xxxxxxxx; dri-devel@xxxxxxxxxxxxxxxxxxxxx; >>>> kyungmin.park@xxxxxxxxxxx; sw0312.kim@xxxxxxxxxxx >>>> Subject: Re: [PATCH 3/4] drm/exynos: added userptr feature. >>>> >>>> On Mon, Apr 23, 2012 at 7:43 AM, Inki Dae <inki.dae@xxxxxxxxxxx> 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? 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.. > 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@xxxxxxxxxxx> >>>> > Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> >>>> > --- >>>> > 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(¤t->mm->mmap_sem); >>>> > + get_npages = get_user_pages(current, current->mm, userptr, >>>> > + npages, write, 1, buf->pages, >>> NULL); >>>> > + up_read(¤t->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@xxxxxxxxxxxxxxxxxxxxx >>>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel >>> >>> _______________________________________________ >>> dri-devel mailing list >>> dri-devel@xxxxxxxxxxxxxxxxxxxxx >>> http://lists.freedesktop.org/mailman/listinfo/dri-devel >> _______________________________________________ >> dri-devel mailing list >> dri-devel@xxxxxxxxxxxxxxxxxxxxx >> http://lists.freedesktop.org/mailman/listinfo/dri-devel > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/dri-devel _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel