WIP
diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index f5061de..74c131b 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c
@@ -49,6 +49,8 @@ init_waitqueue_head(&sync_file->wq); INIT_LIST_HEAD(&sync_file->cb.node); + INIT_LIST_HEAD(&sync_file->chain); + INIT_LIST_HEAD(&sync_file->chain_cb.node); return sync_file; @@ -66,6 +68,20 @@ wake_up_all(&sync_file->wq); } +static void fence_chain_cb_func(struct fence *f, struct fence_cb *cb) +{ + struct sync_file *sync_file, *sync_chain; + + sync_file = container_of(cb, struct sync_file, chain_cb); + + list_for_each_entry(sync_chain, &sync_file->chain, chain) { + pr_err("sync_chain %p\n", sync_chain); + fence_signal(sync_chain->fence); + fence_put(sync_chain->fence); + } + //XXX still not cleaning the list up +} + /** * sync_file_create() - creates a sync file * @fence: fence to add to the sync_fence @@ -446,6 +462,59 @@ return ret; } +static long sync_file_ioctl_chain_fence(struct sync_file *sync_file, + unsigned long arg) +{ + struct sync_chain_data chain; + struct sync_file *sync_chain; + int *fences; + int i; + + if (copy_from_user(&chain, (void __user *)arg, sizeof(chain))) + return -EFAULT; + + if (!chain.fences_count) + return -EINVAL; + + if (chain.flags) + return -EINVAL; + + fences = kcalloc(chain.fences_count, sizeof(*fences), GFP_KERNEL); + if (!fences) + return -ENOMEM; + + if (copy_from_user(fences, u64_to_user_ptr(chain.fences), + sizeof(int) * chain.fences_count)) { + kfree(fences); + return -EFAULT; + } + + for (i = 0 ; i < chain.fences_count ; i++) { + sync_chain = sync_file_fdget(fences[i]); + if (!sync_chain) + goto out; + + if (fence_is_signaled(sync_chain->fence)) { + fence_signal(sync_chain->fence); + fence_put(sync_chain->fence); + } else { + if (list_empty(&sync_file->chain)) + fence_add_callback(sync_file->fence, + &sync_file->chain_cb, + fence_chain_cb_func); + list_add(&sync_chain->chain, &sync_file->chain); + //FIXME: check fence_add_callback return + } + } + + return 0; + +out: + //XXx put fences + kfree(fences); + return -EINVAL; +} + static long sync_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -458,6 +527,8 @@ case SYNC_IOC_FILE_INFO: return sync_file_ioctl_fence_info(sync_file, arg); + case SYNC_IOC_CHAIN: + return sync_file_ioctl_chain_fence(sync_file, arg); default: return -ENOTTY; }
diff --git a/include/linux/sync_file.h b/include/linux/sync_file.h index aa17ccf..1605b0e 100644 --- a/include/linux/sync_file.h +++ b/include/linux/sync_file.h
@@ -43,6 +43,8 @@ struct fence *fence; struct fence_cb cb; + struct list_head chain; + struct fence_cb chain_cb; }; #define POLL_ENABLED FENCE_FLAG_USER_BITS
diff --git a/include/uapi/linux/sync_file.h b/include/uapi/linux/sync_file.h index ee3971a..257d698 100644 --- a/include/uapi/linux/sync_file.h +++ b/include/uapi/linux/sync_file.h
@@ -15,6 +15,16 @@ #include <linux/types.h> /** + * struct sync_chain_data - data passed to merge ioctl + * @flags: chain_data flags + */ +struct sync_chain_data { + __u32 fences_count; + __u32 flags; + __u64 fences; +}; + +/** * struct sync_merge_data - data passed to merge ioctl * @name: name of new fence * @fd2: file descriptor of second fence @@ -105,7 +115,14 @@ #define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info) /** + * DOC: SYNC_IOC_CHAIN_FENCE - chain fences to a fence + * + */ +#define SYNC_IOC_CHAIN _IOWR(SYNC_IOC_MAGIC, 5, struct sync_chain_data) + +/** * DOC: SYNC_IOC_CREATE_FENCE - merge two fences + * XXX: this will become a syscall * */ #define SYNC_IOC_CREATE_FENCE _IOWR(SYNC_IOC_MAGIC, 5, struct sync_empty_fence)