2 * drivers/base/sw_sync.c
4 * Copyright (C) 2012 Google, Inc.
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.
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.
17 #include <linux/kernel.h>
18 #include <linux/file.h>
20 #include <linux/miscdevice.h>
21 #include <linux/module.h>
22 #include <linux/sw_sync.h>
23 #include <linux/syscalls.h>
24 #include <linux/uaccess.h>
26 static int sw_sync_cmp(u32 a
, u32 b
)
31 return ((s32
)a
- (s32
)b
) < 0 ? -1 : 1;
34 struct sync_pt
*sw_sync_pt_create(struct sw_sync_timeline
*obj
, u32 value
)
36 struct sw_sync_pt
*pt
;
38 pt
= (struct sw_sync_pt
*)
39 sync_pt_create(&obj
->obj
, sizeof(struct sw_sync_pt
));
43 return (struct sync_pt
*)pt
;
46 static struct sync_pt
*sw_sync_pt_dup(struct sync_pt
*sync_pt
)
48 struct sw_sync_pt
*pt
= (struct sw_sync_pt
*) sync_pt
;
49 struct sw_sync_timeline
*obj
=
50 (struct sw_sync_timeline
*)sync_pt
->parent
;
52 return (struct sync_pt
*) sw_sync_pt_create(obj
, pt
->value
);
55 static int sw_sync_pt_has_signaled(struct sync_pt
*sync_pt
)
57 struct sw_sync_pt
*pt
= (struct sw_sync_pt
*)sync_pt
;
58 struct sw_sync_timeline
*obj
=
59 (struct sw_sync_timeline
*)sync_pt
->parent
;
61 return sw_sync_cmp(obj
->value
, pt
->value
) >= 0;
64 static int sw_sync_pt_compare(struct sync_pt
*a
, struct sync_pt
*b
)
66 struct sw_sync_pt
*pt_a
= (struct sw_sync_pt
*)a
;
67 struct sw_sync_pt
*pt_b
= (struct sw_sync_pt
*)b
;
69 return sw_sync_cmp(pt_a
->value
, pt_b
->value
);
72 static void sw_sync_print_obj(struct seq_file
*s
,
73 struct sync_timeline
*sync_timeline
)
75 struct sw_sync_timeline
*obj
= (struct sw_sync_timeline
*)sync_timeline
;
77 seq_printf(s
, "%d", obj
->value
);
80 static void sw_sync_print_pt(struct seq_file
*s
, struct sync_pt
*sync_pt
)
82 struct sw_sync_pt
*pt
= (struct sw_sync_pt
*)sync_pt
;
83 struct sw_sync_timeline
*obj
=
84 (struct sw_sync_timeline
*)sync_pt
->parent
;
86 seq_printf(s
, "%d / %d", pt
->value
, obj
->value
);
89 static int sw_sync_fill_driver_data(struct sync_pt
*sync_pt
,
92 struct sw_sync_pt
*pt
= (struct sw_sync_pt
*)sync_pt
;
94 if (size
< sizeof(pt
->value
))
97 memcpy(data
, &pt
->value
, sizeof(pt
->value
));
99 return sizeof(pt
->value
);
102 struct sync_timeline_ops sw_sync_timeline_ops
= {
103 .driver_name
= "sw_sync",
104 .dup
= sw_sync_pt_dup
,
105 .has_signaled
= sw_sync_pt_has_signaled
,
106 .compare
= sw_sync_pt_compare
,
107 .print_obj
= sw_sync_print_obj
,
108 .print_pt
= sw_sync_print_pt
,
109 .fill_driver_data
= sw_sync_fill_driver_data
,
113 struct sw_sync_timeline
*sw_sync_timeline_create(const char *name
)
115 struct sw_sync_timeline
*obj
= (struct sw_sync_timeline
*)
116 sync_timeline_create(&sw_sync_timeline_ops
,
117 sizeof(struct sw_sync_timeline
),
123 void sw_sync_timeline_inc(struct sw_sync_timeline
*obj
, u32 inc
)
127 sync_timeline_signal(&obj
->obj
);
131 #ifdef CONFIG_SW_SYNC_USER
134 * improper use of this can result in deadlocking kernel drivers from userspace.
137 /* opening sw_sync create a new sync obj */
138 int sw_sync_open(struct inode
*inode
, struct file
*file
)
140 struct sw_sync_timeline
*obj
;
141 char task_comm
[TASK_COMM_LEN
];
143 get_task_comm(task_comm
, current
);
145 obj
= sw_sync_timeline_create(task_comm
);
149 file
->private_data
= obj
;
154 int sw_sync_release(struct inode
*inode
, struct file
*file
)
156 struct sw_sync_timeline
*obj
= file
->private_data
;
157 sync_timeline_destroy(&obj
->obj
);
161 long sw_sync_ioctl_create_fence(struct sw_sync_timeline
*obj
, unsigned long arg
)
163 int fd
= get_unused_fd();
166 struct sync_fence
*fence
;
167 struct sw_sync_create_fence_data data
;
169 if (copy_from_user(&data
, (void __user
*)arg
, sizeof(data
)))
172 pt
= sw_sync_pt_create(obj
, data
.value
);
178 data
.name
[sizeof(data
.name
) - 1] = '\0';
179 fence
= sync_fence_create(data
.name
, pt
);
187 if (copy_to_user((void __user
*)arg
, &data
, sizeof(data
))) {
188 sync_fence_put(fence
);
193 sync_fence_install(fence
, fd
);
202 long sw_sync_ioctl_inc(struct sw_sync_timeline
*obj
, unsigned long arg
)
206 if (copy_from_user(&value
, (void __user
*)arg
, sizeof(value
)))
209 sw_sync_timeline_inc(obj
, value
);
214 long sw_sync_ioctl(struct file
*file
, unsigned int cmd
, unsigned long arg
)
216 struct sw_sync_timeline
*obj
= file
->private_data
;
219 case SW_SYNC_IOC_CREATE_FENCE
:
220 return sw_sync_ioctl_create_fence(obj
, arg
);
222 case SW_SYNC_IOC_INC
:
223 return sw_sync_ioctl_inc(obj
, arg
);
230 static const struct file_operations sw_sync_fops
= {
231 .owner
= THIS_MODULE
,
232 .open
= sw_sync_open
,
233 .release
= sw_sync_release
,
234 .unlocked_ioctl
= sw_sync_ioctl
,
237 static struct miscdevice sw_sync_dev
= {
238 .minor
= MISC_DYNAMIC_MINOR
,
240 .fops
= &sw_sync_fops
,
243 int __init
sw_sync_device_init(void)
245 return misc_register(&sw_sync_dev
);
248 void __exit
sw_sync_device_remove(void)
250 misc_deregister(&sw_sync_dev
);
253 module_init(sw_sync_device_init
);
254 module_exit(sw_sync_device_remove
);
256 #endif /* CONFIG_SW_SYNC_USER */