<div dir="ltr"><div>I can't really review for all of the kernel details (though the seem ok to me) so this mostly applies to the API:<br><br></div>Reviewed-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, May 24, 2017 at 12:06 AM, Dave Airlie <span dir="ltr"><<a href="mailto:airlied@gmail.com" target="_blank">airlied@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Dave Airlie <<a href="mailto:airlied@redhat.com">airlied@redhat.com</a>><br>
<br>
Sync objects are new toplevel drm object, that contain a<br>
pointer to a fence. This fence can be updated via command<br>
submission ioctls via drivers.<br>
<br>
There is also a generic wait obj API modelled on the vulkan<br>
wait API (with code modelled on some amdgpu code).<br>
<br>
These objects can be converted to an opaque fd that can be<br>
passes between processes.<br>
<br>
v2: rename reference/unreference to put/get (Chris)<br>
fix leaked reference (David Zhou)<br>
drop mutex in favour of cmpxchg (Chris)<br>
v3: cleanups from danvet, rebase on drm_fops rename<br>
check fd_flags is 0 in ioctls.<br>
<br>
Reviewed-by: Sean Paul <<a href="mailto:seanpaul@chromium.org">seanpaul@chromium.org</a>><br>
Signed-off-by: Dave Airlie <<a href="mailto:airlied@redhat.com">airlied@redhat.com</a>><br>
---<br>
 Documentation/gpu/drm-<wbr>internals.rst |   3 +<br>
 Documentation/gpu/drm-mm.rst        |  12 ++<br>
 drivers/gpu/drm/Makefile            |   2 +-<br>
 drivers/gpu/drm/drm_file.c          |   8 +<br>
 drivers/gpu/drm/drm_internal.h      |  13 ++<br>
 drivers/gpu/drm/drm_ioctl.c         |  12 ++<br>
 drivers/gpu/drm/drm_syncobj.c       | 377 ++++++++++++++++++++++++++++++<wbr>++++++<br>
 include/drm/drmP.h                  |   1 -<br>
 include/drm/drm_drv.h               |   1 +<br>
 include/drm/drm_file.h              |   5 +<br>
 include/drm/drm_syncobj.h           |  87 +++++++++<br>
 include/uapi/drm/drm.h              |  24 +++<br>
 12 files changed, 543 insertions(+), 2 deletions(-)<br>
 create mode 100644 drivers/gpu/drm/drm_syncobj.c<br>
 create mode 100644 include/drm/drm_syncobj.h<br>
<br>
diff --git a/Documentation/gpu/drm-<wbr>internals.rst b/Documentation/gpu/drm-<wbr>internals.rst<br>
index babfb61..2b23d78 100644<br>
--- a/Documentation/gpu/drm-<wbr>internals.rst<br>
+++ b/Documentation/gpu/drm-<wbr>internals.rst<br>
@@ -98,6 +98,9 @@ DRIVER_ATOMIC<br>
     implement appropriate obj->atomic_get_property() vfuncs for any<br>
     modeset objects with driver specific properties.<br>
<br>
+DRIVER_SYNCOBJ<br>
+    Driver support drm sync objects.<br>
+<br>
 Major, Minor and Patchlevel<br>
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>
<br>
diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst<br>
index 96b9c34..9412798 100644<br>
--- a/Documentation/gpu/drm-mm.rst<br>
+++ b/Documentation/gpu/drm-mm.rst<br>
@@ -484,3 +484,15 @@ DRM Cache Handling<br>
<br>
 .. kernel-doc:: drivers/gpu/drm/drm_cache.c<br>
    :export:<br>
