[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