0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/dma-fence-unwrap.h>
0009 #include <linux/export.h>
0010 #include <linux/file.h>
0011 #include <linux/fs.h>
0012 #include <linux/kernel.h>
0013 #include <linux/poll.h>
0014 #include <linux/sched.h>
0015 #include <linux/slab.h>
0016 #include <linux/uaccess.h>
0017 #include <linux/anon_inodes.h>
0018 #include <linux/sync_file.h>
0019 #include <uapi/linux/sync_file.h>
0020
0021 static const struct file_operations sync_file_fops;
0022
0023 static struct sync_file *sync_file_alloc(void)
0024 {
0025 struct sync_file *sync_file;
0026
0027 sync_file = kzalloc(sizeof(*sync_file), GFP_KERNEL);
0028 if (!sync_file)
0029 return NULL;
0030
0031 sync_file->file = anon_inode_getfile("sync_file", &sync_file_fops,
0032 sync_file, 0);
0033 if (IS_ERR(sync_file->file))
0034 goto err;
0035
0036 init_waitqueue_head(&sync_file->wq);
0037
0038 INIT_LIST_HEAD(&sync_file->cb.node);
0039
0040 return sync_file;
0041
0042 err:
0043 kfree(sync_file);
0044 return NULL;
0045 }
0046
0047 static void fence_check_cb_func(struct dma_fence *f, struct dma_fence_cb *cb)
0048 {
0049 struct sync_file *sync_file;
0050
0051 sync_file = container_of(cb, struct sync_file, cb);
0052
0053 wake_up_all(&sync_file->wq);
0054 }
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065 struct sync_file *sync_file_create(struct dma_fence *fence)
0066 {
0067 struct sync_file *sync_file;
0068
0069 sync_file = sync_file_alloc();
0070 if (!sync_file)
0071 return NULL;
0072
0073 sync_file->fence = dma_fence_get(fence);
0074
0075 return sync_file;
0076 }
0077 EXPORT_SYMBOL(sync_file_create);
0078
0079 static struct sync_file *sync_file_fdget(int fd)
0080 {
0081 struct file *file = fget(fd);
0082
0083 if (!file)
0084 return NULL;
0085
0086 if (file->f_op != &sync_file_fops)
0087 goto err;
0088
0089 return file->private_data;
0090
0091 err:
0092 fput(file);
0093 return NULL;
0094 }
0095
0096
0097
0098
0099
0100
0101
0102
0103 struct dma_fence *sync_file_get_fence(int fd)
0104 {
0105 struct sync_file *sync_file;
0106 struct dma_fence *fence;
0107
0108 sync_file = sync_file_fdget(fd);
0109 if (!sync_file)
0110 return NULL;
0111
0112 fence = dma_fence_get(sync_file->fence);
0113 fput(sync_file->file);
0114
0115 return fence;
0116 }
0117 EXPORT_SYMBOL(sync_file_get_fence);
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132 char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len)
0133 {
0134 if (sync_file->user_name[0]) {
0135 strlcpy(buf, sync_file->user_name, len);
0136 } else {
0137 struct dma_fence *fence = sync_file->fence;
0138
0139 snprintf(buf, len, "%s-%s%llu-%lld",
0140 fence->ops->get_driver_name(fence),
0141 fence->ops->get_timeline_name(fence),
0142 fence->context,
0143 fence->seqno);
0144 }
0145
0146 return buf;
0147 }
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
0160 struct sync_file *b)
0161 {
0162 struct sync_file *sync_file;
0163 struct dma_fence *fence;
0164
0165 sync_file = sync_file_alloc();
0166 if (!sync_file)
0167 return NULL;
0168
0169 fence = dma_fence_unwrap_merge(a->fence, b->fence);
0170 if (!fence) {
0171 fput(sync_file->file);
0172 return NULL;
0173 }
0174 sync_file->fence = fence;
0175 strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
0176 return sync_file;
0177 }
0178
0179 static int sync_file_release(struct inode *inode, struct file *file)
0180 {
0181 struct sync_file *sync_file = file->private_data;
0182
0183 if (test_bit(POLL_ENABLED, &sync_file->flags))
0184 dma_fence_remove_callback(sync_file->fence, &sync_file->cb);
0185 dma_fence_put(sync_file->fence);
0186 kfree(sync_file);
0187
0188 return 0;
0189 }
0190
0191 static __poll_t sync_file_poll(struct file *file, poll_table *wait)
0192 {
0193 struct sync_file *sync_file = file->private_data;
0194
0195 poll_wait(file, &sync_file->wq, wait);
0196
0197 if (list_empty(&sync_file->cb.node) &&
0198 !test_and_set_bit(POLL_ENABLED, &sync_file->flags)) {
0199 if (dma_fence_add_callback(sync_file->fence, &sync_file->cb,
0200 fence_check_cb_func) < 0)
0201 wake_up_all(&sync_file->wq);
0202 }
0203
0204 return dma_fence_is_signaled(sync_file->fence) ? EPOLLIN : 0;
0205 }
0206
0207 static long sync_file_ioctl_merge(struct sync_file *sync_file,
0208 unsigned long arg)
0209 {
0210 int fd = get_unused_fd_flags(O_CLOEXEC);
0211 int err;
0212 struct sync_file *fence2, *fence3;
0213 struct sync_merge_data data;
0214
0215 if (fd < 0)
0216 return fd;
0217
0218 if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
0219 err = -EFAULT;
0220 goto err_put_fd;
0221 }
0222
0223 if (data.flags || data.pad) {
0224 err = -EINVAL;
0225 goto err_put_fd;
0226 }
0227
0228 fence2 = sync_file_fdget(data.fd2);
0229 if (!fence2) {
0230 err = -ENOENT;
0231 goto err_put_fd;
0232 }
0233
0234 data.name[sizeof(data.name) - 1] = '\0';
0235 fence3 = sync_file_merge(data.name, sync_file, fence2);
0236 if (!fence3) {
0237 err = -ENOMEM;
0238 goto err_put_fence2;
0239 }
0240
0241 data.fence = fd;
0242 if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
0243 err = -EFAULT;
0244 goto err_put_fence3;
0245 }
0246
0247 fd_install(fd, fence3->file);
0248 fput(fence2->file);
0249 return 0;
0250
0251 err_put_fence3:
0252 fput(fence3->file);
0253
0254 err_put_fence2:
0255 fput(fence2->file);
0256
0257 err_put_fd:
0258 put_unused_fd(fd);
0259 return err;
0260 }
0261
0262 static int sync_fill_fence_info(struct dma_fence *fence,
0263 struct sync_fence_info *info)
0264 {
0265 strlcpy(info->obj_name, fence->ops->get_timeline_name(fence),
0266 sizeof(info->obj_name));
0267 strlcpy(info->driver_name, fence->ops->get_driver_name(fence),
0268 sizeof(info->driver_name));
0269
0270 info->status = dma_fence_get_status(fence);
0271 while (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) &&
0272 !test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
0273 cpu_relax();
0274 info->timestamp_ns =
0275 test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags) ?
0276 ktime_to_ns(fence->timestamp) :
0277 ktime_set(0, 0);
0278
0279 return info->status;
0280 }
0281
0282 static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
0283 unsigned long arg)
0284 {
0285 struct sync_fence_info *fence_info = NULL;
0286 struct dma_fence_unwrap iter;
0287 struct sync_file_info info;
0288 unsigned int num_fences;
0289 struct dma_fence *fence;
0290 int ret;
0291 __u32 size;
0292
0293 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
0294 return -EFAULT;
0295
0296 if (info.flags || info.pad)
0297 return -EINVAL;
0298
0299 num_fences = 0;
0300 dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
0301 ++num_fences;
0302
0303
0304
0305
0306
0307
0308
0309 if (!info.num_fences) {
0310 info.status = dma_fence_get_status(sync_file->fence);
0311 goto no_fences;
0312 } else {
0313 info.status = 1;
0314 }
0315
0316 if (info.num_fences < num_fences)
0317 return -EINVAL;
0318
0319 size = num_fences * sizeof(*fence_info);
0320 fence_info = kzalloc(size, GFP_KERNEL);
0321 if (!fence_info)
0322 return -ENOMEM;
0323
0324 num_fences = 0;
0325 dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
0326 int status;
0327
0328 status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
0329 info.status = info.status <= 0 ? info.status : status;
0330 }
0331
0332 if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info,
0333 size)) {
0334 ret = -EFAULT;
0335 goto out;
0336 }
0337
0338 no_fences:
0339 sync_file_get_name(sync_file, info.name, sizeof(info.name));
0340 info.num_fences = num_fences;
0341
0342 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
0343 ret = -EFAULT;
0344 else
0345 ret = 0;
0346
0347 out:
0348 kfree(fence_info);
0349
0350 return ret;
0351 }
0352
0353 static long sync_file_ioctl(struct file *file, unsigned int cmd,
0354 unsigned long arg)
0355 {
0356 struct sync_file *sync_file = file->private_data;
0357
0358 switch (cmd) {
0359 case SYNC_IOC_MERGE:
0360 return sync_file_ioctl_merge(sync_file, arg);
0361
0362 case SYNC_IOC_FILE_INFO:
0363 return sync_file_ioctl_fence_info(sync_file, arg);
0364
0365 default:
0366 return -ENOTTY;
0367 }
0368 }
0369
0370 static const struct file_operations sync_file_fops = {
0371 .release = sync_file_release,
0372 .poll = sync_file_poll,
0373 .unlocked_ioctl = sync_file_ioctl,
0374 .compat_ioctl = compat_ptr_ioctl,
0375 };