+<br>
+DRM Sync Objects<br>
+===========================<br>
+<br>
+.. kernel-doc:: drivers/gpu/drm/drm_syncobj.c<br>
+   :doc: Overview<br>
+<br>
+.. kernel-doc:: include/drm/drm_syncobj.h<br>
+   :export:<br>
+<br>
+.. kernel-doc:: drivers/gpu/drm/drm_syncobj.c<br>
+   :export:<br>
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile<br>
index 59f0f9b..6f42188 100644<br>
--- a/drivers/gpu/drm/Makefile<br>
+++ b/drivers/gpu/drm/Makefile<br>
@@ -16,7 +16,7 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \<br>
                drm_framebuffer.o drm_connector.o drm_blend.o \<br>
                drm_encoder.o drm_mode_object.o drm_property.o \<br>
                drm_plane.o drm_color_mgmt.o drm_print.o \<br>
-               drm_dumb_buffers.o drm_mode_config.o<br>
+               drm_dumb_buffers.o drm_mode_config.o drm_syncobj.o<br>
<br>
 drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o<br>
 drm-$(CONFIG_DRM_VM) += drm_vm.o<br>
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c<br>
index 3783b65..a20d6a9 100644<br>
--- a/drivers/gpu/drm/drm_file.c<br>
+++ b/drivers/gpu/drm/drm_file.c<br>
@@ -229,6 +229,9 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)<br>
        if (drm_core_check_feature(dev, DRIVER_GEM))<br>
                drm_gem_open(dev, priv);<br>
<br>
+       if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))<br>
+               drm_syncobj_open(priv);<br>
+<br>
        if (drm_core_check_feature(dev, DRIVER_PRIME))<br>
                drm_prime_init_file_private(&<wbr>priv->prime);<br>
<br>
@@ -276,6 +279,8 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)<br>
 out_prime_destroy:<br>
        if (drm_core_check_feature(dev, DRIVER_PRIME))<br>
                drm_prime_destroy_file_<wbr>private(&priv->prime);<br>
+       if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))<br>
+               drm_syncobj_release(priv);<br>
        if (drm_core_check_feature(dev, DRIVER_GEM))<br>
                drm_gem_release(dev, priv);<br>
        put_pid(priv->pid);<br>
@@ -398,6 +403,9 @@ int drm_release(struct inode *inode, struct file *filp)<br>
                drm_property_destroy_user_<wbr>blobs(dev, file_priv);<br>
        }<br>
<br>
+       if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))<br>
+               drm_syncobj_release(file_priv)<wbr>;<br>
+<br>
        if (drm_core_check_feature(dev, DRIVER_GEM))<br>
                drm_gem_release(dev, file_priv);<br>
<br>
diff --git a/drivers/gpu/drm/drm_<wbr>internal.h b/drivers/gpu/drm/drm_<wbr>internal.h<br>
index 3d8e8f8..3fdef2c 100644<br>
--- a/drivers/gpu/drm/drm_<wbr>internal.h<br>
+++ b/drivers/gpu/drm/drm_<wbr>internal.h<br>
@@ -142,4 +142,17 @@ static inline int drm_debugfs_crtc_crc_add(<wbr>struct drm_crtc *crtc)<br>
 {<br>
        return 0;<br>
 }<br>
+<br>
 #endif<br>
+<br>
+/* drm_syncobj.c */<br>
+void drm_syncobj_open(struct drm_file *file_private);<br>
+void drm_syncobj_release(struct drm_file *file_private);<br>
+int drm_syncobj_create_ioctl(<wbr>struct drm_device *dev, void *data,<br>
+                            struct drm_file *file_private);<br>
+int drm_syncobj_destroy_ioctl(<wbr>struct drm_device *dev, void *data,<br>
+                             struct drm_file *file_private);<br>
+int drm_syncobj_handle_to_fd_<wbr>ioctl(struct drm_device *dev, void *data,<br>
+                                  struct drm_file *file_private);<br>
+int drm_syncobj_fd_to_handle_<wbr>ioctl(struct drm_device *dev, void *data,<br>
+                                  struct drm_file *file_private);<br>
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c<br>
index 865e3ee..f1e5681 100644<br>
--- a/drivers/gpu/drm/drm_ioctl.c<br>
+++ b/drivers/gpu/drm/drm_ioctl.c<br>
@@ -241,6 +241,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_<br>
                req->value |= dev->driver->prime_fd_to_<wbr>handle ? DRM_PRIME_CAP_IMPORT : 0;<br>
                req->value |= dev->driver->prime_handle_to_<wbr>fd ? DRM_PRIME_CAP_EXPORT : 0;<br>
                return 0;<br>
+       case DRM_CAP_SYNCOBJ:<br>
+               req->value = drm_core_check_feature(dev, DRIVER_SYNCOBJ);<br>
+               return 0;<br>
        }<br>
<br>
        /* Other caps only work with KMS drivers */<br>
@@ -645,6 +648,15 @@ static const struct drm_ioctl_desc drm_ioctls[] = {<br>
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_<wbr>ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|<wbr>DRM_UNLOCKED),<br>
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_<wbr>CREATEPROPBLOB, drm_mode_createblob_ioctl, DRM_CONTROL_ALLOW|DRM_<wbr>UNLOCKED),<br>
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_<wbr>DESTROYPROPBLOB, drm_mode_destroyblob_ioctl, DRM_CONTROL_ALLOW|DRM_<wbr>UNLOCKED),<br>
+<br>
+       DRM_IOCTL_DEF(DRM_IOCTL_<wbr>SYNCOBJ_CREATE, drm_syncobj_create_ioctl,<br>
+                     DRM_UNLOCKED|DRM_RENDER_ALLOW)<wbr>,<br>
+       DRM_IOCTL_DEF(DRM_IOCTL_<wbr>SYNCOBJ_DESTROY, drm_syncobj_destroy_ioctl,<br>
+                     DRM_UNLOCKED|DRM_RENDER_ALLOW)<wbr>,<br>
+       DRM_IOCTL_DEF(DRM_IOCTL_<wbr>SYNCOBJ_HANDLE_TO_FD, drm_syncobj_handle_to_fd_<wbr>ioctl,<br>
+                     DRM_UNLOCKED|DRM_RENDER_ALLOW)<wbr>,<br>
+       DRM_IOCTL_DEF(DRM_IOCTL_<wbr>SYNCOBJ_FD_TO_HANDLE, drm_syncobj_fd_to_handle_<wbr>ioctl,<br>
+                     DRM_UNLOCKED|DRM_RENDER_ALLOW)<wbr>,<br>
 };<br>
<br>
 #define DRM_CORE_IOCTL_COUNT   ARRAY_SIZE( drm_ioctls )<br>
