dma-buf: Add ioctls to allow userspace to flush 34/115834/2 accepted/tizen/mobile/20170316.101739 accepted/tizen/unified/20170316.101857 submit/tizen/20170316.045621
authorMarek Szyprowski <m.szyprowski@samsung.com>
Tue, 21 Feb 2017 11:20:25 +0000 (12:20 +0100)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Wed, 8 Mar 2017 10:06:30 +0000 (02:06 -0800)
The userspace might need some sort of cache coherency management e.g. when CPU
and GPU domains are being accessed through dma-buf at the same time. To
circumvent this problem there are begin/end coherency markers, that forward
directly to existing dma-buf device drivers vfunc hooks. Userspace can make use
of those markers through the DMA_BUF_IOCTL_SYNC ioctl. The sequence would be
used like following:
     - mmap dma-buf fd
     - for each drawing/upload cycle in CPU 1. SYNC_START ioctl, 2. read/write
       to mmap area 3. SYNC_END ioctl. This can be repeated as often as you
       want (with the new data being consumed by the GPU or say scanout device)
     - munmap once you don't need the buffer any more

v2 (Tiago): Fix header file type names (u64 -> __u64)
v3 (Tiago): Add documentation. Use enum dma_buf_sync_flags to the begin/end
dma-buf functions. Check for overflows in start/length.
v4 (Tiago): use 2d regions for sync.
v5 (Tiago): forget about 2d regions (v4); use _IOW in DMA_BUF_IOCTL_SYNC and
remove range information from struct dma_buf_sync.
v6 (Tiago): use __u64 structured padded flags instead enum. Adjust
documentation about the recommendation on using sync ioctls.
v7 (Tiago): Alex' nit on flags definition and being even more wording in the
doc about sync usage.
v9 (Tiago): remove useless is_dma_buf_file check. Fix sync.flags conditionals
and its mask order check. Add <linux/types.h> include in dma-buf.h.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: David Herrmann <dh.herrmann@gmail.com>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Tiago Vignatti <tiago.vignatti@intel.com>
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
[mszyprow: backport of mainline commit c11e391da2a8fe973c3c2398452000bed505851e]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Change-Id: I74eabf0faafebadabce17cb91e9962a44b5af544

drivers/base/dma-buf.c
drivers/staging/android/ion/ion.c
include/linux/dma-buf.h
include/uapi/linux/dma-buf.h [new file with mode: 0644]

index 08fe897..51a9fb8 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/export.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#include <uapi/linux/dma-buf.h>
 
 static inline int is_dma_buf_file(struct file *);
 
@@ -77,9 +80,52 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
        return dmabuf->ops->mmap(dmabuf, vma);
 }
 
+static long dma_buf_ioctl(struct file *file,
+                         unsigned int cmd, unsigned long arg)
+{
+       struct dma_buf *dmabuf;
+       struct dma_buf_sync sync;
+       enum dma_data_direction direction;
+
+       dmabuf = file->private_data;
+
+       switch (cmd) {
+       case DMA_BUF_IOCTL_SYNC:
+               if (copy_from_user(&sync, (void __user *) arg, sizeof(sync)))
+                       return -EFAULT;
+
+               if (sync.flags & ~DMA_BUF_SYNC_VALID_FLAGS_MASK)
+                       return -EINVAL;
+
+               switch (sync.flags & DMA_BUF_SYNC_RW) {
+               case DMA_BUF_SYNC_READ:
+                       direction = DMA_FROM_DEVICE;
+                       break;
+               case DMA_BUF_SYNC_WRITE:
+                       direction = DMA_TO_DEVICE;
+                       break;
+               case DMA_BUF_SYNC_RW:
+                       direction = DMA_BIDIRECTIONAL;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               if (sync.flags & DMA_BUF_SYNC_END)
+                       dma_buf_end_cpu_access(dmabuf, direction);
+               else
+                       dma_buf_begin_cpu_access(dmabuf, direction);
+
+               return 0;
+       default:
+               return -ENOTTY;
+       }
+}
+
 static const struct file_operations dma_buf_fops = {
        .release        = dma_buf_release,
        .mmap           = dma_buf_mmap_internal,
+       .unlocked_ioctl = dma_buf_ioctl,
 };
 
 /*
@@ -337,13 +383,11 @@ EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
  * preparations. Coherency is only guaranteed in the specified range for the
  * specified access direction.
  * @dmabuf:    [in]    buffer to prepare cpu access for.
- * @start:     [in]    start of range for cpu access.
- * @len:       [in]    length of range for cpu access.
  * @direction: [in]    length of range for cpu access.
  *
  * Can return negative error values, returns 0 on success.
  */
-int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
                             enum dma_data_direction direction)
 {
        int ret = 0;
@@ -352,7 +396,7 @@ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
                return -EINVAL;
 
        if (dmabuf->ops->begin_cpu_access)
-               ret = dmabuf->ops->begin_cpu_access(dmabuf, start, len, direction);
+               ret = dmabuf->ops->begin_cpu_access(dmabuf, direction);
 
        return ret;
 }
@@ -364,19 +408,17 @@ EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
  * actions. Coherency is only guaranteed in the specified range for the
  * specified access direction.
  * @dmabuf:    [in]    buffer to complete cpu access for.
- * @start:     [in]    start of range for cpu access.
- * @len:       [in]    length of range for cpu access.
  * @direction: [in]    length of range for cpu access.
  *
- * This call must always succeed.
+ * Can return negative error values, returns 0 on success.
  */
-void dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+void dma_buf_end_cpu_access(struct dma_buf *dmabuf,
                            enum dma_data_direction direction)
 {
        WARN_ON(!dmabuf);
 
        if (dmabuf->ops->end_cpu_access)
-               dmabuf->ops->end_cpu_access(dmabuf, start, len, direction);
+               dmabuf->ops->end_cpu_access(dmabuf, direction);
 }
 EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
 
index 3d00636..76a8c09 100644 (file)
@@ -1249,8 +1249,7 @@ static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
        return;
 }
 
-static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start,
-                                       size_t len,
+static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
                                        enum dma_data_direction direction)
 {
        struct ion_buffer *buffer = dmabuf->priv;
@@ -1270,8 +1269,7 @@ static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start,
        return 0;
 }
 
-static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start,
-                                      size_t len,
+static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
                                       enum dma_data_direction direction)
 {
        struct ion_buffer *buffer = dmabuf->priv;
index dfac5ed..67c09cf 100644 (file)
@@ -91,10 +91,8 @@ struct dma_buf_ops {
        /* after final dma_buf_put() */
        void (*release)(struct dma_buf *);
 
-       int (*begin_cpu_access)(struct dma_buf *, size_t, size_t,
-                               enum dma_data_direction);
-       void (*end_cpu_access)(struct dma_buf *, size_t, size_t,
-                              enum dma_data_direction);
+       int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction);
+       void (*end_cpu_access)(struct dma_buf *, enum dma_data_direction);
        void *(*kmap_atomic)(struct dma_buf *, unsigned long);
        void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *);
        void *(*kmap)(struct dma_buf *, unsigned long);
@@ -181,9 +179,9 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
                                        enum dma_data_direction);
 void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
                                enum dma_data_direction);
-int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len,
+int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
                             enum dma_data_direction dir);
-void dma_buf_end_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len,
+void dma_buf_end_cpu_access(struct dma_buf *dma_buf,
                            enum dma_data_direction dir);
 void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
 void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);
diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h
new file mode 100644 (file)
index 0000000..fb0dedb
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Framework for buffer objects that can be shared across devices/subsystems.
+ *
+ * Copyright(C) 2015 Intel Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DMA_BUF_UAPI_H_
+#define _DMA_BUF_UAPI_H_
+
+#include <linux/types.h>
+
+/* begin/end dma-buf functions used for userspace mmap. */
+struct dma_buf_sync {
+       __u64 flags;
+};
+
+#define DMA_BUF_SYNC_READ      (1 << 0)
+#define DMA_BUF_SYNC_WRITE     (2 << 0)
+#define DMA_BUF_SYNC_RW        (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE)
+#define DMA_BUF_SYNC_START     (0 << 2)
+#define DMA_BUF_SYNC_END       (1 << 2)
+#define DMA_BUF_SYNC_VALID_FLAGS_MASK \
+       (DMA_BUF_SYNC_RW | DMA_BUF_SYNC_END)
+
+#define DMA_BUF_BASE           'b'
+#define DMA_BUF_IOCTL_SYNC     _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
+
+#endif