blob: 6282046ec13233501c5eec7e4fe225d0bf5f5794 [file] [log] [blame]
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +02001/*
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>
Tapasweni Pathak353fdf12014-10-26 19:20:16 +053028#include <linux/time64.h>
Gustavo Padovan460bfc42016-04-28 10:46:57 -030029#include <linux/sync_file.h>
Gustavo Padovand21858f2016-05-31 16:59:00 -030030#include <linux/types.h>
31#include <linux/kconfig.h>
32
33#include "uapi/sw_sync.h"
34#include "sync.h"
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020035
36#ifdef CONFIG_DEBUG_FS
37
Gustavo Padovan8a004482016-01-21 10:49:17 -020038static struct dentry *dbgfs;
39
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020040static LIST_HEAD(sync_timeline_list_head);
41static DEFINE_SPINLOCK(sync_timeline_list_lock);
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -020042static LIST_HEAD(sync_file_list_head);
43static DEFINE_SPINLOCK(sync_file_list_lock);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020044
45void sync_timeline_debug_add(struct sync_timeline *obj)
46{
47 unsigned long flags;
48
49 spin_lock_irqsave(&sync_timeline_list_lock, flags);
50 list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head);
51 spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
52}
53
54void sync_timeline_debug_remove(struct sync_timeline *obj)
55{
56 unsigned long flags;
57
58 spin_lock_irqsave(&sync_timeline_list_lock, flags);
59 list_del(&obj->sync_timeline_list);
60 spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
61}
62
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -020063void sync_file_debug_add(struct sync_file *sync_file)
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020064{
65 unsigned long flags;
66
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -020067 spin_lock_irqsave(&sync_file_list_lock, flags);
68 list_add_tail(&sync_file->sync_file_list, &sync_file_list_head);
69 spin_unlock_irqrestore(&sync_file_list_lock, flags);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020070}
71
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -020072void sync_file_debug_remove(struct sync_file *sync_file)
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020073{
74 unsigned long flags;
75
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -020076 spin_lock_irqsave(&sync_file_list_lock, flags);
77 list_del(&sync_file->sync_file_list);
78 spin_unlock_irqrestore(&sync_file_list_lock, flags);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020079}
80
81static const char *sync_status_str(int status)
82{
83 if (status == 0)
84 return "signaled";
Peter Senna Tschudin95451352014-07-12 21:55:56 +020085
86 if (status > 0)
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020087 return "active";
Peter Senna Tschudin95451352014-07-12 21:55:56 +020088
89 return "error";
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020090}
91
Gustavo Padovanb55b54b2016-01-21 10:49:21 -020092static void sync_print_fence(struct seq_file *s, struct fence *fence, bool show)
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020093{
94 int status = 1;
Gustavo Padovanb55b54b2016-01-21 10:49:21 -020095 struct sync_timeline *parent = fence_parent(fence);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020096
Gustavo Padovanb55b54b2016-01-21 10:49:21 -020097 if (fence_is_signaled_locked(fence))
98 status = fence->status;
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +020099
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200100 seq_printf(s, " %s%sfence %s",
101 show ? parent->name : "",
102 show ? "_" : "",
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200103 sync_status_str(status));
104
105 if (status <= 0) {
Steve Pennington0541cdf2014-12-24 09:33:02 -0600106 struct timespec64 ts64 =
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200107 ktime_to_timespec64(fence->timestamp);
Peter Senna Tschudin95451352014-07-12 21:55:56 +0200108
Tapasweni Pathak353fdf12014-10-26 19:20:16 +0530109 seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200110 }
111
Gustavo Padovan724812d2016-05-31 16:59:02 -0300112 if (fence->ops->timeline_value_str &&
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200113 fence->ops->fence_value_str) {
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200114 char value[64];
Maarten Lankhorst73465f12015-12-11 13:11:49 +0000115 bool success;
Peter Senna Tschudin95451352014-07-12 21:55:56 +0200116
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200117 fence->ops->fence_value_str(fence, value, sizeof(value));
Maarten Lankhorst73465f12015-12-11 13:11:49 +0000118 success = strlen(value);
119
Gustavo Padovan724812d2016-05-31 16:59:02 -0300120 if (success) {
Maarten Lankhorst73465f12015-12-11 13:11:49 +0000121 seq_printf(s, ": %s", value);
122
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200123 fence->ops->timeline_value_str(fence, value,
124 sizeof(value));
Maarten Lankhorst73465f12015-12-11 13:11:49 +0000125
126 if (strlen(value))
127 seq_printf(s, " / %s", value);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200128 }
129 }
130
131 seq_puts(s, "\n");
132}
133
134static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
135{
136 struct list_head *pos;
137 unsigned long flags;
138
Gustavo Padovanef30afe2016-05-31 16:58:58 -0300139 seq_printf(s, "%s %s: %d\n", obj->name, obj->drv_name, obj->value);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200140
141 spin_lock_irqsave(&obj->child_list_lock, flags);
142 list_for_each(pos, &obj->child_list_head) {
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200143 struct fence *fence =
144 container_of(pos, struct fence, child_list);
145 sync_print_fence(s, fence, false);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200146 }
147 spin_unlock_irqrestore(&obj->child_list_lock, flags);
148}
149
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -0200150static void sync_print_sync_file(struct seq_file *s,
151 struct sync_file *sync_file)
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200152{
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200153 int i;
154
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -0200155 seq_printf(s, "[%p] %s: %s\n", sync_file, sync_file->name,
156 sync_status_str(atomic_read(&sync_file->status)));
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200157
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -0200158 for (i = 0; i < sync_file->num_fences; ++i)
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200159 sync_print_fence(s, sync_file->cbs[i].fence, true);
160}
161
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200162static int sync_debugfs_show(struct seq_file *s, void *unused)
163{
164 unsigned long flags;
165 struct list_head *pos;
166
167 seq_puts(s, "objs:\n--------------\n");
168
169 spin_lock_irqsave(&sync_timeline_list_lock, flags);
170 list_for_each(pos, &sync_timeline_list_head) {
171 struct sync_timeline *obj =
172 container_of(pos, struct sync_timeline,
173 sync_timeline_list);
174
175 sync_print_obj(s, obj);
176 seq_puts(s, "\n");
177 }
178 spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
179
180 seq_puts(s, "fences:\n--------------\n");
181
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -0200182 spin_lock_irqsave(&sync_file_list_lock, flags);
183 list_for_each(pos, &sync_file_list_head) {
184 struct sync_file *sync_file =
185 container_of(pos, struct sync_file, sync_file_list);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200186
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -0200187 sync_print_sync_file(s, sync_file);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200188 seq_puts(s, "\n");
189 }
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -0200190 spin_unlock_irqrestore(&sync_file_list_lock, flags);
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200191 return 0;
192}
193
Gustavo Padovan8a004482016-01-21 10:49:17 -0200194static int sync_info_debugfs_open(struct inode *inode, struct file *file)
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200195{
196 return single_open(file, sync_debugfs_show, inode->i_private);
197}
198
Gustavo Padovan8a004482016-01-21 10:49:17 -0200199static const struct file_operations sync_info_debugfs_fops = {
200 .open = sync_info_debugfs_open,
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200201 .read = seq_read,
202 .llseek = seq_lseek,
203 .release = single_release,
204};
205
Gustavo Padovand21858f2016-05-31 16:59:00 -0300206#if IS_ENABLED(CONFIG_SW_SYNC)
Gustavo Padovana44eb742016-01-21 10:49:18 -0200207/*
208 * *WARNING*
209 *
210 * improper use of this can result in deadlocking kernel drivers from userspace.
211 */
212
213/* opening sw_sync create a new sync obj */
214static int sw_sync_debugfs_open(struct inode *inode, struct file *file)
215{
Gustavo Padovandcc28082016-05-31 16:58:59 -0300216 struct sync_timeline *obj;
Gustavo Padovana44eb742016-01-21 10:49:18 -0200217 char task_comm[TASK_COMM_LEN];
218
219 get_task_comm(task_comm, current);
220
Gustavo Padovand21858f2016-05-31 16:59:00 -0300221 obj = sync_timeline_create(sizeof(*obj), "sw_sync", task_comm);
Gustavo Padovana44eb742016-01-21 10:49:18 -0200222 if (!obj)
223 return -ENOMEM;
224
225 file->private_data = obj;
226
227 return 0;
228}
229
230static int sw_sync_debugfs_release(struct inode *inode, struct file *file)
231{
Gustavo Padovandcc28082016-05-31 16:58:59 -0300232 struct sync_timeline *obj = file->private_data;
Gustavo Padovana44eb742016-01-21 10:49:18 -0200233
Gustavo Padovandcc28082016-05-31 16:58:59 -0300234 sync_timeline_destroy(obj);
Gustavo Padovana44eb742016-01-21 10:49:18 -0200235 return 0;
236}
237
Gustavo Padovandcc28082016-05-31 16:58:59 -0300238static long sw_sync_ioctl_create_fence(struct sync_timeline *obj,
Gustavo Padovana44eb742016-01-21 10:49:18 -0200239 unsigned long arg)
240{
241 int fd = get_unused_fd_flags(O_CLOEXEC);
242 int err;
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200243 struct fence *fence;
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -0200244 struct sync_file *sync_file;
Gustavo Padovana44eb742016-01-21 10:49:18 -0200245 struct sw_sync_create_fence_data data;
246
247 if (fd < 0)
248 return fd;
249
250 if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
251 err = -EFAULT;
252 goto err;
253 }
254
Gustavo Padovand21858f2016-05-31 16:59:00 -0300255 fence = sync_pt_create(obj, sizeof(*fence), data.value);
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200256 if (!fence) {
Gustavo Padovana44eb742016-01-21 10:49:18 -0200257 err = -ENOMEM;
258 goto err;
259 }
260
Gustavo Padovand7c31102016-04-28 10:46:53 -0300261 sync_file = sync_file_create(fence);
Gustavo Padovand7fdb0a2016-01-21 10:49:19 -0200262 if (!sync_file) {
Gustavo Padovanb55b54b2016-01-21 10:49:21 -0200263 fence_put(fence);
Gustavo Padovana44eb742016-01-21 10:49:18 -0200264 err = -ENOMEM;
265 goto err;
266 }
267
268 data.fence = fd;
269 if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
Gustavo Padovan2a7c1db2016-04-28 10:46:49 -0300270 fput(sync_file->file);
Gustavo Padovana44eb742016-01-21 10:49:18 -0200271 err = -EFAULT;
272 goto err;
273 }
274
Gustavo Padovan2a7c1db2016-04-28 10:46:49 -0300275 fd_install(fd, sync_file->file);
Gustavo Padovana44eb742016-01-21 10:49:18 -0200276
277 return 0;
278
279err:
280 put_unused_fd(fd);
281 return err;
282}
283
Gustavo Padovandcc28082016-05-31 16:58:59 -0300284static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg)
Gustavo Padovana44eb742016-01-21 10:49:18 -0200285{
286 u32 value;
287
288 if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
289 return -EFAULT;
290
Gustavo Padovand21858f2016-05-31 16:59:00 -0300291 sync_timeline_signal(obj, value);
Gustavo Padovana44eb742016-01-21 10:49:18 -0200292
293 return 0;
294}
295
296static long sw_sync_ioctl(struct file *file, unsigned int cmd,
297 unsigned long arg)
298{
Gustavo Padovandcc28082016-05-31 16:58:59 -0300299 struct sync_timeline *obj = file->private_data;
Gustavo Padovana44eb742016-01-21 10:49:18 -0200300
301 switch (cmd) {
302 case SW_SYNC_IOC_CREATE_FENCE:
303 return sw_sync_ioctl_create_fence(obj, arg);
304
305 case SW_SYNC_IOC_INC:
306 return sw_sync_ioctl_inc(obj, arg);
307
308 default:
309 return -ENOTTY;
310 }
311}
312
313static const struct file_operations sw_sync_debugfs_fops = {
314 .open = sw_sync_debugfs_open,
315 .release = sw_sync_debugfs_release,
316 .unlocked_ioctl = sw_sync_ioctl,
317 .compat_ioctl = sw_sync_ioctl,
318};
Gustavo Padovand21858f2016-05-31 16:59:00 -0300319#endif
Gustavo Padovana44eb742016-01-21 10:49:18 -0200320
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200321static __init int sync_debugfs_init(void)
322{
Gustavo Padovan8a004482016-01-21 10:49:17 -0200323 dbgfs = debugfs_create_dir("sync", NULL);
324
325 debugfs_create_file("info", 0444, dbgfs, NULL, &sync_info_debugfs_fops);
Gustavo Padovand21858f2016-05-31 16:59:00 -0300326
327#if IS_ENABLED(CONFIG_SW_SYNC)
Gustavo Padovana44eb742016-01-21 10:49:18 -0200328 debugfs_create_file("sw_sync", 0644, dbgfs, NULL,
329 &sw_sync_debugfs_fops);
Gustavo Padovand21858f2016-05-31 16:59:00 -0300330#endif
Gustavo Padovan8a004482016-01-21 10:49:17 -0200331
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200332 return 0;
333}
334late_initcall(sync_debugfs_init);
335
336#define DUMP_CHUNK 256
337static char sync_dump_buf[64 * 1024];
338void sync_dump(void)
339{
340 struct seq_file s = {
341 .buf = sync_dump_buf,
342 .size = sizeof(sync_dump_buf) - 1,
343 };
344 int i;
345
346 sync_debugfs_show(&s, NULL);
347
348 for (i = 0; i < s.count; i += DUMP_CHUNK) {
349 if ((s.count - i) > DUMP_CHUNK) {
350 char c = s.buf[i + DUMP_CHUNK];
Peter Senna Tschudin95451352014-07-12 21:55:56 +0200351
Maarten Lankhorst0f0d8402014-07-01 12:57:31 +0200352 s.buf[i + DUMP_CHUNK] = 0;
353 pr_cont("%s", s.buf + i);
354 s.buf[i + DUMP_CHUNK] = c;
355 } else {
356 s.buf[s.count] = 0;
357 pr_cont("%s", s.buf + i);
358 }
359 }
360}
361
362#endif