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@xxxxxxxxxxxxxxxxxx>: > 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@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/dri-devel > _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel