Enable the standard GEM dma-buf interface provided by the DRM core, but
only for exporting the VGEM object. This allows passing around the VGEM
objects created from the dumb interface and using them as sources
elsewhere. Creating a VGEM object for a foriegn handle is not supported.

v2: With additional completeness.
v3: Need to clear the CPU cache upon exporting the dma-addresses.

Testcase: igt/vgem_basic/dmabuf-*
Testcase: igt/prime_vgem
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Sean Paul <seanpaul at chromium.org>
Cc: Zach Reizner <zachr at google.com>
---
 drivers/gpu/drm/vgem/vgem_drv.c | 112 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
index e1a697d0662f..db48e837992d 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.c
+++ b/drivers/gpu/drm/vgem/vgem_drv.c
@@ -193,14 +193,124 @@ static const struct file_operations vgem_driver_fops = {
        .release        = drm_release,
 };

+static void __put_pages(struct page **pages, long n_pages)
+{
+       while (n_pages--)
+               put_page(pages[n_pages]);
+       drm_free_large(pages);
+}
+
+static int vgem_prime_pin(struct drm_gem_object *obj)
+{
+       long n_pages = obj->size >> PAGE_SHIFT;
+       struct page **pages;
+
+       /* Flush the object from the CPU cache so that importers
+        * can rely on coherent indirect access via access the
+        * exported dma-address.
+        */
+       pages = drm_gem_get_pages(obj);
+       if (IS_ERR(pages))
+               return PTR_ERR(pages);
+
+       drm_clflush_pages(pages, n_pages);
+       __put_pages(pages, n_pages);
+
+       return 0;
+}
+
+static struct sg_table *vgem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+       long n_pages = obj->size >> PAGE_SHIFT;
+       struct sg_table *st;
+       struct page **pages;
+       int ret;
+
+       st = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
+       if (st == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       pages = drm_gem_get_pages(obj);
+       if (IS_ERR(pages)) {
+               ret = PTR_ERR(pages);
+               goto err;
+       }
+
+       ret = sg_alloc_table_from_pages(st, pages, n_pages,
+                                       0, obj->size, GFP_KERNEL);
+       __put_pages(pages, n_pages);
+       if (ret)
+               goto err;
+
+       return st;
+
+err:
+       kfree(st);
+       return ERR_PTR(ret);
+}
+
+static void *vgem_prime_vmap(struct drm_gem_object *obj)
+{
+       long n_pages = obj->size >> PAGE_SHIFT;
+       struct page **pages;
+       void *addr;
+
+       pages = drm_gem_get_pages(obj);
+       if (IS_ERR(pages))
+               return NULL;
+
+       addr = vmap(pages, n_pages, 0, pgprot_writecombine(PAGE_KERNEL_IO));
+       __put_pages(pages, n_pages);
+
+       return addr;
+}
+
+static void vgem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       vunmap(vaddr);
+}
+
+static int vgem_prime_mmap(struct drm_gem_object *obj,
+                          struct vm_area_struct *vma)
+{
+       int ret;
+
+       if (obj->size < vma->vm_end - vma->vm_start)
+               return -EINVAL;
+
+       if (!obj->filp)
+               return -ENODEV;
+
+       ret = obj->filp->f_op->mmap(obj->filp, vma);
+       if (ret)
+               return ret;
+
+       fput(vma->vm_file);
+       vma->vm_file = get_file(obj->filp);
+       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+       vma->vm_page_prot = 
pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+
+       return 0;
+}
+
 static struct drm_driver vgem_driver = {
-       .driver_features                = DRIVER_GEM,
+       .driver_features                = DRIVER_GEM | DRIVER_PRIME,
        .gem_free_object_unlocked       = vgem_gem_free_object,
        .gem_vm_ops                     = &vgem_gem_vm_ops,
        .ioctls                         = vgem_ioctls,
        .fops                           = &vgem_driver_fops,
+
        .dumb_create                    = vgem_gem_dumb_create,
        .dumb_map_offset                = vgem_gem_dumb_map,
+
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .gem_prime_pin = vgem_prime_pin,
+       .gem_prime_export = drm_gem_prime_export,
+       .gem_prime_get_sg_table = vgem_prime_get_sg_table,
+       .gem_prime_vmap = vgem_prime_vmap,
+       .gem_prime_vunmap = vgem_prime_vunmap,
+       .gem_prime_mmap = vgem_prime_mmap,
+
        .name   = DRIVER_NAME,
        .desc   = DRIVER_DESC,
        .date   = DRIVER_DATE,
-- 
2.8.1

Reply via email to