xref: /openbmc/linux/drivers/dma-buf/sw_sync.c (revision e531fdb5)
19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
235538d78SGustavo Padovan /*
335538d78SGustavo Padovan  * Sync File validation framework
435538d78SGustavo Padovan  *
535538d78SGustavo Padovan  * Copyright (C) 2012 Google, Inc.
635538d78SGustavo Padovan  */
735538d78SGustavo Padovan 
835538d78SGustavo Padovan #include <linux/file.h>
935538d78SGustavo Padovan #include <linux/fs.h>
1035538d78SGustavo Padovan #include <linux/uaccess.h>
1135538d78SGustavo Padovan #include <linux/slab.h>
1235538d78SGustavo Padovan #include <linux/sync_file.h>
1335538d78SGustavo Padovan 
1435538d78SGustavo Padovan #include "sync_debug.h"
1535538d78SGustavo Padovan 
1635538d78SGustavo Padovan #define CREATE_TRACE_POINTS
1735538d78SGustavo Padovan #include "sync_trace.h"
1835538d78SGustavo Padovan 
1935538d78SGustavo Padovan /*
2035538d78SGustavo Padovan  * SW SYNC validation framework
2135538d78SGustavo Padovan  *
2235538d78SGustavo Padovan  * A sync object driver that uses a 32bit counter to coordinate
2335538d78SGustavo Padovan  * synchronization.  Useful when there is no hardware primitive backing
2435538d78SGustavo Padovan  * the synchronization.
2535538d78SGustavo Padovan  *
2635538d78SGustavo Padovan  * To start the framework just open:
2735538d78SGustavo Padovan  *
2835538d78SGustavo Padovan  * <debugfs>/sync/sw_sync
2935538d78SGustavo Padovan  *
3035538d78SGustavo Padovan  * That will create a sync timeline, all fences created under this timeline
3135538d78SGustavo Padovan  * file descriptor will belong to the this timeline.
3235538d78SGustavo Padovan  *
3335538d78SGustavo Padovan  * The 'sw_sync' file can be opened many times as to create different
3435538d78SGustavo Padovan  * timelines.
3535538d78SGustavo Padovan  *
3635538d78SGustavo Padovan  * Fences can be created with SW_SYNC_IOC_CREATE_FENCE ioctl with struct
37e56a0fbdSShawn Guo  * sw_sync_create_fence_data as parameter.
3835538d78SGustavo Padovan  *
3935538d78SGustavo Padovan  * To increment the timeline counter, SW_SYNC_IOC_INC ioctl should be used
4035538d78SGustavo Padovan  * with the increment as u32. This will update the last signaled value
4135538d78SGustavo Padovan  * from the timeline and signal any fence that has a seqno smaller or equal
4235538d78SGustavo Padovan  * to it.
4335538d78SGustavo Padovan  *
44e56a0fbdSShawn Guo  * struct sw_sync_create_fence_data
4535538d78SGustavo Padovan  * @value:	the seqno to initialise the fence with
4635538d78SGustavo Padovan  * @name:	the name of the new sync point
4735538d78SGustavo Padovan  * @fence:	return the fd of the new sync_file with the created fence
4835538d78SGustavo Padovan  */
4935538d78SGustavo Padovan struct sw_sync_create_fence_data {
5035538d78SGustavo Padovan 	__u32	value;
5135538d78SGustavo Padovan 	char	name[32];
5235538d78SGustavo Padovan 	__s32	fence; /* fd of new fence */
5335538d78SGustavo Padovan };
5435538d78SGustavo Padovan 
5535538d78SGustavo Padovan #define SW_SYNC_IOC_MAGIC	'W'
5635538d78SGustavo Padovan 
5735538d78SGustavo Padovan #define SW_SYNC_IOC_CREATE_FENCE	_IOWR(SW_SYNC_IOC_MAGIC, 0,\
5835538d78SGustavo Padovan 		struct sw_sync_create_fence_data)
5935538d78SGustavo Padovan 
6035538d78SGustavo Padovan #define SW_SYNC_IOC_INC			_IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
6135538d78SGustavo Padovan 
62f54d1867SChris Wilson static const struct dma_fence_ops timeline_fence_ops;
6335538d78SGustavo Padovan 
dma_fence_to_sync_pt(struct dma_fence * fence)64f54d1867SChris Wilson static inline struct sync_pt *dma_fence_to_sync_pt(struct dma_fence *fence)
6535538d78SGustavo Padovan {
6635538d78SGustavo Padovan 	if (fence->ops != &timeline_fence_ops)
6735538d78SGustavo Padovan 		return NULL;
6835538d78SGustavo Padovan 	return container_of(fence, struct sync_pt, base);
6935538d78SGustavo Padovan }
7035538d78SGustavo Padovan 
7135538d78SGustavo Padovan /**
7235538d78SGustavo Padovan  * sync_timeline_create() - creates a sync object
7335538d78SGustavo Padovan  * @name:	sync_timeline name
7435538d78SGustavo Padovan  *
7535538d78SGustavo Padovan  * Creates a new sync_timeline. Returns the sync_timeline object or NULL in
7635538d78SGustavo Padovan  * case of error.
7735538d78SGustavo Padovan  */
sync_timeline_create(const char * name)7874881588SBaoyou Xie static struct sync_timeline *sync_timeline_create(const char *name)
7935538d78SGustavo Padovan {
8035538d78SGustavo Padovan 	struct sync_timeline *obj;
8135538d78SGustavo Padovan 
8235538d78SGustavo Padovan 	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
8335538d78SGustavo Padovan 	if (!obj)
8435538d78SGustavo Padovan 		return NULL;
8535538d78SGustavo Padovan 
8635538d78SGustavo Padovan 	kref_init(&obj->kref);
87f54d1867SChris Wilson 	obj->context = dma_fence_context_alloc(1);
885565a8e1SAzeem Shaikh 	strscpy(obj->name, name, sizeof(obj->name));
8935538d78SGustavo Padovan 
90f1e8c671SChris Wilson 	obj->pt_tree = RB_ROOT;
91d3862e44SChris Wilson 	INIT_LIST_HEAD(&obj->pt_list);
92d3862e44SChris Wilson 	spin_lock_init(&obj->lock);
9335538d78SGustavo Padovan 
9435538d78SGustavo Padovan 	sync_timeline_debug_add(obj);
9535538d78SGustavo Padovan 
9635538d78SGustavo Padovan 	return obj;
9735538d78SGustavo Padovan }
9835538d78SGustavo Padovan 
sync_timeline_free(struct kref * kref)9935538d78SGustavo Padovan static void sync_timeline_free(struct kref *kref)
10035538d78SGustavo Padovan {
10135538d78SGustavo Padovan 	struct sync_timeline *obj =
10235538d78SGustavo Padovan 		container_of(kref, struct sync_timeline, kref);
10335538d78SGustavo Padovan 
10435538d78SGustavo Padovan 	sync_timeline_debug_remove(obj);
10535538d78SGustavo Padovan 
10635538d78SGustavo Padovan 	kfree(obj);
10735538d78SGustavo Padovan }
10835538d78SGustavo Padovan 
sync_timeline_get(struct sync_timeline * obj)10935538d78SGustavo Padovan static void sync_timeline_get(struct sync_timeline *obj)
11035538d78SGustavo Padovan {
11135538d78SGustavo Padovan 	kref_get(&obj->kref);
11235538d78SGustavo Padovan }
11335538d78SGustavo Padovan 
sync_timeline_put(struct sync_timeline * obj)11435538d78SGustavo Padovan static void sync_timeline_put(struct sync_timeline *obj)
11535538d78SGustavo Padovan {
11635538d78SGustavo Padovan 	kref_put(&obj->kref, sync_timeline_free);
11735538d78SGustavo Padovan }
11835538d78SGustavo Padovan 
timeline_fence_get_driver_name(struct dma_fence * fence)119150b6a9dSGustavo Padovan static const char *timeline_fence_get_driver_name(struct dma_fence *fence)
120150b6a9dSGustavo Padovan {
121150b6a9dSGustavo Padovan 	return "sw_sync";
122150b6a9dSGustavo Padovan }
123150b6a9dSGustavo Padovan 
timeline_fence_get_timeline_name(struct dma_fence * fence)124150b6a9dSGustavo Padovan static const char *timeline_fence_get_timeline_name(struct dma_fence *fence)
125150b6a9dSGustavo Padovan {
126150b6a9dSGustavo Padovan 	struct sync_timeline *parent = dma_fence_parent(fence);
127150b6a9dSGustavo Padovan 
128150b6a9dSGustavo Padovan 	return parent->name;
129150b6a9dSGustavo Padovan }
130150b6a9dSGustavo Padovan 
timeline_fence_release(struct dma_fence * fence)131150b6a9dSGustavo Padovan static void timeline_fence_release(struct dma_fence *fence)
132150b6a9dSGustavo Padovan {
133150b6a9dSGustavo Padovan 	struct sync_pt *pt = dma_fence_to_sync_pt(fence);
134150b6a9dSGustavo Padovan 	struct sync_timeline *parent = dma_fence_parent(fence);
135150b6a9dSGustavo Padovan 	unsigned long flags;
136150b6a9dSGustavo Padovan 
137150b6a9dSGustavo Padovan 	spin_lock_irqsave(fence->lock, flags);
138150b6a9dSGustavo Padovan 	if (!list_empty(&pt->link)) {
139150b6a9dSGustavo Padovan 		list_del(&pt->link);
140150b6a9dSGustavo Padovan 		rb_erase(&pt->node, &parent->pt_tree);
141150b6a9dSGustavo Padovan 	}
142150b6a9dSGustavo Padovan 	spin_unlock_irqrestore(fence->lock, flags);
143150b6a9dSGustavo Padovan 
144150b6a9dSGustavo Padovan 	sync_timeline_put(parent);
145150b6a9dSGustavo Padovan 	dma_fence_free(fence);
146150b6a9dSGustavo Padovan }
147150b6a9dSGustavo Padovan 
timeline_fence_signaled(struct dma_fence * fence)148150b6a9dSGustavo Padovan static bool timeline_fence_signaled(struct dma_fence *fence)
149150b6a9dSGustavo Padovan {
150150b6a9dSGustavo Padovan 	struct sync_timeline *parent = dma_fence_parent(fence);
151150b6a9dSGustavo Padovan 
1525e498abfSChristian König 	return !__dma_fence_is_later(fence->seqno, parent->value, fence->ops);
153150b6a9dSGustavo Padovan }
154150b6a9dSGustavo Padovan 
timeline_fence_enable_signaling(struct dma_fence * fence)155150b6a9dSGustavo Padovan static bool timeline_fence_enable_signaling(struct dma_fence *fence)
156150b6a9dSGustavo Padovan {
157150b6a9dSGustavo Padovan 	return true;
158150b6a9dSGustavo Padovan }
159150b6a9dSGustavo Padovan 
timeline_fence_value_str(struct dma_fence * fence,char * str,int size)160150b6a9dSGustavo Padovan static void timeline_fence_value_str(struct dma_fence *fence,
161150b6a9dSGustavo Padovan 				    char *str, int size)
162150b6a9dSGustavo Padovan {
163b312d8caSChristian König 	snprintf(str, size, "%lld", fence->seqno);
164150b6a9dSGustavo Padovan }
165150b6a9dSGustavo Padovan 
timeline_fence_timeline_value_str(struct dma_fence * fence,char * str,int size)166150b6a9dSGustavo Padovan static void timeline_fence_timeline_value_str(struct dma_fence *fence,
167150b6a9dSGustavo Padovan 					     char *str, int size)
168150b6a9dSGustavo Padovan {
169150b6a9dSGustavo Padovan 	struct sync_timeline *parent = dma_fence_parent(fence);
170150b6a9dSGustavo Padovan 
171150b6a9dSGustavo Padovan 	snprintf(str, size, "%d", parent->value);
172150b6a9dSGustavo Padovan }
173150b6a9dSGustavo Padovan 
174150b6a9dSGustavo Padovan static const struct dma_fence_ops timeline_fence_ops = {
175150b6a9dSGustavo Padovan 	.get_driver_name = timeline_fence_get_driver_name,
176150b6a9dSGustavo Padovan 	.get_timeline_name = timeline_fence_get_timeline_name,
177150b6a9dSGustavo Padovan 	.enable_signaling = timeline_fence_enable_signaling,
178150b6a9dSGustavo Padovan 	.signaled = timeline_fence_signaled,
179150b6a9dSGustavo Padovan 	.release = timeline_fence_release,
180150b6a9dSGustavo Padovan 	.fence_value_str = timeline_fence_value_str,
181150b6a9dSGustavo Padovan 	.timeline_value_str = timeline_fence_timeline_value_str,
182150b6a9dSGustavo Padovan };
183150b6a9dSGustavo Padovan 
18435538d78SGustavo Padovan /**
18535538d78SGustavo Padovan  * sync_timeline_signal() - signal a status change on a sync_timeline
18635538d78SGustavo Padovan  * @obj:	sync_timeline to signal
18735538d78SGustavo Padovan  * @inc:	num to increment on timeline->value
18835538d78SGustavo Padovan  *
18935538d78SGustavo Padovan  * A sync implementation should call this any time one of it's fences
19035538d78SGustavo Padovan  * has signaled or has an error condition.
19135538d78SGustavo Padovan  */
sync_timeline_signal(struct sync_timeline * obj,unsigned int inc)19235538d78SGustavo Padovan static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
19335538d78SGustavo Padovan {
194*e531fdb5SRob Clark 	LIST_HEAD(signalled);
19535538d78SGustavo Padovan 	struct sync_pt *pt, *next;
19635538d78SGustavo Padovan 
19735538d78SGustavo Padovan 	trace_sync_timeline(obj);
19835538d78SGustavo Padovan 
199d3862e44SChris Wilson 	spin_lock_irq(&obj->lock);
20035538d78SGustavo Padovan 
20135538d78SGustavo Padovan 	obj->value += inc;
20235538d78SGustavo Padovan 
203f1e8c671SChris Wilson 	list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
2043792b7c1SGustavo Padovan 		if (!timeline_fence_signaled(&pt->base))
205f1e8c671SChris Wilson 			break;
206f1e8c671SChris Wilson 
207*e531fdb5SRob Clark 		dma_fence_get(&pt->base);
208*e531fdb5SRob Clark 
209*e531fdb5SRob Clark 		list_move_tail(&pt->link, &signalled);
210f1e8c671SChris Wilson 		rb_erase(&pt->node, &obj->pt_tree);
2113792b7c1SGustavo Padovan 
2123792b7c1SGustavo Padovan 		dma_fence_signal_locked(&pt->base);
213f1e8c671SChris Wilson 	}
21435538d78SGustavo Padovan 
215d3862e44SChris Wilson 	spin_unlock_irq(&obj->lock);
216*e531fdb5SRob Clark 
217*e531fdb5SRob Clark 	list_for_each_entry_safe(pt, next, &signalled, link) {
218*e531fdb5SRob Clark 		list_del_init(&pt->link);
219*e531fdb5SRob Clark 		dma_fence_put(&pt->base);
220*e531fdb5SRob Clark 	}
22135538d78SGustavo Padovan }
22235538d78SGustavo Padovan 
22335538d78SGustavo Padovan /**
22435538d78SGustavo Padovan  * sync_pt_create() - creates a sync pt
225b88132b4SChris Wilson  * @obj:	parent sync_timeline
226b88132b4SChris Wilson  * @value:	value of the fence
22735538d78SGustavo Padovan  *
228b88132b4SChris Wilson  * Creates a new sync_pt (fence) as a child of @parent.  @size bytes will be
22935538d78SGustavo Padovan  * allocated allowing for implementation specific data to be kept after
23035538d78SGustavo Padovan  * the generic sync_timeline struct. Returns the sync_pt object or
23135538d78SGustavo Padovan  * NULL in case of error.
23235538d78SGustavo Padovan  */
sync_pt_create(struct sync_timeline * obj,unsigned int value)2333b52ce44SChris Wilson static struct sync_pt *sync_pt_create(struct sync_timeline *obj,
23435538d78SGustavo Padovan 				      unsigned int value)
23535538d78SGustavo Padovan {
23635538d78SGustavo Padovan 	struct sync_pt *pt;
23735538d78SGustavo Padovan 
2383b52ce44SChris Wilson 	pt = kzalloc(sizeof(*pt), GFP_KERNEL);
23935538d78SGustavo Padovan 	if (!pt)
24035538d78SGustavo Padovan 		return NULL;
24135538d78SGustavo Padovan 
24235538d78SGustavo Padovan 	sync_timeline_get(obj);
243d3862e44SChris Wilson 	dma_fence_init(&pt->base, &timeline_fence_ops, &obj->lock,
24435538d78SGustavo Padovan 		       obj->context, value);
245d3862e44SChris Wilson 	INIT_LIST_HEAD(&pt->link);
246a6aa8fcaSChris Wilson 
247d3862e44SChris Wilson 	spin_lock_irq(&obj->lock);
248f1e8c671SChris Wilson 	if (!dma_fence_is_signaled_locked(&pt->base)) {
249f1e8c671SChris Wilson 		struct rb_node **p = &obj->pt_tree.rb_node;
250f1e8c671SChris Wilson 		struct rb_node *parent = NULL;
251f1e8c671SChris Wilson 
252f1e8c671SChris Wilson 		while (*p) {
253f1e8c671SChris Wilson 			struct sync_pt *other;
254f1e8c671SChris Wilson 			int cmp;
255f1e8c671SChris Wilson 
256f1e8c671SChris Wilson 			parent = *p;
257f1e8c671SChris Wilson 			other = rb_entry(parent, typeof(*pt), node);
258f1e8c671SChris Wilson 			cmp = value - other->base.seqno;
259f1e8c671SChris Wilson 			if (cmp > 0) {
260f1e8c671SChris Wilson 				p = &parent->rb_right;
261f1e8c671SChris Wilson 			} else if (cmp < 0) {
262f1e8c671SChris Wilson 				p = &parent->rb_left;
263f1e8c671SChris Wilson 			} else {
264f1e8c671SChris Wilson 				if (dma_fence_get_rcu(&other->base)) {
265d3c6dd1fSChris Wilson 					sync_timeline_put(obj);
266d3c6dd1fSChris Wilson 					kfree(pt);
267f1e8c671SChris Wilson 					pt = other;
268f1e8c671SChris Wilson 					goto unlock;
269f1e8c671SChris Wilson 				}
270f1e8c671SChris Wilson 				p = &parent->rb_left;
271f1e8c671SChris Wilson 			}
272f1e8c671SChris Wilson 		}
273f1e8c671SChris Wilson 		rb_link_node(&pt->node, parent, p);
274f1e8c671SChris Wilson 		rb_insert_color(&pt->node, &obj->pt_tree);
275f1e8c671SChris Wilson 
276f1e8c671SChris Wilson 		parent = rb_next(&pt->node);
277f1e8c671SChris Wilson 		list_add_tail(&pt->link,
278f1e8c671SChris Wilson 			      parent ? &rb_entry(parent, typeof(*pt), node)->link : &obj->pt_list);
279f1e8c671SChris Wilson 	}
280f1e8c671SChris Wilson unlock:
281d3862e44SChris Wilson 	spin_unlock_irq(&obj->lock);
282a6aa8fcaSChris Wilson 
28335538d78SGustavo Padovan 	return pt;
28435538d78SGustavo Padovan }
28535538d78SGustavo Padovan 
28635538d78SGustavo Padovan /*
28735538d78SGustavo Padovan  * *WARNING*
28835538d78SGustavo Padovan  *
28935538d78SGustavo Padovan  * improper use of this can result in deadlocking kernel drivers from userspace.
29035538d78SGustavo Padovan  */
29135538d78SGustavo Padovan 
29235538d78SGustavo Padovan /* opening sw_sync create a new sync obj */
sw_sync_debugfs_open(struct inode * inode,struct file * file)29335538d78SGustavo Padovan static int sw_sync_debugfs_open(struct inode *inode, struct file *file)
29435538d78SGustavo Padovan {
29535538d78SGustavo Padovan 	struct sync_timeline *obj;
29635538d78SGustavo Padovan 	char task_comm[TASK_COMM_LEN];
29735538d78SGustavo Padovan 
29835538d78SGustavo Padovan 	get_task_comm(task_comm, current);
29935538d78SGustavo Padovan 
30035538d78SGustavo Padovan 	obj = sync_timeline_create(task_comm);
30135538d78SGustavo Padovan 	if (!obj)
30235538d78SGustavo Padovan 		return -ENOMEM;
30335538d78SGustavo Padovan 
30435538d78SGustavo Padovan 	file->private_data = obj;
30535538d78SGustavo Padovan 
30635538d78SGustavo Padovan 	return 0;
30735538d78SGustavo Padovan }
30835538d78SGustavo Padovan 
sw_sync_debugfs_release(struct inode * inode,struct file * file)30935538d78SGustavo Padovan static int sw_sync_debugfs_release(struct inode *inode, struct file *file)
31035538d78SGustavo Padovan {
31135538d78SGustavo Padovan 	struct sync_timeline *obj = file->private_data;
312ea4d5a27SDominik Behr 	struct sync_pt *pt, *next;
31335538d78SGustavo Padovan 
314ea4d5a27SDominik Behr 	spin_lock_irq(&obj->lock);
315ea4d5a27SDominik Behr 
316ea4d5a27SDominik Behr 	list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
317ea4d5a27SDominik Behr 		dma_fence_set_error(&pt->base, -ENOENT);
318ea4d5a27SDominik Behr 		dma_fence_signal_locked(&pt->base);
319ea4d5a27SDominik Behr 	}
320ea4d5a27SDominik Behr 
321ea4d5a27SDominik Behr 	spin_unlock_irq(&obj->lock);
32235538d78SGustavo Padovan 
32335538d78SGustavo Padovan 	sync_timeline_put(obj);
32435538d78SGustavo Padovan 	return 0;
32535538d78SGustavo Padovan }
32635538d78SGustavo Padovan 
sw_sync_ioctl_create_fence(struct sync_timeline * obj,unsigned long arg)32735538d78SGustavo Padovan static long sw_sync_ioctl_create_fence(struct sync_timeline *obj,
32835538d78SGustavo Padovan 				       unsigned long arg)
32935538d78SGustavo Padovan {
33035538d78SGustavo Padovan 	int fd = get_unused_fd_flags(O_CLOEXEC);
33135538d78SGustavo Padovan 	int err;
33235538d78SGustavo Padovan 	struct sync_pt *pt;
33335538d78SGustavo Padovan 	struct sync_file *sync_file;
33435538d78SGustavo Padovan 	struct sw_sync_create_fence_data data;
33535538d78SGustavo Padovan 
33635538d78SGustavo Padovan 	if (fd < 0)
33735538d78SGustavo Padovan 		return fd;
33835538d78SGustavo Padovan 
33935538d78SGustavo Padovan 	if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
34035538d78SGustavo Padovan 		err = -EFAULT;
34135538d78SGustavo Padovan 		goto err;
34235538d78SGustavo Padovan 	}
34335538d78SGustavo Padovan 
3443b52ce44SChris Wilson 	pt = sync_pt_create(obj, data.value);
34535538d78SGustavo Padovan 	if (!pt) {
34635538d78SGustavo Padovan 		err = -ENOMEM;
34735538d78SGustavo Padovan 		goto err;
34835538d78SGustavo Padovan 	}
34935538d78SGustavo Padovan 
35035538d78SGustavo Padovan 	sync_file = sync_file_create(&pt->base);
351f54d1867SChris Wilson 	dma_fence_put(&pt->base);
3524592bfcdSGustavo Padovan 	if (!sync_file) {
35335538d78SGustavo Padovan 		err = -ENOMEM;
35435538d78SGustavo Padovan 		goto err;
35535538d78SGustavo Padovan 	}
35635538d78SGustavo Padovan 
35735538d78SGustavo Padovan 	data.fence = fd;
35835538d78SGustavo Padovan 	if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
35935538d78SGustavo Padovan 		fput(sync_file->file);
36035538d78SGustavo Padovan 		err = -EFAULT;
36135538d78SGustavo Padovan 		goto err;
36235538d78SGustavo Padovan 	}
36335538d78SGustavo Padovan 
36435538d78SGustavo Padovan 	fd_install(fd, sync_file->file);
36535538d78SGustavo Padovan 
36635538d78SGustavo Padovan 	return 0;
36735538d78SGustavo Padovan 
36835538d78SGustavo Padovan err:
36935538d78SGustavo Padovan 	put_unused_fd(fd);
37035538d78SGustavo Padovan 	return err;
37135538d78SGustavo Padovan }
37235538d78SGustavo Padovan 
sw_sync_ioctl_inc(struct sync_timeline * obj,unsigned long arg)37335538d78SGustavo Padovan static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg)
37435538d78SGustavo Padovan {
37535538d78SGustavo Padovan 	u32 value;
37635538d78SGustavo Padovan 
37735538d78SGustavo Padovan 	if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
37835538d78SGustavo Padovan 		return -EFAULT;
37935538d78SGustavo Padovan 
3808f66d3aaSChris Wilson 	while (value > INT_MAX)  {
3818f66d3aaSChris Wilson 		sync_timeline_signal(obj, INT_MAX);
3828f66d3aaSChris Wilson 		value -= INT_MAX;
3838f66d3aaSChris Wilson 	}
3848f66d3aaSChris Wilson 
38535538d78SGustavo Padovan 	sync_timeline_signal(obj, value);
38635538d78SGustavo Padovan 
38735538d78SGustavo Padovan 	return 0;
38835538d78SGustavo Padovan }
38935538d78SGustavo Padovan 
sw_sync_ioctl(struct file * file,unsigned int cmd,unsigned long arg)39035538d78SGustavo Padovan static long sw_sync_ioctl(struct file *file, unsigned int cmd,
39135538d78SGustavo Padovan 			  unsigned long arg)
39235538d78SGustavo Padovan {
39335538d78SGustavo Padovan 	struct sync_timeline *obj = file->private_data;
39435538d78SGustavo Padovan 
39535538d78SGustavo Padovan 	switch (cmd) {
39635538d78SGustavo Padovan 	case SW_SYNC_IOC_CREATE_FENCE:
39735538d78SGustavo Padovan 		return sw_sync_ioctl_create_fence(obj, arg);
39835538d78SGustavo Padovan 
39935538d78SGustavo Padovan 	case SW_SYNC_IOC_INC:
40035538d78SGustavo Padovan 		return sw_sync_ioctl_inc(obj, arg);
40135538d78SGustavo Padovan 
40235538d78SGustavo Padovan 	default:
40335538d78SGustavo Padovan 		return -ENOTTY;
40435538d78SGustavo Padovan 	}
40535538d78SGustavo Padovan }
40635538d78SGustavo Padovan 
40735538d78SGustavo Padovan const struct file_operations sw_sync_debugfs_fops = {
40835538d78SGustavo Padovan 	.open           = sw_sync_debugfs_open,
40935538d78SGustavo Padovan 	.release        = sw_sync_debugfs_release,
41035538d78SGustavo Padovan 	.unlocked_ioctl = sw_sync_ioctl,
4111832f2d8SArnd Bergmann 	.compat_ioctl	= compat_ptr_ioctl,
41235538d78SGustavo Padovan };
413