dma-buf export implementation. Heavily influenced by Dave Airlie's proof
of concept work.

Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
Cc: Dave Airlie <airlied at redhat.com>
Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
---
 drivers/gpu/drm/vgem/Makefile       |    2 +-
 drivers/gpu/drm/vgem/vgem_dma_buf.c |  128 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/vgem/vgem_drv.c     |    6 ++
 drivers/gpu/drm/vgem/vgem_drv.h     |    7 ++
 4 files changed, 142 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/vgem/vgem_dma_buf.c

diff --git a/drivers/gpu/drm/vgem/Makefile b/drivers/gpu/drm/vgem/Makefile
index 3f4c7b8..1055cb7 100644
--- a/drivers/gpu/drm/vgem/Makefile
+++ b/drivers/gpu/drm/vgem/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-vgem-y := vgem_drv.o
+vgem-y := vgem_drv.o vgem_dma_buf.o

 obj-$(CONFIG_DRM_VGEM) += vgem.o
diff --git a/drivers/gpu/drm/vgem/vgem_dma_buf.c 
b/drivers/gpu/drm/vgem/vgem_dma_buf.c
new file mode 100644
index 0000000..eca9445
--- /dev/null
+++ b/drivers/gpu/drm/vgem/vgem_dma_buf.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright ? 2012 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.
+ *
+ * Authors:
+ *    Ben Widawsky <ben at bwidawsk.net>
+ *
+ */
+
+#include <linux/dma-buf.h>
+#include "vgem_drv.h"
+
+#define VGEM_FD_PERMS 0600
+
+struct sg_table *vgem_gem_map_dma_buf(struct dma_buf_attachment *attachment,
+                                      enum dma_data_direction dir)
+{
+       struct drm_vgem_gem_object *obj = attachment->dmabuf->priv;
+       struct sg_table *sg;
+       int ret;
+
+       ret = vgem_gem_get_pages(obj);
+       if (ret) {
+               vgem_gem_put_pages(obj);
+               return NULL;
+       }
+
+       BUG_ON(obj->pages == NULL);
+
+       sg = drm_prime_pages_to_sg(obj->pages, obj->base.size / PAGE_SIZE);
+       return sg;
+}
+
+void vgem_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
+                           struct sg_table *sg)
+{
+       sg_free_table(sg);
+       kfree(sg);
+}
+
+void vgem_gem_release(struct dma_buf *buf)
+{
+       struct drm_vgem_gem_object *obj = buf->priv;
+
+       BUG_ON(buf != obj->base.export_dma_buf);
+
+       obj->base.prime_fd = -1;
+       obj->base.export_dma_buf = NULL;
+       drm_gem_object_unreference_unlocked(&obj->base);
+}
+
+struct dma_buf_ops vgem_dmabuf_ops = {
+       .map_dma_buf = vgem_gem_map_dma_buf,
+       .unmap_dma_buf = vgem_gem_unmap_dma_buf,
+       .release = vgem_gem_release
+};
+
+int vgem_prime_to_fd(struct drm_device *dev, struct drm_file *file,
+                    uint32_t handle, int *prime_fd)
+{
+       struct drm_vgem_file_private *file_priv = file->driver_priv;
+       struct drm_vgem_gem_object *obj;
+       int ret;
+
+       DRM_DEBUG_PRIME("Request fd for handle %d\n", handle);
+
+       obj = to_vgem_bo(drm_gem_object_lookup(dev, file, handle));
+       if (!obj)
+               return -EBADF;
+
+       /* This means a user has already called get_fd on this */
+       if (obj->base.prime_fd != -1) {
+               DRM_DEBUG_PRIME("User requested a previously exported buffer "
+                               "%d %d\n", handle, obj->base.prime_fd);
+               drm_gem_object_unreference(&obj->base);
+               goto out_fd;
+       }
+
+       /* Make a dma buf out of our vgem object */
+       obj->base.export_dma_buf = dma_buf_export(obj, &vgem_dmabuf_ops,
+                                                 obj->base.size,
+                                                 VGEM_FD_PERMS);
+       if (IS_ERR(obj->base.export_dma_buf)) {
+               DRM_DEBUG_PRIME("export fail\n");
+               return PTR_ERR(obj->base.export_dma_buf);
+       } else
+               obj->base.prime_fd = dma_buf_fd(obj->base.export_dma_buf);
+
+       mutex_lock(&dev->prime_mutex);
+       ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime,
+                                                obj->base.export_dma_buf,
+                                                handle);
+       WARN_ON(ret);
+       ret = drm_prime_add_dma_buf(dev, &obj->base);
+       mutex_unlock(&dev->prime_mutex);
+       if (ret)
+               return ret;
+
+out_fd:
+       *prime_fd = obj->base.prime_fd;
+
+       return 0;
+}
+
+int vgem_prime_to_handle(struct drm_device *dev,
+                        struct drm_file *file, int prime_fd,
+                        uint32_t *handle)
+{
+       return 0;
+}
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
index cd6ab42..9cd1ed4 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.c
+++ b/drivers/gpu/drm/vgem/vgem_drv.c
@@ -71,12 +71,15 @@ static int vgem_open(struct drm_device *dev, struct 
drm_file *file)

        file->driver_priv = file_priv;

+       drm_prime_init_file_private(&file_priv->prime);
+
        return 0;
 }

 static void vgem_preclose(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_vgem_file_private *file_priv = file->driver_priv;
+       drm_prime_destroy_file_private(&file_priv->prime);
        kfree(file_priv);
 }

@@ -312,6 +315,9 @@ static struct drm_driver vgem_driver = {
        .dumb_create            = vgem_gem_dumb_create,
        .dumb_map_offset        = vgem_gem_dumb_map,

+       .prime_handle_to_fd     = vgem_prime_to_fd,
+       .prime_fd_to_handle     = vgem_prime_to_handle,
+
        .name   = DRIVER_NAME,
        .desc   = DRIVER_DESC,
        .date   = DRIVER_DATE,
diff --git a/drivers/gpu/drm/vgem/vgem_drv.h b/drivers/gpu/drm/vgem/vgem_drv.h
index ca63fa0b..56d1c0f 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.h
+++ b/drivers/gpu/drm/vgem/vgem_drv.h
@@ -42,6 +42,7 @@ struct drm_vgem_gem_object {
 };

 struct drm_vgem_file_private {
+       struct drm_prime_file_private prime;
 };

 /* vgem_drv.c */
@@ -49,6 +50,12 @@ extern void vgem_gem_put_pages(struct drm_vgem_gem_object 
*obj);
 extern int vgem_gem_get_pages(struct drm_vgem_gem_object *obj);

 /* vgem_dma_buf.c */
+extern int vgem_prime_to_fd(struct drm_device *dev,
+                           struct drm_file *file_priv,
+                           uint32_t handle, int *prime_fd);

+extern int vgem_prime_to_handle(struct drm_device *dev,
+                               struct drm_file *file_priv,
+                               int prime_fd, uint32_t *handle);

 #endif
-- 
1.7.9.1

Reply via email to