[RFC] dma-buf: Import/export the implicit fences on the dma-buf
Chris Wilson
chris at chris-wilson.co.uk
Mon Jul 11 21:59:38 UTC 2016
When dealing with user interfaces that utilize explicit fences, it is
convenient to sometimes create those fences after the fact, i.e. to
query the dma-buf for the current set of implicit fences, encapsulate
those into a sync_file and hand that fd back to userspace.
Correspondingly, being able to add an explicit fence back into the mix
of fences being tracked by the dma-buf allows that userspace fence to be
included in any implicit tracking.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Gustavo Padovan <gustavo.padovan at collabora.co.uk>
Cc: Rob Clark <robdclark at gmail.com>
Cc: Sumit Semwal <sumit.semwal at linaro.org>
Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
Cc: dri-devel at lists.freedesktop.org
---
Gustavo, could you look at the sync-file/fence-array handling? There's
definitely room for a cleaner sync_file_create() API.
I was thinking about this for the "why not sync-file" question Gustavo
posed for the vgem_fences. I wanted to add an ioctl to the vgem to allow
exporting and creating fences from sync-file for testing passing
explicit userspaces around between drivers, and realised that I was just
writing a generic mechanism that only required dma-buf.
Whilst this interface could be used for lazily creating explicit fences,
drivers will also likely want to support specific ioctl to skip the
dmabuf creation, I think this interfaces will be useful with the vgem
fences for testing sync_file handling in drivers (on i915 at the moment,
my tests for sync_file involve sleeping and a few white lies). So
fulfilling a similar role in driver testing to debugfs/sw_sync?
(sw_sync is still more apt for testing timelines etc, vgem feels more
apt for ease of testing rendering.)
-Chris
---
drivers/dma-buf/dma-buf.c | 100 +++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/dma-buf.h | 9 ++++
2 files changed, 109 insertions(+)
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 41fbce0c273a..6f066a8affd7 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -26,11 +26,13 @@
#include <linux/slab.h>
#include <linux/dma-buf.h>
#include <linux/fence.h>
+#include <linux/fence-array.h>
#include <linux/anon_inodes.h>
#include <linux/export.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/seq_file.h>
+#include <linux/sync_file.h>
#include <linux/poll.h>
#include <linux/reservation.h>
#include <linux/mm.h>
@@ -254,6 +256,97 @@ out:
return events;
}
+static long dma_buf_import_fence_ioctl(struct dma_buf *dmabuf,
+ struct dma_buf_fence __user *arg)
+{
+ struct reservation_object *resv = dmabuf->resv;
+ struct dma_buf_fence cmd;
+ struct fence *fence;
+ int ret;
+
+ if (copy_from_user(&cmd, arg, sizeof(cmd)))
+ return -EFAULT;
+
+ fence = NULL;
+ //fence = sync_file_get_fence(cmd.fd);
+ if (!fence)
+ return -EINVAL;
+
+ mutex_lock(&resv->lock.base);
+ if (cmd.flags & DMA_BUF_FENCE_WRITE)
+ reservation_object_add_excl_fence(resv, fence);
+ else if ((ret = reservation_object_reserve_shared(resv)) == 0)
+ reservation_object_add_shared_fence(resv, fence);
+ mutex_unlock(&resv->lock.base);
+
+ fence_put(fence);
+ return ret;
+}
+
+static long dma_buf_export_fence_ioctl(struct dma_buf *dmabuf,
+ struct dma_buf_fence __user *arg)
+{
+ struct reservation_object *resv = dmabuf->resv;
+ struct dma_buf_fence cmd;
+ struct fence *excl, **shared;
+ struct sync_file *sync = NULL;
+ unsigned int count, n;
+ int ret;
+
+ if (get_user(cmd.flags, &arg->flags))
+ return -EFAULT;
+
+ ret = reservation_object_get_fences_rcu(resv, &excl, &count, &shared);
+ if (ret)
+ return ret;
+
+ if (cmd.flags & DMA_BUF_FENCE_WRITE) {
+ if (excl) {
+ sync = sync_file_create(excl);
+ if (!sync) {
+ ret = -ENOMEM;
+ fence_put(excl);
+ }
+ }
+ for (n = 0; n < count; n++)
+ fence_put(shared[n]);
+ kfree(shared);
+ } else {
+ if (count) {
+ struct fence_array *array;
+
+ array = fence_array_create(count, shared, 0, 0, false);
+ if (!array) {
+ for (n = 0; n < count; n++)
+ fence_put(shared[n]);
+ kfree(shared);
+ } else
+ sync = sync_file_create(&array->base);
+ if (!sync) {
+ ret = -ENOMEM;
+ fence_put(&array->base);
+ }
+ }
+ fence_put(excl);
+ }
+ if (ret)
+ return ret;
+
+ cmd.fd = get_unused_fd_flags(O_CLOEXEC);
+ if (cmd.fd < 0) {
+ fput(sync->file);
+ return cmd.fd;
+ }
+
+ if (put_user(cmd.fd, &arg->fd)) {
+ fput(sync->file);
+ return -EFAULT;
+ }
+
+ fd_install(cmd.fd, sync->file);
+ return 0;
+}
+
static long dma_buf_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -292,6 +385,13 @@ static long dma_buf_ioctl(struct file *file,
ret = dma_buf_begin_cpu_access(dmabuf, direction);
return ret;
+
+ case DMA_BUF_IOCTL_IMPORT_FENCE:
+ return dma_buf_import_fence_ioctl(dmabuf, (void __user *)arg);
+
+ case DMA_BUF_IOCTL_EXPORT_FENCE:
+ return dma_buf_export_fence_ioctl(dmabuf, (void __user *)arg);
+
default:
return -ENOTTY;
}
diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h
index fb0dedb7c121..8d9a0d73ebaa 100644
--- a/include/uapi/linux/dma-buf.h
+++ b/include/uapi/linux/dma-buf.h
@@ -37,4 +37,13 @@ struct dma_buf_sync {
#define DMA_BUF_BASE 'b'
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
+struct dma_buf_fence {
+ __s32 fd;
+ __u32 flags;
+#define DMA_BUF_FENCE_WRITE (1 << 0)
+};
+
+#define DMA_BUF_IOCTL_IMPORT_FENCE _IOW(DMA_BUF_BASE, 1, struct dma_buf_fence)
+#define DMA_BUF_IOCTL_EXPORT_FENCE _IOWR(DMA_BUF_BASE, 2, struct dma_buf_fence)
+
#endif
--
2.8.1
More information about the dri-devel
mailing list