dma-buf export implementation. Heavily influenced by Dave Airlie's proof of concept work.
Cc: Daniel Vetter daniel.vetter@ffwll.ch Cc: Dave Airlie airlied@redhat.com Signed-off-by: Ben Widawsky ben@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@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