Keep user fences separate from normal fences.

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

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 */
-- 
2.25.1

Reply via email to