Linux Documentation
 help / color / mirror / Atom feed
* [PATCH 03/12] drm/syncobj: make drm_syncobj_array_wait_timeout public
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* [PATCH 04/12] drm/syncobj: add drm_syncobj_register_eventfd
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* [PATCH 05/12] drm/syncobj: have transfer functions accept drm_syncobj directly
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* [PATCH 07/12] drm/syncobj: add drm_syncobj_timeline_signal
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* [PATCH 06/12] drm/syncobj: add drm_syncobj_transfer
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* [PATCH 08/12] drm/syncobj: add drm_syncobj_query
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* [PATCH 09/12] drm/syncobj: fix resource leak in drm_syncobj_import_sync_file_fence
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* [PATCH 11/12] drm/syncobj: add drm_syncobj_export_sync_file
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* [PATCH 10/12] drm/syncobj: add drm_syncobj_import_sync_file
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* [PATCH 12/12] misc/syncobj: add new device
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
In-Reply-To: <20260516-jorth-syncobj-v1-0-88ede9d98a81@gmail.com>

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

* Re: [PATCH 12/12] misc/syncobj: add new device
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
In-Reply-To: <20260516-jorth-syncobj-v1-12-88ede9d98a81@gmail.com>

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

* Re: [PATCH 12/12] misc/syncobj: add new device
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
In-Reply-To: <20260516-jorth-syncobj-v1-12-88ede9d98a81@gmail.com>

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

* Re: [PATCH 12/12] misc/syncobj: add new device
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
In-Reply-To: <2026051652-pork-omission-b762@gregkh>

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

* Re: [PATCH RESEND] Documentation: fix typo in heading for max31730
From: Guenter Roeck @ 2026-05-16 12:29 UTC (permalink / raw)
  To: Hassan Maazu
  Cc: skhan@linuxfoundation.org, corbet@lwn.net,
	linux-doc@vger.kernel.org, linux-hwmon@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <hGgiFItk4iaav9-zfXL4hA_EVmxAaZYRbYviXz8aKKzOVAqduObTpd-PvRy1-9Ksuziam1HIXZNEkXbw3znqWX86Lplbq-Axo3fImYbtNZA=@proton.me>

On Sat, May 16, 2026 at 06:00:01AM +0000, Hassan Maazu wrote:
> Wrong device name used in heading.
> 

That is not a proper commit description.

> Signed-off-by: Hassan Maazu <maazudev@proton.me>

... and you dropped an Acked-by:.

Guenter

> ---
>  Documentation/hwmon/max31730.rst | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> --
> 2.54.0
> 
> diff --git a/Documentation/hwmon/max31730.rst b/Documentation/hwmon/max31730.rst
> index 1c5a32b64187..0936ba2eac24 100644
> --- a/Documentation/hwmon/max31730.rst
> +++ b/Documentation/hwmon/max31730.rst
> @@ -1,4 +1,4 @@
> -Kernel driver max31790
> +Kernel driver max31730
>  ======================
> 
>  Supported chips:

^ permalink raw reply

* Re: [PATCH] Documentation: hwmon: adt7411: document supported sysfs attributes
From: Guenter Roeck @ 2026-05-16 12:31 UTC (permalink / raw)
  To: Chen-Shi-Hong; +Cc: corbet, skhan, linux-hwmon, linux-doc, linux-kernel
In-Reply-To: <20260516035245.1604-1-eric039eric@gmail.com>

On Sat, May 16, 2026 at 11:52:31AM +0800, Chen-Shi-Hong wrote:
> The adt7411 driver exposes additional standard hwmon attributes beyond
> the ones currently listed in Documentation/hwmon/adt7411.rst.
> 
> Document voltage min/max/alarm attributes, temperature min/max and
> min_alarm/max_alarm attributes, and the temp2_fault attribute for the
> external temperature channel.
> 
> Also update the documentation to clarify that analog inputs in1 and in2
> are not available when the external temperature sensor is enabled, and
> remove the outdated statement claiming that external temperature support
> and limit registers are unsupported.
> 
> Signed-off-by: Chen-Shi-Hong <eric039eric@gmail.com>

Applied.

Thanks,
Guenter

^ permalink raw reply

* [PATCH] docs: submitting-patches: Clarify that in English "reviewer" is a person
From: Krzysztof Kozlowski @ 2026-05-16 12:38 UTC (permalink / raw)
  To: Jonathan Corbet, Shuah Khan, workflows, linux-doc, linux-kernel
  Cc: Krzysztof Kozlowski, Greg Kroah-Hartman, Vlastimil Babka,
	Andrew Morton, David Hildenbrand, Linus Torvalds

Common understanding of word "Reviewer" is: a person performing a review
work [1]. Tools are not persons, thus cannot be reviewers in this term.
Also tools cannot make statements ("A Reviewed-by tag is a statement of
opinion"), since making a statement needs some sort of conscious mind.

Our docs already clearly mark that "Reviewed-by" must come from a
person:

 - "By offering my Reviewed-by: tag, I state that:"

   Usage of first person "I" and word "state"

 - "A Reviewed-by tag is *a statement of opinion* that the patch is an
    appropriate modification of the kernel without any remaining serious"

   Only a person can make a statement of opinion.

 - "Any interested reviewer (who has done the work) can offer a
   Reviewed-by"

   A person can offer a tag thus above does not grant the tool
   permission to offer a tag.

However this is not enough and apparently English is not that precise,
so let's clarify that only a person can state the "Reviewer's statement
of oversight".

Link: https://en.wiktionary.org/wiki/reviewer [1]
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

---

I find it silly to need to describe English, but it seems it is needed.

https://lore.kernel.org/all/fd3b2ca7-4d64-4c4b-98a3-7d3285fa6826@roeck-us.net/
---
 Documentation/process/submitting-patches.rst | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst
index d7290e208e72..a989de43f3db 100644
--- a/Documentation/process/submitting-patches.rst
+++ b/Documentation/process/submitting-patches.rst
@@ -581,10 +581,10 @@ By offering my Reviewed-by: tag, I state that:
 
 A Reviewed-by tag is a statement of opinion that the patch is an
 appropriate modification of the kernel without any remaining serious
-technical issues.  Any interested reviewer (who has done the work) can
-offer a Reviewed-by tag for a patch.  This tag serves to give credit to
-reviewers and to inform maintainers of the degree of review which has been
-done on the patch.  Reviewed-by: tags, when supplied by reviewers known to
+technical issues.  Any interested reviewer (who has done the work and is a
+person) can offer a Reviewed-by tag for a patch.  This tag serves to give
+credit to reviewers and to inform maintainers of the degree of review which has
+been done on the patch.  Reviewed-by: tags, when supplied by reviewers known to
 understand the subject area and to perform thorough reviews, will normally
 increase the likelihood of your patch getting into the kernel.
 
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH] docs: fix typo in mpo-overview.rst
From: Jonathan Corbet @ 2026-05-16 14:09 UTC (permalink / raw)
  To: Cheesecake, Alex Deucher, Christian König, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Shuah Khan
  Cc: amd-gfx, dri-devel, linux-doc, linux-kernel, Cheesecake
