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

Reply via email to