1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Sync File validation framework and debug information
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2012 Google, Inc.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/debugfs.h>
9*4882a593Smuzhiyun #include "sync_debug.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun static struct dentry *dbgfs;
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun static LIST_HEAD(sync_timeline_list_head);
14*4882a593Smuzhiyun static DEFINE_SPINLOCK(sync_timeline_list_lock);
15*4882a593Smuzhiyun static LIST_HEAD(sync_file_list_head);
16*4882a593Smuzhiyun static DEFINE_SPINLOCK(sync_file_list_lock);
17*4882a593Smuzhiyun
sync_timeline_debug_add(struct sync_timeline * obj)18*4882a593Smuzhiyun void sync_timeline_debug_add(struct sync_timeline *obj)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun unsigned long flags;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun spin_lock_irqsave(&sync_timeline_list_lock, flags);
23*4882a593Smuzhiyun list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head);
24*4882a593Smuzhiyun spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
25*4882a593Smuzhiyun }
26*4882a593Smuzhiyun
sync_timeline_debug_remove(struct sync_timeline * obj)27*4882a593Smuzhiyun void sync_timeline_debug_remove(struct sync_timeline *obj)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun unsigned long flags;
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun spin_lock_irqsave(&sync_timeline_list_lock, flags);
32*4882a593Smuzhiyun list_del(&obj->sync_timeline_list);
33*4882a593Smuzhiyun spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun
sync_file_debug_add(struct sync_file * sync_file)36*4882a593Smuzhiyun void sync_file_debug_add(struct sync_file *sync_file)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun unsigned long flags;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun spin_lock_irqsave(&sync_file_list_lock, flags);
41*4882a593Smuzhiyun list_add_tail(&sync_file->sync_file_list, &sync_file_list_head);
42*4882a593Smuzhiyun spin_unlock_irqrestore(&sync_file_list_lock, flags);
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
sync_file_debug_remove(struct sync_file * sync_file)45*4882a593Smuzhiyun void sync_file_debug_remove(struct sync_file *sync_file)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun unsigned long flags;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun spin_lock_irqsave(&sync_file_list_lock, flags);
50*4882a593Smuzhiyun list_del(&sync_file->sync_file_list);
51*4882a593Smuzhiyun spin_unlock_irqrestore(&sync_file_list_lock, flags);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
sync_status_str(int status)54*4882a593Smuzhiyun static const char *sync_status_str(int status)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun if (status < 0)
57*4882a593Smuzhiyun return "error";
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun if (status > 0)
60*4882a593Smuzhiyun return "signaled";
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun return "active";
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
sync_print_fence(struct seq_file * s,struct dma_fence * fence,bool show)65*4882a593Smuzhiyun static void sync_print_fence(struct seq_file *s,
66*4882a593Smuzhiyun struct dma_fence *fence, bool show)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct sync_timeline *parent = dma_fence_parent(fence);
69*4882a593Smuzhiyun int status;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun status = dma_fence_get_status_locked(fence);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun seq_printf(s, " %s%sfence %s",
74*4882a593Smuzhiyun show ? parent->name : "",
75*4882a593Smuzhiyun show ? "_" : "",
76*4882a593Smuzhiyun sync_status_str(status));
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags)) {
79*4882a593Smuzhiyun struct timespec64 ts64 =
80*4882a593Smuzhiyun ktime_to_timespec64(fence->timestamp);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (fence->ops->timeline_value_str &&
86*4882a593Smuzhiyun fence->ops->fence_value_str) {
87*4882a593Smuzhiyun char value[64];
88*4882a593Smuzhiyun bool success;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun fence->ops->fence_value_str(fence, value, sizeof(value));
91*4882a593Smuzhiyun success = strlen(value);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun if (success) {
94*4882a593Smuzhiyun seq_printf(s, ": %s", value);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun fence->ops->timeline_value_str(fence, value,
97*4882a593Smuzhiyun sizeof(value));
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (strlen(value))
100*4882a593Smuzhiyun seq_printf(s, " / %s", value);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun seq_putc(s, '\n');
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
sync_print_obj(struct seq_file * s,struct sync_timeline * obj)107*4882a593Smuzhiyun static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun struct list_head *pos;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun seq_printf(s, "%s: %d\n", obj->name, obj->value);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun spin_lock_irq(&obj->lock);
114*4882a593Smuzhiyun list_for_each(pos, &obj->pt_list) {
115*4882a593Smuzhiyun struct sync_pt *pt = container_of(pos, struct sync_pt, link);
116*4882a593Smuzhiyun sync_print_fence(s, &pt->base, false);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun spin_unlock_irq(&obj->lock);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
sync_print_sync_file(struct seq_file * s,struct sync_file * sync_file)121*4882a593Smuzhiyun static void sync_print_sync_file(struct seq_file *s,
122*4882a593Smuzhiyun struct sync_file *sync_file)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun char buf[128];
125*4882a593Smuzhiyun int i;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun seq_printf(s, "[%p] %s: %s\n", sync_file,
128*4882a593Smuzhiyun sync_file_get_name(sync_file, buf, sizeof(buf)),
129*4882a593Smuzhiyun sync_status_str(dma_fence_get_status(sync_file->fence)));
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (dma_fence_is_array(sync_file->fence)) {
132*4882a593Smuzhiyun struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun for (i = 0; i < array->num_fences; ++i)
135*4882a593Smuzhiyun sync_print_fence(s, array->fences[i], true);
136*4882a593Smuzhiyun } else {
137*4882a593Smuzhiyun sync_print_fence(s, sync_file->fence, true);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
sync_info_debugfs_show(struct seq_file * s,void * unused)141*4882a593Smuzhiyun static int sync_info_debugfs_show(struct seq_file *s, void *unused)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun struct list_head *pos;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun seq_puts(s, "objs:\n--------------\n");
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun spin_lock_irq(&sync_timeline_list_lock);
148*4882a593Smuzhiyun list_for_each(pos, &sync_timeline_list_head) {
149*4882a593Smuzhiyun struct sync_timeline *obj =
150*4882a593Smuzhiyun container_of(pos, struct sync_timeline,
151*4882a593Smuzhiyun sync_timeline_list);
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun sync_print_obj(s, obj);
154*4882a593Smuzhiyun seq_putc(s, '\n');
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun spin_unlock_irq(&sync_timeline_list_lock);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun seq_puts(s, "fences:\n--------------\n");
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun spin_lock_irq(&sync_file_list_lock);
161*4882a593Smuzhiyun list_for_each(pos, &sync_file_list_head) {
162*4882a593Smuzhiyun struct sync_file *sync_file =
163*4882a593Smuzhiyun container_of(pos, struct sync_file, sync_file_list);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun sync_print_sync_file(s, sync_file);
166*4882a593Smuzhiyun seq_putc(s, '\n');
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun spin_unlock_irq(&sync_file_list_lock);
169*4882a593Smuzhiyun return 0;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun DEFINE_SHOW_ATTRIBUTE(sync_info_debugfs);
173*4882a593Smuzhiyun
sync_debugfs_init(void)174*4882a593Smuzhiyun static __init int sync_debugfs_init(void)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun dbgfs = debugfs_create_dir("sync", NULL);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /*
179*4882a593Smuzhiyun * The debugfs files won't ever get removed and thus, there is
180*4882a593Smuzhiyun * no need to protect it against removal races. The use of
181*4882a593Smuzhiyun * debugfs_create_file_unsafe() is actually safe here.
182*4882a593Smuzhiyun */
183*4882a593Smuzhiyun debugfs_create_file_unsafe("info", 0444, dbgfs, NULL,
184*4882a593Smuzhiyun &sync_info_debugfs_fops);
185*4882a593Smuzhiyun debugfs_create_file_unsafe("sw_sync", 0644, dbgfs, NULL,
186*4882a593Smuzhiyun &sw_sync_debugfs_fops);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun return 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun late_initcall(sync_debugfs_init);
191