All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/12] misc/syncobj: add /dev/syncobj device
@ 2026-05-16 11:06 Julian Orth
  2026-05-16 11:06 ` [PATCH 01/12] drm/syncobj: add drm_syncobj_from_fd Julian Orth
                   ` (11 more replies)
  0 siblings, 12 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This series adds a new device /dev/syncobj that can be used to create
and manipulate DRM syncobjs. Previously, these operations required the
use of a DRM device and the device needed to support the DRIVER_SYNCOBJ
and DRIVER_SYNCOBJ_TIMELINE features.

There are several issues with the existing API:

- Syncobjs are the only explicit sync mechanism available on wayland.
  Most compositors do not use GPU waits. Instead, they use the
  DRM_IOCTL_SYNCOBJ_EVENTFD ioctl to perform a CPU wait. Being tied to
  DRM devices means that compositors cannot consistently offer this
  feature even though no device-specific logic is involved.
- llvmpipe currently cannot offer syncobj interop because it does not
  have access to a DRM device. This means that applications using
  llvmpipe cannot present images before they have finished rendering,
  despite llvmpipe using threaded rendering.
- Clients that do not use the Vulkan WSI need to manually probe /dev/dri
  for devices that support the syncobj ioctls in order to use the
  wayland syncobj protocol.
- Similarly, clients that want to use screen capture have no equivalent
  to the WSI and are therefore forced into that path.
- Having to keep a DRM device open has potentially negative interactions
  with GPU hotplug.
- Having to translate between syncobj FDs and handles is troublesome in
  the compositor usecase since syncobjs come and go frequently and need
  to be cleaned up when clients disconnect.

/dev/syncobj solves these issues by providing all syncobj ioctls under a
consistent path that is not tied to any DRM device. It also operates
directly on file descriptors instead of syncobj handles.

The series starts with a number of small refactorings in drm_syncobj.c
to make its functionality available outside of the file and without the
need for drm_file/handle pairs.

The last commit adds the /dev/syncobj module. I've added it as a misc
device but maybe this should instead live somewhere under gpu/drm.

An application using the new interface can be found at [1].

[1]: https://github.com/mahkoh/jay/pull/947

---
Julian Orth (12):
      drm/syncobj: add drm_syncobj_from_fd
      drm/syncobj: add drm_syncobj_fence_lookup
      drm/syncobj: make drm_syncobj_array_wait_timeout public
      drm/syncobj: add drm_syncobj_register_eventfd
      drm/syncobj: have transfer functions accept drm_syncobj directly
      drm/syncobj: add drm_syncobj_transfer
      drm/syncobj: add drm_syncobj_timeline_signal
      drm/syncobj: add drm_syncobj_query
      drm/syncobj: fix resource leak in drm_syncobj_import_sync_file_fence
      drm/syncobj: add drm_syncobj_import_sync_file
      drm/syncobj: add drm_syncobj_export_sync_file
      misc/syncobj: add new device

 Documentation/userspace-api/ioctl/ioctl-number.rst |   1 +
 drivers/gpu/drm/drm_syncobj.c                      | 374 ++++++++++++++-----
 drivers/misc/Kconfig                               |  10 +
 drivers/misc/Makefile                              |   1 +
 drivers/misc/syncobj.c                             | 404 +++++++++++++++++++++
 include/drm/drm_syncobj.h                          |  21 ++
 include/uapi/linux/syncobj.h                       |  75 ++++
 7 files changed, 795 insertions(+), 91 deletions(-)
---
base-commit: 6916d5703ddf9a38f1f6c2cc793381a24ee914c6
change-id: 20260516-jorth-syncobj-d4d374c8c61b

Best regards,
--  
Julian Orth <ju.orth@gmail.com>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 01/12] drm/syncobj: add drm_syncobj_from_fd
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 02/12] drm/syncobj: add drm_syncobj_fence_lookup Julian Orth
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

Given a syncobj FD, returns the underlying drm_syncobj.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 37 +++++++++++++++++++++++++++----------
 include/drm/drm_syncobj.h     |  1 +
 2 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 8d9fd1917c6e..d992aa082ace 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -684,6 +684,31 @@ int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)
 }
 EXPORT_SYMBOL(drm_syncobj_get_fd);
 
+/**
+ * drm_syncobj_from_fd - lookup and reference a syncobj.
+ * @fd: syncobj file descriptor
+ *
+ * Returns a reference to the syncobj pointed to by @fd or NULL. The
+ * reference must be released by calling drm_syncobj_put().
+ */
+struct drm_syncobj *drm_syncobj_from_fd(int fd)
+{
+	struct drm_syncobj *syncobj;
+
+	CLASS(fd, f)(fd);
+
+	if (fd_empty(f))
+		return NULL;
+
+	if (fd_file(f)->f_op != &drm_syncobj_file_fops)
+		return NULL;
+
+	syncobj = fd_file(f)->private_data;
+	drm_syncobj_get(syncobj);
+	return syncobj;
+}
+EXPORT_SYMBOL(drm_syncobj_from_fd);
+
 static int drm_syncobj_handle_to_fd(struct drm_file *file_private,
 				    u32 handle, int *p_fd)
 {
@@ -701,20 +726,12 @@ static int drm_syncobj_handle_to_fd(struct drm_file *file_private,
 static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
 				    int fd, u32 *handle)
 {
-	struct drm_syncobj *syncobj;
-	CLASS(fd, f)(fd);
+	struct drm_syncobj *syncobj = drm_syncobj_from_fd(fd);
 	int ret;
 
-	if (fd_empty(f))
-		return -EINVAL;
-
-	if (fd_file(f)->f_op != &drm_syncobj_file_fops)
+	if (!syncobj)
 		return -EINVAL;
 
-	/* take a reference to put in the xarray */
-	syncobj = fd_file(f)->private_data;
-	drm_syncobj_get(syncobj);
-
 	ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b,
 		       GFP_KERNEL);
 	if (ret)
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index b40052132e52..5da9988834b5 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -117,6 +117,7 @@ drm_syncobj_fence_get(struct drm_syncobj *syncobj)
 
 struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
 				     u32 handle);
