@@ -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)) {
@@ -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 */
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(-)