i915: add dma-buf vmap support for exporting vmapped buffer
authorDave Airlie <airlied@redhat.com>
Tue, 22 May 2012 12:09:21 +0000 (13:09 +0100)
committerDave Airlie <airlied@redhat.com>
Thu, 31 May 2012 13:13:57 +0000 (14:13 +0100)
This is used to export a vmapping to the udl driver so that
i915 and udl can share the udl scanout.

Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_dmabuf.c

index 377c21f531e49ba93bdcb31aaaff290b15292bc2..c9cfc67c2cf58acdf7871a6e81fda66d3c45dedb 100644 (file)
@@ -942,6 +942,9 @@ struct drm_i915_gem_object {
 
        /* prime dma-buf support */
        struct sg_table *sg_table;
+       void *dma_buf_vmapping;
+       int vmapping_count;
+
        /**
         * Used for performing relocations during execbuffer insertion.
         */
index 4fba63e896d7aa454b6657d9910098ddfb9c2356..aa308e1337db7c8bacbf73d00dc80badecb617a2 100644 (file)
@@ -74,6 +74,59 @@ static void i915_gem_dmabuf_release(struct dma_buf *dma_buf)
        }
 }
 
+static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
+{
+       struct drm_i915_gem_object *obj = dma_buf->priv;
+       struct drm_device *dev = obj->base.dev;
+       int ret;
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ERR_PTR(ret);
+
+       if (obj->dma_buf_vmapping) {
+               obj->vmapping_count++;
+               goto out_unlock;
+       }
+
+       if (!obj->pages) {
+               ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN);
+               if (ret) {
+                       mutex_unlock(&dev->struct_mutex);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       obj->dma_buf_vmapping = vmap(obj->pages, obj->base.size / PAGE_SIZE, 0, PAGE_KERNEL);
+       if (!obj->dma_buf_vmapping) {
+               DRM_ERROR("failed to vmap object\n");
+               goto out_unlock;
+       }
+
+       obj->vmapping_count = 1;
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return obj->dma_buf_vmapping;
+}
+
+static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
+{
+       struct drm_i915_gem_object *obj = dma_buf->priv;
+       struct drm_device *dev = obj->base.dev;
+       int ret;
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return;
+
+       --obj->vmapping_count;
+       if (obj->vmapping_count == 0) {
+               vunmap(obj->dma_buf_vmapping);
+               obj->dma_buf_vmapping = NULL;
+       }
+       mutex_unlock(&dev->struct_mutex);
+}
+
 static void *i915_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num)
 {
        return NULL;
@@ -107,6 +160,8 @@ static const struct dma_buf_ops i915_dmabuf_ops =  {
        .kunmap = i915_gem_dmabuf_kunmap,
        .kunmap_atomic = i915_gem_dmabuf_kunmap_atomic,
        .mmap = i915_gem_dmabuf_mmap,
+       .vmap = i915_gem_dmabuf_vmap,
+       .vunmap = i915_gem_dmabuf_vunmap,
 };
 
 struct dma_buf *i915_gem_prime_export(struct drm_device *dev,