diff mbox series

[09/15] dma-buf/sync_file: add user fence support

Message ID 20220502163722.3957-10-christian.koenig@amd.com
State New
Headers show
Series [01/15] dma-buf: rename DMA_FENCE_FLAG_USER_BITS to _DEVICE | expand

Commit Message

Christian König May 2, 2022, 4:37 p.m. UTC
Keep user fences separate from normal fences.

Signed-off-by: Christian König <christian.koenig@amd.com>
---
 drivers/dma-buf/sync_file.c | 82 +++++++++++++++++++++++++++++++++----
 include/linux/sync_file.h   |  4 +-
 2 files changed, 76 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
index fe149d7e3ce2..630472d79dc1 100644
--- a/drivers/dma-buf/sync_file.c
+++ b/drivers/dma-buf/sync_file.c
@@ -70,7 +70,13 @@  struct sync_file *sync_file_create(struct dma_fence *fence)
 	if (!sync_file)
 		return NULL;
 
-	sync_file->fence = dma_fence_get(fence);
+	if (test_bit(DMA_FENCE_FLAG_USER, &fence->flags)) {
+		sync_file->fence = dma_fence_get_stub(false);
+		sync_file->user_fence = dma_fence_get(fence);
+	} else {
+		sync_file->fence = dma_fence_get(fence);
+		sync_file->user_fence = dma_fence_get_stub(true);
+	}
 
 	return sync_file;
 }
@@ -116,6 +122,28 @@  struct dma_fence *sync_file_get_fence(int fd)
 }
 EXPORT_SYMBOL(sync_file_get_fence);
 
+/**
+ * sync_file_get_user_fence - get user fence related to the sync_file fd
+ * @fd:		sync_file fd to get the fence from
+ *
+ * Ensures @fd references a valid sync_file and returns an user fence reference
+ * which represents all fence in the sync_file. On error NULL is returned.
+ */
+struct dma_fence *sync_file_get_user_fence(int fd)
+{
+	struct sync_file *sync_file;
+	struct dma_fence *fence;
+
+	sync_file = sync_file_fdget(fd);
+	if (!sync_file)
+		return NULL;
+
+	fence = dma_fence_merge(sync_file->fence, sync_file->user_fence);
+	fput(sync_file->file);
+	return fence;
+}
+EXPORT_SYMBOL(sync_file_get_user_fence);
+
 /**
  * sync_file_get_name - get the name of the sync_file
  * @sync_file:		sync_file to get the fence from
@@ -136,6 +164,9 @@  char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len)
 	} else {
 		struct dma_fence *fence = sync_file->fence;
 
+		if (dma_fence_is_signaled(fence))
+			fence = sync_file->user_fence;
+
 		snprintf(buf, len, "%s-%s%llu-%lld",
 			 fence->ops->get_driver_name(fence),
 			 fence->ops->get_timeline_name(fence),
@@ -159,21 +190,32 @@  char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len)
 static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
 					 struct sync_file *b)
 {
+	struct dma_fence *fence, *user_fence;
 	struct sync_file *sync_file;
-	struct dma_fence *fence;
 
 	sync_file = sync_file_alloc();
 	if (!sync_file)
 		return NULL;
 
 	fence = dma_fence_merge(a->fence, b->fence);
-	if (!fence) {
-		fput(sync_file->file);
-		return NULL;
-	}
+	if (!fence)
+		goto error_fput;
+
+	user_fence = dma_fence_merge(a->user_fence, b->user_fence);
+	if (!user_fence)
+		goto error_put_fence;
+
 	sync_file->fence = fence;
+	sync_file->user_fence = user_fence;
 	strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
 	return sync_file;
+
+error_put_fence:
+	dma_fence_put(fence);
+
+error_fput:
+	fput(sync_file->file);
+	return NULL;
 }
 
 static int sync_file_release(struct inode *inode, struct file *file)
@@ -183,6 +225,7 @@  static int sync_file_release(struct inode *inode, struct file *file)
 	if (test_bit(POLL_ENABLED, &sync_file->flags))
 		dma_fence_remove_callback(sync_file->fence, &sync_file->cb);
 	dma_fence_put(sync_file->fence);
+	dma_fence_put(sync_file->user_fence);
 	kfree(sync_file);
 
 	return 0;
@@ -191,17 +234,25 @@  static int sync_file_release(struct inode *inode, struct file *file)
 static __poll_t sync_file_poll(struct file *file, poll_table *wait)
 {
 	struct sync_file *sync_file = file->private_data;
+	int ret;
 
 	poll_wait(file, &sync_file->wq, wait);
 
 	if (list_empty(&sync_file->cb.node) &&
 	    !test_and_set_bit(POLL_ENABLED, &sync_file->flags)) {
-		if (dma_fence_add_callback(sync_file->fence, &sync_file->cb,
-					   fence_check_cb_func) < 0)
+		ret = dma_fence_add_callback(sync_file->fence, &sync_file->cb,
+					     fence_check_cb_func);
+		if (ret) {
+			ret = dma_fence_add_callback(sync_file->user_fence,
+						     &sync_file->cb,
+						     fence_check_cb_func);
+		}
+		if (ret)
 			wake_up_all(&sync_file->wq);
 	}
 
-	return dma_fence_is_signaled(sync_file->fence) ? EPOLLIN : 0;
+	return (dma_fence_is_signaled(sync_file->fence) &&
+		dma_fence_is_signaled(sync_file->user_fence)) ? EPOLLIN : 0;
 }
 
 static long sync_file_ioctl_merge(struct sync_file *sync_file,
@@ -299,6 +350,8 @@  static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
 	num_fences = 0;
 	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
 		++num_fences;
+	dma_fence_unwrap_for_each(fence, &iter, sync_file->user_fence)
+		++num_fences;
 
 	/*
 	 * Passing num_fences = 0 means that userspace doesn't want to
@@ -307,7 +360,12 @@  static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
 	 * info->num_fences.
 	 */
 	if (!info.num_fences) {
+		int status;
+
 		info.status = dma_fence_get_status(sync_file->fence);
+		status = dma_fence_get_status(sync_file->user_fence);
+		if (!info.status)
+			info.status = status;
 		goto no_fences;
 	} else {
 		info.status = 1;
@@ -328,6 +386,12 @@  static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
 		status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
 		info.status = info.status <= 0 ? info.status : status;
 	}
+	dma_fence_unwrap_for_each(fence, &iter, sync_file->user_fence) {
+		int status;
+
+		status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
+		info.status = info.status <= 0 ? info.status : status;
+	}
 
 	if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info,
 			 size)) {
diff --git a/include/linux/sync_file.h b/include/linux/sync_file.h
index 790ca021203a..14aff1a4ee75 100644
--- a/include/linux/sync_file.h
+++ b/include/linux/sync_file.h
@@ -50,13 +50,15 @@  struct sync_file {
 	unsigned long		flags;
 
 	struct dma_fence	*fence;
-	struct dma_fence_cb cb;
+	struct dma_fence	*user_fence;
+	struct dma_fence_cb	cb;
 };
 
 #define POLL_ENABLED 0
 
 struct sync_file *sync_file_create(struct dma_fence *fence);
 struct dma_fence *sync_file_get_fence(int fd);
+struct dma_fence *sync_file_get_user_fence(int fd);
 char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len);
 
 #endif /* _LINUX_SYNC_H */