diff --git a/drivers/gpu/drm/drm_syncobj.<wbr>c b/drivers/gpu/drm/drm_syncobj.<wbr>c<br>
new file mode 100644<br>
index 0000000..b611480<br>
--- /dev/null<br>
+++ b/drivers/gpu/drm/drm_syncobj.<wbr>c<br>
@@ -0,0 +1,377 @@<br>
+/*<br>
+ * Copyright 2017 Red Hat<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ *<br>
+ * Authors:<br>
+ *<br>
+ */<br>
+<br>
+/**<br>
+ * DOC: Overview<br>
+ *<br>
+ * DRM synchronisation objects (syncobj) are a persistent objects,<br>
+ * that contain an optional fence. The fence can be updated with a new<br>
+ * fence, or be NULL.<br>
+ *<br>
+ * syncobj's can be export to fd's and back, these fd's are opaque and<br>
+ * have no other use case, except passing the syncobj between processes.<br>
+ *<br>
+ * Their primary use-case is to implement Vulkan fences and semaphores.<br>
+ *<br>
+ * syncobj have a kref reference count, but also have an optional file.<br>
+ * The file is only created once the syncobj is exported.<br>
+ * The file takes a reference on the kref.<br>
+ */<br>
+<br>
+#include <drm/drmP.h><br>
+#include <linux/file.h><br>
+#include <linux/fs.h><br>
+#include <linux/anon_inodes.h><br>
+<br>
+#include "drm_internal.h"<br>
+#include <drm/drm_syncobj.h><br>
+<br>
+static struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,<br>
+                                          u32 handle)<br>
+{<br>
+       struct drm_syncobj *syncobj;<br>
+<br>
+       spin_lock(&file_private-><wbr>syncobj_table_lock);<br>
+<br>
+       /* Check if we currently have a reference on the object */<br>
+       syncobj = idr_find(&file_private-><wbr>syncobj_idr, handle);<br>
+       if (syncobj)<br>
+               drm_syncobj_get(syncobj);<br>
+<br>
+       spin_unlock(&file_private-><wbr>syncobj_table_lock);<br>
+<br>
+       return syncobj;<br>
+}<br>
+<br>
+/**<br>
+ * drm_syncobj_replace_fence - lookup and replace fence in a sync object.<br>
+ * @file_private - drm file private pointer.<br>
+ * @handle - syncobj handle to lookup<br>
+ * @fence - fence to install in sync file.<br>
+ * Returns:<br>
+ * 0 on success, or -EINVAL when the handle doesn't point at a valid sem file.<br>
+ *<br>
+ * This looks up a sync object and replaces the fence on it, freeing<br>
+ * the old one.<br>
+ */<br>
+int drm_syncobj_replace_fence(<wbr>struct drm_file *file_private,<br>
+                             u32 handle,<br>
+                             struct dma_fence *fence)<br>
+{<br>
+       struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);<br>
+       struct dma_fence *old_fence = NULL;<br>
+<br>
+       if (!syncobj)<br>
+               return -EINVAL;<br>
+<br>
+       if (fence)<br>
+               dma_fence_get(fence);<br>
+       old_fence = xchg(&syncobj->fence, fence);<br>
+<br>
+       dma_fence_put(old_fence);<br>
+       drm_syncobj_put(syncobj);<br>
+<br>
+       return 0;<br>
+}<br>
+EXPORT_SYMBOL(drm_syncobj_<wbr>replace_fence);<br>
+<br>
+int drm_syncobj_fence_get(struct drm_file *file_private,<br>
+                         u32 handle,<br>
+                         struct dma_fence **fence)<br>
+{<br>
+       struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);<br>
+       int ret = 0;<br>
+<br>
+       if (!syncobj)<br>
+               return -ENOENT;<br>
+<br>
+       *fence = dma_fence_get(syncobj->fence);<br>
+       if (!*fence) {<br>
+               ret = -EINVAL;<br>
+       }<br>
+       drm_syncobj_put(syncobj);<br>
+       return ret;<br>
+}<br>
+EXPORT_SYMBOL(drm_syncobj_<wbr>fence_get);<br>
+<br>
+void drm_syncobj_free(struct kref *kref)<br>
+{<br>
+       struct drm_syncobj *syncobj = container_of(kref,<br>
+                                                  struct drm_syncobj,<br>
+                                                  refcount);<br>
+       dma_fence_put(syncobj->fence);<br>
+       kfree(syncobj);<br>
+}<br>
+<br>
+static int drm_syncobj_create(struct drm_file *file_private,<br>
+                             u32 *handle)<br>
+{<br>
+       int ret;<br>
+       struct drm_syncobj *syncobj;<br>
+<br>
+       syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL);<br>
+       if (!syncobj)<br>
+               return -ENOMEM;<br>
+<br>
+       kref_init(&syncobj->refcount);<br>
+<br>
+       idr_preload(GFP_KERNEL);<br>
+       spin_lock(&file_private-><wbr>syncobj_table_lock);<br>
+       ret = idr_alloc(&file_private-><wbr>syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);<br>
+       spin_unlock(&file_private-><wbr>syncobj_table_lock);<br>
+<br>
+       idr_preload_end();<br>
+<br>
+       if (ret < 0) {<br>
+               drm_syncobj_put(syncobj);<br>
+               return ret;<br>
+       }<br>
+<br>
+       *handle = ret;<br>
+       return 0;<br>
+}<br>
+<br>
+static int drm_syncobj_destroy(struct drm_file *file_private,<br>
+                              u32 handle)<br>
+{<br>
+       struct drm_syncobj *syncobj;<br>
+<br>
+       spin_lock(&file_private-><wbr>syncobj_table_lock);<br>
+       syncobj = idr_remove(&file_private-><wbr>syncobj_idr, handle);<br>
+       spin_unlock(&file_private-><wbr>syncobj_table_lock);<br>
+<br>
+       if (!syncobj)<br>
+               return -EINVAL;<br>
+<br>
+       drm_syncobj_put(syncobj);<br>
+       return 0;<br>
+}<br>
+<br>
+static int drm_syncobj_file_release(<wbr>struct inode *inode, struct file *file)<br>
+{<br>
+       struct drm_syncobj *syncobj = file->private_data;<br>
+<br>
+       drm_syncobj_put(syncobj);<br>
+       return 0;<br>
+}<br>
+<br>
+static const struct file_operations drm_syncobj_file_fops = {<br>
+       .release = drm_syncobj_file_release,<br>
+};<br>
+<br>
+static int drm_syncobj_alloc_file(struct drm_syncobj *syncobj)<br>
+{<br>
+       struct file *file = anon_inode_getfile("syncobj_<wbr>file",<br>
+                                              &drm_syncobj_file_fops,<br>
+                                              syncobj, 0);<br>
+       if (IS_ERR(file))<br>
+               return PTR_ERR(file);<br>
+<br>
+       drm_syncobj_get(syncobj);<br>
+       if (cmpxchg(&syncobj->file, NULL, file)) {<br>
+               /* lost the race */<br>
+               fput(file);<br>
+       }<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static int drm_syncobj_handle_to_fd(<wbr>struct drm_file *file_private,<br>
+                                   u32 handle, int *p_fd)<br>
+{<br>
+       struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);<br>
+       int ret;<br>
+       int fd;<br>
+<br>
+       if (!syncobj)<br>
+               return -EINVAL;<br>
+<br>
+       fd = get_unused_fd_flags(O_CLOEXEC)<wbr>;<br>
+       if (fd < 0) {<br>
+               drm_syncobj_put(syncobj);<br>
+               return fd;<br>
+       }<br>
+<br>
+       if (!syncobj->file) {<br>
+               ret = drm_syncobj_alloc_file(<wbr>syncobj);<br>
+               if (ret)<br>
+                       goto out_put_fd;<br>
+       }<br>
+       fd_install(fd, syncobj->file);<br>
+       drm_syncobj_put(syncobj);<br>
+       *p_fd = fd;<br>
+       return 0;<br>
+out_put_fd:<br>
+       put_unused_fd(fd);<br>
+       drm_syncobj_put(syncobj);<br>
+       return ret;<br>
+}<br>
+<br>
+static struct drm_syncobj *drm_syncobj_fdget(int fd)<br>
+{<br>
+       struct file *file = fget(fd);<br>
+<br>
+       if (!file)<br>
+               return NULL;<br>
+       if (file->f_op != &drm_syncobj_file_fops)<br>
+               goto err;<br>
+<br>
+       return file->private_data;<br>
+err:<br>
+       fput(file);<br>
+       return NULL;<br>
+};<br>
+<br>
+static int drm_syncobj_fd_to_handle(<wbr>struct drm_file *file_private,<br>
+                                   int fd, u32 *handle)<br>
+{<br>
+       struct drm_syncobj *syncobj = drm_syncobj_fdget(fd);<br>
+       int ret;<br>
+<br>
+       if (!syncobj)<br>
+               return -EINVAL;<br>
+<br>
+       /* take a reference to put in the idr */<br>
+       drm_syncobj_get(syncobj);<br>
+<br>
+       idr_preload(GFP_KERNEL);<br>
+       spin_lock(&file_private-><wbr>syncobj_table_lock);<br>
+       ret = idr_alloc(&file_private-><wbr>syncobj_idr, syncobj, 1, 0, GFP_NOWAIT);<br>
+       spin_unlock(&file_private-><wbr>syncobj_table_lock);<br>
+       idr_preload_end();<br>
+<br>
+       if (ret < 0) {<br>
+               fput(syncobj->file);<br>
+               return ret;<br>
+       }<br>
+       *handle = ret;<br>
+       return 0;<br>
+}<br>
+<br>
+/**<br>
+ * drm_syncobj_open - initalizes syncobj file-private structures at devnode open time<br>
+ * @dev: drm_device which is being opened by userspace<br>
+ * @file_private: drm file-private structure to set up<br>
+ *<br>
+ * Called at device open time, sets up the structure for handling refcounting<br>
+ * of sync objects.<br>
+ */<br>
+void<br>
+drm_syncobj_open(struct drm_file *file_private)<br>
+{<br>
+       idr_init(&file_private-><wbr>syncobj_idr);<br>
+       spin_lock_init(&file_private-><wbr>syncobj_table_lock);<br>
+}<br>
+<br>
+static int<br>
+drm_syncobj_release_handle(<wbr>int id, void *ptr, void *data)<br>
+{<br>
+       struct drm_syncobj *syncobj = ptr;<br>
+<br>
+       drm_syncobj_put(syncobj);<br>
+       return 0;<br>
+}<br>
+<br>
+/**<br>
+ * drm_syncobj_release - release file-private sync object resources<br>
+ * @dev: drm_device which is being closed by userspace<br>
+ * @file_private: drm file-private structure to clean up<br>
+ *<br>
+ * Called at close time when the filp is going away.<br>
+ *<br>
+ * Releases any remaining references on objects by this filp.<br>
+ */<br>
+void<br>
+drm_syncobj_release(struct drm_file *file_private)<br>
+{<br>
+       idr_for_each(&file_private-><wbr>syncobj_idr,<br>
+                    &drm_syncobj_release_handle, file_private);<br>
+       idr_destroy(&file_private-><wbr>syncobj_idr);<br>
+}<br>
+<br>
+int<br>
+drm_syncobj_create_ioctl(<wbr>struct drm_device *dev, void *data,<br>
+                        struct drm_file *file_private)<br>
+{<br>
+       struct drm_syncobj_create *args = data;<br>
+<br>
+       if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))<br>
+               return -ENODEV;<br>
+<br>
+       /* no valid flags yet */<br>
+       if (args->flags)<br>
+               return -EINVAL;<br>
+<br>
+       return drm_syncobj_create(file_<wbr>private,<br>
+                                 &args->handle);<br>
+}<br>
+<br>
+int<br>
+drm_syncobj_destroy_ioctl(<wbr>struct drm_device *dev, void *data,<br>
+                         struct drm_file *file_private)<br>
+{<br>
+       struct drm_syncobj_destroy *args = data;<br>
+<br>
+       if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))<br>
+               return -ENODEV;<br>
+<br>
+       /* make sure padding is empty */<br>
+       if (args->pad)<br>
+               return -EINVAL;<br>
+       return drm_syncobj_destroy(file_<wbr>private, args->handle);<br>
+}<br>
+<br>
+int<br>
+drm_syncobj_handle_to_fd_<wbr>ioctl(struct drm_device *dev, void *data,<br>
+                                  struct drm_file *file_private)<br>
+{<br>
+       struct drm_syncobj_handle *args = data;<br>
+<br>
+       if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))<br>
+               return -ENODEV;<br>
+<br>
+       if (args->pad || args->flags)<br>
+               return -EINVAL;<br>
+<br>
+       return drm_syncobj_handle_to_fd(file_<wbr>private, args->handle,<br>
+                                       &args->fd);<br>
+}<br>
+<br>
+int<br>
+drm_syncobj_fd_to_handle_<wbr>ioctl(struct drm_device *dev, void *data,<br>
+                                  struct drm_file *file_private)<br>
+{<br>
+       struct drm_syncobj_handle *args = data;<br>
+<br>
+       if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))<br>
+               return -ENODEV;<br>
+<br>
+       if (args->pad || args->flags)<br>
+               return -EINVAL;<br>
+<br>
+       return drm_syncobj_fd_to_handle(file_<wbr>private, args->fd,<br>
+                                       &args->handle);<br>
+}<br>
diff --git a/include/drm/drmP.h b/include/drm/drmP.h<br>
index e1daa4f..4fad9f2 100644<br>
--- a/include/drm/drmP.h<br>
+++ b/include/drm/drmP.h<br>
@@ -319,7 +319,6 @@ struct pci_controller;<br>
<br>
 #define DRM_IF_VERSION(maj, min) (maj << 16 | min)<br>
<br>
-<br>
 /* Flags and return codes for get_vblank_timestamp() driver function. */<br>
 #define DRM_CALLED_FROM_VBLIRQ 1<br>
 #define DRM_VBLANKTIME_SCANOUTPOS_<wbr>METHOD (1 << 0)<br>
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h<br>
index 53b9832..1c66c1c 100644<br>
--- a/include/drm/drm_drv.h<br>
+++ b/include/drm/drm_drv.h<br>
@@ -53,6 +53,7 @@ struct drm_mode_create_dumb;<br>
 #define DRIVER_RENDER                  0x8000<br>
 #define DRIVER_ATOMIC                  0x10000<br>
 #define DRIVER_KMS_LEGACY_CONTEXT      0x20000<br>
+#define DRIVER_SYNCOBJ                  0x40000<br>
<br>
 /**<br>
  * struct drm_driver - DRM driver structure<br>
diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h<br>
index 5dd27ae..cea7354 100644<br>
--- a/include/drm/drm_file.h<br>
+++ b/include/drm/drm_file.h<br>
@@ -231,6 +231,11 @@ struct drm_file {<br>
        /** @table_lock: Protects @object_idr. */<br>
        spinlock_t table_lock;<br>
<br>
+       /** @syncobj_idr: Mapping of sync object handles to object pointers. */<br>
+       struct idr syncobj_idr;<br>
+       /** @syncobj_table_lock: Protects @syncobj_idr. */<br>
+       spinlock_t syncobj_table_lock;<br>
+<br>
        /** @filp: Pointer to the core file structure. */<br>
        struct file *filp;<br>
