From: Dave Airlie <airlied@xxxxxxxxxx> This allows us to create sync files with different semantics, and clearly define the interoperation between them it also provides flags to allow for tweaks on those semantics. This provides a validation interface for drivers that accept types from userspace so they can return EINVAL instead of ENOMEM. This provides an ioctl for userspace to retrieve the type/flags of an object it may recieve from somewhere else. Reviewed-by: Christian König <christian.koenig at amd.com> Signed-off-by: Dave Airlie <airlied at redhat.com> --- Documentation/driver-api/dma-buf.rst | 6 ++++ drivers/dma-buf/sw_sync.c | 2 +- drivers/dma-buf/sync_file.c | 64 +++++++++++++++++++++++++++++++++--- drivers/gpu/drm/drm_atomic.c | 2 +- include/linux/sync_file.h | 9 ++++- include/uapi/linux/sync_file.h | 27 +++++++++++++++ 6 files changed, 103 insertions(+), 7 deletions(-) diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst index 31671b4..bf2f7d5 100644 --- a/Documentation/driver-api/dma-buf.rst +++ b/Documentation/driver-api/dma-buf.rst @@ -163,3 +163,9 @@ DMA Fence uABI/Sync File .. kernel-doc:: include/linux/sync_file.h :internal: + +Sync File IOCTL Definitions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: include/uapi/linux/sync_file.h + :internal: diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 69c5ff3..1c47de6 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -315,7 +315,7 @@ static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, goto err; } - sync_file = sync_file_create(&pt->base); + sync_file = sync_file_create(&pt->base, SYNC_FILE_TYPE_FENCE, 0); dma_fence_put(&pt->base); if (!sync_file) { err = -ENOMEM; diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 2321035..07392af 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -28,9 +28,32 @@ static const struct file_operations sync_file_fops; -static struct sync_file *sync_file_alloc(void) +/** + * sync_file_validate_type_flags - validate type/flags for support + * @type: type of sync file object + * @flags: flags to sync object. + * + * Validates the flags are correct so userspace can get a more + * detailed error type. + */ +int sync_file_validate_type_flags(uint32_t type, uint32_t flags) +{ + if (flags) + return -EINVAL; + if (type != SYNC_FILE_TYPE_FENCE) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(sync_file_validate_type_flags); + +static struct sync_file *sync_file_alloc(uint32_t type, uint32_t flags) { struct sync_file *sync_file; + int ret; + + ret = sync_file_validate_type_flags(type, flags); + if (ret) + return NULL; sync_file = kzalloc(sizeof(*sync_file), GFP_KERNEL); if (!sync_file) @@ -47,6 +70,8 @@ static struct sync_file *sync_file_alloc(void) INIT_LIST_HEAD(&sync_file->cb.node); + sync_file->type = type; + sync_file->flags = flags; return sync_file; err: @@ -66,17 +91,21 @@ static void fence_check_cb_func(struct dma_fence *f, struct dma_fence_cb *cb) /** * sync_file_create() - creates a sync file * @fence: fence to add to the sync_fence + * @type: type of sync file to create + * @flags: flags to create sync file with. * * Creates a sync_file containg @fence. This function acquires and additional * reference of @fence for the newly-created &sync_file, if it succeeds. The * sync_file can be released with fput(sync_file->file). Returns the * sync_file or NULL in case of error. */ -struct sync_file *sync_file_create(struct dma_fence *fence) +struct sync_file *sync_file_create(struct dma_fence *fence, + uint32_t type, + uint32_t flags) { struct sync_file *sync_file; - sync_file = sync_file_alloc(); + sync_file = sync_file_alloc(type, flags); if (!sync_file) return NULL; @@ -200,7 +229,10 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, struct dma_fence **fences, **nfences, **a_fences, **b_fences; int i, i_a, i_b, num_fences, a_num_fences, b_num_fences; - sync_file = sync_file_alloc(); + if (a->type != b->type) + return NULL; + + sync_file = sync_file_alloc(a->type, a->flags); if (!sync_file) return NULL; @@ -437,6 +469,27 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file, return ret; } +static long sync_file_ioctl_type(struct sync_file *sync_file, + unsigned long arg) +{ + struct sync_file_type type; + int ret; + if (copy_from_user(&type, (void __user *)arg, sizeof(type))) + return -EFAULT; + + if (type.flags || type.type) + return -EINVAL; + + type.type = sync_file->type; + type.flags = sync_file->flags; + + if (copy_to_user((void __user *)arg, &type, sizeof(type))) + ret = -EFAULT; + else + ret = 0; + return ret; +} + static long sync_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -449,6 +502,9 @@ static long sync_file_ioctl(struct file *file, unsigned int cmd, case SYNC_IOC_FILE_INFO: return sync_file_ioctl_fence_info(sync_file, arg); + case SYNC_IOC_TYPE: + return sync_file_ioctl_type(sync_file, arg); + default: return -ENOTTY; } diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index a567310..bb5a740 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1917,7 +1917,7 @@ static int setup_out_fence(struct drm_out_fence_state *fence_state, if (put_user(fence_state->fd, fence_state->out_fence_ptr)) return -EFAULT; - fence_state->sync_file = sync_file_create(fence); + fence_state->sync_file = sync_file_create(fence, SYNC_FILE_TYPE_FENCE, 0); if (!fence_state->sync_file) return -ENOMEM; diff --git a/include/linux/sync_file.h b/include/linux/sync_file.h index 3e3ab84..ede4182 100644 --- a/include/linux/sync_file.h +++ b/include/linux/sync_file.h @@ -20,6 +20,8 @@ #include <linux/spinlock.h> #include <linux/dma-fence.h> #include <linux/dma-fence-array.h> +#include <uapi/linux/sync_file.h> + /** * struct sync_file - sync file to export to the userspace @@ -30,6 +32,8 @@ * @wq: wait queue for fence signaling * @fence: fence with the fences in the sync_file * @cb: fence callback information + * @type: sync file type + * @flags: flags used to create sync file */ struct sync_file { struct file *file; @@ -43,11 +47,14 @@ struct sync_file { struct dma_fence *fence; struct dma_fence_cb cb; + uint32_t type; + uint32_t flags; }; #define POLL_ENABLED DMA_FENCE_FLAG_USER_BITS -struct sync_file *sync_file_create(struct dma_fence *fence); +int sync_file_validate_type_flags(uint32_t type, uint32_t flags); +struct sync_file *sync_file_create(struct dma_fence *fence, uint32_t type, uint32_t flags); struct dma_fence *sync_file_get_fence(int fd); #endif /* _LINUX_SYNC_H */ diff --git a/include/uapi/linux/sync_file.h b/include/uapi/linux/sync_file.h index 5b287d6..f439cda 100644 --- a/include/uapi/linux/sync_file.h +++ b/include/uapi/linux/sync_file.h @@ -69,6 +69,26 @@ struct sync_file_info { #define SYNC_IOC_MAGIC '>' /** + * DOC: SYNC_FILE_TYPE_FENCE - fence sync file object + * + * This sync file is a wrapper around a dma fence or a dma fence array. + * It can be merged with another fence sync file object to create a new + * merged object. + * The fence backing this object cannot be replaced. + * This is useful for shared fences. + */ +#define SYNC_FILE_TYPE_FENCE 0 + +/** + * struct sync_file_type - data returned from sync file type ioctl + * @type: sync_file type + * @flags: sync_file creation flags + */ +struct sync_file_type { + __u32 type; + __u32 flags; +}; +/** * Opcodes 0, 1 and 2 were burned during a API change to avoid users of the * old API to get weird errors when trying to handling sync_files. The API * change happened during the de-stage of the Sync Framework when there was @@ -94,4 +114,11 @@ struct sync_file_info { */ #define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info) +/** + * DOC: SYNC_IOC_TYPE - get creation type and flags of sync_file. + * + * Takes a struct sync_file_type. Returns the created values of type and flags. + */ +#define SYNC_IOC_TYPE _IOWR(SYNC_IOC_MAGIC, 5, struct sync_file_type) + #endif /* _UAPI_LINUX_SYNC_H */ -- 2.9.3