• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * drivers/base/sync.c
3  *
4  * Copyright (C) 2012 Google, Inc.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16 
17 #include <linux/debugfs.h>
18 #include <linux/export.h>
19 #include <linux/file.h>
20 #include <linux/fs.h>
21 #include <linux/kernel.h>
22 #include <linux/poll.h>
23 #include <linux/sched.h>
24 #include <linux/seq_file.h>
25 #include <linux/slab.h>
26 #include <linux/uaccess.h>
27 #include <linux/anon_inodes.h>
28 
29 #include "sync.h"
30 
31 #define CREATE_TRACE_POINTS
32 #include "trace/sync.h"
33 
34 static void sync_fence_signal_pt(struct sync_pt *pt);
35 static int _sync_pt_has_signaled(struct sync_pt *pt);
36 static void sync_fence_free(struct kref *kref);
37 static void sync_dump(void);
38 
39 static LIST_HEAD(sync_timeline_list_head);
40 static DEFINE_SPINLOCK(sync_timeline_list_lock);
41 
42 static LIST_HEAD(sync_fence_list_head);
43 static DEFINE_SPINLOCK(sync_fence_list_lock);
44 
sync_timeline_create(const struct sync_timeline_ops * ops,int size,const char * name)45 struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
46 					   int size, const char *name)
47 {
48 	struct sync_timeline *obj;
49 	unsigned long flags;
50 
51 	if (size < sizeof(struct sync_timeline))
52 		return NULL;
53 
54 	obj = kzalloc(size, GFP_KERNEL);
55 	if (obj == NULL)
56 		return NULL;
57 
58 	kref_init(&obj->kref);
59 	obj->ops = ops;
60 	strlcpy(obj->name, name, sizeof(obj->name));
61 
62 	INIT_LIST_HEAD(&obj->child_list_head);
63 	spin_lock_init(&obj->child_list_lock);
64 
65 	INIT_LIST_HEAD(&obj->active_list_head);
66 	spin_lock_init(&obj->active_list_lock);
67 
68 	spin_lock_irqsave(&sync_timeline_list_lock, flags);
69 	list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head);
70 	spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
71 
72 	return obj;
73 }
74 EXPORT_SYMBOL(sync_timeline_create);
75 
sync_timeline_free(struct kref * kref)76 static void sync_timeline_free(struct kref *kref)
77 {
78 	struct sync_timeline *obj =
79 		container_of(kref, struct sync_timeline, kref);
80 	unsigned long flags;
81 
82 	spin_lock_irqsave(&sync_timeline_list_lock, flags);
83 	list_del(&obj->sync_timeline_list);
84 	spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
85 
86 	if (obj->ops->release_obj)
87 		obj->ops->release_obj(obj);
88 
89 	kfree(obj);
90 }
91 
sync_timeline_destroy(struct sync_timeline * obj)92 void sync_timeline_destroy(struct sync_timeline *obj)
93 {
94 	obj->destroyed = true;
95 	smp_wmb();
96 
97 	/*
98 	 * signal any children that their parent is going away.
99 	 */
100 	sync_timeline_signal(obj);
101 
102 	kref_put(&obj->kref, sync_timeline_free);
103 }
104 EXPORT_SYMBOL(sync_timeline_destroy);
105 
sync_timeline_add_pt(struct sync_timeline * obj,struct sync_pt * pt)106 static void sync_timeline_add_pt(struct sync_timeline *obj, struct sync_pt *pt)
107 {
108 	unsigned long flags;
109 
110 	pt->parent = obj;
111 
112 	spin_lock_irqsave(&obj->child_list_lock, flags);
113 	list_add_tail(&pt->child_list, &obj->child_list_head);
114 	spin_unlock_irqrestore(&obj->child_list_lock, flags);
115 }
116 
sync_timeline_remove_pt(struct sync_pt * pt)117 static void sync_timeline_remove_pt(struct sync_pt *pt)
118 {
119 	struct sync_timeline *obj = pt->parent;
120 	unsigned long flags;
121 
122 	spin_lock_irqsave(&obj->active_list_lock, flags);
123 	if (!list_empty(&pt->active_list))
124 		list_del_init(&pt->active_list);
125 	spin_unlock_irqrestore(&obj->active_list_lock, flags);
126 
127 	spin_lock_irqsave(&obj->child_list_lock, flags);
128 	if (!list_empty(&pt->child_list)) {
129 		list_del_init(&pt->child_list);
130 	}
131 	spin_unlock_irqrestore(&obj->child_list_lock, flags);
132 }
133 
sync_timeline_signal(struct sync_timeline * obj)134 void sync_timeline_signal(struct sync_timeline *obj)
135 {
136 	unsigned long flags;
137 	LIST_HEAD(signaled_pts);
138 	struct list_head *pos, *n;
139 
140 	trace_sync_timeline(obj);
141 
142 	spin_lock_irqsave(&obj->active_list_lock, flags);
143 
144 	list_for_each_safe(pos, n, &obj->active_list_head) {
145 		struct sync_pt *pt =
146 			container_of(pos, struct sync_pt, active_list);
147 
148 		if (_sync_pt_has_signaled(pt)) {
149 			list_del_init(pos);
150 			list_add(&pt->signaled_list, &signaled_pts);
151 			kref_get(&pt->fence->kref);
152 		}
153 	}
154 
155 	spin_unlock_irqrestore(&obj->active_list_lock, flags);
156 
157 	list_for_each_safe(pos, n, &signaled_pts) {
158 		struct sync_pt *pt =
159 			container_of(pos, struct sync_pt, signaled_list);
160 
161 		list_del_init(pos);
162 		sync_fence_signal_pt(pt);
163 		kref_put(&pt->fence->kref, sync_fence_free);
164 	}
165 }
166 EXPORT_SYMBOL(sync_timeline_signal);
167 
sync_pt_create(struct sync_timeline * parent,int size)168 struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size)
169 {
170 	struct sync_pt *pt;
171 
172 	if (size < sizeof(struct sync_pt))
173 		return NULL;
174 
175 	pt = kzalloc(size, GFP_KERNEL);
176 	if (pt == NULL)
177 		return NULL;
178 
179 	INIT_LIST_HEAD(&pt->active_list);
180 	kref_get(&parent->kref);
181 	sync_timeline_add_pt(parent, pt);
182 
183 	return pt;
184 }
185 EXPORT_SYMBOL(sync_pt_create);
186 
sync_pt_free(struct sync_pt * pt)187 void sync_pt_free(struct sync_pt *pt)
188 {
189 	if (pt->parent->ops->free_pt)
190 		pt->parent->ops->free_pt(pt);
191 
192 	sync_timeline_remove_pt(pt);
193 
194 	kref_put(&pt->parent->kref, sync_timeline_free);
195 
196 	kfree(pt);
197 }
198 EXPORT_SYMBOL(sync_pt_free);
199 
200 /* call with pt->parent->active_list_lock held */
_sync_pt_has_signaled(struct sync_pt * pt)201 static int _sync_pt_has_signaled(struct sync_pt *pt)
202 {
203 	int old_status = pt->status;
204 
205 	if (!pt->status)
206 		pt->status = pt->parent->ops->has_signaled(pt);
207 
208 	if (!pt->status && pt->parent->destroyed)
209 		pt->status = -ENOENT;
210 
211 	if (pt->status != old_status)
212 		pt->timestamp = ktime_get();
213 
214 	return pt->status;
215 }
216 
sync_pt_dup(struct sync_pt * pt)217 static struct sync_pt *sync_pt_dup(struct sync_pt *pt)
218 {
219 	return pt->parent->ops->dup(pt);
220 }
221 
222 /* Adds a sync pt to the active queue.  Called when added to a fence */
sync_pt_activate(struct sync_pt * pt)223 static void sync_pt_activate(struct sync_pt *pt)
224 {
225 	struct sync_timeline *obj = pt->parent;
226 	unsigned long flags;
227 	int err;
228 
229 	spin_lock_irqsave(&obj->active_list_lock, flags);
230 
231 	err = _sync_pt_has_signaled(pt);
232 	if (err != 0)
233 		goto out;
234 
235 	list_add_tail(&pt->active_list, &obj->active_list_head);
236 
237 out:
238 	spin_unlock_irqrestore(&obj->active_list_lock, flags);
239 }
240 
241 static int sync_fence_release(struct inode *inode, struct file *file);
242 static unsigned int sync_fence_poll(struct file *file, poll_table *wait);
243 static long sync_fence_ioctl(struct file *file, unsigned int cmd,
244 			     unsigned long arg);
245 
246 
247 static const struct file_operations sync_fence_fops = {
248 	.release = sync_fence_release,
249 	.poll = sync_fence_poll,
250 	.unlocked_ioctl = sync_fence_ioctl,
251 	.compat_ioctl = sync_fence_ioctl,
252 };
253 
sync_fence_alloc(const char * name)254 static struct sync_fence *sync_fence_alloc(const char *name)
255 {
256 	struct sync_fence *fence;
257 	unsigned long flags;
258 
259 	fence = kzalloc(sizeof(struct sync_fence), GFP_KERNEL);
260 	if (fence == NULL)
261 		return NULL;
262 
263 	fence->file = anon_inode_getfile("sync_fence", &sync_fence_fops,
264 					 fence, 0);
265 	if (IS_ERR(fence->file))
266 		goto err;
267 
268 	kref_init(&fence->kref);
269 	strlcpy(fence->name, name, sizeof(fence->name));
270 
271 	INIT_LIST_HEAD(&fence->pt_list_head);
272 	INIT_LIST_HEAD(&fence->waiter_list_head);
273 	spin_lock_init(&fence->waiter_list_lock);
274 
275 	init_waitqueue_head(&fence->wq);
276 
277 	spin_lock_irqsave(&sync_fence_list_lock, flags);
278 	list_add_tail(&fence->sync_fence_list, &sync_fence_list_head);
279 	spin_unlock_irqrestore(&sync_fence_list_lock, flags);
280 
281 	return fence;
282 
283 err:
284 	kfree(fence);
285 	return NULL;
286 }
287 
288 /* TODO: implement a create which takes more that one sync_pt */
sync_fence_create(const char * name,struct sync_pt * pt)289 struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt)
290 {
291 	struct sync_fence *fence;
292 
293 	if (pt->fence)
294 		return NULL;
295 
296 	fence = sync_fence_alloc(name);
297 	if (fence == NULL)
298 		return NULL;
299 
300 	pt->fence = fence;
301 	list_add(&pt->pt_list, &fence->pt_list_head);
302 	sync_pt_activate(pt);
303 
304 	/*
305 	 * signal the fence in case pt was activated before
306 	 * sync_pt_activate(pt) was called
307 	 */
308 	sync_fence_signal_pt(pt);
309 
310 	return fence;
311 }
312 EXPORT_SYMBOL(sync_fence_create);
313 
sync_fence_copy_pts(struct sync_fence * dst,struct sync_fence * src)314 static int sync_fence_copy_pts(struct sync_fence *dst, struct sync_fence *src)
315 {
316 	struct list_head *pos;
317 
318 	list_for_each(pos, &src->pt_list_head) {
319 		struct sync_pt *orig_pt =
320 			container_of(pos, struct sync_pt, pt_list);
321 		struct sync_pt *new_pt = sync_pt_dup(orig_pt);
322 
323 		if (new_pt == NULL)
324 			return -ENOMEM;
325 
326 		new_pt->fence = dst;
327 		list_add(&new_pt->pt_list, &dst->pt_list_head);
328 	}
329 
330 	return 0;
331 }
332 
sync_fence_merge_pts(struct sync_fence * dst,struct sync_fence * src)333 static int sync_fence_merge_pts(struct sync_fence *dst, struct sync_fence *src)
334 {
335 	struct list_head *src_pos, *dst_pos, *n;
336 
337 	list_for_each(src_pos, &src->pt_list_head) {
338 		struct sync_pt *src_pt =
339 			container_of(src_pos, struct sync_pt, pt_list);
340 		bool collapsed = false;
341 
342 		list_for_each_safe(dst_pos, n, &dst->pt_list_head) {
343 			struct sync_pt *dst_pt =
344 				container_of(dst_pos, struct sync_pt, pt_list);
345 			/* collapse two sync_pts on the same timeline
346 			 * to a single sync_pt that will signal at
347 			 * the later of the two
348 			 */
349 			if (dst_pt->parent == src_pt->parent) {
350 				if (dst_pt->parent->ops->compare(dst_pt, src_pt)
351 						 == -1) {
352 					struct sync_pt *new_pt =
353 						sync_pt_dup(src_pt);
354 					if (new_pt == NULL)
355 						return -ENOMEM;
356 
357 					new_pt->fence = dst;
358 					list_replace(&dst_pt->pt_list,
359 						     &new_pt->pt_list);
360 					sync_pt_free(dst_pt);
361 				}
362 				collapsed = true;
363 				break;
364 			}
365 		}
366 
367 		if (!collapsed) {
368 			struct sync_pt *new_pt = sync_pt_dup(src_pt);
369 
370 			if (new_pt == NULL)
371 				return -ENOMEM;
372 
373 			new_pt->fence = dst;
374 			list_add(&new_pt->pt_list, &dst->pt_list_head);
375 		}
376 	}
377 
378 	return 0;
379 }
380 
sync_fence_detach_pts(struct sync_fence * fence)381 static void sync_fence_detach_pts(struct sync_fence *fence)
382 {
383 	struct list_head *pos, *n;
384 
385 	list_for_each_safe(pos, n, &fence->pt_list_head) {
386 		struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
387 
388 		sync_timeline_remove_pt(pt);
389 	}
390 }
391 
sync_fence_free_pts(struct sync_fence * fence)392 static void sync_fence_free_pts(struct sync_fence *fence)
393 {
394 	struct list_head *pos, *n;
395 
396 	list_for_each_safe(pos, n, &fence->pt_list_head) {
397 		struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
398 
399 		sync_pt_free(pt);
400 	}
401 }
402 
sync_fence_fdget(int fd)403 struct sync_fence *sync_fence_fdget(int fd)
404 {
405 	struct file *file = fget(fd);
406 
407 	if (file == NULL)
408 		return NULL;
409 
410 	if (file->f_op != &sync_fence_fops)
411 		goto err;
412 
413 	return file->private_data;
414 
415 err:
416 	fput(file);
417 	return NULL;
418 }
419 EXPORT_SYMBOL(sync_fence_fdget);
420 
sync_fence_put(struct sync_fence * fence)421 void sync_fence_put(struct sync_fence *fence)
422 {
423 	fput(fence->file);
424 }
425 EXPORT_SYMBOL(sync_fence_put);
426 
sync_fence_install(struct sync_fence * fence,int fd)427 void sync_fence_install(struct sync_fence *fence, int fd)
428 {
429 	fd_install(fd, fence->file);
430 }
431 EXPORT_SYMBOL(sync_fence_install);
432 
sync_fence_get_status(struct sync_fence * fence)433 static int sync_fence_get_status(struct sync_fence *fence)
434 {
435 	struct list_head *pos;
436 	int status = 1;
437 
438 	list_for_each(pos, &fence->pt_list_head) {
439 		struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
440 		int pt_status = pt->status;
441 
442 		if (pt_status < 0) {
443 			status = pt_status;
444 			break;
445 		} else if (status == 1) {
446 			status = pt_status;
447 		}
448 	}
449 
450 	return status;
451 }
452 
sync_fence_merge(const char * name,struct sync_fence * a,struct sync_fence * b)453 struct sync_fence *sync_fence_merge(const char *name,
454 				    struct sync_fence *a, struct sync_fence *b)
455 {
456 	struct sync_fence *fence;
457 	struct list_head *pos;
458 	int err;
459 
460 	fence = sync_fence_alloc(name);
461 	if (fence == NULL)
462 		return NULL;
463 
464 	err = sync_fence_copy_pts(fence, a);
465 	if (err < 0)
466 		goto err;
467 
468 	err = sync_fence_merge_pts(fence, b);
469 	if (err < 0)
470 		goto err;
471 
472 	list_for_each(pos, &fence->pt_list_head) {
473 		struct sync_pt *pt =
474 			container_of(pos, struct sync_pt, pt_list);
475 		sync_pt_activate(pt);
476 	}
477 
478 	/*
479 	 * signal the fence in case one of it's pts were activated before
480 	 * they were activated
481 	 */
482 	sync_fence_signal_pt(list_first_entry(&fence->pt_list_head,
483 					      struct sync_pt,
484 					      pt_list));
485 
486 	return fence;
487 err:
488 	sync_fence_free_pts(fence);
489 	kfree(fence);
490 	return NULL;
491 }
492 EXPORT_SYMBOL(sync_fence_merge);
493 
sync_fence_signal_pt(struct sync_pt * pt)494 static void sync_fence_signal_pt(struct sync_pt *pt)
495 {
496 	LIST_HEAD(signaled_waiters);
497 	struct sync_fence *fence = pt->fence;
498 	struct list_head *pos;
499 	struct list_head *n;
500 	unsigned long flags;
501 	int status;
502 
503 	status = sync_fence_get_status(fence);
504 
505 	spin_lock_irqsave(&fence->waiter_list_lock, flags);
506 	/*
507 	 * this should protect against two threads racing on the signaled
508 	 * false -> true transition
509 	 */
510 	if (status && !fence->status) {
511 		list_for_each_safe(pos, n, &fence->waiter_list_head)
512 			list_move(pos, &signaled_waiters);
513 
514 		fence->status = status;
515 	} else {
516 		status = 0;
517 	}
518 	spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
519 
520 	if (status) {
521 		list_for_each_safe(pos, n, &signaled_waiters) {
522 			struct sync_fence_waiter *waiter =
523 				container_of(pos, struct sync_fence_waiter,
524 					     waiter_list);
525 
526 			list_del(pos);
527 			waiter->callback(fence, waiter);
528 		}
529 		wake_up(&fence->wq);
530 	}
531 }
532 
sync_fence_wait_async(struct sync_fence * fence,struct sync_fence_waiter * waiter)533 int sync_fence_wait_async(struct sync_fence *fence,
534 			  struct sync_fence_waiter *waiter)
535 {
536 	unsigned long flags;
537 	int err = 0;
538 
539 	spin_lock_irqsave(&fence->waiter_list_lock, flags);
540 
541 	if (fence->status) {
542 		err = fence->status;
543 		goto out;
544 	}
545 
546 	list_add_tail(&waiter->waiter_list, &fence->waiter_list_head);
547 out:
548 	spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
549 
550 	return err;
551 }
552 EXPORT_SYMBOL(sync_fence_wait_async);
553 
sync_fence_cancel_async(struct sync_fence * fence,struct sync_fence_waiter * waiter)554 int sync_fence_cancel_async(struct sync_fence *fence,
555 			     struct sync_fence_waiter *waiter)
556 {
557 	struct list_head *pos;
558 	struct list_head *n;
559 	unsigned long flags;
560 	int ret = -ENOENT;
561 
562 	spin_lock_irqsave(&fence->waiter_list_lock, flags);
563 	/*
564 	 * Make sure waiter is still in waiter_list because it is possible for
565 	 * the waiter to be removed from the list while the callback is still
566 	 * pending.
567 	 */
568 	list_for_each_safe(pos, n, &fence->waiter_list_head) {
569 		struct sync_fence_waiter *list_waiter =
570 			container_of(pos, struct sync_fence_waiter,
571 				     waiter_list);
572 		if (list_waiter == waiter) {
573 			list_del(pos);
574 			ret = 0;
575 			break;
576 		}
577 	}
578 	spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
579 	return ret;
580 }
581 EXPORT_SYMBOL(sync_fence_cancel_async);
582 
sync_fence_check(struct sync_fence * fence)583 static bool sync_fence_check(struct sync_fence *fence)
584 {
585 	/*
586 	 * Make sure that reads to fence->status are ordered with the
587 	 * wait queue event triggering
588 	 */
589 	smp_rmb();
590 	return fence->status != 0;
591 }
592 
sync_fence_wait(struct sync_fence * fence,long timeout)593 int sync_fence_wait(struct sync_fence *fence, long timeout)
594 {
595 	int err = 0;
596 	struct sync_pt *pt;
597 
598 	trace_sync_wait(fence, 1);
599 	list_for_each_entry(pt, &fence->pt_list_head, pt_list)
600 		trace_sync_pt(pt);
601 
602 	if (timeout > 0) {
603 		timeout = msecs_to_jiffies(timeout);
604 		err = wait_event_interruptible_timeout(fence->wq,
605 						       sync_fence_check(fence),
606 						       timeout);
607 	} else if (timeout < 0) {
608 		err = wait_event_interruptible(fence->wq,
609 					       sync_fence_check(fence));
610 	}
611 	trace_sync_wait(fence, 0);
612 
613 	if (err < 0)
614 		return err;
615 
616 	if (fence->status < 0) {
617 		pr_info("fence error %d on [%p]\n", fence->status, fence);
618 		sync_dump();
619 		return fence->status;
620 	}
621 
622 	if (fence->status == 0) {
623 		if (timeout > 0) {
624 			pr_info("fence timeout on [%p] after %dms\n", fence,
625 				jiffies_to_msecs(timeout));
626 			sync_dump();
627 		}
628 		return -ETIME;
629 	}
630 
631 	return 0;
632 }
633 EXPORT_SYMBOL(sync_fence_wait);
634 
sync_fence_free(struct kref * kref)635 static void sync_fence_free(struct kref *kref)
636 {
637 	struct sync_fence *fence = container_of(kref, struct sync_fence, kref);
638 
639 	sync_fence_free_pts(fence);
640 
641 	kfree(fence);
642 }
643 
sync_fence_release(struct inode * inode,struct file * file)644 static int sync_fence_release(struct inode *inode, struct file *file)
645 {
646 	struct sync_fence *fence = file->private_data;
647 	unsigned long flags;
648 
649 	/*
650 	 * We need to remove all ways to access this fence before droping
651 	 * our ref.
652 	 *
653 	 * start with its membership in the global fence list
654 	 */
655 	spin_lock_irqsave(&sync_fence_list_lock, flags);
656 	list_del(&fence->sync_fence_list);
657 	spin_unlock_irqrestore(&sync_fence_list_lock, flags);
658 
659 	/*
660 	 * remove its pts from their parents so that sync_timeline_signal()
661 	 * can't reference the fence.
662 	 */
663 	sync_fence_detach_pts(fence);
664 
665 	kref_put(&fence->kref, sync_fence_free);
666 
667 	return 0;
668 }
669 
sync_fence_poll(struct file * file,poll_table * wait)670 static unsigned int sync_fence_poll(struct file *file, poll_table *wait)
671 {
672 	struct sync_fence *fence = file->private_data;
673 
674 	poll_wait(file, &fence->wq, wait);
675 
676 	/*
677 	 * Make sure that reads to fence->status are ordered with the
678 	 * wait queue event triggering
679 	 */
680 	smp_rmb();
681 
682 	if (fence->status == 1)
683 		return POLLIN;
684 	else if (fence->status < 0)
685 		return POLLERR;
686 	else
687 		return 0;
688 }
689 
sync_fence_ioctl_wait(struct sync_fence * fence,unsigned long arg)690 static long sync_fence_ioctl_wait(struct sync_fence *fence, unsigned long arg)
691 {
692 	__s32 value;
693 
694 	if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
695 		return -EFAULT;
696 
697 	return sync_fence_wait(fence, value);
698 }
699 
sync_fence_ioctl_merge(struct sync_fence * fence,unsigned long arg)700 static long sync_fence_ioctl_merge(struct sync_fence *fence, unsigned long arg)
701 {
702 	int fd = get_unused_fd();
703 	int err;
704 	struct sync_fence *fence2, *fence3;
705 	struct sync_merge_data data;
706 
707 	if (fd < 0)
708 		return fd;
709 
710 	if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
711 		err = -EFAULT;
712 		goto err_put_fd;
713 	}
714 
715 	fence2 = sync_fence_fdget(data.fd2);
716 	if (fence2 == NULL) {
717 		err = -ENOENT;
718 		goto err_put_fd;
719 	}
720 
721 	data.name[sizeof(data.name) - 1] = '\0';
722 	fence3 = sync_fence_merge(data.name, fence, fence2);
723 	if (fence3 == NULL) {
724 		err = -ENOMEM;
725 		goto err_put_fence2;
726 	}
727 
728 	data.fence = fd;
729 	if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
730 		err = -EFAULT;
731 		goto err_put_fence3;
732 	}
733 
734 	sync_fence_install(fence3, fd);
735 	sync_fence_put(fence2);
736 	return 0;
737 
738 err_put_fence3:
739 	sync_fence_put(fence3);
740 
741 err_put_fence2:
742 	sync_fence_put(fence2);
743 
744 err_put_fd:
745 	put_unused_fd(fd);
746 	return err;
747 }
748 
sync_fill_pt_info(struct sync_pt * pt,void * data,int size)749 static int sync_fill_pt_info(struct sync_pt *pt, void *data, int size)
750 {
751 	struct sync_pt_info *info = data;
752 	int ret;
753 
754 	if (size < sizeof(struct sync_pt_info))
755 		return -ENOMEM;
756 
757 	info->len = sizeof(struct sync_pt_info);
758 
759 	if (pt->parent->ops->fill_driver_data) {
760 		ret = pt->parent->ops->fill_driver_data(pt, info->driver_data,
761 							size - sizeof(*info));
762 		if (ret < 0)
763 			return ret;
764 
765 		info->len += ret;
766 	}
767 
768 	strlcpy(info->obj_name, pt->parent->name, sizeof(info->obj_name));
769 	strlcpy(info->driver_name, pt->parent->ops->driver_name,
770 		sizeof(info->driver_name));
771 	info->status = pt->status;
772 	info->timestamp_ns = ktime_to_ns(pt->timestamp);
773 
774 	return info->len;
775 }
776 
sync_fence_ioctl_fence_info(struct sync_fence * fence,unsigned long arg)777 static long sync_fence_ioctl_fence_info(struct sync_fence *fence,
778 					unsigned long arg)
779 {
780 	struct sync_fence_info_data *data;
781 	struct list_head *pos;
782 	__u32 size;
783 	__u32 len = 0;
784 	int ret;
785 
786 	if (copy_from_user(&size, (void __user *)arg, sizeof(size)))
787 		return -EFAULT;
788 
789 	if (size < sizeof(struct sync_fence_info_data))
790 		return -EINVAL;
791 
792 	if (size > 4096)
793 		size = 4096;
794 
795 	data = kzalloc(size, GFP_KERNEL);
796 	if (data == NULL)
797 		return -ENOMEM;
798 
799 	strlcpy(data->name, fence->name, sizeof(data->name));
800 	data->status = fence->status;
801 	len = sizeof(struct sync_fence_info_data);
802 
803 	list_for_each(pos, &fence->pt_list_head) {
804 		struct sync_pt *pt =
805 			container_of(pos, struct sync_pt, pt_list);
806 
807 		ret = sync_fill_pt_info(pt, (u8 *)data + len, size - len);
808 
809 		if (ret < 0)
810 			goto out;
811 
812 		len += ret;
813 	}
814 
815 	data->len = len;
816 
817 	if (copy_to_user((void __user *)arg, data, len))
818 		ret = -EFAULT;
819 	else
820 		ret = 0;
821 
822 out:
823 	kfree(data);
824 
825 	return ret;
826 }
827 
sync_fence_ioctl(struct file * file,unsigned int cmd,unsigned long arg)828 static long sync_fence_ioctl(struct file *file, unsigned int cmd,
829 			     unsigned long arg)
830 {
831 	struct sync_fence *fence = file->private_data;
832 
833 	switch (cmd) {
834 	case SYNC_IOC_WAIT:
835 		return sync_fence_ioctl_wait(fence, arg);
836 
837 	case SYNC_IOC_MERGE:
838 		return sync_fence_ioctl_merge(fence, arg);
839 
840 	case SYNC_IOC_FENCE_INFO:
841 		return sync_fence_ioctl_fence_info(fence, arg);
842 
843 	default:
844 		return -ENOTTY;
845 	}
846 }
847 
848 #ifdef CONFIG_DEBUG_FS
sync_status_str(int status)849 static const char *sync_status_str(int status)
850 {
851 	if (status > 0)
852 		return "signaled";
853 	else if (status == 0)
854 		return "active";
855 	else
856 		return "error";
857 }
858 
sync_print_pt(struct seq_file * s,struct sync_pt * pt,bool fence)859 static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence)
860 {
861 	int status = pt->status;
862 
863 	seq_printf(s, "  %s%spt %s",
864 		   fence ? pt->parent->name : "",
865 		   fence ? "_" : "",
866 		   sync_status_str(status));
867 	if (pt->status) {
868 		struct timeval tv = ktime_to_timeval(pt->timestamp);
869 
870 		seq_printf(s, "@%ld.%06ld", tv.tv_sec, tv.tv_usec);
871 	}
872 
873 	if (pt->parent->ops->timeline_value_str &&
874 	    pt->parent->ops->pt_value_str) {
875 		char value[64];
876 
877 		pt->parent->ops->pt_value_str(pt, value, sizeof(value));
878 		seq_printf(s, ": %s", value);
879 		if (fence) {
880 			pt->parent->ops->timeline_value_str(pt->parent, value,
881 						    sizeof(value));
882 			seq_printf(s, " / %s", value);
883 		}
884 	} else if (pt->parent->ops->print_pt) {
885 		seq_printf(s, ": ");
886 		pt->parent->ops->print_pt(s, pt);
887 	}
888 
889 	seq_printf(s, "\n");
890 }
891 
sync_print_obj(struct seq_file * s,struct sync_timeline * obj)892 static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
893 {
894 	struct list_head *pos;
895 	unsigned long flags;
896 
897 	seq_printf(s, "%s %s", obj->name, obj->ops->driver_name);
898 
899 	if (obj->ops->timeline_value_str) {
900 		char value[64];
901 
902 		obj->ops->timeline_value_str(obj, value, sizeof(value));
903 		seq_printf(s, ": %s", value);
904 	} else if (obj->ops->print_obj) {
905 		seq_printf(s, ": ");
906 		obj->ops->print_obj(s, obj);
907 	}
908 
909 	seq_printf(s, "\n");
910 
911 	spin_lock_irqsave(&obj->child_list_lock, flags);
912 	list_for_each(pos, &obj->child_list_head) {
913 		struct sync_pt *pt =
914 			container_of(pos, struct sync_pt, child_list);
915 		sync_print_pt(s, pt, false);
916 	}
917 	spin_unlock_irqrestore(&obj->child_list_lock, flags);
918 }
919 
sync_print_fence(struct seq_file * s,struct sync_fence * fence)920 static void sync_print_fence(struct seq_file *s, struct sync_fence *fence)
921 {
922 	struct list_head *pos;
923 	unsigned long flags;
924 
925 	seq_printf(s, "[%p] %s: %s\n", fence, fence->name,
926 		   sync_status_str(fence->status));
927 
928 	list_for_each(pos, &fence->pt_list_head) {
929 		struct sync_pt *pt =
930 			container_of(pos, struct sync_pt, pt_list);
931 		sync_print_pt(s, pt, true);
932 	}
933 
934 	spin_lock_irqsave(&fence->waiter_list_lock, flags);
935 	list_for_each(pos, &fence->waiter_list_head) {
936 		struct sync_fence_waiter *waiter =
937 			container_of(pos, struct sync_fence_waiter,
938 				     waiter_list);
939 
940 		seq_printf(s, "waiter %pF\n", waiter->callback);
941 	}
942 	spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
943 }
944 
sync_debugfs_show(struct seq_file * s,void * unused)945 static int sync_debugfs_show(struct seq_file *s, void *unused)
946 {
947 	unsigned long flags;
948 	struct list_head *pos;
949 
950 	seq_printf(s, "objs:\n--------------\n");
951 
952 	spin_lock_irqsave(&sync_timeline_list_lock, flags);
953 	list_for_each(pos, &sync_timeline_list_head) {
954 		struct sync_timeline *obj =
955 			container_of(pos, struct sync_timeline,
956 				     sync_timeline_list);
957 
958 		sync_print_obj(s, obj);
959 		seq_printf(s, "\n");
960 	}
961 	spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
962 
963 	seq_printf(s, "fences:\n--------------\n");
964 
965 	spin_lock_irqsave(&sync_fence_list_lock, flags);
966 	list_for_each(pos, &sync_fence_list_head) {
967 		struct sync_fence *fence =
968 			container_of(pos, struct sync_fence, sync_fence_list);
969 
970 		sync_print_fence(s, fence);
971 		seq_printf(s, "\n");
972 	}
973 	spin_unlock_irqrestore(&sync_fence_list_lock, flags);
974 	return 0;
975 }
976 
sync_debugfs_open(struct inode * inode,struct file * file)977 static int sync_debugfs_open(struct inode *inode, struct file *file)
978 {
979 	return single_open(file, sync_debugfs_show, inode->i_private);
980 }
981 
982 static const struct file_operations sync_debugfs_fops = {
983 	.open           = sync_debugfs_open,
984 	.read           = seq_read,
985 	.llseek         = seq_lseek,
986 	.release        = single_release,
987 };
988 
sync_debugfs_init(void)989 static __init int sync_debugfs_init(void)
990 {
991 	debugfs_create_file("sync", S_IRUGO, NULL, NULL, &sync_debugfs_fops);
992 	return 0;
993 }
994 late_initcall(sync_debugfs_init);
995 
996 #define DUMP_CHUNK 256
997 static char sync_dump_buf[64 * 1024];
sync_dump(void)998 void sync_dump(void)
999 {
1000 	struct seq_file s = {
1001 		.buf = sync_dump_buf,
1002 		.size = sizeof(sync_dump_buf) - 1,
1003 	};
1004 	int i;
1005 
1006 	sync_debugfs_show(&s, NULL);
1007 
1008 	for (i = 0; i < s.count; i += DUMP_CHUNK) {
1009 		if ((s.count - i) > DUMP_CHUNK) {
1010 			char c = s.buf[i + DUMP_CHUNK];
1011 
1012 			s.buf[i + DUMP_CHUNK] = 0;
1013 			pr_cont("%s", s.buf + i);
1014 			s.buf[i + DUMP_CHUNK] = c;
1015 		} else {
1016 			s.buf[s.count] = 0;
1017 			pr_cont("%s", s.buf + i);
1018 		}
1019 	}
1020 }
1021 #else
sync_dump(void)1022 static void sync_dump(void)
1023 {
1024 }
1025 #endif
1026