+struct drm_syncobj *drm_syncobj_from_fd(int fd);
 void drm_syncobj_add_point(struct drm_syncobj *syncobj,
 			   struct dma_fence_chain *chain,
 			   struct dma_fence *fence,

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 02/12] drm/syncobj: add drm_syncobj_fence_lookup
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
  2026-05-16 11:06 ` [PATCH 01/12] drm/syncobj: add drm_syncobj_from_fd Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 03/12] drm/syncobj: make drm_syncobj_array_wait_timeout public Julian Orth
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This makes the logic from drm_syncobj_find_fence available to callers
that have a drm_syncobj instead of a drm_file/handle pair.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 34 ++++++++++++++++++++++++++++------
 include/drm/drm_syncobj.h     |  2 ++
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index d992aa082ace..8df438fe0807 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -427,7 +427,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
  * @fence: out parameter for the fence
  *
  * This is just a convenience function that combines drm_syncobj_find() and
- * drm_syncobj_fence_get().
+ * drm_syncobj_fence_lookup().
  *
  * Returns 0 on success or a negative error value on failure. On success @fence
  * contains a reference to the fence, which must be released by calling
@@ -438,8 +438,6 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
 			   struct dma_fence **fence)
 {
 	struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
-	struct syncobj_wait_entry wait;
-	u64 timeout = nsecs_to_jiffies64(DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT);
 	int ret;
 
 	if (flags & ~DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)
@@ -448,6 +446,32 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
 	if (!syncobj)
 		return -ENOENT;
 
+	ret = drm_syncobj_fence_lookup(syncobj, point, flags, fence);
+
+	drm_syncobj_put(syncobj);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_syncobj_find_fence);
+
+/**
+ * drm_syncobj_fence_lookup - lookup and reference the fence in a sync object
+ * @syncobj: sync object to lookup.
+ * @point: timeline point
+ * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not
+ * @fence: out parameter for the fence
+ *
+ * Returns 0 on success or a negative error value on failure. On success @fence
+ * contains a reference to the fence, which must be released by calling
+ * dma_fence_put().
+ */
+int drm_syncobj_fence_lookup(struct drm_syncobj *syncobj, u64 point,
+			     u64 flags, struct dma_fence **fence)
+{
+	struct syncobj_wait_entry wait;
+	u64 timeout = nsecs_to_jiffies64(DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT);
+	int ret;
+
 	/* Waiting for userspace with locks help is illegal cause that can
 	 * trivial deadlock with page faults for example. Make lockdep complain
 	 * about it early on.
@@ -511,11 +535,9 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
 		drm_syncobj_remove_wait(syncobj, &wait);
 
 out:
-	drm_syncobj_put(syncobj);
-
 	return ret;
 }
-EXPORT_SYMBOL(drm_syncobj_find_fence);
+EXPORT_SYMBOL(drm_syncobj_fence_lookup);
 
 /**
  * drm_syncobj_free - free a sync object.
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index 5da9988834b5..580a967ae364 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -124,6 +124,8 @@ void drm_syncobj_add_point(struct drm_syncobj *syncobj,
 			   uint64_t point);
 void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
 			       struct dma_fence *fence);
+int drm_syncobj_fence_lookup(struct drm_syncobj *syncobj, u64 point,
+			     u64 flags, struct dma_fence **fence);
 int drm_syncobj_find_fence(struct drm_file *file_private,
 			   u32 handle, u64 point, u64 flags,
 			   struct dma_fence **fence);

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 03/12] drm/syncobj: make drm_syncobj_array_wait_timeout public
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
  2026-05-16 11:06 ` [PATCH 01/12] drm/syncobj: add drm_syncobj_from_fd Julian Orth
  2026-05-16 11:06 ` [PATCH 02/12] drm/syncobj: add drm_syncobj_fence_lookup Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 04/12] drm/syncobj: add drm_syncobj_register_eventfd Julian Orth
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

For use by the upcoming misc/syncobj module.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 15 ++++++++-------
 include/drm/drm_syncobj.h     |  5 +++++
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 8df438fe0807..648afd1f4fdd 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -1069,13 +1069,13 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
 	list_del_init(&wait->node);
 }
 
-static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
-						  void __user *user_points,
-						  uint32_t count,
-						  uint32_t flags,
-						  signed long timeout,
-						  uint32_t *idx,
-						  ktime_t *deadline)
+signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
+					   void __user *user_points,
+					   uint32_t count,
+					   uint32_t flags,
+					   signed long timeout,
+					   uint32_t *idx,
+					   ktime_t *deadline)
 {
 	struct syncobj_wait_entry *entries;
 	struct dma_fence *fence;
@@ -1229,6 +1229,7 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
 
 	return timeout;
 }
+EXPORT_SYMBOL(drm_syncobj_array_wait_timeout);
 
 /**
  * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index 580a967ae364..7677fd995be0 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -129,6 +129,11 @@ int drm_syncobj_fence_lookup(struct drm_syncobj *syncobj, u64 point,
 int drm_syncobj_find_fence(struct drm_file *file_private,
 			   u32 handle, u64 point, u64 flags,
 			   struct dma_fence **fence);
+signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
+					   void __user *user_points,
+					   uint32_t count, uint32_t flags,
+					   signed long timeout, uint32_t *idx,
+					   ktime_t *deadline);
 void drm_syncobj_free(struct kref *kref);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 		       struct dma_fence *fence);

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 04/12] drm/syncobj: add drm_syncobj_register_eventfd
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
                   ` (2 preceding siblings ...)
  2026-05-16 11:06 ` [PATCH 03/12] drm/syncobj: make drm_syncobj_array_wait_timeout public Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 05/12] drm/syncobj: have transfer functions accept drm_syncobj directly Julian Orth
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This makes the logic from drm_syncobj_eventfd_ioctl available to callers
that already have a drm_syncobj.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 37 ++++++++++++++++++++++++++++++-------
 include/drm/drm_syncobj.h     |  2 ++
 2 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 648afd1f4fdd..3e8fb7e0cace 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -1502,8 +1502,6 @@ drm_syncobj_eventfd_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_syncobj_eventfd *args = data;
 	struct drm_syncobj *syncobj;
-	struct eventfd_ctx *ev_fd_ctx;
-	struct syncobj_eventfd_entry *entry;
 	int ret;
 
 	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
@@ -1519,7 +1517,33 @@ drm_syncobj_eventfd_ioctl(struct drm_device *dev, void *data,
 	if (!syncobj)
 		return -ENOENT;
 
-	ev_fd_ctx = eventfd_ctx_fdget(args->fd);
+	ret = drm_syncobj_register_eventfd(syncobj, args->fd, args->point, args->flags);
+
+	drm_syncobj_put(syncobj);
+
+	return ret;
+}
+
+/**
+ * drm_syncobj_register_eventfd - register an eventfd for a syncobj
+ * @syncobj: sync object to add the eventfd to
+ * @ev_fd: eventfd file descriptor to signal
+ * @point: timeline point to wait for
+ * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE or 0
+ *
+ * Registers an eventfd that will be signaled when the point is
+ * signaled or available.
+ *
+ * Returns 0 on success or a negative error value on failure.
+ */
+int drm_syncobj_register_eventfd(struct drm_syncobj *syncobj,
+				 int ev_fd, u64 point, u32 flags)
+{
+	struct eventfd_ctx *ev_fd_ctx;
+	struct syncobj_eventfd_entry *entry;
+	int ret;
+
+	ev_fd_ctx = eventfd_ctx_fdget(ev_fd);
 	if (IS_ERR(ev_fd_ctx)) {
 		ret = PTR_ERR(ev_fd_ctx);
 		goto err_fdget;
@@ -1532,20 +1556,19 @@ drm_syncobj_eventfd_ioctl(struct drm_device *dev, void *data,
 	}
 	entry->syncobj = syncobj;
 	entry->ev_fd_ctx = ev_fd_ctx;
-	entry->point = args->point;
-	entry->flags = args->flags;
+	entry->point = point;
+	entry->flags = flags;
 
 	drm_syncobj_add_eventfd(syncobj, entry);
-	drm_syncobj_put(syncobj);
 
 	return 0;
 
 err_kzalloc:
 	eventfd_ctx_put(ev_fd_ctx);
 err_fdget:
-	drm_syncobj_put(syncobj);
 	return ret;
 }
+EXPORT_SYMBOL(drm_syncobj_register_eventfd);
 
 int
 drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index 7677fd995be0..85e7ca7f7896 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -134,6 +134,8 @@ signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
 					   uint32_t count, uint32_t flags,
 					   signed long timeout, uint32_t *idx,
 					   ktime_t *deadline);
+int drm_syncobj_register_eventfd(struct drm_syncobj *syncobj,
+				 int ev_fd, u64 point, u32 flags);
 void drm_syncobj_free(struct kref *kref);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 		       struct dma_fence *fence);

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 05/12] drm/syncobj: have transfer functions accept drm_syncobj directly
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
                   ` (3 preceding siblings ...)
  2026-05-16 11:06 ` [PATCH 04/12] drm/syncobj: add drm_syncobj_register_eventfd Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 06/12] drm/syncobj: add drm_syncobj_transfer Julian Orth
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This removes the implicit flags check from drm_syncobj_find_fence. The
check is moved to the only caller drm_syncobj_transfer_ioctl.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 62 ++++++++++++++++++++++++-------------------
 1 file changed, 35 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 3e8fb7e0cace..a746e787882d 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -955,29 +955,23 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
 					&args->handle);
 }
 
-static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private,
-					    struct drm_syncobj_transfer *args)
+static int drm_syncobj_transfer_to_timeline(struct drm_syncobj *src, u64 src_point,
+					    struct drm_syncobj *dst, u64 dst_point,
+					    u32 flags)
 {
-	struct drm_syncobj *timeline_syncobj = NULL;
 	struct dma_fence *fence, *tmp;
 	struct dma_fence_chain *chain;
 	int ret;
 
-	timeline_syncobj = drm_syncobj_find(file_private, args->dst_handle);
-	if (!timeline_syncobj) {
-		return -ENOENT;
-	}
-	ret = drm_syncobj_find_fence(file_private, args->src_handle,
-				     args->src_point, args->flags,
-				     &tmp);
+	ret = drm_syncobj_fence_lookup(src, src_point, flags, &tmp);
 	if (ret)
-		goto err_put_timeline;
+		goto out;
 
 	fence = dma_fence_unwrap_merge(tmp);
 	dma_fence_put(tmp);
 	if (!fence) {
 		ret = -ENOMEM;
-		goto err_put_timeline;
+		goto out;
 	}
 
 	chain = dma_fence_chain_alloc();
@@ -986,34 +980,27 @@ static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private,
 		goto err_free_fence;
 	}
 
-	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->dst_point);
+	drm_syncobj_add_point(dst, chain, fence, dst_point);
 err_free_fence:
 	dma_fence_put(fence);
-err_put_timeline:
-	drm_syncobj_put(timeline_syncobj);
+out:
 
 	return ret;
 }
 
 static int
-drm_syncobj_transfer_to_binary(struct drm_file *file_private,
-			       struct drm_syncobj_transfer *args)
+drm_syncobj_transfer_to_binary(struct drm_syncobj *src, u64 src_point,
+			       struct drm_syncobj *dst, u32 flags)
 {
-	struct drm_syncobj *binary_syncobj = NULL;
 	struct dma_fence *fence;
 	int ret;
 
-	binary_syncobj = drm_syncobj_find(file_private, args->dst_handle);
-	if (!binary_syncobj)
-		return -ENOENT;
-	ret = drm_syncobj_find_fence(file_private, args->src_handle,
-				     args->src_point, args->flags, &fence);
+	ret = drm_syncobj_fence_lookup(src, src_point, flags, &fence);
 	if (ret)
 		goto err;
-	drm_syncobj_replace_fence(binary_syncobj, fence);
+	drm_syncobj_replace_fence(dst, fence);
 	dma_fence_put(fence);
 err:
-	drm_syncobj_put(binary_syncobj);
 
 	return ret;
 }
@@ -1022,18 +1009,39 @@ drm_syncobj_transfer_ioctl(struct drm_device *dev, void *data,
 			   struct drm_file *file_private)
 {
 	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *src, *dst;
 	int ret;
 
 	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
 		return -EOPNOTSUPP;
 
+	if (args->flags & ~DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)
+		return -EINVAL;
+
 	if (args->pad)
 		return -EINVAL;
 
+	src = drm_syncobj_find(file_private, args->src_handle);
+	if (!src)
+		return -ENOENT;
+
+	dst = drm_syncobj_find(file_private, args->dst_handle);
+	if (!dst) {
+		ret = -ENOENT;
+		goto err_dst;
+	}
+
 	if (args->dst_point)
-		ret = drm_syncobj_transfer_to_timeline(file_private, args);
+		ret = drm_syncobj_transfer_to_timeline(src, args->src_point,
+						       dst, args->dst_point,
+						       args->flags);
 	else
-		ret = drm_syncobj_transfer_to_binary(file_private, args);
+		ret = drm_syncobj_transfer_to_binary(src, args->src_point,
+						     dst, args->flags);
+
+	drm_syncobj_put(dst);
+err_dst:
+	drm_syncobj_put(src);
 
 	return ret;
 }

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 06/12] drm/syncobj: add drm_syncobj_transfer
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
                   ` (4 preceding siblings ...)
  2026-05-16 11:06 ` [PATCH 05/12] drm/syncobj: have transfer functions accept drm_syncobj directly Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 07/12] drm/syncobj: add drm_syncobj_timeline_signal Julian Orth
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This makes the logic from drm_syncobj_transfer_ioctl available to
callers that already have two drm_syncobj.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 36 +++++++++++++++++++++++++++++-------
 include/drm/drm_syncobj.h     |  3 +++
 2 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index a746e787882d..8ccfbd972191 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -1031,13 +1031,9 @@ drm_syncobj_transfer_ioctl(struct drm_device *dev, void *data,
 		goto err_dst;
 	}
 
-	if (args->dst_point)
-		ret = drm_syncobj_transfer_to_timeline(src, args->src_point,
-						       dst, args->dst_point,
-						       args->flags);
-	else
-		ret = drm_syncobj_transfer_to_binary(src, args->src_point,
-						     dst, args->flags);
+	ret = drm_syncobj_transfer(src, args->src_point,
+				   dst, args->dst_point,
+				   args->flags);
 
 	drm_syncobj_put(dst);
 err_dst:
@@ -1046,6 +1042,32 @@ drm_syncobj_transfer_ioctl(struct drm_device *dev, void *data,
 	return ret;
 }
 
+/**
+ * drm_syncobj_transfer - transfer a fence between syncobjs
+ * @src: source syncobj
+ * @src_point: source point
+ * @dst: destination syncobj
+ * @dst_point: destination point
+ * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or 0
+ *
+ * Copies the fence at @src_point in @src to @dst_point in @dst.
+ *
+ * Returns 0 on success or a negative error value on failure.
+ */
+int drm_syncobj_transfer(struct drm_syncobj *src, u64 src_point,
+			 struct drm_syncobj *dst, u64 dst_point,
+			 u32 flags)
+{
+	if (dst_point)
+		return drm_syncobj_transfer_to_timeline(src, src_point,
+							dst, dst_point,
+							flags);
+	else
+		return drm_syncobj_transfer_to_binary(src, src_point,
+						      dst, flags);
+}
+EXPORT_SYMBOL(drm_syncobj_transfer);
+
 static void syncobj_wait_fence_func(struct dma_fence *fence,
 				    struct dma_fence_cb *cb)
 {
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index 85e7ca7f7896..ec8042d61466 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -136,6 +136,9 @@ signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
 					   ktime_t *deadline);
 int drm_syncobj_register_eventfd(struct drm_syncobj *syncobj,
 				 int ev_fd, u64 point, u32 flags);
+int drm_syncobj_transfer(struct drm_syncobj *src, u64 src_point,
+			 struct drm_syncobj *dst, u64 dst_point,
+			 u32 flags);
 void drm_syncobj_free(struct kref *kref);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 		       struct dma_fence *fence);

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 07/12] drm/syncobj: add drm_syncobj_timeline_signal
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
                   ` (5 preceding siblings ...)
  2026-05-16 11:06 ` [PATCH 06/12] drm/syncobj: add drm_syncobj_transfer Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 08/12] drm/syncobj: add drm_syncobj_query Julian Orth
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This makes the logic from drm_syncobj_timeline_signal_ioctl available to
callers that already have an array of drm_syncobj.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 50 ++++++++++++++++++++++++++++++++-----------
 include/drm/drm_syncobj.h     |  2 ++
 2 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 8ccfbd972191..948084f56c32 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -1675,9 +1675,6 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_syncobj_timeline_array *args = data;
 	struct drm_syncobj **syncobjs;
-	struct dma_fence_chain **chains;
-	uint64_t *points;
-	uint32_t i, j;
 	int ret;
 
 	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
@@ -1696,26 +1693,55 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
 	if (ret < 0)
 		return ret;
 
-	points = kmalloc_array(args->count_handles, sizeof(*points),
+	ret = drm_syncobj_timeline_signal(syncobjs, args->points, args->count_handles);
+
+	drm_syncobj_array_free(syncobjs, args->count_handles);
+
+	return ret;
+}
+
+/**
+ * drm_syncobj_timeline_signal - signal timeline points on syncobjs
+ * @syncobjs: array of syncobjs
+ * @user_points: user pointer to array of timeline points
+ * @count: number of syncobjs
+ *
+ * Signals each syncobj at the corresponding timeline point.
+ *
+ * Returns 0 on success or a negative error value on failure.
+ */
+int
+drm_syncobj_timeline_signal(struct drm_syncobj **syncobjs,
+			    u64 user_points, u32 count)
+{
+	struct dma_fence_chain **chains;
+	uint64_t *points;
+	uint32_t i, j;
+	int ret = 0;
+
+	if (count == 0)
+		return -EINVAL;
+
+	points = kmalloc_array(count, sizeof(*points),
 			       GFP_KERNEL);
 	if (!points) {
 		ret = -ENOMEM;
 		goto out;
 	}
-	if (!u64_to_user_ptr(args->points)) {
-		memset(points, 0, args->count_handles * sizeof(uint64_t));
-	} else if (copy_from_user(points, u64_to_user_ptr(args->points),
-				  sizeof(uint64_t) * args->count_handles)) {
+	if (!u64_to_user_ptr(user_points)) {
+		memset(points, 0, count * sizeof(uint64_t));
+	} else if (copy_from_user(points, u64_to_user_ptr(user_points),
+				  sizeof(uint64_t) * count)) {
 		ret = -EFAULT;
 		goto err_points;
 	}
 
-	chains = kmalloc_array(args->count_handles, sizeof(void *), GFP_KERNEL);
+	chains = kmalloc_array(count, sizeof(void *), GFP_KERNEL);
 	if (!chains) {
 		ret = -ENOMEM;
 		goto err_points;
 	}
-	for (i = 0; i < args->count_handles; i++) {
+	for (i = 0; i < count; i++) {
 		chains[i] = dma_fence_chain_alloc();
 		if (!chains[i]) {
 			for (j = 0; j < i; j++)
@@ -1725,7 +1751,7 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
 		}
 	}
 
-	for (i = 0; i < args->count_handles; i++) {
+	for (i = 0; i < count; i++) {
 		struct dma_fence *fence = dma_fence_get_stub();
 
 		drm_syncobj_add_point(syncobjs[i], chains[i],
@@ -1737,10 +1763,10 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
 err_points:
 	kfree(points);
 out:
-	drm_syncobj_array_free(syncobjs, args->count_handles);
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_syncobj_timeline_signal);
 
 int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
 			    struct drm_file *file_private)
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index ec8042d61466..a9216ea07946 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -139,6 +139,8 @@ int drm_syncobj_register_eventfd(struct drm_syncobj *syncobj,
 int drm_syncobj_transfer(struct drm_syncobj *src, u64 src_point,
 			 struct drm_syncobj *dst, u64 dst_point,
 			 u32 flags);
+int drm_syncobj_timeline_signal(struct drm_syncobj **syncobjs,
+				u64 user_points, u32 count);
 void drm_syncobj_free(struct kref *kref);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 		       struct dma_fence *fence);

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 08/12] drm/syncobj: add drm_syncobj_query
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
                   ` (6 preceding siblings ...)
  2026-05-16 11:06 ` [PATCH 07/12] drm/syncobj: add drm_syncobj_timeline_signal Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 09/12] drm/syncobj: fix resource leak in drm_syncobj_import_sync_file_fence Julian Orth
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This makes the logic from drm_syncobj_query_ioctl available to callers
that already have an array of drm_syncobj.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 32 +++++++++++++++++++++++++++-----
 include/drm/drm_syncobj.h     |  2 ++
 2 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 948084f56c32..9b7ecc2978f5 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -1773,8 +1773,6 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_syncobj_timeline_array *args = data;
 	struct drm_syncobj **syncobjs;
-	uint64_t __user *points = u64_to_user_ptr(args->points);
-	uint32_t i;
 	int ret;
 
 	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
@@ -1793,7 +1791,31 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
 	if (ret < 0)
 		return ret;
 
-	for (i = 0; i < args->count_handles; i++) {
+	ret = drm_syncobj_query(syncobjs, args->points,
+				args->count_handles, args->flags);
+
+	drm_syncobj_array_free(syncobjs, args->count_handles);
+
+	return ret;
+}
+
+/**
+ * drm_syncobj_query - query timeline points of syncobjs
+ * @syncobjs: array of syncobjs
+ * @user_points: user pointer to array of timeline points
+ * @count: number of syncobjs
+ * @flags: DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED or 0
+ *
+ * Queries the timeline point of each syncobj and writes it to @points.
+ */
+int drm_syncobj_query(struct drm_syncobj **syncobjs, u64 user_points,
+		      u32 count, u32 flags)
+{
+	uint64_t __user *points = u64_to_user_ptr(user_points);
+	uint32_t i;
+	int ret = 0;
+
+	for (i = 0; i < count; i++) {
 		struct dma_fence_chain *chain;
 		struct dma_fence *fence;
 		uint64_t point;
@@ -1804,7 +1826,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
 			struct dma_fence *iter, *last_signaled =
 				dma_fence_get(fence);
 
-			if (args->flags &
+			if (flags &
 			    DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED) {
 				point = fence->seqno;
 			} else {
@@ -1832,7 +1854,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
 		if (ret)
 			break;
 	}
-	drm_syncobj_array_free(syncobjs, args->count_handles);
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_syncobj_query);
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index a9216ea07946..da237ca3e61f 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -141,6 +141,8 @@ int drm_syncobj_transfer(struct drm_syncobj *src, u64 src_point,
 			 u32 flags);
 int drm_syncobj_timeline_signal(struct drm_syncobj **syncobjs,
 				u64 user_points, u32 count);
+int drm_syncobj_query(struct drm_syncobj **syncobjs, u64 user_points,
+		      u32 count, u32 flags);
 void drm_syncobj_free(struct kref *kref);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 		       struct dma_fence *fence);

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 09/12] drm/syncobj: fix resource leak in drm_syncobj_import_sync_file_fence
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
                   ` (7 preceding siblings ...)
  2026-05-16 11:06 ` [PATCH 08/12] drm/syncobj: add drm_syncobj_query Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 10/12] drm/syncobj: add drm_syncobj_import_sync_file Julian Orth
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

Previously, if dma_fence_chain_alloc() failed, the syncobj and fence
would be leaked.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 9b7ecc2978f5..1da96e23dfc0 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -767,30 +767,35 @@ static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
 {
 	struct dma_fence *fence = sync_file_get_fence(fd);
 	struct drm_syncobj *syncobj;
+	int ret = 0;
 
 	if (!fence)
 		return -EINVAL;
 
 	syncobj = drm_syncobj_find(file_private, handle);
 	if (!syncobj) {
-		dma_fence_put(fence);
-		return -ENOENT;
+		ret = -ENOENT;
+		goto err_syncobj;
 	}
 
 	if (point) {
 		struct dma_fence_chain *chain = dma_fence_chain_alloc();
 
-		if (!chain)
-			return -ENOMEM;
+		if (!chain) {
+			ret = -ENOMEM;
+			goto err;
+		}
 
 		drm_syncobj_add_point(syncobj, chain, fence, point);
 	} else {
 		drm_syncobj_replace_fence(syncobj, fence);
 	}
 
-	dma_fence_put(fence);
+err:
 	drm_syncobj_put(syncobj);
-	return 0;
+err_syncobj:
+	dma_fence_put(fence);
+	return ret;
 }
 
 static int drm_syncobj_export_sync_file(struct drm_file *file_private,

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 10/12] drm/syncobj: add drm_syncobj_import_sync_file
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
                   ` (8 preceding siblings ...)
  2026-05-16 11:06 ` [PATCH 09/12] drm/syncobj: fix resource leak in drm_syncobj_import_sync_file_fence Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 11/12] drm/syncobj: add drm_syncobj_export_sync_file Julian Orth
  2026-05-16 11:06 ` [PATCH 12/12] misc/syncobj: add new device Julian Orth
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This makes the logic from drm_syncobj_import_sync_file_fence available
to callers that have a drm_syncobj instead of a drm_file/handle pair.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 35 ++++++++++++++++++++++++++---------
 include/drm/drm_syncobj.h     |  2 ++
 2 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 1da96e23dfc0..4c1667c67cb7 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -765,19 +765,37 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
 static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
 					      int fd, int handle, u64 point)
 {
-	struct dma_fence *fence = sync_file_get_fence(fd);
 	struct drm_syncobj *syncobj;
 	int ret = 0;
 
+	syncobj = drm_syncobj_find(file_private, handle);
+	if (!syncobj)
+		return -ENOENT;
+
+	ret = drm_syncobj_import_sync_file(syncobj, fd, point);
+
+	drm_syncobj_put(syncobj);
+
+	return ret;
+}
+
+/**
+ * drm_syncobj_import_sync_file - import a sync_file fd into a syncobj
+ * @syncobj: syncobj to import into
+ * @fd: sync_file file descriptor
+ * @point: timeline point or 0
+ *
+ * Returns 0 on success or a negative error value on failure.
+ */
+int drm_syncobj_import_sync_file(struct drm_syncobj *syncobj,
+				 int fd, u64 point)
+{
+	struct dma_fence *fence = sync_file_get_fence(fd);
+	int ret = 0;
+
 	if (!fence)
 		return -EINVAL;
 
-	syncobj = drm_syncobj_find(file_private, handle);
-	if (!syncobj) {
-		ret = -ENOENT;
-		goto err_syncobj;
-	}
-
 	if (point) {
 		struct dma_fence_chain *chain = dma_fence_chain_alloc();
 
@@ -792,11 +810,10 @@ static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
 	}
 
 err:
-	drm_syncobj_put(syncobj);
-err_syncobj:
 	dma_fence_put(fence);
 	return ret;
 }
