* [PATCH] drm: base prime/dma-buf support
@ 2012-03-26 15:02 Dave Airlie
2012-03-26 15:45 ` daeinki
2012-03-26 16:32 ` Ville Syrjälä
0 siblings, 2 replies; 3+ messages in thread
From: Dave Airlie @ 2012-03-26 15:02 UTC (permalink / raw)
To: dri-devel
From: Dave Airlie <airlied@redhat.com>
This adds the basic drm dma-buf interface layer, called PRIME,
The main APIs exposed to userspace allow translating a 32-bit object handle
to a file descriptor, and a file descriptor to a 32-bit object handle.
The flags value is currently limited to O_CLOEXEC.
Acknowledgements:
Daniel Vetter: lots of review
Rob Clark: cleaned up lots of the internals and did lifetime review.
This is what I intend to send to Linus to form the basis for prime work
in the drivers.
Signed-off-by: Dave Airlie <airlied@redhat.com>
---
drivers/gpu/drm/Kconfig | 1 +
drivers/gpu/drm/Makefile | 2 +-
drivers/gpu/drm/drm_drv.c | 4 +
drivers/gpu/drm/drm_fops.c | 7 +
drivers/gpu/drm/drm_gem.c | 9 ++
drivers/gpu/drm/drm_prime.c | 281 +++++++++++++++++++++++++++++++++++++++++++
include/drm/drm.h | 14 ++-
include/drm/drmP.h | 61 ++++++++++
8 files changed, 377 insertions(+), 2 deletions(-)
create mode 100644 drivers/gpu/drm/drm_prime.c
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index cc11488..e354bc0 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -9,6 +9,7 @@ menuconfig DRM
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
select I2C
select I2C_ALGOBIT
+ select DMA_SHARED_BUFFER
help
Kernel-level support for the Direct Rendering Infrastructure (DRI)
introduced in XFree86 4.0. If you say Y here, you need to select
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index a858532..c20da5b 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -12,7 +12,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
- drm_trace_points.o drm_global.o
+ drm_trace_points.o drm_global.o drm_prime.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 0b65fbc..6116e3b 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -136,6 +136,10 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED),
+
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 7348a3d..cdfbf27 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -271,6 +271,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
if (dev->driver->driver_features & DRIVER_GEM)
drm_gem_open(dev, priv);
+ if (drm_core_check_feature(dev, DRIVER_PRIME))
+ drm_prime_init_file_private(&priv->prime);
+
if (dev->driver->open) {
ret = dev->driver->open(dev, priv);
if (ret < 0)
@@ -571,6 +574,10 @@ int drm_release(struct inode *inode, struct file *filp)
if (dev->driver->postclose)
dev->driver->postclose(dev, file_priv);
+
+ if (drm_core_check_feature(dev, DRIVER_PRIME))
+ drm_prime_destroy_file_private(&file_priv->prime);
+
kfree(file_priv);
/* ========================================================
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 0ef358e..f337497 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -35,6 +35,7 @@
#include <linux/mman.h>
#include <linux/pagemap.h>
#include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
#include "drmP.h"
/** @file drm_gem.c
@@ -232,6 +233,10 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
idr_remove(&filp->object_idr, handle);
spin_unlock(&filp->table_lock);
+ if (obj->import_attach)
+ drm_prime_remove_fd_handle_mapping(&filp->prime,
+ obj->import_attach->dmabuf);
+
if (dev->driver->gem_close_object)
dev->driver->gem_close_object(obj, filp);
drm_gem_object_handle_unreference_unlocked(obj);
@@ -527,6 +532,10 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
struct drm_gem_object *obj = ptr;
struct drm_device *dev = obj->dev;
+ if (obj->import_attach)
+ drm_prime_remove_fd_handle_mapping(&file_priv->prime,
+ obj->import_attach->dmabuf);
+
if (dev->driver->gem_close_object)
dev->driver->gem_close_object(obj, file_priv);
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
new file mode 100644
index 0000000..1c7f057
--- /dev/null
+++ b/drivers/gpu/drm/drm_prime.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright © 2012 Red Hat
+ *
+ * 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:
+ * Dave Airlie <airlied@redhat.com>
+ * Rob Clark
+ *
+ */
+
+#include <linux/export.h>
+#include <linux/dma-buf.h>
+#include "drmP.h"
+
+/*
+ * DMA-BUF/GEM Object references and lifetime overview:
+ *
+ * On the export the dma_buf holds a reference to the exporting GEM
+ * object. It takes this reference in handle_to_fd_ioctl, when it
+ * first calls .prime_export and stores the exporting GEM object in
+ * the dma_buf priv. This reference is released when the dma_buf
+ * object goes away in the driver .release function.
+ *
+ * On the import the importing GEM object holds a reference to the
+ * dma_buf (which in turn holds a ref to the exporting GEM object).
+ * It takes that reference in the fd_to_handle ioctl.
+ * It calls dma_buf_get, creates an attachment to it and stores the
+ * attachment in the GEM object. When this attachment is destroyed
+ * when the imported object is destroyed, we remove the attachment
+ * and drop the reference to the dma_buf.
+ *
+ * Thus the chain of references always flows in one direction
+ * (avoiding loops): importing_gem -> dmabuf -> exporting_gem
+ */
+
+struct drm_prime_member {
+ struct list_head entry;
+ struct dma_buf *dma_buf;
+ uint32_t handle;
+};
+
+int drm_gem_prime_handle_to_fd(struct drm_device *dev,
+ struct drm_file *file_priv, uint32_t handle, uint32_t flags,
+ int *prime_fd)
+{
+ struct drm_gem_object *obj;
+
+ obj = drm_gem_object_lookup(dev, file_priv, handle);
+ if (!obj)
+ return -ENOENT;
+
+ /* don't allow imported buffers to be re-exported */
+ if (obj->import_attach) {
+ drm_gem_object_unreference_unlocked(obj);
+ return -EINVAL;
+ }
+
+ if (obj->export_dma_buf) {
+ get_file(obj->export_dma_buf->file);
+ *prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
+ drm_gem_object_unreference_unlocked(obj);
+ } else {
+ obj->export_dma_buf =
+ dev->driver->gem_prime_export(dev, obj, flags);
+ if (IS_ERR_OR_NULL(obj->export_dma_buf)) {
+ /* normally the created dma-buf takes ownership of the ref,
+ * but if that fails then drop the ref
+ */
+ drm_gem_object_unreference_unlocked(obj);
+ return PTR_ERR(obj->export_dma_buf);
+ }
+ *prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
+
+int drm_gem_prime_fd_to_handle(struct drm_device *dev,
+ struct drm_file *file_priv, int prime_fd, uint32_t *handle)
+{
+ struct dma_buf *dma_buf;
+ struct drm_gem_object *obj;
+ int ret;
+
+ dma_buf = dma_buf_get(prime_fd);
+ if (IS_ERR(dma_buf))
+ return PTR_ERR(dma_buf);
+
+ ret = drm_prime_lookup_fd_handle_mapping(&file_priv->prime,
+ dma_buf, handle);
+ if (!ret) {
+ dma_buf_put(dma_buf);
+ return 0;
+ }
+
+ /* never seen this one, need to import */
+ obj = dev->driver->gem_prime_import(dev, dma_buf);
+ if (IS_ERR_OR_NULL(obj)) {
+ ret = PTR_ERR(obj);
+ goto fail_put;
+ }
+
+ ret = drm_gem_handle_create(file_priv, obj, handle);
+ drm_gem_object_unreference_unlocked(obj);
+ if (ret)
+ goto fail_put;
+
+ ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime,
+ dma_buf, *handle);
+ if (ret)
+ goto fail;
+
+ return 0;
+
+fail:
+ /* hmm, if driver attached, we are relying on the free-object path
+ * to detach.. which seems ok..
+ */
+ drm_gem_object_handle_unreference_unlocked(obj);
+fail_put:
+ dma_buf_put(dma_buf);
+ return ret;
+}
+EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
+
+int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_prime_handle *args = data;
+ uint32_t flags;
+
+ if (!drm_core_check_feature(dev, DRIVER_PRIME))
+ return -EINVAL;
+
+ if (!dev->driver->prime_handle_to_fd)
+ return -ENOSYS;
+
+ /* we only want to pass DRM_CLOEXEC which is == O_CLOEXEC */
+ flags = args->flags & DRM_CLOEXEC;
+
+ return dev->driver->prime_handle_to_fd(dev, file_priv,
+ args->handle, flags, &args->fd);
+}
+
+int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_prime_handle *args = data;
+
+ if (!drm_core_check_feature(dev, DRIVER_PRIME))
+ return -EINVAL;
+
+ if (!dev->driver->prime_fd_to_handle)
+ return -ENOSYS;
+
+ return dev->driver->prime_fd_to_handle(dev, file_priv,
+ args->fd, &args->handle);
+}
+
+/*
+ * drm_prime_pages_to_sg
+ *
+ * this helper creates an sg table object from a set of pages
+ * the driver is responsible for mapping the pages into the
+ * importers address space
+ */
+struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
+{
+ struct sg_table *sg = NULL;
+ struct scatterlist *iter;
+ int i;
+ int ret;
+
+ sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!sg)
+ goto out;
+
+ ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL);
+ if (ret)
+ goto out;
+
+ for_each_sg(sg->sgl, iter, nr_pages, i)
+ sg_set_page(iter, pages[i], PAGE_SIZE, 0);
+
+ return sg;
+out:
+ kfree(sg);
+ return NULL;
+}
+EXPORT_SYMBOL(drm_prime_pages_to_sg);
+
+/* helper function to cleanup a GEM/prime object */
+void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)
+{
+ struct dma_buf_attachment *attach;
+ struct dma_buf *dma_buf;
+ attach = obj->import_attach;
+ if (sg)
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+ dma_buf = attach->dmabuf;
+ dma_buf_detach(attach->dmabuf, attach);
+ /* remove the reference */
+ dma_buf_put(dma_buf);
+}
+EXPORT_SYMBOL(drm_prime_gem_destroy);
+
+void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
+{
+ INIT_LIST_HEAD(&prime_fpriv->head);
+}
+EXPORT_SYMBOL(drm_prime_init_file_private);
+
+void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
+{
+ struct drm_prime_member *member, *safe;
+ list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
+ list_del(&member->entry);
+ kfree(member);
+ }
+}
+EXPORT_SYMBOL(drm_prime_destroy_file_private);
+
+int drm_prime_insert_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle)
+{
+ struct drm_prime_member *member;
+
+ member = kmalloc(sizeof(*member), GFP_KERNEL);
+ if (!member)
+ return -ENOMEM;
+
+ member->dma_buf = dma_buf;
+ member->handle = handle;
+ list_add(&member->entry, &prime_fpriv->head);
+ return 0;
+}
+EXPORT_SYMBOL(drm_prime_insert_fd_handle_mapping);
+
+int drm_prime_lookup_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle)
+{
+ struct drm_prime_member *member;
+
+ list_for_each_entry(member, &prime_fpriv->head, entry) {
+ if (member->dma_buf == dma_buf) {
+ *handle = member->handle;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+EXPORT_SYMBOL(drm_prime_lookup_fd_handle_mapping);
+
+void drm_prime_remove_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf)
+{
+ struct drm_prime_member *member, *safe;
+
+ list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
+ if (member->dma_buf == dma_buf) {
+ list_del(&member->entry);
+ kfree(member);
+ }
+ }
+}
+EXPORT_SYMBOL(drm_prime_remove_fd_handle_mapping);
diff --git a/include/drm/drm.h b/include/drm/drm.h
index 34a7b89..64ff02d 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -617,6 +617,17 @@ struct drm_get_cap {
__u64 value;
};
+#define DRM_CLOEXEC O_CLOEXEC
+struct drm_prime_handle {
+ __u32 handle;
+
+ /** Flags.. only applicable for handle->fd */
+ __u32 flags;
+
+ /** Returned dmabuf file descriptor */
+ __s32 fd;
+};
+
#include "drm_mode.h"
#define DRM_IOCTL_BASE 'd'
@@ -673,7 +684,8 @@ struct drm_get_cap {
#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock)
#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock)
-#define DRM_IOCTL_GEM_PRIME_OPEN DRM_IOWR(0x2e, struct drm_gem_open)
+#define DRM_IOCTL_PRIME_HANDLE_TO_FD DRM_IOWR(0x2d, struct drm_prime_handle)
+#define DRM_IOCTL_PRIME_FD_TO_HANDLE DRM_IOWR(0x2e, struct drm_prime_handle)
#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30)
#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31)
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 574bd1c..f1e9c89 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -91,6 +91,7 @@ struct drm_device;
#define DRM_UT_CORE 0x01
#define DRM_UT_DRIVER 0x02
#define DRM_UT_KMS 0x04
+#define DRM_UT_PRIME 0x08
/*
* Three debug levels are defined.
* drm_core, drm_driver, drm_kms
@@ -150,6 +151,7 @@ int drm_err(const char *func, const char *format, ...);
#define DRIVER_IRQ_VBL2 0x800
#define DRIVER_GEM 0x1000
#define DRIVER_MODESET 0x2000
+#define DRIVER_PRIME 0x4000
#define DRIVER_BUS_PCI 0x1
#define DRIVER_BUS_PLATFORM 0x2
@@ -215,6 +217,11 @@ int drm_err(const char *func, const char *format, ...);
drm_ut_debug_printk(DRM_UT_KMS, DRM_NAME, \
__func__, fmt, ##args); \
} while (0)
+#define DRM_DEBUG_PRIME(fmt, args...) \
+ do { \
+ drm_ut_debug_printk(DRM_UT_PRIME, DRM_NAME, \
+ __func__, fmt, ##args); \
+ } while (0)
#define DRM_LOG(fmt, args...) \
do { \
drm_ut_debug_printk(DRM_UT_CORE, NULL, \
@@ -238,6 +245,7 @@ int drm_err(const char *func, const char *format, ...);
#else
#define DRM_DEBUG_DRIVER(fmt, args...) do { } while (0)
#define DRM_DEBUG_KMS(fmt, args...) do { } while (0)
+#define DRM_DEBUG_PRIME(fmt, args...) do { } while (0)
#define DRM_DEBUG(fmt, arg...) do { } while (0)
#define DRM_LOG(fmt, arg...) do { } while (0)
#define DRM_LOG_KMS(fmt, args...) do { } while (0)
@@ -410,6 +418,11 @@ struct drm_pending_event {
void (*destroy)(struct drm_pending_event *event);
};
+/* initial implementaton using a linked list - todo hashtab */
+struct drm_prime_file_private {
+ struct list_head head;
+};
+
/** File private data */
struct drm_file {
int authenticated;
@@ -437,6 +450,8 @@ struct drm_file {
wait_queue_head_t event_wait;
struct list_head event_list;
int event_space;
+
+ struct drm_prime_file_private prime;
};
/** Wait queue */
@@ -652,6 +667,12 @@ struct drm_gem_object {
uint32_t pending_write_domain;
void *driver_private;
+
+ /* dma buf exported from this GEM object */
+ struct dma_buf *export_dma_buf;
+
+ /* dma buf attachment backing this object */
+ struct dma_buf_attachment *import_attach;
};
#include "drm_crtc.h"
@@ -890,6 +911,20 @@ struct drm_driver {
int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
+ /* prime: */
+ /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */
+ int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
+ uint32_t handle, uint32_t flags, int *prime_fd);
+ /* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */
+ int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv,
+ int prime_fd, uint32_t *handle);
+ /* export GEM -> dmabuf */
+ struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags);
+ /* import dmabuf -> GEM */
+ struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
+ struct dma_buf *dma_buf);
+
/* vga arb irq handler */
void (*vgaarb_irq)(struct drm_device *dev, bool state);
@@ -1509,6 +1544,32 @@ extern int drm_vblank_info(struct seq_file *m, void *data);
extern int drm_clients_info(struct seq_file *m, void* data);
extern int drm_gem_name_info(struct seq_file *m, void *data);
+
+extern int drm_gem_prime_handle_to_fd(struct drm_device *dev,
+ struct drm_file *file_priv, uint32_t handle, uint32_t flags,
+ int *prime_fd);
+extern int drm_gem_prime_fd_to_handle(struct drm_device *dev,
+ struct drm_file *file_priv, int prime_fd, uint32_t *handle);
+
+extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+
+extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages);
+extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
+
+
+void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
+void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
+int drm_prime_insert_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle);
+int drm_prime_lookup_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle);
+void drm_prime_remove_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf);
+
+int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj);
+int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf,
+ struct drm_gem_object **obj);
+
#if DRM_DEBUG_CODE
extern int drm_vma_info(struct seq_file *m, void *data);
#endif
--
1.7.7.6
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] drm: base prime/dma-buf support
2012-03-26 15:02 [PATCH] drm: base prime/dma-buf support Dave Airlie
@ 2012-03-26 15:45 ` daeinki
2012-03-26 16:32 ` Ville Syrjälä
1 sibling, 0 replies; 3+ messages in thread
From: daeinki @ 2012-03-26 15:45 UTC (permalink / raw)
To: Dave Airlie; +Cc: dri-devel@lists.freedesktop.org
Reviewed-by: Inki Dae <inki.dae@samsung.com>
2012. 3. 27. 오전 12:02 Dave Airlie <airlied@gmail.com> 작성:
> From: Dave Airlie <airlied@redhat.com>
>
> This adds the basic drm dma-buf interface layer, called PRIME,
>
> The main APIs exposed to userspace allow translating a 32-bit object handle
> to a file descriptor, and a file descriptor to a 32-bit object handle.
>
> The flags value is currently limited to O_CLOEXEC.
>
> Acknowledgements:
> Daniel Vetter: lots of review
> Rob Clark: cleaned up lots of the internals and did lifetime review.
>
> This is what I intend to send to Linus to form the basis for prime work
> in the drivers.
>
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> ---
> drivers/gpu/drm/Kconfig | 1 +
> drivers/gpu/drm/Makefile | 2 +-
> drivers/gpu/drm/drm_drv.c | 4 +
> drivers/gpu/drm/drm_fops.c | 7 +
> drivers/gpu/drm/drm_gem.c | 9 ++
> drivers/gpu/drm/drm_prime.c | 281 +++++++++++++++++++++++++++++++++++++++++++
> include/drm/drm.h | 14 ++-
> include/drm/drmP.h | 61 ++++++++++
> 8 files changed, 377 insertions(+), 2 deletions(-)
> create mode 100644 drivers/gpu/drm/drm_prime.c
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index cc11488..e354bc0 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -9,6 +9,7 @@ menuconfig DRM
> depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
> select I2C
> select I2C_ALGOBIT
> + select DMA_SHARED_BUFFER
> help
> Kernel-level support for the Direct Rendering Infrastructure (DRI)
> introduced in XFree86 4.0. If you say Y here, you need to select
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index a858532..c20da5b 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -12,7 +12,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
> drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
> drm_crtc.o drm_modes.o drm_edid.o \
> drm_info.o drm_debugfs.o drm_encoder_slave.o \
> - drm_trace_points.o drm_global.o
> + drm_trace_points.o drm_global.o drm_prime.o
>
> drm-$(CONFIG_COMPAT) += drm_ioc32.o
>
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index 0b65fbc..6116e3b 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -136,6 +136,10 @@ static struct drm_ioctl_desc drm_ioctls[] = {
> DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
>
> DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> +
> + DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED),
> + DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED),
> +
> DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
> index 7348a3d..cdfbf27 100644
> --- a/drivers/gpu/drm/drm_fops.c
> +++ b/drivers/gpu/drm/drm_fops.c
> @@ -271,6 +271,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
> if (dev->driver->driver_features & DRIVER_GEM)
> drm_gem_open(dev, priv);
>
> + if (drm_core_check_feature(dev, DRIVER_PRIME))
> + drm_prime_init_file_private(&priv->prime);
> +
> if (dev->driver->open) {
> ret = dev->driver->open(dev, priv);
> if (ret < 0)
> @@ -571,6 +574,10 @@ int drm_release(struct inode *inode, struct file *filp)
>
> if (dev->driver->postclose)
> dev->driver->postclose(dev, file_priv);
> +
> + if (drm_core_check_feature(dev, DRIVER_PRIME))
> + drm_prime_destroy_file_private(&file_priv->prime);
> +
> kfree(file_priv);
>
> /* ========================================================
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index 0ef358e..f337497 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -35,6 +35,7 @@
> #include <linux/mman.h>
> #include <linux/pagemap.h>
> #include <linux/shmem_fs.h>
> +#include <linux/dma-buf.h>
> #include "drmP.h"
>
> /** @file drm_gem.c
> @@ -232,6 +233,10 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
> idr_remove(&filp->object_idr, handle);
> spin_unlock(&filp->table_lock);
>
> + if (obj->import_attach)
> + drm_prime_remove_fd_handle_mapping(&filp->prime,
> + obj->import_attach->dmabuf);
> +
> if (dev->driver->gem_close_object)
> dev->driver->gem_close_object(obj, filp);
> drm_gem_object_handle_unreference_unlocked(obj);
> @@ -527,6 +532,10 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
> struct drm_gem_object *obj = ptr;
> struct drm_device *dev = obj->dev;
>
> + if (obj->import_attach)
> + drm_prime_remove_fd_handle_mapping(&file_priv->prime,
> + obj->import_attach->dmabuf);
> +
> if (dev->driver->gem_close_object)
> dev->driver->gem_close_object(obj, file_priv);
>
> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> new file mode 100644
> index 0000000..1c7f057
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_prime.c
> @@ -0,0 +1,281 @@
> +/*
> + * Copyright © 2012 Red Hat
> + *
> + * 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:
> + * Dave Airlie <airlied@redhat.com>
> + * Rob Clark
> + *
> + */
> +
> +#include <linux/export.h>
> +#include <linux/dma-buf.h>
> +#include "drmP.h"
> +
> +/*
> + * DMA-BUF/GEM Object references and lifetime overview:
> + *
> + * On the export the dma_buf holds a reference to the exporting GEM
> + * object. It takes this reference in handle_to_fd_ioctl, when it
> + * first calls .prime_export and stores the exporting GEM object in
> + * the dma_buf priv. This reference is released when the dma_buf
> + * object goes away in the driver .release function.
> + *
> + * On the import the importing GEM object holds a reference to the
> + * dma_buf (which in turn holds a ref to the exporting GEM object).
> + * It takes that reference in the fd_to_handle ioctl.
> + * It calls dma_buf_get, creates an attachment to it and stores the
> + * attachment in the GEM object. When this attachment is destroyed
> + * when the imported object is destroyed, we remove the attachment
> + * and drop the reference to the dma_buf.
> + *
> + * Thus the chain of references always flows in one direction
> + * (avoiding loops): importing_gem -> dmabuf -> exporting_gem
> + */
> +
> +struct drm_prime_member {
> + struct list_head entry;
> + struct dma_buf *dma_buf;
> + uint32_t handle;
> +};
> +
> +int drm_gem_prime_handle_to_fd(struct drm_device *dev,
> + struct drm_file *file_priv, uint32_t handle, uint32_t flags,
> + int *prime_fd)
> +{
> + struct drm_gem_object *obj;
> +
> + obj = drm_gem_object_lookup(dev, file_priv, handle);
> + if (!obj)
> + return -ENOENT;
> +
> + /* don't allow imported buffers to be re-exported */
> + if (obj->import_attach) {
> + drm_gem_object_unreference_unlocked(obj);
> + return -EINVAL;
> + }
> +
> + if (obj->export_dma_buf) {
> + get_file(obj->export_dma_buf->file);
> + *prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
> + drm_gem_object_unreference_unlocked(obj);
> + } else {
> + obj->export_dma_buf =
> + dev->driver->gem_prime_export(dev, obj, flags);
> + if (IS_ERR_OR_NULL(obj->export_dma_buf)) {
> + /* normally the created dma-buf takes ownership of the ref,
> + * but if that fails then drop the ref
> + */
> + drm_gem_object_unreference_unlocked(obj);
> + return PTR_ERR(obj->export_dma_buf);
> + }
> + *prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
> + }
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
> +
> +int drm_gem_prime_fd_to_handle(struct drm_device *dev,
> + struct drm_file *file_priv, int prime_fd, uint32_t *handle)
> +{
> + struct dma_buf *dma_buf;
> + struct drm_gem_object *obj;
> + int ret;
> +
> + dma_buf = dma_buf_get(prime_fd);
> + if (IS_ERR(dma_buf))
> + return PTR_ERR(dma_buf);
> +
> + ret = drm_prime_lookup_fd_handle_mapping(&file_priv->prime,
> + dma_buf, handle);
> + if (!ret) {
> + dma_buf_put(dma_buf);
> + return 0;
> + }
> +
> + /* never seen this one, need to import */
> + obj = dev->driver->gem_prime_import(dev, dma_buf);
> + if (IS_ERR_OR_NULL(obj)) {
> + ret = PTR_ERR(obj);
> + goto fail_put;
> + }
> +
> + ret = drm_gem_handle_create(file_priv, obj, handle);
> + drm_gem_object_unreference_unlocked(obj);
> + if (ret)
> + goto fail_put;
> +
> + ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime,
> + dma_buf, *handle);
> + if (ret)
> + goto fail;
> +
> + return 0;
> +
> +fail:
> + /* hmm, if driver attached, we are relying on the free-object path
> + * to detach.. which seems ok..
> + */
> + drm_gem_object_handle_unreference_unlocked(obj);
> +fail_put:
> + dma_buf_put(dma_buf);
> + return ret;
> +}
> +EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
> +
> +int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv)
> +{
> + struct drm_prime_handle *args = data;
> + uint32_t flags;
> +
> + if (!drm_core_check_feature(dev, DRIVER_PRIME))
> + return -EINVAL;
> +
> + if (!dev->driver->prime_handle_to_fd)
> + return -ENOSYS;
> +
> + /* we only want to pass DRM_CLOEXEC which is == O_CLOEXEC */
> + flags = args->flags & DRM_CLOEXEC;
> +
> + return dev->driver->prime_handle_to_fd(dev, file_priv,
> + args->handle, flags, &args->fd);
> +}
> +
> +int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv)
> +{
> + struct drm_prime_handle *args = data;
> +
> + if (!drm_core_check_feature(dev, DRIVER_PRIME))
> + return -EINVAL;
> +
> + if (!dev->driver->prime_fd_to_handle)
> + return -ENOSYS;
> +
> + return dev->driver->prime_fd_to_handle(dev, file_priv,
> + args->fd, &args->handle);
> +}
> +
> +/*
> + * drm_prime_pages_to_sg
> + *
> + * this helper creates an sg table object from a set of pages
> + * the driver is responsible for mapping the pages into the
> + * importers address space
> + */
> +struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
> +{
> + struct sg_table *sg = NULL;
> + struct scatterlist *iter;
> + int i;
> + int ret;
> +
> + sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
> + if (!sg)
> + goto out;
> +
> + ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL);
> + if (ret)
> + goto out;
> +
> + for_each_sg(sg->sgl, iter, nr_pages, i)
> + sg_set_page(iter, pages[i], PAGE_SIZE, 0);
> +
> + return sg;
> +out:
> + kfree(sg);
> + return NULL;
> +}
> +EXPORT_SYMBOL(drm_prime_pages_to_sg);
> +
> +/* helper function to cleanup a GEM/prime object */
> +void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)
> +{
> + struct dma_buf_attachment *attach;
> + struct dma_buf *dma_buf;
> + attach = obj->import_attach;
> + if (sg)
> + dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
> + dma_buf = attach->dmabuf;
> + dma_buf_detach(attach->dmabuf, attach);
> + /* remove the reference */
> + dma_buf_put(dma_buf);
> +}
> +EXPORT_SYMBOL(drm_prime_gem_destroy);
> +
> +void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
> +{
> + INIT_LIST_HEAD(&prime_fpriv->head);
> +}
> +EXPORT_SYMBOL(drm_prime_init_file_private);
> +
> +void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
> +{
> + struct drm_prime_member *member, *safe;
> + list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
> + list_del(&member->entry);
> + kfree(member);
> + }
> +}
> +EXPORT_SYMBOL(drm_prime_destroy_file_private);
> +
> +int drm_prime_insert_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle)
> +{
> + struct drm_prime_member *member;
> +
> + member = kmalloc(sizeof(*member), GFP_KERNEL);
> + if (!member)
> + return -ENOMEM;
> +
> + member->dma_buf = dma_buf;
> + member->handle = handle;
> + list_add(&member->entry, &prime_fpriv->head);
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_prime_insert_fd_handle_mapping);
> +
> +int drm_prime_lookup_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle)
> +{
> + struct drm_prime_member *member;
> +
> + list_for_each_entry(member, &prime_fpriv->head, entry) {
> + if (member->dma_buf == dma_buf) {
> + *handle = member->handle;
> + return 0;
> + }
> + }
> + return -ENOENT;
> +}
> +EXPORT_SYMBOL(drm_prime_lookup_fd_handle_mapping);
> +
> +void drm_prime_remove_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf)
> +{
> + struct drm_prime_member *member, *safe;
> +
> + list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
> + if (member->dma_buf == dma_buf) {
> + list_del(&member->entry);
> + kfree(member);
> + }
> + }
> +}
> +EXPORT_SYMBOL(drm_prime_remove_fd_handle_mapping);
> diff --git a/include/drm/drm.h b/include/drm/drm.h
> index 34a7b89..64ff02d 100644
> --- a/include/drm/drm.h
> +++ b/include/drm/drm.h
> @@ -617,6 +617,17 @@ struct drm_get_cap {
> __u64 value;
> };
>
> +#define DRM_CLOEXEC O_CLOEXEC
> +struct drm_prime_handle {
> + __u32 handle;
> +
> + /** Flags.. only applicable for handle->fd */
> + __u32 flags;
> +
> + /** Returned dmabuf file descriptor */
> + __s32 fd;
> +};
> +
> #include "drm_mode.h"
>
> #define DRM_IOCTL_BASE 'd'
> @@ -673,7 +684,8 @@ struct drm_get_cap {
> #define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock)
> #define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock)
>
> -#define DRM_IOCTL_GEM_PRIME_OPEN DRM_IOWR(0x2e, struct drm_gem_open)
> +#define DRM_IOCTL_PRIME_HANDLE_TO_FD DRM_IOWR(0x2d, struct drm_prime_handle)
> +#define DRM_IOCTL_PRIME_FD_TO_HANDLE DRM_IOWR(0x2e, struct drm_prime_handle)
>
> #define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30)
> #define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31)
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index 574bd1c..f1e9c89 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -91,6 +91,7 @@ struct drm_device;
> #define DRM_UT_CORE 0x01
> #define DRM_UT_DRIVER 0x02
> #define DRM_UT_KMS 0x04
> +#define DRM_UT_PRIME 0x08
> /*
> * Three debug levels are defined.
> * drm_core, drm_driver, drm_kms
> @@ -150,6 +151,7 @@ int drm_err(const char *func, const char *format, ...);
> #define DRIVER_IRQ_VBL2 0x800
> #define DRIVER_GEM 0x1000
> #define DRIVER_MODESET 0x2000
> +#define DRIVER_PRIME 0x4000
>
> #define DRIVER_BUS_PCI 0x1
> #define DRIVER_BUS_PLATFORM 0x2
> @@ -215,6 +217,11 @@ int drm_err(const char *func, const char *format, ...);
> drm_ut_debug_printk(DRM_UT_KMS, DRM_NAME, \
> __func__, fmt, ##args); \
> } while (0)
> +#define DRM_DEBUG_PRIME(fmt, args...) \
> + do { \
> + drm_ut_debug_printk(DRM_UT_PRIME, DRM_NAME, \
> + __func__, fmt, ##args); \
> + } while (0)
> #define DRM_LOG(fmt, args...) \
> do { \
> drm_ut_debug_printk(DRM_UT_CORE, NULL, \
> @@ -238,6 +245,7 @@ int drm_err(const char *func, const char *format, ...);
> #else
> #define DRM_DEBUG_DRIVER(fmt, args...) do { } while (0)
> #define DRM_DEBUG_KMS(fmt, args...) do { } while (0)
> +#define DRM_DEBUG_PRIME(fmt, args...) do { } while (0)
> #define DRM_DEBUG(fmt, arg...) do { } while (0)
> #define DRM_LOG(fmt, arg...) do { } while (0)
> #define DRM_LOG_KMS(fmt, args...) do { } while (0)
> @@ -410,6 +418,11 @@ struct drm_pending_event {
> void (*destroy)(struct drm_pending_event *event);
> };
>
> +/* initial implementaton using a linked list - todo hashtab */
> +struct drm_prime_file_private {
> + struct list_head head;
> +};
> +
> /** File private data */
> struct drm_file {
> int authenticated;
> @@ -437,6 +450,8 @@ struct drm_file {
> wait_queue_head_t event_wait;
> struct list_head event_list;
> int event_space;
> +
> + struct drm_prime_file_private prime;
> };
>
> /** Wait queue */
> @@ -652,6 +667,12 @@ struct drm_gem_object {
> uint32_t pending_write_domain;
>
> void *driver_private;
> +
> + /* dma buf exported from this GEM object */
> + struct dma_buf *export_dma_buf;
> +
> + /* dma buf attachment backing this object */
> + struct dma_buf_attachment *import_attach;
> };
>
> #include "drm_crtc.h"
> @@ -890,6 +911,20 @@ struct drm_driver {
> int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
> void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
>
> + /* prime: */
> + /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */
> + int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
> + uint32_t handle, uint32_t flags, int *prime_fd);
> + /* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */
> + int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv,
> + int prime_fd, uint32_t *handle);
> + /* export GEM -> dmabuf */
> + struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
> + struct drm_gem_object *obj, int flags);
> + /* import dmabuf -> GEM */
> + struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
> + struct dma_buf *dma_buf);
> +
> /* vga arb irq handler */
> void (*vgaarb_irq)(struct drm_device *dev, bool state);
>
> @@ -1509,6 +1544,32 @@ extern int drm_vblank_info(struct seq_file *m, void *data);
> extern int drm_clients_info(struct seq_file *m, void* data);
> extern int drm_gem_name_info(struct seq_file *m, void *data);
>
> +
> +extern int drm_gem_prime_handle_to_fd(struct drm_device *dev,
> + struct drm_file *file_priv, uint32_t handle, uint32_t flags,
> + int *prime_fd);
> +extern int drm_gem_prime_fd_to_handle(struct drm_device *dev,
> + struct drm_file *file_priv, int prime_fd, uint32_t *handle);
> +
> +extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv);
> +extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv);
> +
> +extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages);
> +extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
> +
> +
> +void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
> +void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
> +int drm_prime_insert_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle);
> +int drm_prime_lookup_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle);
> +void drm_prime_remove_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf);
> +
> +int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj);
> +int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf,
> + struct drm_gem_object **obj);
> +
> #if DRM_DEBUG_CODE
> extern int drm_vma_info(struct seq_file *m, void *data);
> #endif
> --
> 1.7.7.6
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] drm: base prime/dma-buf support
2012-03-26 15:02 [PATCH] drm: base prime/dma-buf support Dave Airlie
2012-03-26 15:45 ` daeinki
@ 2012-03-26 16:32 ` Ville Syrjälä
1 sibling, 0 replies; 3+ messages in thread
From: Ville Syrjälä @ 2012-03-26 16:32 UTC (permalink / raw)
To: Dave Airlie; +Cc: dri-devel
On Mon, Mar 26, 2012 at 04:02:55PM +0100, Dave Airlie wrote:
<snip>
> +int drm_gem_prime_handle_to_fd(struct drm_device *dev,
> + struct drm_file *file_priv, uint32_t handle, uint32_t flags,
> + int *prime_fd)
> +{
> + struct drm_gem_object *obj;
> +
> + obj = drm_gem_object_lookup(dev, file_priv, handle);
> + if (!obj)
> + return -ENOENT;
> +
> + /* don't allow imported buffers to be re-exported */
> + if (obj->import_attach) {
> + drm_gem_object_unreference_unlocked(obj);
> + return -EINVAL;
> + }
> +
> + if (obj->export_dma_buf) {
> + get_file(obj->export_dma_buf->file);
> + *prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
> + drm_gem_object_unreference_unlocked(obj);
> + } else {
> + obj->export_dma_buf =
> + dev->driver->gem_prime_export(dev, obj, flags);
> + if (IS_ERR_OR_NULL(obj->export_dma_buf)) {
> + /* normally the created dma-buf takes ownership of the ref,
> + * but if that fails then drop the ref
> + */
> + drm_gem_object_unreference_unlocked(obj);
> + return PTR_ERR(obj->export_dma_buf);
PTR_ERR(NULL) seems like a bad idea. Also, you're accessing 'obj' after
dropping the reference.
> + }
> + *prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
> + }
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
> +
> +int drm_gem_prime_fd_to_handle(struct drm_device *dev,
> + struct drm_file *file_priv, int prime_fd, uint32_t *handle)
> +{
> + struct dma_buf *dma_buf;
> + struct drm_gem_object *obj;
> + int ret;
> +
> + dma_buf = dma_buf_get(prime_fd);
> + if (IS_ERR(dma_buf))
> + return PTR_ERR(dma_buf);
> +
> + ret = drm_prime_lookup_fd_handle_mapping(&file_priv->prime,
> + dma_buf, handle);
> + if (!ret) {
> + dma_buf_put(dma_buf);
> + return 0;
> + }
> +
> + /* never seen this one, need to import */
> + obj = dev->driver->gem_prime_import(dev, dma_buf);
> + if (IS_ERR_OR_NULL(obj)) {
> + ret = PTR_ERR(obj);
PTR_ERR(NULL) again.
> + goto fail_put;
> + }
> +
> + ret = drm_gem_handle_create(file_priv, obj, handle);
> + drm_gem_object_unreference_unlocked(obj);
> + if (ret)
> + goto fail_put;
> +
> + ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime,
> + dma_buf, *handle);
> + if (ret)
> + goto fail;
> +
> + return 0;
> +
> +fail:
> + /* hmm, if driver attached, we are relying on the free-object path
> + * to detach.. which seems ok..
> + */
> + drm_gem_object_handle_unreference_unlocked(obj);
> +fail_put:
> + dma_buf_put(dma_buf);
> + return ret;
> +}
> +EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
> +
> +int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv)
> +{
> + struct drm_prime_handle *args = data;
> + uint32_t flags;
> +
> + if (!drm_core_check_feature(dev, DRIVER_PRIME))
> + return -EINVAL;
> +
> + if (!dev->driver->prime_handle_to_fd)
> + return -ENOSYS;
> +
> + /* we only want to pass DRM_CLOEXEC which is == O_CLOEXEC */
> + flags = args->flags & DRM_CLOEXEC;
Check that the unused flags are 0? If you allow broken userspace to
pass uninitialized 'flags' to the kernel, you may have compatibility
problems if/when you want to add more flags.
> +
> + return dev->driver->prime_handle_to_fd(dev, file_priv,
> + args->handle, flags, &args->fd);
> +}
> +
> +int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv)
> +{
> + struct drm_prime_handle *args = data;
> +
> + if (!drm_core_check_feature(dev, DRIVER_PRIME))
> + return -EINVAL;
> +
> + if (!dev->driver->prime_fd_to_handle)
> + return -ENOSYS;
> +
> + return dev->driver->prime_fd_to_handle(dev, file_priv,
> + args->fd, &args->handle);
> +}
> +
> +/*
> + * drm_prime_pages_to_sg
> + *
> + * this helper creates an sg table object from a set of pages
> + * the driver is responsible for mapping the pages into the
> + * importers address space
> + */
> +struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
> +{
> + struct sg_table *sg = NULL;
> + struct scatterlist *iter;
> + int i;
> + int ret;
> +
> + sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
kmalloc() would be enough. sg_alloc_table() already does a memset().
> + if (!sg)
> + goto out;
> +
> + ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL);
> + if (ret)
> + goto out;
> +
> + for_each_sg(sg->sgl, iter, nr_pages, i)
> + sg_set_page(iter, pages[i], PAGE_SIZE, 0);
> +
> + return sg;
> +out:
> + kfree(sg);
> + return NULL;
> +}
> +EXPORT_SYMBOL(drm_prime_pages_to_sg);
--
Ville Syrjälä
Intel OTC
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-03-26 16:24 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-26 15:02 [PATCH] drm: base prime/dma-buf support Dave Airlie
2012-03-26 15:45 ` daeinki
2012-03-26 16:32 ` Ville Syrjälä
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.