[PATCH] Mapping snooped user pages into the GTT

april aapril03 at gmail.com
Tue Jan 11 23:40:33 PST 2011


Dear  Chris:

what do u mean " blit between snooped and unsnooped memory"?
It seems you want to map user-space pixmap to GTT space, and use 2d
copy to do upload/download?

TTM can map user space memory to GTT aperture by using
"ttm_bo_type_user", but no dirver use it yet.??

Thanks

2011/1/8 Chris Wilson <chris at chris-wilson.co.uk>:
> I've been looking at how we can improve upload/download performance on our
> UMA gfx. One under-used aspect of the IGP is its ability to blit between
> snooped-and-unsnooped memory i.e. from normal ram into the GTT. Only the
> BLT has this ability, almost all other functions of the GPU most be from
> unsnooped memory. SNB introduces its own cache handling that we need to
> exploit further, however the BLT remains and is orders of magnitude faster
> for read back than an UC read by the CPU...
>
> It is surprisingly simple to replace the shmem_getpage with
> get_user_pages and insert a user-bo into the GTT. The downside is that
> this pins user-memory until it becomes inactive and so care needs to be
> taken by the client to synchronize appropriately. Another issue that I've
> not dealt with successfully is tracking memory protection on user pages.
> Different processes will need different protection on potentially the same
> PTEs. (I've also looked at implementing 2D pwrite/pread using the BLT but
> I'm dissatisfied with the per-request overhead; though that too is still
> many times faster for pread.)
>
> I'm slightly concerned about pinning user-memory for undeterminable
> lengths of time. However, this is no worse than any other bo, and the
> pages will be reaped under memory pressure by eviction.
>
> Any other comments or suggestions?
> -Chris
>
> ---
>  drivers/gpu/drm/drm_gem.c              |    3 +-
>  drivers/gpu/drm/i915/Makefile          |    1 +
>  drivers/gpu/drm/i915/i915_dma.c        |    3 +-
>  drivers/gpu/drm/i915/i915_drv.h        |   12 +++
>  drivers/gpu/drm/i915/i915_gem.c        |   93 ++++++++++++++------
>  drivers/gpu/drm/i915/i915_gem_gtt.c    |    4 +-
>  drivers/gpu/drm/i915/i915_gem_io.c     |   10 ++
>  drivers/gpu/drm/i915/i915_gem_tiling.c |    5 +
>  drivers/gpu/drm/i915/i915_gem_vmap.c   |  145 ++++++++++++++++++++++++++++++++
>  include/drm/i915_drm.h                 |   16 ++++
>  10 files changed, 260 insertions(+), 32 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/i915_gem_vmap.c
>
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index ea1c4b0..adb886a 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -425,7 +425,8 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
>  void
>  drm_gem_object_release(struct drm_gem_object *obj)
>  {
> -       fput(obj->filp);
> +       if (obj->filp)
> +               fput(obj->filp);
>  }
>  EXPORT_SYMBOL(drm_gem_object_release);
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 07a351f..4b901c5 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -13,6 +13,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
>          i915_gem_gtt.o \
>          i915_gem_io.o \
>          i915_gem_tiling.o \
> +         i915_gem_vmap.o \
>          i915_trace_points.o \
>          intel_display.o \
>          intel_crt.o \
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 8def614..52efa11 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -783,7 +783,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
>                value = INTEL_INFO(dev)->gen >= 4;
>                break;
>        case I915_PARAM_HAS_2D_IO:
> -               /* depends on GEM */
> +       case I915_PARAM_HAS_VMAP:
>                value = dev_priv->has_gem;
>                break;
>        default:
> @@ -2256,6 +2256,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
>        DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>        DRM_IOCTL_DEF_DRV(I915_GEM_PREAD_2D, i915_gem_pread_2d_ioctl, DRM_UNLOCKED),
>        DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE_2D, i915_gem_pwrite_2d_ioctl, DRM_UNLOCKED),
> +       DRM_IOCTL_DEF_DRV(I915_GEM_VMAP, i915_gem_vmap_ioctl, DRM_UNLOCKED),
>  };
>
>  int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 64033cc..6899bde 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -695,6 +695,11 @@ typedef struct drm_i915_private {
>        struct intel_fbdev *fbdev;
>  } drm_i915_private_t;
>
> +struct drm_i915_gem_object_ops {
> +       int (*get_pages)(struct drm_i915_gem_object *, gfp_t, u32 *offset);
> +       void (*put_pages)(struct drm_i915_gem_object *);
> +};
> +
>  struct drm_i915_gem_object {
>        struct drm_gem_object base;
>
> @@ -782,6 +787,7 @@ struct drm_i915_gem_object {
>        unsigned int fenced_gpu_access:1;
>
>        struct page **pages;
> +       int num_pages;
>
>        /**
>         * DMAR support
> @@ -1097,6 +1103,7 @@ void i915_gem_flush_ring(struct drm_device *dev,
>                         uint32_t flush_domains);
>  struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
>                                                  size_t size);
> +void i915_gem_object_init(struct drm_i915_gem_object *obj);
>  void i915_gem_free_object(struct drm_gem_object *obj);
>  int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
>                                     uint32_t alignment,
> @@ -1113,6 +1120,11 @@ void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
>                                    struct intel_ring_buffer *ring,
>                                    u32 seqno);
>
> +/* i915_gem_vmap.c */
> +int
> +i915_gem_vmap_ioctl(struct drm_device *dev, void *data,
> +                   struct drm_file *file);
> +
>  /**
>  * Returns true if seq1 is later than seq2.
>  */
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 439ad78..d529de4 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -513,6 +513,12 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
>                goto unlock;
>        }
>
> +       if (obj->agp_type == AGP_USER_CACHED_MEMORY) {
> +               /* XXX worth handling? */
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
>        /* Bounds check source.  */
>        if (args->offset > obj->base.size ||
>            args->size > obj->base.size - args->offset) {
> @@ -954,6 +960,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
>                goto unlock;
>        }
>
> +       if (obj->agp_type == AGP_USER_CACHED_MEMORY) {
> +               /* XXX worth handling? */
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
>        /* Bounds check destination. */
>        if (args->offset > obj->base.size ||
>            args->size > obj->base.size - args->offset) {
> @@ -1125,6 +1137,11 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
>        if (obj == NULL)
>                return -ENOENT;
>
> +       if (to_intel_bo(obj)->agp_type == AGP_USER_CACHED_MEMORY) {
> +               drm_gem_object_unreference_unlocked(obj);
> +               return -EINVAL;
> +       }
> +
>        if (obj->size > dev_priv->mm.gtt_mappable_end) {
>                drm_gem_object_unreference_unlocked(obj);
>                return -E2BIG;
> @@ -1484,25 +1501,26 @@ unlock:
>
>  static int
>  i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
> -                             gfp_t gfpmask)
> +                             gfp_t gfpmask,
> +                             u32 *offset)
>  {
> -       int page_count, i;
>        struct address_space *mapping;
>        struct inode *inode;
>        struct page *page;
> +       int i;
>
>        /* Get the list of pages out of our struct file.  They'll be pinned
>         * at this point until we release them.
>         */
> -       page_count = obj->base.size / PAGE_SIZE;
> +       obj->num_pages = obj->base.size / PAGE_SIZE;
>        BUG_ON(obj->pages != NULL);
> -       obj->pages = drm_malloc_ab(page_count, sizeof(struct page *));
> +       obj->pages = drm_malloc_ab(obj->num_pages, sizeof(struct page *));
>        if (obj->pages == NULL)
>                return -ENOMEM;
>
>        inode = obj->base.filp->f_path.dentry->d_inode;
>        mapping = inode->i_mapping;
> -       for (i = 0; i < page_count; i++) {
> +       for (i = 0; i < obj->num_pages; i++) {
>                page = read_cache_page_gfp(mapping, i,
>                                           GFP_HIGHUSER |
>                                           __GFP_COLD |
> @@ -1517,6 +1535,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
>        if (obj->tiling_mode != I915_TILING_NONE)
>                i915_gem_object_do_bit_17_swizzle(obj);
>
> +       *offset = 0;
>        return 0;
>
>  err_pages:
> @@ -1531,7 +1550,6 @@ err_pages:
>  static void
>  i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
>  {
> -       int page_count = obj->base.size / PAGE_SIZE;
>        int i;
>
>        BUG_ON(obj->madv == __I915_MADV_PURGED);
> @@ -1542,7 +1560,7 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
>        if (obj->madv == I915_MADV_DONTNEED)
>                obj->dirty = 0;
>
> -       for (i = 0; i < page_count; i++) {
> +       for (i = 0; i < obj->num_pages; i++) {
>                if (obj->dirty)
>                        set_page_dirty(obj->pages[i]);
>
> @@ -1643,6 +1661,9 @@ i915_gem_object_truncate(struct drm_i915_gem_object *obj)
>  {
>        struct inode *inode;
>
> +       if (obj->base.filp == NULL)
> +               return;
> +
>        /* Our goal here is to return as much of the memory as
>         * is possible back to the system as we are called from OOM.
>         * To do this we must instruct the shmfs to drop all of its
> @@ -2090,6 +2111,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
>  int
>  i915_gem_object_unbind(struct drm_i915_gem_object *obj)
>  {
> +       const struct drm_i915_gem_object_ops *ops = obj->base.driver_private;
>        int ret = 0;
>
>        if (obj->gtt_space == NULL)
> @@ -2127,7 +2149,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
>                return ret;
>
>        i915_gem_gtt_unbind_object(obj);
> -       i915_gem_object_put_pages_gtt(obj);
> +       ops->put_pages(obj);
>
>        list_del_init(&obj->gtt_list);
>        list_del_init(&obj->mm_list);
> @@ -2667,11 +2689,13 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
>                            unsigned alignment,
>                            bool map_and_fenceable)
>  {
> +       const struct drm_i915_gem_object_ops *ops = obj->base.driver_private;
>        struct drm_device *dev = obj->base.dev;
>        drm_i915_private_t *dev_priv = dev->dev_private;
>        struct drm_mm_node *free_space;
>        gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
>        u32 size, fence_size, fence_alignment, unfenced_alignment;
> +       u32 offset;
>        bool mappable, fenceable;
>        int ret;
>
> @@ -2737,7 +2761,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
>                goto search_free;
>        }
>
> -       ret = i915_gem_object_get_pages_gtt(obj, gfpmask);
> +       ret = ops->get_pages(obj, gfpmask, &offset);
>        if (ret) {
>                drm_mm_put_block(obj->gtt_space);
>                obj->gtt_space = NULL;
> @@ -2765,7 +2789,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
>
>        ret = i915_gem_gtt_bind_object(obj);
>        if (ret) {
> -               i915_gem_object_put_pages_gtt(obj);
> +               ops->put_pages(obj);
>                drm_mm_put_block(obj->gtt_space);
>                obj->gtt_space = NULL;
>
> @@ -2787,11 +2811,11 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
>        BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
>        BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
>
> -       obj->gtt_offset = obj->gtt_space->start;
> +       obj->gtt_offset = obj->gtt_space->start + offset;
>
>        fenceable =
>                obj->gtt_space->size == fence_size &&
> -               (obj->gtt_space->start & (fence_alignment -1)) == 0;
> +               (obj->gtt_offset & (fence_alignment -1)) == 0;
>
>        mappable =
>                obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end;
> @@ -2809,7 +2833,7 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj)
>         * to GPU, and we can ignore the cache flush because it'll happen
>         * again at bind time.
>         */
> -       if (obj->pages == NULL)
> +       if (obj->pages == NULL || obj->agp_type == AGP_USER_CACHED_MEMORY)
>                return;
>
>        trace_i915_gem_object_clflush(obj);
> @@ -3464,6 +3488,31 @@ unlock:
>        return ret;
>  }
>
> +void
> +i915_gem_object_init(struct drm_i915_gem_object *obj)
> +{
> +       obj->base.write_domain = I915_GEM_DOMAIN_CPU;
> +       obj->base.read_domains = I915_GEM_DOMAIN_CPU;
> +
> +       obj->agp_type = AGP_USER_MEMORY;
> +
> +       obj->fence_reg = I915_FENCE_REG_NONE;
> +       INIT_LIST_HEAD(&obj->mm_list);
> +       INIT_LIST_HEAD(&obj->gtt_list);
> +       INIT_LIST_HEAD(&obj->ring_list);
> +       INIT_LIST_HEAD(&obj->exec_list);
> +       INIT_LIST_HEAD(&obj->gpu_write_list);
> +       obj->madv = I915_MADV_WILLNEED;
> +
> +       /* Avoid an unnecessary call to unbind on the first bind. */
> +       obj->map_and_fenceable = true;
> +}
> +
> +static const struct drm_i915_gem_object_ops i915_gem_object_ops = {
> +       .get_pages = i915_gem_object_get_pages_gtt,
> +       .put_pages = i915_gem_object_put_pages_gtt,
> +};
> +
>  struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
>                                                  size_t size)
>  {
> @@ -3479,22 +3528,10 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
>                return NULL;
>        }
>
> -       i915_gem_info_add_obj(dev_priv, size);
> +       obj->base.driver_private = (void *)&i915_gem_object_ops;
>
> -       obj->base.write_domain = I915_GEM_DOMAIN_CPU;
> -       obj->base.read_domains = I915_GEM_DOMAIN_CPU;
> -
> -       obj->agp_type = AGP_USER_MEMORY;
> -       obj->base.driver_private = NULL;
> -       obj->fence_reg = I915_FENCE_REG_NONE;
> -       INIT_LIST_HEAD(&obj->mm_list);
> -       INIT_LIST_HEAD(&obj->gtt_list);
> -       INIT_LIST_HEAD(&obj->ring_list);
> -       INIT_LIST_HEAD(&obj->exec_list);
> -       INIT_LIST_HEAD(&obj->gpu_write_list);
> -       obj->madv = I915_MADV_WILLNEED;
> -       /* Avoid an unnecessary call to unbind on the first bind. */
> -       obj->map_and_fenceable = true;
> +       i915_gem_object_init(obj);
> +       i915_gem_info_add_obj(dev_priv, size);
>
>        return obj;
>  }
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index 92161bb..429f529 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -64,7 +64,7 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
>
>        if (dev_priv->mm.gtt->needs_dmar) {
>                ret = intel_gtt_map_memory(obj->pages,
> -                                          obj->base.size >> PAGE_SHIFT,
> +                                          obj->num_pages,
>                                           &obj->sg_list,
>                                           &obj->num_sg);
>                if (ret != 0)
> @@ -76,7 +76,7 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
>                                            obj->agp_type);
>        } else
>                intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
> -                                      obj->base.size >> PAGE_SHIFT,
> +                                      obj->num_pages,
>                                       obj->pages,
>                                       obj->agp_type);
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_io.c b/drivers/gpu/drm/i915/i915_gem_io.c
> index 6c1def1..e83b8e3 100644
> --- a/drivers/gpu/drm/i915/i915_gem_io.c
> +++ b/drivers/gpu/drm/i915/i915_gem_io.c
> @@ -549,6 +549,11 @@ i915_gem_pwrite_2d_ioctl(struct drm_device *dev,
>                goto unlock;
>        }
>
> +       if (obj->agp_type == AGP_USER_CACHED_MEMORY) {
> +               ret = -EINVAL;
> +               goto unref;
> +       }
> +
>        /* Bounds check destination. */
>        offset = args->dst_x * args->cpp + args->dst_y * args->dst_stride;
>        size = args->dst_stride * (args->height-1) + args->width * args->cpp;
> @@ -961,6 +966,11 @@ i915_gem_pread_2d_ioctl(struct drm_device *dev,
>                goto unlock;
>        }
>
> +       if (obj->agp_type == AGP_USER_CACHED_MEMORY) {
> +               ret = -EINVAL;
> +               goto unref;
> +       }
> +
>        /* Bounds check source. */
>        offset = args->src_x * args->cpp + args->src_y * args->src_stride;
>        size = args->src_stride * (args->height-1) + args->width * args->cpp;
> diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
> index 22a32b9..3a9c88e 100644
> --- a/drivers/gpu/drm/i915/i915_gem_tiling.c
> +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
> @@ -294,6 +294,11 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
>        if (obj == NULL)
>                return -ENOENT;
>
> +       if (obj->agp_type == AGP_USER_CACHED_MEMORY) {
> +               drm_gem_object_unreference_unlocked(&obj->base);
> +               return -EINVAL;
> +       }
> +
>        if (!i915_tiling_ok(dev,
>                            args->stride, obj->base.size, args->tiling_mode)) {
>                drm_gem_object_unreference_unlocked(&obj->base);
> diff --git a/drivers/gpu/drm/i915/i915_gem_vmap.c b/drivers/gpu/drm/i915/i915_gem_vmap.c
> new file mode 100644
> index 0000000..780a514
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/i915_gem_vmap.c
> @@ -0,0 +1,145 @@
> +/*
> + * Copyright © 2010 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#include "drmP.h"
> +#include "drm.h"
> +#include "i915_drm.h"
> +#include "i915_drv.h"
> +#include "i915_trace.h"
> +#include "intel_drv.h"
> +#include <linux/swap.h>
> +
> +struct i915_gem_vmap_object {
> +       struct drm_i915_gem_object gem;
> +       uintptr_t user_ptr;
> +       int read_only;
> +};
> +
> +static struct i915_gem_vmap_object *to_vmap_object(struct drm_i915_gem_object *obj)
> +{
> +       return container_of(obj, struct i915_gem_vmap_object, gem);
> +}
> +
> +static int
> +i915_gem_vmap_get_pages(struct drm_i915_gem_object *obj, gfp_t gfp, u32 *offset)
> +{
> +       struct i915_gem_vmap_object *vmap = to_vmap_object(obj);
> +       loff_t first_data_page, last_data_page;
> +       int pinned_pages, i;
> +
> +       if (!access_ok(vmap->read_only ? VERIFY_READ : VERIFY_WRITE,
> +                      (char __user *)vmap->user_ptr,
> +                      vmap->gem.base.size))
> +               return -EFAULT;
> +
> +       first_data_page = vmap->user_ptr / PAGE_SIZE;
> +       last_data_page = (vmap->user_ptr + vmap->gem.base.size - 1) / PAGE_SIZE;
> +       vmap->gem.num_pages = last_data_page - first_data_page + 1;
> +
> +       vmap->gem.pages = drm_malloc_ab(vmap->gem.num_pages,
> +                                       sizeof(struct page *));
> +       if (vmap->gem.pages == NULL)
> +               return -ENOMEM;
> +
> +       pinned_pages = get_user_pages_fast(vmap->user_ptr,
> +                                          vmap->gem.num_pages,
> +                                          !vmap->read_only,
> +                                          vmap->gem.pages);
> +       if (pinned_pages < vmap->gem.num_pages) {
> +               for (i = 0; i < pinned_pages; i++)
> +                       page_cache_release(vmap->gem.pages[i]);
> +               drm_free_large(vmap->gem.pages);
> +               return -EFAULT;
> +       }
> +
> +       *offset = vmap->user_ptr & ~PAGE_MASK;
> +       return 0;
> +}
> +
> +static void
> +i915_gem_vmap_put_pages(struct drm_i915_gem_object *obj)
> +{
> +       int i;
> +
> +       for (i = 0; i < obj->num_pages; i++) {
> +               if (obj->dirty)
> +                       set_page_dirty(obj->pages[i]);
> +
> +               mark_page_accessed(obj->pages[i]);
> +               page_cache_release(obj->pages[i]);
> +       }
> +
> +       obj->dirty = 0;
> +       drm_free_large(obj->pages);
> +}
> +
> +static const struct drm_i915_gem_object_ops i915_gem_vmap_ops = {
> +       .get_pages = i915_gem_vmap_get_pages,
> +       .put_pages = i915_gem_vmap_put_pages,
> +};
> +
> +/**
> + * Creates a new mm object that wraps some user memory.
> + */
> +int
> +i915_gem_vmap_ioctl(struct drm_device *dev, void *data,
> +                   struct drm_file *file)
> +{
> +       struct drm_i915_gem_vmap *args = data;
> +       struct i915_gem_vmap_object *obj;
> +       int ret;
> +       u32 handle;
> +
> +       /* Allocate the new object */
> +       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
> +       if (obj == NULL)
> +               return -ENOMEM;
> +
> +       obj->gem.base.driver_private = (void *)&i915_gem_vmap_ops;
> +
> +       obj->gem.base.dev = dev;
> +       obj->gem.base.size = args->user_size;
> +
> +       kref_init(&obj->gem.base.refcount);
> +       atomic_set(&obj->gem.base.handle_count, 0);
> +
> +       i915_gem_object_init(&obj->gem);
> +       obj->gem.agp_type = AGP_USER_CACHED_MEMORY;
> +
> +       obj->user_ptr = args->user_ptr;
> +       obj->read_only = args->flags & I915_VMAP_READ_ONLY;
> +
> +       ret = drm_gem_handle_create(file, &obj->gem.base, &handle);
> +       if (ret) {
> +               drm_gem_object_release(&obj->gem.base);
> +               kfree(obj);
> +               return ret;
> +       }
> +
> +       /* drop reference from allocate - handle holds it now */
> +       drm_gem_object_unreference(&obj->gem.base);
> +
> +       args->handle = handle;
> +       return 0;
> +}
> diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
> index d3c93be..3b8b7f9 100644
> --- a/include/drm/i915_drm.h
> +++ b/include/drm/i915_drm.h
> @@ -200,6 +200,7 @@ typedef struct _drm_i915_sarea {
>  #define DRM_I915_GEM_EXECBUFFER2       0x29
>  #define DRM_I915_GEM_PREAD_2D  0x2a
>  #define DRM_I915_GEM_PWRITE_2D 0x2b
> +#define DRM_I915_GEM_VMAP      0x2c
>
>  #define DRM_IOCTL_I915_INIT            DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
>  #define DRM_IOCTL_I915_FLUSH           DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
> @@ -243,6 +244,7 @@ typedef struct _drm_i915_sarea {
>  #define DRM_IOCTL_I915_OVERLAY_ATTRS   DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
>  #define DRM_IOCTL_I915_GEM_PREAD_2D    DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD_2D, struct drm_i915_gem_pread_2d)
>  #define DRM_IOCTL_I915_GEM_PWRITE_2D   DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE_2D, struct drm_i915_gem_pwrite_2d)
> +#define DRM_IOCTL_I915_GEM_VMAP        DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_VMAP, struct drm_i915_gem_vmap)
>
>  /* Allow drivers to submit batchbuffers directly to hardware, relying
>  * on the security mechanisms provided by hardware.
> @@ -295,6 +297,7 @@ typedef struct drm_i915_irq_wait {
>  #define I915_PARAM_HAS_COHERENT_RINGS   13
>  #define I915_PARAM_HAS_EXEC_CONSTANTS   14
>  #define I915_PARAM_HAS_2D_IO            15
> +#define I915_PARAM_HAS_VMAP             16
>
>  typedef struct drm_i915_getparam {
>        int param;
> @@ -392,6 +395,19 @@ struct drm_i915_gem_create {
>        __u32 pad;
>  };
>
> +struct drm_i915_gem_vmap {
> +       __u64 user_ptr;
> +       __u32 user_size;
> +       __u32 flags;
> +#define I915_VMAP_READ_ONLY 0x1
> +       /**
>         * Returned handle for the object.
> +        *
> +        * Object handles are nonzero.
> +        */
> +       __u32 handle;
> +};
> +
>  struct drm_i915_gem_pread {
>        /** Handle for the object being read. */
>        __u32 handle;
> --
> 1.7.2.3
>
> _______________________________________________
> 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