1
2
3
4
5
6
7
8#include <linux/dma-fence-unwrap.h>
9#include <linux/export.h>
10#include <linux/file.h>
11#include <linux/fs.h>
12#include <linux/kernel.h>
13#include <linux/poll.h>
14#include <linux/sched.h>
15#include <linux/slab.h>
16#include <linux/uaccess.h>
17#include <linux/anon_inodes.h>
18#include <linux/sync_file.h>
19#include <uapi/linux/sync_file.h>
20
21static const struct file_operations sync_file_fops;
22
23static struct sync_file *sync_file_alloc(void)
24{
25 struct sync_file *sync_file;
26
27 sync_file = kzalloc(sizeof(*sync_file), GFP_KERNEL);
28 if (!sync_file)
29 return NULL;
30
31 sync_file->file = anon_inode_getfile("sync_file", &sync_file_fops,
32 sync_file, 0);
33 if (IS_ERR(sync_file->file))
34 goto err;
35
36 init_waitqueue_head(&sync_file->wq);
37
38 INIT_LIST_HEAD(&sync_file->cb.node);
39
40 return sync_file;
41
42err:
43 kfree(sync_file);
44 return NULL;
45}
46
47static void fence_check_cb_func(struct dma_fence *f, struct dma_fence_cb *cb)
48{
49 struct sync_file *sync_file;
50
51 sync_file = container_of(cb, struct sync_file, cb);
52
53 wake_up_all(&sync_file->wq);
54}
55
56
57
58
59
60
61
62
63
64
65struct sync_file *sync_file_create(struct dma_fence *fence)
66{
67 struct sync_file *sync_file;
68
69 sync_file = sync_file_alloc();
70 if (!sync_file)
71 return NULL;
72
73 sync_file->fence = dma_fence_get(fence);
74
75 return sync_file;
76}
77EXPORT_SYMBOL(sync_file_create);
78
79static struct sync_file *sync_file_fdget(int fd)
80{
81 struct file *file = fget(fd);
82
83 if (!file)
84 return NULL;
85
86 if (file->f_op != &sync_file_fops)
87 goto err;
88
89 return file->private_data;
90
91err:
92 fput(file);
93 return NULL;
94}
95
96
97
98
99
100
101
102
103struct dma_fence *sync_file_get_fence(int fd)
104{
105 struct sync_file *sync_file;
106 struct dma_fence *fence;
107
108 sync_file = sync_file_fdget(fd);
109 if (!sync_file)
110 return NULL;
111
112 fence = dma_fence_get(sync_file->fence);
113 fput(sync_file->file);
114
115 return fence;
116}
117EXPORT_SYMBOL(sync_file_get_fence);
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len)
133{
134 if (sync_file->user_name[0]) {
135 strlcpy(buf, sync_file->user_name, len);
136 } else {
137 struct dma_fence *fence = sync_file->fence;
138
139 snprintf(buf, len, "%s-%s%llu-%lld",
140 fence->ops->get_driver_name(fence),
141 fence->ops->get_timeline_name(fence),
142 fence->context,
143 fence->seqno);
144 }
145
146 return buf;
147}
148
149static int sync_file_set_fence(struct sync_file *sync_file,
150 struct dma_fence **fences, int num_fences)
151{
152 struct dma_fence_array *array;
153
154
155
156
157
158
159
160 if (num_fences == 1) {
161 sync_file->fence = fences[0];
162 kfree(fences);
163 } else {
164 array = dma_fence_array_create(num_fences, fences,
165 dma_fence_context_alloc(1),
166 1, false);
167 if (!array)
168 return -ENOMEM;
169
170 sync_file->fence = &array->base;
171 }
172
173 return 0;
174}
175
176static void add_fence(struct dma_fence **fences,
177 int *i, struct dma_fence *fence)
178{
179 fences[*i] = fence;
180
181 if (!dma_fence_is_signaled(fence)) {
182 dma_fence_get(fence);
183 (*i)++;
184 }
185}
186
187
188
189
190
191
192
193
194
195
196
197static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
198 struct sync_file *b)
199{
200 struct dma_fence *a_fence, *b_fence, **fences;
201 struct dma_fence_unwrap a_iter, b_iter;
202 unsigned int index, num_fences;
203 struct sync_file *sync_file;
204
205 sync_file = sync_file_alloc();
206 if (!sync_file)
207 return NULL;
208
209 num_fences = 0;
210 dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
211 ++num_fences;
212 dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
213 ++num_fences;
214
215 if (num_fences > INT_MAX)
216 goto err_free_sync_file;
217
218 fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
219 if (!fences)
220 goto err_free_sync_file;
221
222
223
224
225
226
227
228
229
230 index = 0;
231 for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
232 b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
233 a_fence || b_fence; ) {
234
235 if (!b_fence) {
236 add_fence(fences, &index, a_fence);
237 a_fence = dma_fence_unwrap_next(&a_iter);
238
239 } else if (!a_fence) {
240 add_fence(fences, &index, b_fence);
241 b_fence = dma_fence_unwrap_next(&b_iter);
242
243 } else if (a_fence->context < b_fence->context) {
244 add_fence(fences, &index, a_fence);
245 a_fence = dma_fence_unwrap_next(&a_iter);
246
247 } else if (b_fence->context < a_fence->context) {
248 add_fence(fences, &index, b_fence);
249 b_fence = dma_fence_unwrap_next(&b_iter);
250
251 } else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
252 a_fence->ops)) {
253 add_fence(fences, &index, a_fence);
254 a_fence = dma_fence_unwrap_next(&a_iter);
255 b_fence = dma_fence_unwrap_next(&b_iter);
256
257 } else {
258 add_fence(fences, &index, b_fence);
259 a_fence = dma_fence_unwrap_next(&a_iter);
260 b_fence = dma_fence_unwrap_next(&b_iter);
261 }
262 }
263
264 if (index == 0)
265 fences[index++] = dma_fence_get_stub();
266
267 if (num_fences > index) {
268 struct dma_fence **tmp;
269
270
271 tmp = krealloc_array(fences, index, sizeof(*fences),
272 GFP_KERNEL);
273 if (tmp)
274 fences = tmp;
275 }
276
277 if (sync_file_set_fence(sync_file, fences, index) < 0)
278 goto err_put_fences;
279
280 strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
281 return sync_file;
282
283err_put_fences:
284 while (index)
285 dma_fence_put(fences[--index]);
286 kfree(fences);
287
288err_free_sync_file:
289 fput(sync_file->file);
290 return NULL;
291}
292
293static int sync_file_release(struct inode *inode, struct file *file)
294{
295 struct sync_file *sync_file = file->private_data;
296
297 if (test_bit(POLL_ENABLED, &sync_file->flags))
298 dma_fence_remove_callback(sync_file->fence, &sync_file->cb);
299 dma_fence_put(sync_file->fence);
300 kfree(sync_file);
301
302 return 0;
303}
304
305static __poll_t sync_file_poll(struct file *file, poll_table *wait)
306{
307 struct sync_file *sync_file = file->private_data;
308
309 poll_wait(file, &sync_file->wq, wait);
310
311 if (list_empty(&sync_file->cb.node) &&
312 !test_and_set_bit(POLL_ENABLED, &sync_file->flags)) {
313 if (dma_fence_add_callback(sync_file->fence, &sync_file->cb,
314 fence_check_cb_func) < 0)
315 wake_up_all(&sync_file->wq);
316 }
317
318 return dma_fence_is_signaled(sync_file->fence) ? EPOLLIN : 0;
319}
320
321static long sync_file_ioctl_merge(struct sync_file *sync_file,
322 unsigned long arg)
323{
324 int fd = get_unused_fd_flags(O_CLOEXEC);
325 int err;
326 struct sync_file *fence2, *fence3;
327 struct sync_merge_data data;
328
329 if (fd < 0)
330 return fd;
331
332 if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
333 err = -EFAULT;
334 goto err_put_fd;
335 }
336
337 if (data.flags || data.pad) {
338 err = -EINVAL;
339 goto err_put_fd;
340 }
341
342 fence2 = sync_file_fdget(data.fd2);
343 if (!fence2) {
344 err = -ENOENT;
345 goto err_put_fd;
346 }
347
348 data.name[sizeof(data.name) - 1] = '\0';
349 fence3 = sync_file_merge(data.name, sync_file, fence2);
350 if (!fence3) {
351 err = -ENOMEM;
352 goto err_put_fence2;
353 }
354
355 data.fence = fd;
356 if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
357 err = -EFAULT;
358 goto err_put_fence3;
359 }
360
361 fd_install(fd, fence3->file);
362 fput(fence2->file);
363 return 0;
364
365err_put_fence3:
366 fput(fence3->file);
367
368err_put_fence2:
369 fput(fence2->file);
370
371err_put_fd:
372 put_unused_fd(fd);
373 return err;
374}
375
376static int sync_fill_fence_info(struct dma_fence *fence,
377 struct sync_fence_info *info)
378{
379 strlcpy(info->obj_name, fence->ops->get_timeline_name(fence),
380 sizeof(info->obj_name));
381 strlcpy(info->driver_name, fence->ops->get_driver_name(fence),
382 sizeof(info->driver_name));
383
384 info->status = dma_fence_get_status(fence);
385 while (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) &&
386 !test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
387 cpu_relax();
388 info->timestamp_ns =
389 test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags) ?
390 ktime_to_ns(fence->timestamp) :
391 ktime_set(0, 0);
392
393 return info->status;
394}
395
396static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
397 unsigned long arg)
398{
399 struct sync_fence_info *fence_info = NULL;
400 struct dma_fence_unwrap iter;
401 struct sync_file_info info;
402 unsigned int num_fences;
403 struct dma_fence *fence;
404 int ret;
405 __u32 size;
406
407 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
408 return -EFAULT;
409
410 if (info.flags || info.pad)
411 return -EINVAL;
412
413 num_fences = 0;
414 dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
415 ++num_fences;
416
417
418
419
420
421
422
423 if (!info.num_fences) {
424 info.status = dma_fence_get_status(sync_file->fence);
425 goto no_fences;
426 } else {
427 info.status = 1;
428 }
429
430 if (info.num_fences < num_fences)
431 return -EINVAL;
432
433 size = num_fences * sizeof(*fence_info);
434 fence_info = kzalloc(size, GFP_KERNEL);
435 if (!fence_info)
436 return -ENOMEM;
437
438 num_fences = 0;
439 dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
440 int status;
441
442 status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
443 info.status = info.status <= 0 ? info.status : status;
444 }
445
446 if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info,
447 size)) {
448 ret = -EFAULT;
449 goto out;
450 }
451
452no_fences:
453 sync_file_get_name(sync_file, info.name, sizeof(info.name));
454 info.num_fences = num_fences;
455
456 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
457 ret = -EFAULT;
458 else
459 ret = 0;
460
461out:
462 kfree(fence_info);
463
464 return ret;
465}
466
467static long sync_file_ioctl(struct file *file, unsigned int cmd,
468 unsigned long arg)
469{
470 struct sync_file *sync_file = file->private_data;
471
472 switch (cmd) {
473 case SYNC_IOC_MERGE:
474 return sync_file_ioctl_merge(sync_file, arg);
475
476 case SYNC_IOC_FILE_INFO:
477 return sync_file_ioctl_fence_info(sync_file, arg);
478
479 default:
480 return -ENOTTY;
481 }
482}
483
484static const struct file_operations sync_file_fops = {
485 .release = sync_file_release,
486 .poll = sync_file_poll,
487 .unlocked_ioctl = sync_file_ioctl,
488 .compat_ioctl = compat_ptr_ioctl,
489};
490