In-Reply-To: <20260516100406.21070-1-cheesecake2960@icloud.com>

Cheesecake <cheesecake2960@icloud.com> writes:

> Replace "transparant" with "transparent"
>
> Signed-off-by: Cheesecake <cheesecake2960@icloud.com>

Patches need a proper signoff with a real name, please.

Thanks,

jo

^ permalink raw reply

* Re: [PATCH v2] docs: kernel-parameters: document scope of irqaffinity= parameter
From: Aaron Tomlin @ 2026-05-16 14:12 UTC (permalink / raw)
  To: Bagas Sanjaya
  Cc: corbet, skhan, tglx, akpm, bp, rdunlap, dave.hansen, feng.tang,
	pawan.kumar.gupta, dapeng1.mi, kees, elver, paulmck, lirongqing,
	bhelgaas, bigeasy, linux-doc, linux-kernel
In-Reply-To: <afMAAL4lB72HiSQI@archie.me>

On Thu, Apr 30, 2026 at 02:08:48PM +0700, Bagas Sanjaya wrote:
> On Tue, Apr 21, 2026 at 11:09:11AM -0400, Aaron Tomlin wrote:
> > -  This can be verified via the debugfs interface
> > -  (/sys/kernel/debug/irq/irqs/48). The dstate field will include
> > +  If the Linux kernel was built with Kconfig CONFIG_GENERIC_IRQ_DEBUGFS
> > +  enabled, this can be verified via the debugfs interface (e.g.,
> > +  /sys/kernel/debug/irq/irqs/48). The dstate field will include
> >    IRQD_IRQ_DISABLED, IRQD_IRQ_MASKED and IRQD_MANAGED_SHUTDOWN.
> > +  A managed IRQ will also include IRQD_AFFINITY_MANAGED. For example:
> 
> Use double-colon syntax (i.e. ``For example::``) for literal code block
> below.
> 
> > +
> > +    # cat /sys/kernel/debug/irq/irqs/87
> 

Hi Bagas,

Thank you for the feedback.

I will resolve this in the next iteration.


Kind regards,
-- 
Aaron Tomlin

^ permalink raw reply

* Re: Re: Re: [PATCH] dcache: add fs.dentry-limit sysctl with negative-first reaper
From: Horst Birthelmer @ 2026-05-16 14:15 UTC (permalink / raw)
  To: Stafford Horne
  Cc: kernel test robot, Horst Birthelmer, Miklos Szeredi,
	Jonathan Corbet, Shuah Khan, Alexander Viro, Christian Brauner,
	Jan Kara, oe-kbuild-all, linux-doc, linux-kernel, linux-fsdevel,
	Horst Birthelmer
In-Reply-To: <aghIDLYW91C4fcd7@antec>

On Sat, May 16, 2026 at 11:33:48AM +0100, Stafford Horne wrote:
> On Sat, May 16, 2026 at 08:55:16AM +0200, Horst Birthelmer wrote:
> > On Fri, May 15, 2026 at 11:09:54PM +0800, kernel test robot wrote:
> > > Hi Horst,
> > > 
> > > kernel test robot noticed the following build errors:
> > > 
> > > [auto build test ERROR on 5d6919055dec134de3c40167a490f33c74c12581]
> > > 
> > > url:    https://github.com/intel-lab-lkp/linux/commits/Horst-Birthelmer/dcache-add-fs-dentry-limit-sysctl-with-negative-first-reaper/20260515-154600
> > > base:   5d6919055dec134de3c40167a490f33c74c12581
> > > patch link:    https://lore.kernel.org/r/20260514-limit-dentries-cache-v1-1-431b9eb0c530%40ddn.com
> > > patch subject: [PATCH] dcache: add fs.dentry-limit sysctl with negative-first reaper
> > > config: openrisc-randconfig-r073-20260515 (https://download.01.org/0day-ci/archive/20260515/202605152333.0pOd2zJR-lkp@intel.com/config)
> > > compiler: or1k-linux-gcc (GCC) 10.5.0
> > > smatch: v0.5.0-9185-gbcc58b9c
> > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260515/202605152333.0pOd2zJR-lkp@intel.com/reproduce)
> > > 
> > > If you fix the issue in a separate patch/commit (i.e. not just a new version of
> > > the same patch/commit), kindly add following tags
> > > | Reported-by: kernel test robot <lkp@intel.com>
> > > | Closes: https://lore.kernel.org/oe-kbuild-all/202605152333.0pOd2zJR-lkp@intel.com/
> > > 
> > > All errors (new ones prefixed by >>):
> > > 
> > >    fs/dcache.c: In function 'dentry_limit_worker_fn':
> > > >> fs/dcache.c:1474:7: error: implicit declaration of function 'get_nr_dentry'; did you mean 'retain_dentry'? [-Werror=implicit-function-declaration]
> > >     1474 |  nr = get_nr_dentry();
> > >          |       ^~~~~~~~~~~~~
> > >          |       retain_dentry
> > >    cc1: some warnings being treated as errors
> > > 
> > > 
> > > vim +1474 fs/dcache.c
> > > 
> > ...
> > > 
> > > --
> > > 0-DAY CI Kernel Test Service
> > > https://github.com/intel/lkp-tests/wiki
> > 
> > This is puzzling to me get_nr_dentry() is defined in line 178 in the same file and first used in line 209 
> > and has been there since 2013.
> > 
> > Builds fine applied to tag v7.1-rc3 and to the current master with gcc and clang.
> 
> Hi
> 
> They are protected in:
> 
> #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
> 
> With #endif on line 247.

You are right, of course.
Thank you!

I will send a corrected version.

> 
> In the rand config as least I see:
>  # CONFIG_PROC_FS is not set
> 
> -Stafford
> 

^ permalink raw reply

* Re: [PATCH v10 8/9] platform/chrome: Protect cros_ec_device lifecycle with revocable
From: Tzung-Bi Shih @ 2026-05-16 14:34 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Bartosz Golaszewski,
	Linus Walleij, Benson Leung, linux-kernel, chrome-platform,
	driver-core, linux-doc, linux-gpio, Rafael J. Wysocki,
	Danilo Krummrich, Jonathan Corbet, Shuah Khan, Laurent Pinchart,
	Wolfram Sang, Johan Hovold, Paul E . McKenney