+EXPORT_SYMBOL(drm_syncobj_import_sync_file);
 
 static int drm_syncobj_export_sync_file(struct drm_file *file_private,
 					int handle, u64 point, int *p_fd)
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index da237ca3e61f..1571ffa12a5c 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -143,6 +143,8 @@ int drm_syncobj_timeline_signal(struct drm_syncobj **syncobjs,
 				u64 user_points, u32 count);
 int drm_syncobj_query(struct drm_syncobj **syncobjs, u64 user_points,
 		      u32 count, u32 flags);
+int drm_syncobj_import_sync_file(struct drm_syncobj *syncobj,
+				 int sync_file_fd, u64 point);
 void drm_syncobj_free(struct kref *kref);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 		       struct dma_fence *fence);

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 11/12] drm/syncobj: add drm_syncobj_export_sync_file
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
                   ` (9 preceding siblings ...)
  2026-05-16 11:06 ` [PATCH 10/12] drm/syncobj: add drm_syncobj_import_sync_file Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:06 ` [PATCH 12/12] misc/syncobj: add new device Julian Orth
  11 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This makes the logic from drm_syncobj_export_sync_file_by_handle
available to callers that have a drm_syncobj instead of a
drm_file/handle pair.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 drivers/gpu/drm/drm_syncobj.c | 39 ++++++++++++++++++++++++++++++++++-----
 include/drm/drm_syncobj.h     |  2 ++
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 4c1667c67cb7..d5e633738730 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -815,8 +815,34 @@ int drm_syncobj_import_sync_file(struct drm_syncobj *syncobj,
 }
 EXPORT_SYMBOL(drm_syncobj_import_sync_file);
 
-static int drm_syncobj_export_sync_file(struct drm_file *file_private,
-					int handle, u64 point, int *p_fd)
+static int drm_syncobj_export_sync_file_by_handle(struct drm_file *file_private,
+						   int handle, u64 point,
+						   int *p_fd)
+{
+	struct drm_syncobj *syncobj;
+	int ret;
+
+	syncobj = drm_syncobj_find(file_private, handle);
+	if (!syncobj)
+		return -ENOENT;
+
+	ret = drm_syncobj_export_sync_file(syncobj, point, p_fd);
+
+	drm_syncobj_put(syncobj);
+
+	return ret;
+}
+
+/**
+ * drm_syncobj_export_sync_file - export a syncobj fence as a sync_file fd
+ * @syncobj: syncobj to export from
+ * @point: timeline point or 0
+ * @p_fd: out parameter for the new file descriptor
+ *
+ * Returns 0 on success or a negative error value on failure.
+ */
+int drm_syncobj_export_sync_file(struct drm_syncobj *syncobj,
+				 u64 point, int *p_fd)
 {
 	int ret;
 	struct dma_fence *fence;
@@ -826,7 +852,7 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private,
 	if (fd < 0)
 		return fd;
 
-	ret = drm_syncobj_find_fence(file_private, handle, point, 0, &fence);
+	ret = drm_syncobj_fence_lookup(syncobj, point, 0, &fence);
 	if (ret)
 		goto err_put_fd;
 
@@ -847,6 +873,8 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private,
 	put_unused_fd(fd);
 	return ret;
 }
+EXPORT_SYMBOL(drm_syncobj_export_sync_file);
+
 /**
  * drm_syncobj_open - initializes syncobj file-private structures at devnode open time
  * @file_private: drm file-private structure to set up
@@ -933,8 +961,9 @@ drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
 		point = args->point;
 
 	if (args->flags & DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE)
-		return drm_syncobj_export_sync_file(file_private, args->handle,
-						    point, &args->fd);
+		return drm_syncobj_export_sync_file_by_handle(file_private,
+							      args->handle,
+							      point, &args->fd);
 
 	if (args->point)
 		return -EINVAL;
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index 1571ffa12a5c..48476c570595 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -145,6 +145,8 @@ int drm_syncobj_query(struct drm_syncobj **syncobjs, u64 user_points,
 		      u32 count, u32 flags);
 int drm_syncobj_import_sync_file(struct drm_syncobj *syncobj,
 				 int sync_file_fd, u64 point);
+int drm_syncobj_export_sync_file(struct drm_syncobj *syncobj,
+				 u64 point, int *p_fd);
 void drm_syncobj_free(struct kref *kref);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 		       struct dma_fence *fence);

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 12/12] misc/syncobj: add new device
  2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
                   ` (10 preceding siblings ...)
  2026-05-16 11:06 ` [PATCH 11/12] drm/syncobj: add drm_syncobj_export_sync_file Julian Orth
@ 2026-05-16 11:06 ` Julian Orth
  2026-05-16 11:37   ` Greg Kroah-Hartman
  2026-05-16 11:38   ` Greg Kroah-Hartman
  11 siblings, 2 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, Greg Kroah-Hartman
  Cc: dri-devel, linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel, ju.orth

