Merge tag 'drm-next-2022-08-03' of git://anongit.freedesktop.org/drm/drm
[linux-2.6-microblaze.git] / drivers / dma-buf / dma-buf.c
index 3f08e0b..efb4990 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/debugfs.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
+#include <linux/sync_file.h>
 #include <linux/poll.h>
 #include <linux/dma-resv.h>
 #include <linux/mm.h>
@@ -192,6 +193,9 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
  * Note that this only signals the completion of the respective fences, i.e. the
  * DMA transfers are complete. Cache flushing and any other necessary
  * preparations before CPU access can begin still need to happen.
+ *
+ * As an alternative to poll(), the set of fences on DMA buffer can be
+ * exported as a &sync_file using &dma_buf_sync_file_export.
  */
 
 static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
@@ -326,6 +330,101 @@ static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_SYNC_FILE)
+static long dma_buf_export_sync_file(struct dma_buf *dmabuf,
+                                    void __user *user_data)
+{
+       struct dma_buf_export_sync_file arg;
+       enum dma_resv_usage usage;
+       struct dma_fence *fence = NULL;
+       struct sync_file *sync_file;
+       int fd, ret;
+
+       if (copy_from_user(&arg, user_data, sizeof(arg)))
+               return -EFAULT;
+
+       if (arg.flags & ~DMA_BUF_SYNC_RW)
+               return -EINVAL;
+
+       if ((arg.flags & DMA_BUF_SYNC_RW) == 0)
+               return -EINVAL;
+
+       fd = get_unused_fd_flags(O_CLOEXEC);
+       if (fd < 0)
+               return fd;
+
+       usage = dma_resv_usage_rw(arg.flags & DMA_BUF_SYNC_WRITE);
+       ret = dma_resv_get_singleton(dmabuf->resv, usage, &fence);
+       if (ret)
+               goto err_put_fd;
+
+       if (!fence)
+               fence = dma_fence_get_stub();
+
+       sync_file = sync_file_create(fence);
+
+       dma_fence_put(fence);
+
+       if (!sync_file) {
+               ret = -ENOMEM;
+               goto err_put_fd;
+       }
+
+       arg.fd = fd;
+       if (copy_to_user(user_data, &arg, sizeof(arg))) {
+               ret = -EFAULT;
+               goto err_put_file;
+       }
+
+       fd_install(fd, sync_file->file);
+
+       return 0;
+
+err_put_file:
+       fput(sync_file->file);
+err_put_fd:
+       put_unused_fd(fd);
+       return ret;
+}
+
+static long dma_buf_import_sync_file(struct dma_buf *dmabuf,
+                                    const void __user *user_data)
+{
+       struct dma_buf_import_sync_file arg;
+       struct dma_fence *fence;
+       enum dma_resv_usage usage;
+       int ret = 0;
+
+       if (copy_from_user(&arg, user_data, sizeof(arg)))
+               return -EFAULT;
+
+       if (arg.flags & ~DMA_BUF_SYNC_RW)
+               return -EINVAL;
+
+       if ((arg.flags & DMA_BUF_SYNC_RW) == 0)
+               return -EINVAL;
+
+       fence = sync_file_get_fence(arg.fd);
+       if (!fence)
+               return -EINVAL;
+
+       usage = (arg.flags & DMA_BUF_SYNC_WRITE) ? DMA_RESV_USAGE_WRITE :
+                                                  DMA_RESV_USAGE_READ;
+
+       dma_resv_lock(dmabuf->resv, NULL);
+
+       ret = dma_resv_reserve_fences(dmabuf->resv, 1);
+       if (!ret)
+               dma_resv_add_fence(dmabuf->resv, fence, usage);
+
+       dma_resv_unlock(dmabuf->resv);
+
+       dma_fence_put(fence);
+
+       return ret;
+}
+#endif
+
 static long dma_buf_ioctl(struct file *file,
                          unsigned int cmd, unsigned long arg)
 {
@@ -369,6 +468,13 @@ static long dma_buf_ioctl(struct file *file,
        case DMA_BUF_SET_NAME_B:
                return dma_buf_set_name(dmabuf, (const char __user *)arg);
 
+#if IS_ENABLED(CONFIG_SYNC_FILE)
+       case DMA_BUF_IOCTL_EXPORT_SYNC_FILE:
+               return dma_buf_export_sync_file(dmabuf, (void __user *)arg);
+       case DMA_BUF_IOCTL_IMPORT_SYNC_FILE:
+               return dma_buf_import_sync_file(dmabuf, (const void __user *)arg);
+#endif
+
        default:
                return -ENOTTY;
        }
@@ -1358,7 +1464,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
                return ret;
 
        seq_puts(s, "\nDma-buf Objects:\n");
-       seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\n",
+       seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\tname\n",
                   "size", "flags", "mode", "count", "ino");
 
        list_for_each_entry(buf_obj, &db_list.head, list_node) {
@@ -1375,7 +1481,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
                                file_count(buf_obj->file),
                                buf_obj->exp_name,
                                file_inode(buf_obj->file)->i_ino,
-                               buf_obj->name ?: "");
+                               buf_obj->name ?: "<none>");
                spin_unlock(&buf_obj->name_lock);
 
                dma_resv_describe(buf_obj->resv, s);