In-Reply-To: <agbZLY0wn85JqTFV@google.com>

On Fri, May 15, 2026 at 08:28:29AM +0000, Tzung-Bi Shih wrote:
> On Thu, May 14, 2026 at 01:02:14PM -0300, Jason Gunthorpe wrote:
> > On Thu, May 14, 2026 at 03:33:55AM +0000, Tzung-Bi Shih wrote:
> > 
> > > > Given you say this is such a bug I think you really should be sending
> > > > a series that is patches 5 through 7 from the other series and a
> > > > simple rwsem instead of misc_deregister_sync() to deal with this bug
> > > > ASAP. No need to complicate a simple bug fix in a driver with all
> > > > these core changes.
> > > 
> > > Apologies for missing this suggestion.
> > > 
> > > For "patches 5 through 7 from the other series" I guess you're referring:
> > > - https://lore.kernel.org/all/20260427134659.95181-6-tzungbi@kernel.org
> > > - https://lore.kernel.org/all/20260427134659.95181-7-tzungbi@kernel.org
> > > - https://lore.kernel.org/all/20260427134659.95181-8-tzungbi@kernel.org
> > 
> > Yes
> > 
> > > Could you provide a bit more detail on the rwsem approach?  I'm not
> > > entirely clear on what data or operations the rwsem would be protecting.
> > 
> > Just put a rwsem, or even scru, inside the driver's fops.
> > 
> > You can refactor that out to a misc or revocable later.
> 
> I see.  Thank you for your suggestion.  I will explore it and send out a
> new version.

https://lore.kernel.org/all/20260516143017.18560-1-tzungbi@kernel.org
is an attempt at it.

^ permalink raw reply

* Re: [PATCH] docs: submitting-patches: Clarify that in English "reviewer" is a person
From: Vlastimil Babka (SUSE) @ 2026-05-16 14:39 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Jonathan Corbet, Shuah Khan, workflows,
	linux-doc, linux-kernel
  Cc: Greg Kroah-Hartman, Andrew Morton, David Hildenbrand,
	Linus Torvalds, Guenter Roeck
In-Reply-To: <20260516123846.63413-2-krzysztof.kozlowski@oss.qualcomm.com>

On 5/16/26 14:38, Krzysztof Kozlowski wrote:
> Common understanding of word "Reviewer" is: a person performing a review
> work [1]. Tools are not persons, thus cannot be reviewers in this term.
> Also tools cannot make statements ("A Reviewed-by tag is a statement of
> opinion"), since making a statement needs some sort of conscious mind.
> 
> Our docs already clearly mark that "Reviewed-by" must come from a
> person:
> 
>  - "By offering my Reviewed-by: tag, I state that:"
> 
>    Usage of first person "I" and word "state"
> 
>  - "A Reviewed-by tag is *a statement of opinion* that the patch is an
>     appropriate modification of the kernel without any remaining serious"
> 
>    Only a person can make a statement of opinion.
> 
>  - "Any interested reviewer (who has done the work) can offer a
>    Reviewed-by"
> 
>    A person can offer a tag thus above does not grant the tool
>    permission to offer a tag.
> 
> However this is not enough and apparently English is not that precise,
> so let's clarify that only a person can state the "Reviewer's statement
> of oversight".
> 
> Link: https://en.wiktionary.org/wiki/reviewer [1]
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Vlastimil Babka <vbabka@kernel.org>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: David Hildenbrand <david@kernel.org>
> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

I agree with the intent that the tag is for people (whether they use a tool
or not to help them). We also don't put "Tested-by: kernel test robot" or
syzkaller on every commit that they test and find no bugs. Review is also
not just about absence of bugs, but agreeing with the larger design and
whether the change makes sense to do in the first place.

So whether that's achieved with this particular wording or differently,

Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>

> 
> ---
> 
> I find it silly to need to describe English, but it seems it is needed.
> 
> https://lore.kernel.org/all/fd3b2ca7-4d64-4c4b-98a3-7d3285fa6826@roeck-us.net/
> ---
>  Documentation/process/submitting-patches.rst | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst
> index d7290e208e72..a989de43f3db 100644
> --- a/Documentation/process/submitting-patches.rst
> +++ b/Documentation/process/submitting-patches.rst
> @@ -581,10 +581,10 @@ By offering my Reviewed-by: tag, I state that:
>  
>  A Reviewed-by tag is a statement of opinion that the patch is an
>  appropriate modification of the kernel without any remaining serious
> -technical issues.  Any interested reviewer (who has done the work) can
> -offer a Reviewed-by tag for a patch.  This tag serves to give credit to
> -reviewers and to inform maintainers of the degree of review which has been
> -done on the patch.  Reviewed-by: tags, when supplied by reviewers known to
> +technical issues.  Any interested reviewer (who has done the work and is a
> +person) can offer a Reviewed-by tag for a patch.  This tag serves to give
> +credit to reviewers and to inform maintainers of the degree of review which has
> +been done on the patch.  Reviewed-by: tags, when supplied by reviewers known to
>  understand the subject area and to perform thorough reviews, will normally
>  increase the likelihood of your patch getting into the kernel.
>  


^ permalink raw reply

* Re: [PATCH v11 4/5] platform/chrome: Protect cros_ec_device lifecycle with revocable
From: Tzung-Bi Shih @ 2026-05-16 14:42 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Bartosz Golaszewski,
	Linus Walleij, Benson Leung, linux-kernel, chrome-platform,
	driver-core, linux-doc, linux-gpio, Rafael J. Wysocki,
	Danilo Krummrich, Jonathan Corbet, Shuah Khan, Laurent Pinchart,
	Wolfram Sang, Johan Hovold, Paul E . McKenney
In-Reply-To: <20260514160043.GG787748@nvidia.com>

On Thu, May 14, 2026 at 01:00:43PM -0300, Jason Gunthorpe wrote:
> On Thu, May 14, 2026 at 03:34:12AM +0000, Tzung-Bi Shih wrote:
> 
> > To help me understand, could you elaborate on why the revocable mechanism
> > isn't suitable here?
> 
> Stay within one driver. Create the revokable is probe, consume it
> within that drivers fops/etc, destroy it on remove. Do not randomly
> pass it to other drivers.

In that sense, after applying [1], does the patch make sense to you?

[1] https://lore.kernel.org/all/20260516143017.18560-1-tzungbi@kernel.org

diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
index 450f79759122..27e52fee59f6 100644
--- a/drivers/platform/chrome/cros_ec_chardev.c
+++ b/drivers/platform/chrome/cros_ec_chardev.c
@@ -23,7 +23,7 @@
 #include <linux/platform_data/cros_ec_proto.h>
 #include <linux/platform_device.h>
 #include <linux/poll.h>
-#include <linux/rwsem.h>
+#include <linux/revocable.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
@@ -39,8 +39,7 @@
 struct chardev_pdata {
 	struct miscdevice misc;
 	struct kref kref;
-	struct rw_semaphore ec_dev_sem;
-	struct cros_ec_device *ec_dev;
+	struct revocable ec_rev;
 	u16 cmd_offset;
 	struct blocking_notifier_head subscribers;
 	struct notifier_block relay;
@@ -50,6 +49,7 @@ static void chardev_pdata_release(struct kref *kref)
 {
 	struct chardev_pdata *pdata = container_of(kref, typeof(*pdata), kref);
 
+	revocable_put(&pdata->ec_rev);
 	kfree(pdata);
 }
 
@@ -87,6 +87,7 @@ static int ec_get_version(struct chardev_priv *priv, char *str, int maxlen)
 	};
 	struct ec_response_get_version *resp;
 	struct cros_ec_command *msg;
+	struct cros_ec_device *ec_dev;
 	int ret;
 
 	msg = kzalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL);
