<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>