This device makes the DRM_IOCTL_SYNCOBJ_* ioctls available via a
dedicated device. This allows applications to use syncobjs without
having to open device nodes in /dev/dri, on systems that don't have any
such nodes, or on systems whose devices don't support the
DRIVER_SYNCOBJ_TIMELINE feature.

Wayland uses syncobjs as its buffer synchronization mechanism. Most
compositors use the DRM_IOCTL_SYNCOBJ_EVENTFD ioctl to perform a pure
CPU wait for syncobj point. DRM devices are not involved in this process
except insofar that a DRM device needs to be used to access the ioctl.

Similarly, a software-rendered client might perform rendering on a
dedicated thread and use the wayland syncobj protocol to submit frames
before they finish rendering. Again, this does not involve DRM devices
except insofar ... as above.

As an added benefit, this device removes the need to translate between
file descriptors and handles.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
---
 Documentation/userspace-api/ioctl/ioctl-number.rst |   1 +
 drivers/misc/Kconfig                               |  10 +
 drivers/misc/Makefile                              |   1 +
 drivers/misc/syncobj.c                             | 404 +++++++++++++++++++++
 include/uapi/linux/syncobj.h                       |  75 ++++
 5 files changed, 491 insertions(+)

diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 331223761fff..5e140ae5735e 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -395,6 +395,7 @@ Code  Seq#    Include File                                             Comments
                                                                        <mailto:michael.klein@puffin.lb.shuttle.de>
 0xCC  00-0F  drivers/misc/ibmvmc.h                                     pseries VMC driver
 0xCD  01     linux/reiserfs_fs.h                                       Dead since 6.13
+0xCD  00-0F  uapi/linux/syncobj.h
 0xCE  01-02  uapi/linux/cxl_mem.h                                      Compute Express Link Memory Devices
 0xCF  02     fs/smb/client/cifs_ioctl.h
 0xDD  00-3F                                                            ZFCP device driver see drivers/s390/scsi/
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 00683bf06258..c1e7749bd356 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -644,6 +644,16 @@ config MCHP_LAN966X_PCI
 	    - lan966x-miim (MDIO_MSCC_MIIM)
 	    - lan966x-switch (LAN966X_SWITCH)
 
+config SYNCOBJ_DEV
+	tristate "DRM syncobj device (/dev/syncobj)"
+	depends on DRM
+	help
+	  Creates a /dev/syncobj device node that provides DRM synchronization
+	  objects (syncobjs) without requiring a DRM device.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called syncobj.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b32a2597d246..9e5deb1d0d76 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -75,3 +75,4 @@ obj-$(CONFIG_MCHP_LAN966X_PCI)	+= lan966x-pci.o
 obj-y				+= keba/
 obj-y				+= amd-sbi/
 obj-$(CONFIG_MISC_RP1)		+= rp1/
+obj-$(CONFIG_SYNCOBJ_DEV)	+= syncobj.o
diff --git a/drivers/misc/syncobj.c b/drivers/misc/syncobj.c
new file mode 100644
index 000000000000..11ef46ddfeef
--- /dev/null
+++ b/drivers/misc/syncobj.c
@@ -0,0 +1,404 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * syncobj.c - Standalone device for syncobj manipulation.
+ *
+ * Copyright (C) 2026 Julian Orth <ju.orth@gmail.com>
+ */
+
+#include <linux/fdtable.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <drm/drm_syncobj.h>
+#include <drm/drm_utils.h>
+#include <uapi/drm/drm.h>
+#include <uapi/linux/syncobj.h>
+
+static int syncobj_array_find(void __user *user_fds, u32 count,
+			      struct drm_syncobj ***syncobjs_out)
+{
+	u32 i;
+	s32 *fds;
+	struct drm_syncobj **syncobjs;
+	int ret;
+
+	fds = kmalloc_array(count, sizeof(*fds), GFP_KERNEL);
+	if (!fds)
+		return -ENOMEM;
+
+	if (copy_from_user(fds, user_fds, sizeof(s32) * count)) {
+		ret = -EFAULT;
+		goto err_free_fds;
+	}
+
+	syncobjs = kmalloc_array(count, sizeof(*syncobjs), GFP_KERNEL);
+	if (!syncobjs) {
+		ret = -ENOMEM;
+		goto err_free_fds;
+	}
+
+	for (i = 0; i < count; i++) {
+		syncobjs[i] = drm_syncobj_from_fd(fds[i]);
+		if (!syncobjs[i]) {
+			ret = -EBADF;
+			goto err_put_syncobjs;
+		}
+	}
+
+	kfree(fds);
+	*syncobjs_out = syncobjs;
+	return 0;
+
+err_put_syncobjs:
+	while (i-- > 0)
+		drm_syncobj_put(syncobjs[i]);
+	kfree(syncobjs);
+err_free_fds:
+	kfree(fds);
+	return ret;
+}
+
+static void syncobj_array_free(struct drm_syncobj **syncobjs, u32 count)
+{
+	u32 i;
+
+	for (i = 0; i < count; i++)
+		drm_syncobj_put(syncobjs[i]);
+	kfree(syncobjs);
+}
+
+static int syncobj_ioctl_create(void __user *argp)
+{
+	struct syncobj_create_args args;
+	struct drm_syncobj *syncobj;
+	int fd, ret;
+
+	if (copy_from_user(&args, argp, sizeof(args)))
+		return -EFAULT;
+
+	if (args.flags & ~SYNCOBJ_CREATE_SIGNALED)
+		return -EINVAL;
+
+	static_assert(SYNCOBJ_CREATE_SIGNALED == DRM_SYNCOBJ_CREATE_SIGNALED);
+
+	ret = drm_syncobj_create(&syncobj, args.flags, NULL);
+	if (ret)
+		return ret;
+
+	ret = drm_syncobj_get_fd(syncobj, &fd);
+	drm_syncobj_put(syncobj);
+	if (ret)
+		return ret;
+
+	args.fd = fd;
+	if (copy_to_user(argp, &args, sizeof(args))) {
+		close_fd(fd);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int syncobj_ioctl_wait(void __user *argp)
+{
+	struct syncobj_wait_args args;
+	struct drm_syncobj **syncobjs;
+	signed long timeout;
+	u32 first = ~0;
+	ktime_t t, *tp = NULL;
+	int ret;
+
+	if (copy_from_user(&args, argp, sizeof(args)))
+		return -EFAULT;
+
+	if (args.flags & ~(SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
+			   SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
+			   SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE |
+			   SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE))
+		return -EINVAL;
+
+	static_assert(SYNCOBJ_WAIT_FLAGS_WAIT_ALL        == DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL);
+	static_assert(SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT == DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT);
+	static_assert(SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE  == DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
+	static_assert(SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE   == DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE);
+
+	if (args.pad)
+		return -EINVAL;
+
+	if (args.count == 0)
+		return 0;
+
+	ret = syncobj_array_find(u64_to_user_ptr(args.fds),
+				 args.count, &syncobjs);
+	if (ret < 0)
+		return ret;
+
+	if (args.flags & SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE) {
+		t = ns_to_ktime(args.deadline_nsec);
+		tp = &t;
+	}
+
+	timeout = drm_timeout_abs_to_jiffies(args.timeout_nsec);
+	timeout = drm_syncobj_array_wait_timeout(syncobjs,
+						 u64_to_user_ptr(args.points),
+						 args.count,
+						 args.flags,
+						 timeout, &first, tp);
+
+	syncobj_array_free(syncobjs, args.count);
+
+	if (timeout < 0)
+		return timeout;
+
+	args.first_signaled = first;
+	if (copy_to_user(argp, &args, sizeof(args)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int syncobj_ioctl_reset(void __user *argp)
+{
+	struct syncobj_array_args args;
+	struct drm_syncobj **syncobjs;
+	u32 i;
+	int ret;
+
+	if (copy_from_user(&args, argp, sizeof(args)))
+		return -EFAULT;
+
+	if (args.flags)
+		return -EINVAL;
+
+	if (args.points)
+		return -EINVAL;
+
+	if (args.count == 0)
+		return -EINVAL;
+
+	ret = syncobj_array_find(u64_to_user_ptr(args.fds),
+				 args.count, &syncobjs);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < args.count; i++)
+		drm_syncobj_replace_fence(syncobjs[i], NULL);
+
+	syncobj_array_free(syncobjs, args.count);
+	return 0;
+}
+
+static int syncobj_ioctl_signal(void __user *argp)
+{
+	struct syncobj_array_args args;
+	struct drm_syncobj **syncobjs;
+	int ret;
+
+	if (copy_from_user(&args, argp, sizeof(args)))
+		return -EFAULT;
+
+	if (args.flags)
+		return -EINVAL;
+
+	if (args.count == 0)
+		return -EINVAL;
+
+	ret = syncobj_array_find(u64_to_user_ptr(args.fds),
+				 args.count, &syncobjs);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_syncobj_timeline_signal(syncobjs, args.points, args.count);
+
+	syncobj_array_free(syncobjs, args.count);
+	return ret;
+}
+
+static int syncobj_ioctl_query(void __user *argp)
+{
+	struct syncobj_array_args args;
+	struct drm_syncobj **syncobjs;
+	int ret;
+
+	if (copy_from_user(&args, argp, sizeof(args)))
+		return -EFAULT;
+
+	if (args.flags & ~SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED)
+		return -EINVAL;
+
+	static_assert(SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED == DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED);
+
+	if (args.count == 0)
+		return -EINVAL;
+
+	ret = syncobj_array_find(u64_to_user_ptr(args.fds),
+				 args.count, &syncobjs);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_syncobj_query(syncobjs, args.points, args.count, args.flags);
+
+	syncobj_array_free(syncobjs, args.count);
+	return ret;
+}
+
+static int syncobj_ioctl_transfer(void __user *argp)
+{
+	struct syncobj_transfer_args args;
+	struct drm_syncobj *src, *dst;
+	int ret;
+
+	if (copy_from_user(&args, argp, sizeof(args)))
+		return -EFAULT;
+
+	if (args.pad)
+		return -EINVAL;
+
+	if (args.flags & ~SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)
+		return -EINVAL;
+
+	static_assert(SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT == DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT);
+
+	src = drm_syncobj_from_fd(args.src_fd);
+	if (!src)
+		return -EBADF;
+
+	dst = drm_syncobj_from_fd(args.dst_fd);
+	if (!dst) {
+		drm_syncobj_put(src);
+		return -EBADF;
+	}
+
+	ret = drm_syncobj_transfer(src, args.src_point,
+				   dst, args.dst_point, args.flags);
+
+	drm_syncobj_put(dst);
+	drm_syncobj_put(src);
+
+	return ret;
+}
+
+static int syncobj_ioctl_eventfd(void __user *argp)
+{
+	struct syncobj_eventfd_args args;
+	struct drm_syncobj *syncobj;
+	int ret;
+
+	if (copy_from_user(&args, argp, sizeof(args)))
+		return -EFAULT;
+
+	if (args.flags & ~SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)
+		return -EINVAL;
+
+	static_assert(SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE == DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
+
+	if (args.pad)
+		return -EINVAL;
+
+	syncobj = drm_syncobj_from_fd(args.syncobj_fd);
+	if (!syncobj)
+		return -EBADF;
+
+	ret = drm_syncobj_register_eventfd(syncobj, args.eventfd,
+					   args.point, args.flags);
+
+	drm_syncobj_put(syncobj);
+
+	return ret;
+}
+
+static int syncobj_ioctl_export_sync_file(void __user *argp)
+{
+	struct syncobj_sync_file_args args;
+	struct drm_syncobj *syncobj;
+	int ret;
+
+	if (copy_from_user(&args, argp, sizeof(args)))
+		return -EFAULT;
+
+	syncobj = drm_syncobj_from_fd(args.syncobj_fd);
+	if (!syncobj)
+		return -EBADF;
+
+	ret = drm_syncobj_export_sync_file(syncobj, args.point,
+					   &args.sync_file_fd);
+	drm_syncobj_put(syncobj);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(argp, &args, sizeof(args))) {
+		close_fd(args.sync_file_fd);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int syncobj_ioctl_import_sync_file(void __user *argp)
+{
+	struct syncobj_sync_file_args args;
+	struct drm_syncobj *syncobj;
+	int ret;
+
+	if (copy_from_user(&args, argp, sizeof(args)))
+		return -EFAULT;
+
+	syncobj = drm_syncobj_from_fd(args.syncobj_fd);
+	if (!syncobj)
+		return -EBADF;
+
+	ret = drm_syncobj_import_sync_file(syncobj, args.sync_file_fd,
+					   args.point);
+
+	drm_syncobj_put(syncobj);
+
+	return ret;
+}
+
+static long syncobj_dev_ioctl(struct file *file, unsigned int cmd,
+			      unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+
+	switch (cmd) {
+	case SYNCOBJ_IOC_CREATE:
+		return syncobj_ioctl_create(argp);
+	case SYNCOBJ_IOC_WAIT:
+		return syncobj_ioctl_wait(argp);
+	case SYNCOBJ_IOC_RESET:
+		return syncobj_ioctl_reset(argp);
+	case SYNCOBJ_IOC_SIGNAL:
+		return syncobj_ioctl_signal(argp);
+	case SYNCOBJ_IOC_QUERY:
+		return syncobj_ioctl_query(argp);
+	case SYNCOBJ_IOC_TRANSFER:
+		return syncobj_ioctl_transfer(argp);
+	case SYNCOBJ_IOC_EVENTFD:
+		return syncobj_ioctl_eventfd(argp);
+	case SYNCOBJ_IOC_EXPORT_SYNC_FILE:
+		return syncobj_ioctl_export_sync_file(argp);
+	case SYNCOBJ_IOC_IMPORT_SYNC_FILE:
+		return syncobj_ioctl_import_sync_file(argp);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static const struct file_operations syncobj_dev_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= syncobj_dev_ioctl,
+	.compat_ioctl	= compat_ptr_ioctl,
+};
+
+static struct miscdevice syncobj_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "syncobj",
+	.fops	= &syncobj_dev_fops,
+	.mode	= 0666,
+};
+
+module_misc_device(syncobj_misc);
+
+MODULE_AUTHOR("Julian Orth");
+MODULE_DESCRIPTION("DRM syncobj device");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/syncobj.h b/include/uapi/linux/syncobj.h
new file mode 100644
index 000000000000..c4068fbd5773
--- /dev/null
+++ b/include/uapi/linux/syncobj.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_SYNCOBJ_H_
+#define _UAPI_LINUX_SYNCOBJ_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define SYNCOBJ_CREATE_SIGNALED			(1 << 0)
+
+#define SYNCOBJ_WAIT_FLAGS_WAIT_ALL		(1 << 0)
+#define SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT	(1 << 1)
+#define SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE	(1 << 2)
+#define SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE	(1 << 3)
+
+#define SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED	(1 << 0)
+
+struct syncobj_create_args {
+	__s32 fd;
+	__u32 flags;
+};
+
+struct syncobj_wait_args {
+	__u64 fds;
+	__u64 points;
+	__s64 timeout_nsec;
+	__u32 count;
+	__u32 flags;
+	__u32 first_signaled;
+	__u32 pad;
+	__u64 deadline_nsec;
+};
+
+struct syncobj_array_args {
+	__u64 fds;
+	__u64 points;
+	__u32 count;
+	__u32 flags;
+};
+
+struct syncobj_transfer_args {
+	__s32 src_fd;
+	__s32 dst_fd;
+	__u64 src_point;
+	__u64 dst_point;
+	__u32 flags;
+	__u32 pad;
+};
+
+struct syncobj_eventfd_args {
+	__s32 syncobj_fd;
+	__s32 eventfd;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
+struct syncobj_sync_file_args {
+	__s32 syncobj_fd;
+	__s32 sync_file_fd;
+	__u64 point;
+};
+
+#define SYNCOBJ_IOC_BASE		0xCD
+
+#define SYNCOBJ_IOC_CREATE		_IOWR(SYNCOBJ_IOC_BASE, 0, struct syncobj_create_args)
+#define SYNCOBJ_IOC_WAIT		_IOWR(SYNCOBJ_IOC_BASE, 1, struct syncobj_wait_args)
+#define SYNCOBJ_IOC_RESET		_IOW(SYNCOBJ_IOC_BASE,  2, struct syncobj_array_args)
+#define SYNCOBJ_IOC_SIGNAL		_IOW(SYNCOBJ_IOC_BASE,  3, struct syncobj_array_args)
+#define SYNCOBJ_IOC_QUERY		_IOW(SYNCOBJ_IOC_BASE,  4, struct syncobj_array_args)
+#define SYNCOBJ_IOC_TRANSFER		_IOW(SYNCOBJ_IOC_BASE,  5, struct syncobj_transfer_args)
+#define SYNCOBJ_IOC_EVENTFD		_IOW(SYNCOBJ_IOC_BASE,  6, struct syncobj_eventfd_args)
+#define SYNCOBJ_IOC_EXPORT_SYNC_FILE	_IOWR(SYNCOBJ_IOC_BASE, 7, struct syncobj_sync_file_args)
+#define SYNCOBJ_IOC_IMPORT_SYNC_FILE	_IOW(SYNCOBJ_IOC_BASE,  8, struct syncobj_sync_file_args)
+
+#endif /* _UAPI_LINUX_SYNCOBJ_H_ */

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 12/12] misc/syncobj: add new device
  2026-05-16 11:06 ` [PATCH 12/12] misc/syncobj: add new device Julian Orth
@ 2026-05-16 11:37   ` Greg Kroah-Hartman
  2026-05-16 11:38   ` Greg Kroah-Hartman
  1 sibling, 0 replies; 16+ messages in thread
From: Greg Kroah-Hartman @ 2026-05-16 11:37 UTC (permalink / raw)
  To: Julian Orth
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, dri-devel,
	linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel

On Sat, May 16, 2026 at 01:06:15PM +0200, Julian Orth wrote:
> This device makes the DRM_IOCTL_SYNCOBJ_* ioctls available via a
> dedicated device. This allows applications to use syncobjs without
> having to open device nodes in /dev/dri, on systems that don't have any
> such nodes, or on systems whose devices don't support the
> DRIVER_SYNCOBJ_TIMELINE feature.
> 
> Wayland uses syncobjs as its buffer synchronization mechanism. Most
> compositors use the DRM_IOCTL_SYNCOBJ_EVENTFD ioctl to perform a pure
> CPU wait for syncobj point. DRM devices are not involved in this process
> except insofar that a DRM device needs to be used to access the ioctl.
> 
> Similarly, a software-rendered client might perform rendering on a
> dedicated thread and use the wayland syncobj protocol to submit frames
> before they finish rendering. Again, this does not involve DRM devices
> except insofar ... as above.
> 
> As an added benefit, this device removes the need to translate between
> file descriptors and handles.
> 
> Signed-off-by: Julian Orth <ju.orth@gmail.com>
> ---
>  Documentation/userspace-api/ioctl/ioctl-number.rst |   1 +
>  drivers/misc/Kconfig                               |  10 +
>  drivers/misc/Makefile                              |   1 +
>  drivers/misc/syncobj.c                             | 404 +++++++++++++++++++++
>  include/uapi/linux/syncobj.h                       |  75 ++++
>  5 files changed, 491 insertions(+)
> 
> diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
> index 331223761fff..5e140ae5735e 100644
> --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
> +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
> @@ -395,6 +395,7 @@ Code  Seq#    Include File                                             Comments
>                                                                         <mailto:michael.klein@puffin.lb.shuttle.de>
>  0xCC  00-0F  drivers/misc/ibmvmc.h                                     pseries VMC driver
>  0xCD  01     linux/reiserfs_fs.h                                       Dead since 6.13
> +0xCD  00-0F  uapi/linux/syncobj.h
>  0xCE  01-02  uapi/linux/cxl_mem.h                                      Compute Express Link Memory Devices
>  0xCF  02     fs/smb/client/cifs_ioctl.h
>  0xDD  00-3F                                                            ZFCP device driver see drivers/s390/scsi/
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index 00683bf06258..c1e7749bd356 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -644,6 +644,16 @@ config MCHP_LAN966X_PCI
>  	    - lan966x-miim (MDIO_MSCC_MIIM)
>  	    - lan966x-switch (LAN966X_SWITCH)
>  
> +config SYNCOBJ_DEV
> +	tristate "DRM syncobj device (/dev/syncobj)"
> +	depends on DRM

If this is a drm-only thing, then please put it in the drm subdirs, not
in drivers/misc/ as that would imply that I have to maintain this, not
the DRM developers :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 12/12] misc/syncobj: add new device
  2026-05-16 11:06 ` [PATCH 12/12] misc/syncobj: add new device Julian Orth
  2026-05-16 11:37   ` Greg Kroah-Hartman
@ 2026-05-16 11:38   ` Greg Kroah-Hartman
  2026-05-16 12:08     ` Julian Orth
  1 sibling, 1 reply; 16+ messages in thread
From: Greg Kroah-Hartman @ 2026-05-16 11:38 UTC (permalink / raw)
  To: Julian Orth
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, dri-devel,
	linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel

On Sat, May 16, 2026 at 01:06:15PM +0200, Julian Orth wrote:
> This device makes the DRM_IOCTL_SYNCOBJ_* ioctls available via a
> dedicated device. This allows applications to use syncobjs without
> having to open device nodes in /dev/dri, on systems that don't have any
> such nodes, or on systems whose devices don't support the
> DRIVER_SYNCOBJ_TIMELINE feature.
> 
> Wayland uses syncobjs as its buffer synchronization mechanism. Most
> compositors use the DRM_IOCTL_SYNCOBJ_EVENTFD ioctl to perform a pure
> CPU wait for syncobj point. DRM devices are not involved in this process
> except insofar that a DRM device needs to be used to access the ioctl.
> 
> Similarly, a software-rendered client might perform rendering on a
> dedicated thread and use the wayland syncobj protocol to submit frames
> before they finish rendering. Again, this does not involve DRM devices
> except insofar ... as above.
> 
> As an added benefit, this device removes the need to translate between
> file descriptors and handles.
> 
> Signed-off-by: Julian Orth <ju.orth@gmail.com>
> ---
>  Documentation/userspace-api/ioctl/ioctl-number.rst |   1 +
>  drivers/misc/Kconfig                               |  10 +
>  drivers/misc/Makefile                              |   1 +
>  drivers/misc/syncobj.c                             | 404 +++++++++++++++++++++
>  include/uapi/linux/syncobj.h                       |  75 ++++
>  5 files changed, 491 insertions(+)

As this is a bunch of user-facing code, why not do this in rust to at
least get some semblance of proper parsing of user data sanity?  Or is
the api to the drm layer just to complex for that at the moment?

Just curious, not a criticism of this in C at all.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 12/12] misc/syncobj: add new device
  2026-05-16 11:38   ` Greg Kroah-Hartman
@ 2026-05-16 12:08     ` Julian Orth
  0 siblings, 0 replies; 16+ messages in thread
From: Julian Orth @ 2026-05-16 12:08 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Sumit Semwal, Christian König,
	Jonathan Corbet, Shuah Khan, Arnd Bergmann, dri-devel,
	linux-kernel, linux-media, linaro-mm-sig, linux-doc,
	wayland-devel

On Sat, May 16, 2026 at 1:38 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> On Sat, May 16, 2026 at 01:06:15PM +0200, Julian Orth wrote:
> > This device makes the DRM_IOCTL_SYNCOBJ_* ioctls available via a
> > dedicated device. This allows applications to use syncobjs without
> > having to open device nodes in /dev/dri, on systems that don't have any
> > such nodes, or on systems whose devices don't support the
> > DRIVER_SYNCOBJ_TIMELINE feature.
> >
> > Wayland uses syncobjs as its buffer synchronization mechanism. Most
> > compositors use the DRM_IOCTL_SYNCOBJ_EVENTFD ioctl to perform a pure
> > CPU wait for syncobj point. DRM devices are not involved in this process
> > except insofar that a DRM device needs to be used to access the ioctl.
> >
> > Similarly, a software-rendered client might perform rendering on a
> > dedicated thread and use the wayland syncobj protocol to submit frames
> > before they finish rendering. Again, this does not involve DRM devices
> > except insofar ... as above.
> >
> > As an added benefit, this device removes the need to translate between
> > file descriptors and handles.
> >
> > Signed-off-by: Julian Orth <ju.orth@gmail.com>
> > ---
> >  Documentation/userspace-api/ioctl/ioctl-number.rst |   1 +
> >  drivers/misc/Kconfig                               |  10 +
> >  drivers/misc/Makefile                              |   1 +
> >  drivers/misc/syncobj.c                             | 404 +++++++++++++++++++++
> >  include/uapi/linux/syncobj.h                       |  75 ++++
> >  5 files changed, 491 insertions(+)
>
> As this is a bunch of user-facing code, why not do this in rust to at
> least get some semblance of proper parsing of user data sanity?  Or is
> the api to the drm layer just to complex for that at the moment?

I didn't consider using rust because I'm not familiar with rust in the kernel.

But even if I had considered it, I probably would not have done it
because drm_syncobj currently has no rust bindings. The driver as-is
is just a thin layer around drm_syncobj.c so if drm_syncobj gains rust
bindings it should be easy to convert the driver.

>
> Just curious, not a criticism of this in C at all.
>
> thanks,
>
> greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-05-16 12:08 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-16 11:06 [PATCH 00/12] misc/syncobj: add /dev/syncobj device Julian Orth
2026-05-16 11:06 ` [PATCH 01/12] drm/syncobj: add drm_syncobj_from_fd Julian Orth
2026-05-16 11:06 ` [PATCH 02/12] drm/syncobj: add drm_syncobj_fence_lookup Julian Orth
2026-05-16 11:06 ` [PATCH 03/12] drm/syncobj: make drm_syncobj_array_wait_timeout public Julian Orth
2026-05-16 11:06 ` [PATCH 04/12] drm/syncobj: add drm_syncobj_register_eventfd Julian Orth
2026-05-16 11:06 ` [PATCH 05/12] drm/syncobj: have transfer functions accept drm_syncobj directly Julian Orth
2026-05-16 11:06 ` [PATCH 06/12] drm/syncobj: add drm_syncobj_transfer Julian Orth
2026-05-16 11:06 ` [PATCH 07/12] drm/syncobj: add drm_syncobj_timeline_signal Julian Orth
2026-05-16 11:06 ` [PATCH 08/12] drm/syncobj: add drm_syncobj_query Julian Orth
2026-05-16 11:06 ` [PATCH 09/12] drm/syncobj: fix resource leak in drm_syncobj_import_sync_file_fence Julian Orth
2026-05-16 11:06 ` [PATCH 10/12] drm/syncobj: add drm_syncobj_import_sync_file Julian Orth
2026-05-16 11:06 ` [PATCH 11/12] drm/syncobj: add drm_syncobj_export_sync_file Julian Orth
2026-05-16 11:06 ` [PATCH 12/12] misc/syncobj: add new device Julian Orth
2026-05-16 11:37   ` Greg Kroah-Hartman
2026-05-16 11:38   ` Greg Kroah-Hartman
2026-05-16 12:08     ` Julian Orth

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.