@@ -96,13 +97,13 @@ static int ec_get_version(struct chardev_priv *priv, char *str, int maxlen)
 	msg->command = EC_CMD_GET_VERSION + priv->pdata->cmd_offset;
 	msg->insize = sizeof(*resp);
 
-	scoped_guard(rwsem_read, &priv->pdata->ec_dev_sem) {
-		if (!priv->pdata->ec_dev) {
+	revocable_try_access_with_scoped(&priv->pdata->ec_rev, ec_dev) {
+		if (!ec_dev) {
 			ret = -ENODEV;
 			goto exit;
 		}
 
-		ret = cros_ec_cmd_xfer_status(priv->pdata->ec_dev, msg);
+		ret = cros_ec_cmd_xfer_status(ec_dev, msg);
 		if (ret < 0) {
 			snprintf(str, maxlen,
 				 "Unknown EC version, returned error: %d\n",
@@ -136,10 +137,8 @@ static int cros_ec_chardev_mkbp_event(struct notifier_block *nb,
 	unsigned long event_bit;
 	int total_size;
 
-	guard(rwsem_read)(&priv->pdata->ec_dev_sem);
-	if (!priv->pdata->ec_dev)
-		return NOTIFY_DONE;
-	ec_dev = priv->pdata->ec_dev;
+	revocable_try_access_or_return_err(&priv->pdata->ec_rev, ec_dev,
+					   NOTIFY_DONE);
 
 	event_bit = 1 << ec_dev->event_data.event_type;
 	total_size = sizeof(*event) + ec_dev->event_size;
@@ -206,6 +205,7 @@ static int cros_ec_chardev_open(struct inode *inode, struct file *filp)
 	struct miscdevice *mdev = filp->private_data;
 	struct chardev_pdata *pdata = container_of(mdev, typeof(*pdata), misc);
 	struct chardev_priv *priv;
+	struct cros_ec_device *ec_dev;
 	int ret;
 
 	priv = kzalloc_obj(*priv);
@@ -223,11 +223,9 @@ static int cros_ec_chardev_open(struct inode *inode, struct file *filp)
 	ret = blocking_notifier_chain_register(&pdata->subscribers,
 					       &priv->notifier);
 	if (ret) {
-		scoped_guard(rwsem_read, &pdata->ec_dev_sem) {
-			if (pdata->ec_dev)
-				dev_err(pdata->ec_dev->dev,
-					"failed to register event notifier\n");
-		}
+		revocable_try_access_or_skip_scoped(&pdata->ec_rev, ec_dev)
+			dev_err(ec_dev->dev,
+				"failed to register event notifier\n");
 		kref_put(&priv->pdata->kref, chardev_pdata_release);
 		kfree(priv);
 	}
@@ -324,6 +322,7 @@ static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *a
 {
 	struct cros_ec_command *s_cmd;
 	struct cros_ec_command u_cmd;
+	struct cros_ec_device *ec_dev;
 	long ret;
 
 	if (copy_from_user(&u_cmd, arg, sizeof(u_cmd)))
@@ -351,13 +350,13 @@ static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *a
 
 	s_cmd->command += priv->pdata->cmd_offset;
 
-	scoped_guard(rwsem_read, &priv->pdata->ec_dev_sem) {
-		if (!priv->pdata->ec_dev) {
+	revocable_try_access_with_scoped(&priv->pdata->ec_rev, ec_dev) {
+		if (!ec_dev) {
 			ret = -ENODEV;
 			goto exit;
 		}
 
-		ret = cros_ec_cmd_xfer(priv->pdata->ec_dev, s_cmd);
+		ret = cros_ec_cmd_xfer(ec_dev, s_cmd);
 		/* Only copy data to userland if data was received. */
 		if (ret < 0)
 			goto exit;
@@ -376,10 +375,7 @@ static long cros_ec_chardev_ioctl_readmem(struct chardev_priv *priv, void __user
 	struct cros_ec_readmem s_mem = { };
 	long num;
 
-	guard(rwsem_read)(&priv->pdata->ec_dev_sem);
-	if (!priv->pdata->ec_dev)
-		return -ENODEV;
-	ec_dev = priv->pdata->ec_dev;
+	revocable_try_access_or_return(&priv->pdata->ec_rev, ec_dev);
 
 	/* Not every platform supports direct reads */
 	if (!ec_dev->cmd_readmem)
@@ -438,25 +434,29 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
 {
 	struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent);
 	struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
+	struct cros_ec_device *ec_dev = ec->ec_dev;
 	struct chardev_pdata *pdata;
 	int ret;
 
 	pdata = kzalloc_obj(*pdata);
 	if (!pdata)
 		return -ENOMEM;
+	ret = revocable_init(&pdata->ec_rev, ec_dev);
+	if (ret) {
+		kfree(pdata);
+		return ret;
+	}
 
 	platform_set_drvdata(pdev, pdata);
 	kref_init(&pdata->kref);
-	init_rwsem(&pdata->ec_dev_sem);
-	pdata->ec_dev = ec->ec_dev;
 	pdata->cmd_offset = ec->cmd_offset;
 	BLOCKING_INIT_NOTIFIER_HEAD(&pdata->subscribers);
 	pdata->relay.notifier_call = cros_ec_chardev_relay_event;
-	ret = blocking_notifier_chain_register(&pdata->ec_dev->event_notifier,
+	ret = blocking_notifier_chain_register(&ec_dev->event_notifier,
 					       &pdata->relay);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register event notifier\n");
-		goto err_put_pdata;
+		goto err_revoke_ec_rev;
 	}
 
 	pdata->misc.minor = MISC_DYNAMIC_MINOR;
@@ -472,9 +472,10 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
 
 	return 0;
 err_unregister_notifier:
-	blocking_notifier_chain_unregister(&pdata->ec_dev->event_notifier,
+	blocking_notifier_chain_unregister(&ec_dev->event_notifier,
 					   &pdata->relay);
-err_put_pdata:
+err_revoke_ec_rev:
+	revocable_revoke(&pdata->ec_rev);
 	kref_put(&pdata->kref, chardev_pdata_release);
 	return ret;
 }
@@ -482,11 +483,12 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
 static void cros_ec_chardev_remove(struct platform_device *pdev)
 {
 	struct chardev_pdata *pdata = platform_get_drvdata(pdev);
+	struct cros_ec_device *ec_dev;
 
-	blocking_notifier_chain_unregister(&pdata->ec_dev->event_notifier,
-					   &pdata->relay);
-	scoped_guard(rwsem_write, &pdata->ec_dev_sem)
-		pdata->ec_dev = NULL;
+	revocable_try_access_or_skip_scoped(&pdata->ec_rev, ec_dev)
+		blocking_notifier_chain_unregister(&ec_dev->event_notifier,
+						   &pdata->relay);
+	revocable_revoke(&pdata->ec_rev);
 	misc_deregister(&pdata->misc);
 	kref_put(&pdata->kref, chardev_pdata_release);
 }

^ permalink raw reply related

* [PATCH v2] dcache: add fs.dentry-limit sysctl with negative-first reaper
From: Horst Birthelmer @ 2026-05-16 14:52 UTC (permalink / raw)
  To: Miklos Szeredi, Jonathan Corbet, Shuah Khan, Alexander Viro,
	Christian Brauner, Jan Kara
  Cc: linux-doc, linux-kernel, linux-fsdevel, Horst Birthelmer

From: Horst Birthelmer <hbirthelmer@ddn.com>

The dcache only shrinks under memory pressure, which is rarely reached
on machines with ample RAM, so cached negative dentries can accumulate
without bound.  Give administrators a soft cap they can set,
and a background worker that prefers negative dentries when reclaiming.

Two new sysctls under /proc/sys/fs/:

  dentry-limit             -- soft cap on nr_dentry.  0 (default)
                              disables the feature; behaviour is then
                              identical to before.
  dentry-limit-interval-ms -- pacing for the worker while still over
                              the cap.  Default 1000, minimum 1.

When the cap is exceeded, a delayed_work runs in two phases:

  1. iterate_supers() draining only negative dentries from every LRU.
     Positive entries are rotated past so the walk makes progress.
     DCACHE_REFERENCED is ignored here on purpose -- an admin-imposed
     cap should evict even hot negatives before any positive entry.
  2. If still over the cap, iterate_supers() again with the same
     isolate callback the memory-pressure shrinker uses.

Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com>
---
There was a discussion at LSFMM about servers with too many cached
negative dentries.
That gave me the idea to keep the dentries in general limited
if the system administrator needs it to.

This is somewhat related to [1] where it would address the same
symptoms but in a more unobtrusive way, by just garbage collecting
the negative and then the unused cache entries.

The other effect I have seen regarding this is that FUSE
will not forget inodes (no FORGET call to the FUSE server)
even after the latest reference has been closed until much later.

In a FUSE server that mirrors the kernel cached inodes in user space
because it has to keep a lot of private data for every node
this puts an unnecessarry memory strain on that userspace entity
especially if the memory is limited for its cgroup.

[1]: https://lore.kernel.org/linux-fsdevel/20260331012925.74840-1-raven@themaw.net/
---
Changes in v2:
- get_nr_dentry() was protected by #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) 
  fix the location for the reaper code to be inside the #if bracket
- Link to v1: https://lore.kernel.org/r/20260514-limit-dentries-cache-v1-1-431b9eb0c530@ddn.com
---
 Documentation/admin-guide/sysctl/fs.rst |  28 +++++
 fs/dcache.c                             | 207 ++++++++++++++++++++++++++++++++
 2 files changed, 235 insertions(+)

diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst
index 9b7f65c3efd8..0229aea45d85 100644
--- a/Documentation/admin-guide/sysctl/fs.rst
+++ b/Documentation/admin-guide/sysctl/fs.rst
@@ -38,6 +38,34 @@ requests.  ``aio-max-nr`` allows you to change the maximum value
 ``aio-max-nr`` does not result in the
 pre-allocation or re-sizing of any kernel data structures.
 
+dentry-limit
+------------
+
+Soft cap on the total number of dentries allocated system-wide (i.e. on
+``nr_dentry`` from ``dentry-state``).  A value of ``0`` (the default)
+disables the feature and the dcache grows or shrinks only under memory
+pressure as before.
+
+When set to a non-zero value, a background worker is woken whenever
+the live dentry count exceeds the limit. The worker walks every
+superblock's LRU and prefers to evict negative dentries first; if it
+cannot get back under the limit using negative entries alone it falls
+back to the same LRU policy used by the memory-pressure shrinker.
+
+The limit is *soft*: allocations never fail because of it, and brief
+overshoots while the worker catches up are expected. Set the cap a
+comfortable margin above your steady-state working set.
+
+dentry-limit-interval-ms
+------------------------
+
+How often, in milliseconds, the ``dentry-limit`` worker re-runs while
+``nr_dentry`` is still above the cap. Defaults to ``1000`` (one
+second); the minimum accepted value is ``1``. Smaller values trim the
+cache more aggressively at the cost of more CPU spent walking LRUs;
+larger values let temporary spikes ride out before any work is done.
+Has no effect when ``dentry-limit`` is ``0``.
+
 dentry-negative
 ----------------------------
 
diff --git a/fs/dcache.c b/fs/dcache.c
index 2c61aeea41f4..196f842845ed 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -145,6 +145,26 @@ static DEFINE_PER_CPU(long, nr_dentry_negative);
 static int dentry_negative_policy;
 
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
+/*
+ * Soft cap on the total number of dentries. When non-zero and exceeded,
+ * a background worker prunes unused dentries (preferring negative ones)
+ * until we are back under the limit. Zero (the default) disables the
+ * feature entirely; the fast path in __d_alloc() only pays the cost of
+ * a READ_ONCE and a branch in that case.
+ */
+static unsigned long sysctl_dentry_limit __read_mostly;
+static unsigned int sysctl_dentry_limit_interval_ms __read_mostly = 1000;
+static unsigned long dentry_limit_last_kick;
+
+static void dentry_limit_kick(void);
+
+/* Forward decls: the helpers used by the reaper live further down. */
+static void d_lru_isolate(struct list_lru_one *lru, struct dentry *dentry);
+static void d_lru_shrink_move(struct list_lru_one *lru, struct dentry *dentry,
+			      struct list_head *list);
+static enum lru_status dentry_lru_isolate(struct list_head *item,
+			      struct list_lru_one *lru, void *arg);
+
 /* Statistics gathering. */
 static struct dentry_stat_t dentry_stat = {
 	.age_limit = 45,
@@ -171,6 +191,161 @@ static long get_nr_dentry(void)
 	return sum < 0 ? 0 : sum;
 }
 
+#define DENTRY_LIMIT_BATCH	1024UL
+
+static void dentry_limit_worker_fn(struct work_struct *work);
+static DECLARE_DELAYED_WORK(dentry_limit_work, dentry_limit_worker_fn);
+
+/*
+ * Variant of dentry_lru_isolate() that only frees negative dentries.
+ * DCACHE_REFERENCED is intentionally not honoured here: the whole point
+ * of an admin-imposed cap on negatives is that even frequently-looked-up
+ * negative entries should be evicted before any positive dentry.
+ * Positive entries are rotated to the tail so the walk continues to
+ * make progress without disturbing their LRU position.
+ */
+static enum lru_status dentry_lru_isolate_negative(struct list_head *item,
+		struct list_lru_one *lru, void *arg)
+{
+	struct list_head *freeable = arg;
+	struct dentry *dentry = container_of(item, struct dentry, d_lru);
+
+	if (!spin_trylock(&dentry->d_lock))
+		return LRU_SKIP;
+
+	/* Same handling as dentry_lru_isolate() for in-use entries. */
+	if (dentry->d_lockref.count) {
+		d_lru_isolate(lru, dentry);
+		spin_unlock(&dentry->d_lock);
+		return LRU_REMOVED;
+	}
+
+	if (!d_is_negative(dentry)) {
+		spin_unlock(&dentry->d_lock);
+		return LRU_ROTATE;
+	}
+
+	d_lru_shrink_move(lru, dentry, freeable);
+	spin_unlock(&dentry->d_lock);
+	return LRU_REMOVED;
+}
+
+struct dentry_limit_ctx {
+	long over;		/* remaining dentries to evict */
+	list_lru_walk_cb isolate;
+};
+
+static void dentry_limit_prune_sb(struct super_block *sb, void *arg)
+{
+	struct dentry_limit_ctx *ctx = arg;
+	unsigned long walked = 0;
+	unsigned long budget;
+
+	if (ctx->over <= 0)
+		return;
+
+	/*
+	 * Walk up to one full pass of this superblock's LRU, in
+	 * DENTRY_LIMIT_BATCH-sized chunks. The loop matters mainly for
+	 * phase 1: dentry_lru_isolate_negative() returns LRU_ROTATE for
+	 * positive dentries, which still counts against list_lru_walk()'s
+	 * nr_to_walk. A single batch can therefore finish having freed
+	 * nothing when positives crowd the head of the LRU, and without
+	 * the inner loop the worker would have to wait a full
+	 * dentry-limit-interval-ms before retrying never reaching the
+	 * negatives buried behind a long run of positives.
+	 *
+	 * The budget is snapshot at entry so a filesystem allocating
+	 * dentries faster than we drain them can't keep us spinning here
+	 * forever; freshly added dentries are picked up on the next
+	 * worker invocation.
+	 *
+	 * Phase 2 normally exits much sooner: its isolate callback frees
+	 * any non-referenced dentry, so ctx->over typically hits zero
+	 * inside the first batch. The worst-case over-eviction is one
+	 * batch past the cap, which is within the soft semantics of
+	 * fs.dentry-limit.
+	 */
+	budget = list_lru_count(&sb->s_dentry_lru);
+
+	while (ctx->over > 0 && walked < budget) {
+		LIST_HEAD(dispose);
+		unsigned long nr;
+		long freed;
+
+		nr = min(DENTRY_LIMIT_BATCH, budget - walked);
+		freed = list_lru_walk(&sb->s_dentry_lru, ctx->isolate,
+				      &dispose, nr);
+		shrink_dentry_list(&dispose);
+
+		ctx->over -= freed;
+		walked += nr;
+
+		cond_resched();
+	}
+}
+
+static void dentry_limit_worker_fn(struct work_struct *work)
+{
+	struct dentry_limit_ctx ctx;
+	unsigned long limit = READ_ONCE(sysctl_dentry_limit);
+	unsigned int ms;
+	long nr;
+
+	if (!limit)
+		return;
+
+	nr = get_nr_dentry();
+	if (nr <= (long)limit)
+		return;
+
+	ctx.over = nr - (long)limit;
+
+	/* Phase 1: drain negative dentries across every superblock. */
+	ctx.isolate = dentry_lru_isolate_negative;
+	iterate_supers(dentry_limit_prune_sb, &ctx);
+
+	/* Phase 2: still over? Apply the ordinary LRU policy. */
+	if (ctx.over > 0) {
+		ctx.isolate = dentry_lru_isolate;
+		iterate_supers(dentry_limit_prune_sb, &ctx);
+	}
+
+	/*
+	 * Re-arm while still above the limit. Re-read the sysctls in
+	 * case the admin raised the cap or disabled the feature during
+	 * the walk.
+	 */
+	limit = READ_ONCE(sysctl_dentry_limit);
+	if (!limit || get_nr_dentry() <= (long)limit)
+		return;
+
+	ms = READ_ONCE(sysctl_dentry_limit_interval_ms);
+	queue_delayed_work(system_unbound_wq, &dentry_limit_work,
+			   msecs_to_jiffies(ms));
+}
+
+static void dentry_limit_kick(void)
+{
+	unsigned long limit = READ_ONCE(sysctl_dentry_limit);
+	unsigned long now;
+
+	if (!limit)
+		return;
+	if (delayed_work_pending(&dentry_limit_work))
+		return;
+
+	now = jiffies;
+	if (time_before(now, READ_ONCE(dentry_limit_last_kick) + HZ / 10))
+		return;
+	WRITE_ONCE(dentry_limit_last_kick, now);
+
+	if (get_nr_dentry() <= (long)limit)
+		return;
+
+	queue_delayed_work(system_unbound_wq, &dentry_limit_work, 0);
+}
+
 static long get_nr_dentry_unused(void)
 {
 	int i;
@@ -199,6 +374,20 @@ static int proc_nr_dentry(const struct ctl_table *table, int write, void *buffer
 	return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
 }
 
+/*
+ * Writing fs.dentry-limit should give prompt feedback to admins
+ * lowering the cap, so kick the worker on every successful write.
+ */
+static int proc_dentry_limit(const struct ctl_table *table, int write,
+			     void *buffer, size_t *lenp, loff_t *ppos)
+{
+	int ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
+
+	if (write && !ret)
+		dentry_limit_kick();
+	return ret;
+}
+
 static const struct ctl_table fs_dcache_sysctls[] = {
 	{
 		.procname	= "dentry-state",
@@ -207,6 +396,21 @@ static const struct ctl_table fs_dcache_sysctls[] = {
 		.mode		= 0444,
 		.proc_handler	= proc_nr_dentry,
 	},
+	{
+		.procname	= "dentry-limit",
+		.data		= &sysctl_dentry_limit,
+		.maxlen		= sizeof(sysctl_dentry_limit),
+		.mode		= 0644,
+		.proc_handler	= proc_dentry_limit,
+	},
+	{
+		.procname	= "dentry-limit-interval-ms",
+		.data		= &sysctl_dentry_limit_interval_ms,
+		.maxlen		= sizeof(sysctl_dentry_limit_interval_ms),
+		.mode		= 0644,
+		.proc_handler	= proc_douintvec_minmax,
+		.extra1		= SYSCTL_ONE,
+	},
 	{
 		.procname	= "dentry-negative",
 		.data		= &dentry_negative_policy,
@@ -1868,6 +2072,9 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
 	}
 
 	this_cpu_inc(nr_dentry);
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
+	dentry_limit_kick();
+#endif
 
 	return dentry;
 }

---
base-commit: 6916d5703ddf9a38f1f6c2cc793381a24ee914c6
change-id: 20260513-limit-dentries-cache-63685729672b

Best regards,
-- 
Horst Birthelmer <hbirthelmer@ddn.com>


^ permalink raw reply related

* Re: [PATCH v4 1/2] dt-bindings: trivial-devices: Add Murata D1U74T PSU
From: Guenter Roeck @ 2026-05-16 15:11 UTC (permalink / raw)
  To: Abdurrahman Hussain
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet,
	Shuah Khan, linux-hwmon, devicetree, linux-kernel, linux-doc
In-Reply-To: <20260514-d1u74t-v4-1-1f1ee7b002ec@nexthop.ai>

On Thu, May 14, 2026 at 08:03:25PM -0700, Abdurrahman Hussain wrote:
> The Murata D1U74T-W series are hot-pluggable 1U AC/DC front-end
> power supplies in the Intel CRPS-185 / OCP M-CRPS form factor.
> Each variant delivers a 12 V main output plus a 12 V standby output
> from a wide AC input (90-264 Vac) or HVDC supply, and includes an
> internal variable-speed cooling fan and on-board voltage, current,
> power, fan-speed, and temperature telemetry.
> 
> The host-side digital interface is a PMBus 1.2 port on I2C.  The
> PSU's other electrical signals (status, alert, current-share) live
> on the CRPS edge connector and are consumed by the chassis
> controller rather than the host SoC, so there are no host-described
> supplies, GPIOs, clocks, or interrupts.  Add the compatible to
> trivial-devices.yaml rather than carrying a standalone binding file.
> 
> Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

Applied.

Thanks,
Guenter

^ permalink raw reply

* Re: [PATCH v4 2/2] hwmon: (pmbus/d1u74t) Add Murata D1U74T PSU driver
From: Guenter Roeck @ 2026-05-16 15:13 UTC (permalink / raw)
  To: Abdurrahman Hussain
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet,
	Shuah Khan, linux-hwmon, devicetree, linux-kernel, linux-doc,
	kernel test robot
In-Reply-To: <20260514-d1u74t-v4-2-1f1ee7b002ec@nexthop.ai>

On Thu, May 14, 2026 at 08:03:26PM -0700, Abdurrahman Hussain wrote:
> Add PMBUS driver for Murata D1U74T power supplies.
> 
> Reported-by: kernel test robot <lkp@intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202605122253.zInzmUeX-lkp@intel.com/
> Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>

Applied, after dropping the above Reported-by: and Closes: tags.
Those are inappropriate for new drivers.

I also added the missing include files.

Guenter

> ---
>  Documentation/hwmon/d1u74t.rst | 81 +++++++++++++++++++++++++++++++++++++++
>  Documentation/hwmon/index.rst  |  1 +
>  MAINTAINERS                    |  7 ++++
>  drivers/hwmon/pmbus/Kconfig    |  9 +++++
>  drivers/hwmon/pmbus/Makefile   |  1 +
>  drivers/hwmon/pmbus/d1u74t.c   | 86 ++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 185 insertions(+)
> 
> diff --git a/Documentation/hwmon/d1u74t.rst b/Documentation/hwmon/d1u74t.rst
> new file mode 100644
> index 000000000000..3a9eedbda483
> --- /dev/null
> +++ b/Documentation/hwmon/d1u74t.rst
> @@ -0,0 +1,81 @@
> +.. SPDX-License-Identifier: GPL-2.0-or-later
> +
> +Kernel driver d1u74t
> +====================
> +
> +Supported chips:
> +
> +  * Murata D1U74T
> +
> +    Prefix: 'd1u74t'
> +
> +    Addresses scanned: -
> +
> +    Datasheet: Publicly available at the Murata website
> +
> +Authors:
> +    Abdurrahman Hussain <abdurrahman@nexthop.ai>
> +
> +
> +Description
> +-----------
> +
> +This driver implements support for Murata D1U74T Power Supply with
> +PMBus support.
> +
> +The driver is a client driver to the core PMBus driver.
> +Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
> +
> +
> +Usage Notes
> +-----------
> +
> +This driver does not auto-detect devices. You will have to instantiate the
> +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
> +details.
> +
> +
> +Sysfs entries
> +-------------
> +
> +======================= ======================================================
> +curr1_label		"iin"
> +curr1_input		Measured input current
> +curr1_alarm		Input current alarm
> +curr1_rated_max		Maximum rated input current
> +
> +curr2_label		"iout1"
> +curr2_input		Measured output current
> +curr2_max		Maximum output current
> +curr2_max_alarm		Output current high alarm
> +curr2_crit		Critical high output current
> +curr2_crit_alarm	Output current critical high alarm
> +curr2_rated_max		Maximum rated output current
> +
> +in1_label		"vin"
> +in1_input		Measured input voltage
> +in1_alarm		Input voltage alarm
> +in1_rated_min		Minimum rated input voltage
> +in1_rated_max		Maximum rated input voltage
> +
> +in2_label		"vout1"
> +in2_input		Measured output voltage
> +in2_alarm		Output voltage alarm
> +in2_rated_min		Minimum rated output voltage
> +in2_rated_max		Maximum rated output voltage
> +
> +power1_label		"pin"
> +power1_input		Measured input power
> +power1_alarm		Input power alarm
> +power1_rated_max	Maximum rated input power
> +
> +temp[1-3]_input		Measured temperature
> +temp[1-3]_max		Maximum temperature
> +temp[1-3]_max_alarm	Maximum temperature alarm
> +temp[1-3]_rated_max	Maximum rated temperature
> +
> +fan1_alarm		Fan 1 warning
> +fan1_fault		Fan 1 fault
> +fan1_input		Fan 1 speed in RPM
> +fan1_target		Fan 1 target
> +======================= ======================================================
> diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
> index 8b655e5d6b68..97b1ef65b1c1 100644
> --- a/Documentation/hwmon/index.rst
> +++ b/Documentation/hwmon/index.rst
> @@ -60,6 +60,7 @@ Hardware Monitoring Kernel Drivers
>     corsair-psu
>     cros_ec_hwmon
>     crps
> +   d1u74t
>     da9052
>     da9055
>     dell-smm-hwmon
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b2040011a386..3106cf725dfc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -18249,6 +18249,13 @@ F:	drivers/mux/
>  F:	include/dt-bindings/mux/
>  F:	include/linux/mux/
>  
> +MURATA D1U74T PSU DRIVER
> +M:	Abdurrahman Hussain <abdurrahman@nexthop.ai>
> +L:	linux-hwmon@vger.kernel.org
> +S:	Maintained
> +F:	Documentation/hwmon/d1u74t.rst
> +F:	drivers/hwmon/pmbus/d1u74t.c
> +
>  MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
>  M:	Bin Liu <b-liu@ti.com>
>  L:	linux-usb@vger.kernel.org
> diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
> index 8f4bff375ecb..ee93b22d2887 100644
> --- a/drivers/hwmon/pmbus/Kconfig
> +++ b/drivers/hwmon/pmbus/Kconfig
> @@ -113,6 +113,15 @@ config SENSORS_CRPS
>  	  This driver can also be built as a module. If so, the module will
>  	  be called crps.
>  
> +config SENSORS_D1U74T
> +	tristate "Murata D1U74T Power Supply"
> +	help
> +	  If you say yes here you get hardware monitoring support for the Murata
> +	  D1U74T Power Supply.
> +
> +	  This driver can also be built as a module. If so, the module will
> +	  be called d1u74t.
> +
>  config SENSORS_DELTA_AHE50DC_FAN
>  	tristate "Delta AHE-50DC fan control module"
>  	help
> diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
> index 7129b62bc00f..8cf7d3075371 100644
> --- a/drivers/hwmon/pmbus/Makefile
> +++ b/drivers/hwmon/pmbus/Makefile
> @@ -76,3 +76,4 @@ obj-$(CONFIG_SENSORS_XDPE1A2G7B)	+= xdpe1a2g7b.o
>  obj-$(CONFIG_SENSORS_ZL6100)	+= zl6100.o
>  obj-$(CONFIG_SENSORS_PIM4328)	+= pim4328.o
>  obj-$(CONFIG_SENSORS_CRPS)	+= crps.o
> +obj-$(CONFIG_SENSORS_D1U74T)	+= d1u74t.o
> diff --git a/drivers/hwmon/pmbus/d1u74t.c b/drivers/hwmon/pmbus/d1u74t.c
> new file mode 100644
> index 000000000000..286ba492e336
> --- /dev/null
> +++ b/drivers/hwmon/pmbus/d1u74t.c
> @@ -0,0 +1,86 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright 2026 Nexthop Systems.
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/of.h>
> +#include <linux/pmbus.h>
> +
> +#include "pmbus.h"
> +
> +static const struct i2c_device_id d1u74t_id[] = {
> +	{ "d1u74t" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(i2c, d1u74t_id);
> +
> +static struct pmbus_driver_info d1u74t_info = {
> +	.pages = 1,
> +	/* PSU uses default linear data format. */
> +	.func[0] = PMBUS_HAVE_PIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
> +		   PMBUS_HAVE_IIN | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT |
> +		   PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_TEMP |
> +		   PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
> +		   PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_FAN12 |
> +		   PMBUS_HAVE_STATUS_FAN12,
> +};
> +
> +static int d1u74t_probe(struct i2c_client *client)
> +{
> +	char buf[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
> +	struct device *dev = &client->dev;
> +	int rc;
> +
> +	rc = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
> +	if (rc < 0)
> +		return dev_err_probe(dev, rc, "Failed to read PMBUS_MFR_ID\n");
> +
> +	if (rc != 9 || strncmp(buf, "Murata-PS", 9)) {
> +		buf[rc] = '\0';
> +		return dev_err_probe(dev, -ENODEV,
> +				     "Unsupported Manufacturer ID '%s'\n",
> +				     buf);
> +	}
> +
> +	rc = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
> +	if (rc < 0)
> +		return dev_err_probe(dev, rc,
> +				     "Failed to read PMBUS_MFR_MODEL\n");
> +
> +	if (rc < 8 || strncmp(buf, "D1U74T-W", 8)) {
> +		buf[rc] = '\0';
> +		return dev_err_probe(dev, -ENODEV, "Model '%s' not supported\n",
> +				     buf);
> +	}
> +
> +	rc = pmbus_do_probe(client, &d1u74t_info);
> +	if (rc)
> +		return dev_err_probe(dev, rc, "Failed to probe\n");
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id d1u74t_of_match[] = {
> +	{
> +		.compatible = "murata,d1u74t",
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, d1u74t_of_match);
> +
> +static struct i2c_driver d1u74t_driver = {
> +	.driver = {
> +		.name = "d1u74t",
> +		.of_match_table = d1u74t_of_match,
> +	},
> +	.probe = d1u74t_probe,
> +	.id_table = d1u74t_id,
> +};
> +
> +module_i2c_driver(d1u74t_driver);
> +
> +MODULE_AUTHOR("Abdurrahman Hussain");
> +MODULE_DESCRIPTION("PMBus driver for Murata D1U74T-W power supplies");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("PMBUS");

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox