dc85d5f8cbd07f678a942c113b1ac27ea12e8ccb
[cascardo/linux.git] / drivers / staging / android / sync_debug.c
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 #include <linux/time64.h>
29 #include <linux/sync_file.h>
30 #include <linux/types.h>
31 #include <linux/kconfig.h>
32
33 #include "uapi/sw_sync.h"
34 #include "sync.h"
35
36 #ifdef CONFIG_DEBUG_FS
37
38 static struct dentry *dbgfs;
39
40 static LIST_HEAD(sync_timeline_list_head);
41 static DEFINE_SPINLOCK(sync_timeline_list_lock);
42 static LIST_HEAD(sync_file_list_head);
43 static DEFINE_SPINLOCK(sync_file_list_lock);
44
45 void 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
54 void 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
63 void sync_file_debug_add(struct sync_file *sync_file)
64 {
65         unsigned long flags;
66
67         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);
70 }
71
72 void sync_file_debug_remove(struct sync_file *sync_file)
73 {
74         unsigned long flags;
75
76         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);
79 }
80
81 static const char *sync_status_str(int status)
82 {
83         if (status == 0)
84                 return "signaled";
85
86         if (status > 0)
87                 return "active";
88
89         return "error";
90 }
91
92 static void sync_print_fence(struct seq_file *s, struct fence *fence, bool show)
93 {
94         int status = 1;
95         struct sync_timeline *parent = fence_parent(fence);
96
97         if (fence_is_signaled_locked(fence))
98                 status = fence->status;
99
100         seq_printf(s, "  %s%sfence %s",
101                    show ? parent->name : "",
102                    show ? "_" : "",
103                    sync_status_str(status));
104
105         if (status <= 0) {
106                 struct timespec64 ts64 =
107                         ktime_to_timespec64(fence->timestamp);
108
109                 seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
110         }
111
112         if ((!fence || fence->ops->timeline_value_str) &&
113                 fence->ops->fence_value_str) {
114                 char value[64];
115                 bool success;
116
117                 fence->ops->fence_value_str(fence, value, sizeof(value));
118                 success = strlen(value);
119
120                 if (success)
121                         seq_printf(s, ": %s", value);
122
123                 if (success && fence) {
124                         fence->ops->timeline_value_str(fence, value,
125                                                        sizeof(value));
126
127                         if (strlen(value))
128                                 seq_printf(s, " / %s", value);
129                 }
130         }
131
132         seq_puts(s, "\n");
133 }
134
135 static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
136 {
137         struct list_head *pos;
138         unsigned long flags;
139
140         seq_printf(s, "%s %s: %d\n", obj->name, obj->drv_name, obj->value);
141
142         spin_lock_irqsave(&obj->child_list_lock, flags);
143         list_for_each(pos, &obj->child_list_head) {
144                 struct fence *fence =
145                         container_of(pos, struct fence, child_list);
146                 sync_print_fence(s, fence, false);
147         }
148         spin_unlock_irqrestore(&obj->child_list_lock, flags);
149 }
150
151 static void sync_print_sync_file(struct seq_file *s,
152                                   struct sync_file *sync_file)
153 {
154         int i;
155
156         seq_printf(s, "[%p] %s: %s\n", sync_file, sync_file->name,
157                    sync_status_str(atomic_read(&sync_file->status)));
158
159         for (i = 0; i < sync_file->num_fences; ++i)
160                 sync_print_fence(s, sync_file->cbs[i].fence, true);
161 }
162
163 static int sync_debugfs_show(struct seq_file *s, void *unused)
164 {
165         unsigned long flags;
166         struct list_head *pos;
167
168         seq_puts(s, "objs:\n--------------\n");
169
170         spin_lock_irqsave(&sync_timeline_list_lock, flags);
171         list_for_each(pos, &sync_timeline_list_head) {
172                 struct sync_timeline *obj =
173                         container_of(pos, struct sync_timeline,
174                                      sync_timeline_list);
175
176                 sync_print_obj(s, obj);
177                 seq_puts(s, "\n");
178         }
179         spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
180
181         seq_puts(s, "fences:\n--------------\n");
182
183         spin_lock_irqsave(&sync_file_list_lock, flags);
184         list_for_each(pos, &sync_file_list_head) {
185                 struct sync_file *sync_file =
186                         container_of(pos, struct sync_file, sync_file_list);
187
188                 sync_print_sync_file(s, sync_file);
189                 seq_puts(s, "\n");
190         }
191         spin_unlock_irqrestore(&sync_file_list_lock, flags);
192         return 0;
193 }
194
195 static int sync_info_debugfs_open(struct inode *inode, struct file *file)
196 {
197         return single_open(file, sync_debugfs_show, inode->i_private);
198 }
199
200 static const struct file_operations sync_info_debugfs_fops = {
201         .open           = sync_info_debugfs_open,
202         .read           = seq_read,
203         .llseek         = seq_lseek,
204         .release        = single_release,
205 };
206
207 #if IS_ENABLED(CONFIG_SW_SYNC)
208 /*
209  * *WARNING*
210  *
211  * improper use of this can result in deadlocking kernel drivers from userspace.
212  */
213
214 /* opening sw_sync create a new sync obj */
215 static int sw_sync_debugfs_open(struct inode *inode, struct file *file)
216 {
217         struct sync_timeline *obj;
218         char task_comm[TASK_COMM_LEN];
219
220         get_task_comm(task_comm, current);
221
222         obj = sync_timeline_create(sizeof(*obj), "sw_sync", task_comm);
223         if (!obj)
224                 return -ENOMEM;
225
226         file->private_data = obj;
227
228         return 0;
229 }
230
231 static int sw_sync_debugfs_release(struct inode *inode, struct file *file)
232 {
233         struct sync_timeline *obj = file->private_data;
234
235         sync_timeline_destroy(obj);
236         return 0;
237 }
238
239 static long sw_sync_ioctl_create_fence(struct sync_timeline *obj,
240                                        unsigned long arg)
241 {
242         int fd = get_unused_fd_flags(O_CLOEXEC);
243         int err;
244         struct fence *fence;
245         struct sync_file *sync_file;
246         struct sw_sync_create_fence_data data;
247
248         if (fd < 0)
249                 return fd;
250
251         if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
252                 err = -EFAULT;
253                 goto err;
254         }
255
256         fence = sync_pt_create(obj, sizeof(*fence), data.value);
257         if (!fence) {
258                 err = -ENOMEM;
259                 goto err;
260         }
261
262         sync_file = sync_file_create(fence);
263         if (!sync_file) {
264                 fence_put(fence);
265                 err = -ENOMEM;
266                 goto err;
267         }
268
269         data.fence = fd;
270         if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
271                 fput(sync_file->file);
272                 err = -EFAULT;
273                 goto err;
274         }
275
276         fd_install(fd, sync_file->file);
277
278         return 0;
279
280 err:
281         put_unused_fd(fd);
282         return err;
283 }
284
285 static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg)
286 {
287         u32 value;
288
289         if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
290                 return -EFAULT;
291
292         sync_timeline_signal(obj, value);
293
294         return 0;
295 }
296
297 static long sw_sync_ioctl(struct file *file, unsigned int cmd,
298                           unsigned long arg)
299 {
300         struct sync_timeline *obj = file->private_data;
301
302         switch (cmd) {
303         case SW_SYNC_IOC_CREATE_FENCE:
304                 return sw_sync_ioctl_create_fence(obj, arg);
305
306         case SW_SYNC_IOC_INC:
307                 return sw_sync_ioctl_inc(obj, arg);
308
309         default:
310                 return -ENOTTY;
311         }
312 }
313
314 static const struct file_operations sw_sync_debugfs_fops = {
315         .open           = sw_sync_debugfs_open,
316         .release        = sw_sync_debugfs_release,
317         .unlocked_ioctl = sw_sync_ioctl,
318         .compat_ioctl = sw_sync_ioctl,
319 };
320 #endif
321
322 static __init int sync_debugfs_init(void)
323 {
324         dbgfs = debugfs_create_dir("sync", NULL);
325
326         debugfs_create_file("info", 0444, dbgfs, NULL, &sync_info_debugfs_fops);
327
328 #if IS_ENABLED(CONFIG_SW_SYNC)
329         debugfs_create_file("sw_sync", 0644, dbgfs, NULL,
330                             &sw_sync_debugfs_fops);
331 #endif
332
333         return 0;
334 }
335 late_initcall(sync_debugfs_init);
336
337 #define DUMP_CHUNK 256
338 static char sync_dump_buf[64 * 1024];
339 void sync_dump(void)
340 {
341         struct seq_file s = {
342                 .buf = sync_dump_buf,
343                 .size = sizeof(sync_dump_buf) - 1,
344         };
345         int i;
346
347         sync_debugfs_show(&s, NULL);
348
349         for (i = 0; i < s.count; i += DUMP_CHUNK) {
350                 if ((s.count - i) > DUMP_CHUNK) {
351                         char c = s.buf[i + DUMP_CHUNK];
352
353                         s.buf[i + DUMP_CHUNK] = 0;
354                         pr_cont("%s", s.buf + i);
355                         s.buf[i + DUMP_CHUNK] = c;
356                 } else {
357                         s.buf[s.count] = 0;
358                         pr_cont("%s", s.buf + i);
359                 }
360         }
361 }
362
363 #endif