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/export.h>
19 #include <linux/file.h>
21 #include <linux/miscdevice.h>
22 #include <linux/module.h>
23 #include <linux/syscalls.h>
24 #include <linux/uaccess.h>
28 static int sw_sync_cmp(u32 a
, u32 b
)
33 return ((s32
)a
- (s32
)b
) < 0 ? -1 : 1;
36 struct sync_pt
*sw_sync_pt_create(struct sw_sync_timeline
*obj
, u32 value
)
38 struct sw_sync_pt
*pt
;
40 pt
= (struct sw_sync_pt
*)
41 sync_pt_create(&obj
->obj
, sizeof(struct sw_sync_pt
));
45 return (struct sync_pt
*)pt
;
47 EXPORT_SYMBOL(sw_sync_pt_create
);
49 static struct sync_pt
*sw_sync_pt_dup(struct sync_pt
*sync_pt
)
51 struct sw_sync_pt
*pt
= (struct sw_sync_pt
*) sync_pt
;
52 struct sw_sync_timeline
*obj
=
53 (struct sw_sync_timeline
*)sync_pt
->parent
;
55 return (struct sync_pt
*) sw_sync_pt_create(obj
, pt
->value
);
58 static int sw_sync_pt_has_signaled(struct sync_pt
*sync_pt
)
60 struct sw_sync_pt
*pt
= (struct sw_sync_pt
*)sync_pt
;
61 struct sw_sync_timeline
*obj
=
62 (struct sw_sync_timeline
*)sync_pt
->parent
;
64 return sw_sync_cmp(obj
->value
, pt
->value
) >= 0;
67 static int sw_sync_pt_compare(struct sync_pt
*a
, struct sync_pt
*b
)
69 struct sw_sync_pt
*pt_a
= (struct sw_sync_pt
*)a
;
70 struct sw_sync_pt
*pt_b
= (struct sw_sync_pt
*)b
;
72 return sw_sync_cmp(pt_a
->value
, pt_b
->value
);
75 static int sw_sync_fill_driver_data(struct sync_pt
*sync_pt
,
78 struct sw_sync_pt
*pt
= (struct sw_sync_pt
*)sync_pt
;
80 if (size
< sizeof(pt
->value
))
83 memcpy(data
, &pt
->value
, sizeof(pt
->value
));
85 return sizeof(pt
->value
);
88 static void sw_sync_timeline_value_str(struct sync_timeline
*sync_timeline
,
91 struct sw_sync_timeline
*timeline
=
92 (struct sw_sync_timeline
*)sync_timeline
;
93 snprintf(str
, size
, "%d", timeline
->value
);
96 static void sw_sync_pt_value_str(struct sync_pt
*sync_pt
,
99 struct sw_sync_pt
*pt
= (struct sw_sync_pt
*)sync_pt
;
100 snprintf(str
, size
, "%d", pt
->value
);
103 static struct sync_timeline_ops sw_sync_timeline_ops
= {
104 .driver_name
= "sw_sync",
105 .dup
= sw_sync_pt_dup
,
106 .has_signaled
= sw_sync_pt_has_signaled
,
107 .compare
= sw_sync_pt_compare
,
108 .fill_driver_data
= sw_sync_fill_driver_data
,
109 .timeline_value_str
= sw_sync_timeline_value_str
,
110 .pt_value_str
= sw_sync_pt_value_str
,
114 struct sw_sync_timeline
*sw_sync_timeline_create(const char *name
)
116 struct sw_sync_timeline
*obj
= (struct sw_sync_timeline
*)
117 sync_timeline_create(&sw_sync_timeline_ops
,
118 sizeof(struct sw_sync_timeline
),
123 EXPORT_SYMBOL(sw_sync_timeline_create
);
125 void sw_sync_timeline_inc(struct sw_sync_timeline
*obj
, u32 inc
)
129 sync_timeline_signal(&obj
->obj
);
131 EXPORT_SYMBOL(sw_sync_timeline_inc
);
133 #ifdef CONFIG_SW_SYNC_USER
136 * improper use of this can result in deadlocking kernel drivers from userspace.
139 /* opening sw_sync create a new sync obj */
140 static int sw_sync_open(struct inode
*inode
, struct file
*file
)
142 struct sw_sync_timeline
*obj
;
143 char task_comm
[TASK_COMM_LEN
];
145 get_task_comm(task_comm
, current
);
147 obj
= sw_sync_timeline_create(task_comm
);
151 file
->private_data
= obj
;
156 static int sw_sync_release(struct inode
*inode
, struct file
*file
)
158 struct sw_sync_timeline
*obj
= file
->private_data
;
159 sync_timeline_destroy(&obj
->obj
);
163 static long sw_sync_ioctl_create_fence(struct sw_sync_timeline
*obj
,
166 int fd
= get_unused_fd_flags(O_CLOEXEC
);
169 struct sync_fence
*fence
;
170 struct sw_sync_create_fence_data data
;
175 if (copy_from_user(&data
, (void __user
*)arg
, sizeof(data
))) {
180 pt
= sw_sync_pt_create(obj
, data
.value
);
186 data
.name
[sizeof(data
.name
) - 1] = '\0';
187 fence
= sync_fence_create(data
.name
, pt
);
195 if (copy_to_user((void __user
*)arg
, &data
, sizeof(data
))) {
196 sync_fence_put(fence
);
201 sync_fence_install(fence
, fd
);
210 static long sw_sync_ioctl_inc(struct sw_sync_timeline
*obj
, unsigned long arg
)
214 if (copy_from_user(&value
, (void __user
*)arg
, sizeof(value
)))
217 sw_sync_timeline_inc(obj
, value
);
222 static long sw_sync_ioctl(struct file
*file
, unsigned int cmd
,
225 struct sw_sync_timeline
*obj
= file
->private_data
;
228 case SW_SYNC_IOC_CREATE_FENCE
:
229 return sw_sync_ioctl_create_fence(obj
, arg
);
231 case SW_SYNC_IOC_INC
:
232 return sw_sync_ioctl_inc(obj
, arg
);
239 static const struct file_operations sw_sync_fops
= {
240 .owner
= THIS_MODULE
,
241 .open
= sw_sync_open
,
242 .release
= sw_sync_release
,
243 .unlocked_ioctl
= sw_sync_ioctl
,
244 .compat_ioctl
= sw_sync_ioctl
,
247 static struct miscdevice sw_sync_dev
= {
248 .minor
= MISC_DYNAMIC_MINOR
,
250 .fops
= &sw_sync_fops
,
253 static int __init
sw_sync_device_init(void)
255 return misc_register(&sw_sync_dev
);
258 static void __exit
sw_sync_device_remove(void)
260 misc_deregister(&sw_sync_dev
);
263 module_init(sw_sync_device_init
);
264 module_exit(sw_sync_device_remove
);
266 #endif /* CONFIG_SW_SYNC_USER */