<br>
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h<br>
new file mode 100644<br>
index 0000000..372c398<br>
--- /dev/null<br>
+++ b/include/drm/drm_syncobj.h<br>
@@ -0,0 +1,87 @@<br>
+/*<br>
+ * Copyright © 2017 Red Hat<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ *<br>
+ * Authors:<br>
+ *<br>
+ */<br>
+#ifndef __DRM_SYNCOBJ_H__<br>
+#define __DRM_SYNCOBJ_H__<br>
+<br>
+#include "linux/dma-fence.h"<br>
+<br>
+/**<br>
+ * struct drm_syncobj - sync object.<br>
+ *<br>
+ * This structure defines a generic sync object which wraps a dma fence.<br>
+ */<br>
+struct drm_syncobj {<br>
+       /**<br>
+        * @refcount:<br>
+        *<br>
+        * Reference count of this object.<br>
+        */<br>
+       struct kref refcount;<br>
+       /**<br>
+        * @fence:<br>
+        * NULL or a pointer to the fence bound to this object.<br>
+        */<br>
+       struct dma_fence *fence;<br>
+       /**<br>
+        * @file:<br>
+        * a file backing for this syncobj.<br>
+        */<br>
+       struct file *file;<br>
+};<br>
+<br>
+void drm_syncobj_free(struct kref *kref);<br>
+<br>
+/**<br>
+ * drm_syncobj_get - acquire a syncobj reference<br>
+ * @obj: sync object<br>
+ *<br>
+ * This acquires additional reference to @obj. It is illegal to call this<br>
+ * without already holding a reference. No locks required.<br>
+ */<br>
+static inline void<br>
+drm_syncobj_get(struct drm_syncobj *obj)<br>
+{<br>
+       kref_get(&obj->refcount);<br>
+}<br>
+<br>
+/**<br>
+ * drm_syncobj_put - release a reference to a sync object.<br>
+ * @obj: sync object.<br>
+ */<br>
+static inline void<br>
+drm_syncobj_put(struct drm_syncobj *obj)<br>
+{<br>
+       kref_put(&obj->refcount, drm_syncobj_free);<br>
+}<br>
+<br>
+int drm_syncobj_fence_get(struct drm_file *file_private,<br>
+                         u32 handle,<br>
+                         struct dma_fence **fence);<br>
+int drm_syncobj_replace_fence(<wbr>struct drm_file *file_private,<br>
+                             u32 handle,<br>
+                             struct dma_fence *fence);<br>
+<br>
+#endif<br>
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h<br>
index 42d9f64..96c5c78 100644<br>
--- a/include/uapi/drm/drm.h<br>
+++ b/include/uapi/drm/drm.h<br>
@@ -648,6 +648,7 @@ struct drm_gem_open {<br>
 #define DRM_CAP_ADDFB2_MODIFIERS       0x10<br>
 #define DRM_CAP_PAGE_FLIP_TARGET       0x11<br>
 #define DRM_CAP_CRTC_IN_VBLANK_EVENT   0x12<br>
+#define DRM_CAP_SYNCOBJ                0x13<br>
<br>
 /** DRM_IOCTL_GET_CAP ioctl argument type */<br>
 struct drm_get_cap {<br>
@@ -697,6 +698,24 @@ struct drm_prime_handle {<br>
        __s32 fd;<br>
 };<br>
<br>
+struct drm_syncobj_create {<br>
+       __u32 handle;<br>
+       __u32 flags;<br>
+};<br>
+<br>
+struct drm_syncobj_destroy {<br>
+       __u32 handle;<br>
+       __u32 pad;<br>
+};<br>
+<br>
+struct drm_syncobj_handle {<br>
+       __u32 handle;<br>
+       __u32 flags;<br>
+<br>
+       __s32 fd;<br>
+       __u32 pad;<br>
+};<br>
+<br>
 #if defined(__cplusplus)<br>
 }<br>
 #endif<br>
@@ -815,6 +834,11 @@ extern "C" {<br>
 #define DRM_IOCTL_MODE_CREATEPROPBLOB  DRM_IOWR(0xBD, struct drm_mode_create_blob)<br>
 #define DRM_IOCTL_MODE_DESTROYPROPBLOB DRM_IOWR(0xBE, struct drm_mode_destroy_blob)<br>
<br>
+#define DRM_IOCTL_SYNCOBJ_CREATE       DRM_IOWR(0xBF, struct drm_syncobj_create)<br>
+#define DRM_IOCTL_SYNCOBJ_DESTROY      DRM_IOWR(0xC0, struct drm_syncobj_destroy)<br>
+#define DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD DRM_IOWR(0xC1, struct drm_syncobj_handle)<br>
+#define DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE DRM_IOWR(0xC2, struct drm_syncobj_handle)<br>
+<br>
 /**<br>
  * Device specific ioctls should only be in their respective headers<br>
  * The device specific ioctl range is from 0x40 to 0x9f.<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.9.4<br>
<br>
______________________________<wbr>_________________<br>
dri-devel mailing list<br>
<a href="mailto:dri-devel@lists.freedesktop.org">dri-devel@lists.freedesktop.<wbr>org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/dri-devel" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/dri-devel</a><br>
</font></span></blockquote></div><br></div>