0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/debugfs.h>
0009 #include "sync_debug.h"
0010
0011 static struct dentry *dbgfs;
0012
0013 static LIST_HEAD(sync_timeline_list_head);
0014 static DEFINE_SPINLOCK(sync_timeline_list_lock);
0015 static LIST_HEAD(sync_file_list_head);
0016 static DEFINE_SPINLOCK(sync_file_list_lock);
0017
0018 void sync_timeline_debug_add(struct sync_timeline *obj)
0019 {
0020 unsigned long flags;
0021
0022 spin_lock_irqsave(&sync_timeline_list_lock, flags);
0023 list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head);
0024 spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
0025 }
0026
0027 void sync_timeline_debug_remove(struct sync_timeline *obj)
0028 {
0029 unsigned long flags;
0030
0031 spin_lock_irqsave(&sync_timeline_list_lock, flags);
0032 list_del(&obj->sync_timeline_list);
0033 spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
0034 }
0035
0036 void sync_file_debug_add(struct sync_file *sync_file)
0037 {
0038 unsigned long flags;
0039
0040 spin_lock_irqsave(&sync_file_list_lock, flags);
0041 list_add_tail(&sync_file->sync_file_list, &sync_file_list_head);
0042 spin_unlock_irqrestore(&sync_file_list_lock, flags);
0043 }
0044
0045 void sync_file_debug_remove(struct sync_file *sync_file)
0046 {
0047 unsigned long flags;
0048
0049 spin_lock_irqsave(&sync_file_list_lock, flags);
0050 list_del(&sync_file->sync_file_list);
0051 spin_unlock_irqrestore(&sync_file_list_lock, flags);
0052 }
0053
0054 static const char *sync_status_str(int status)
0055 {
0056 if (status < 0)
0057 return "error";
0058
0059 if (status > 0)
0060 return "signaled";
0061
0062 return "active";
0063 }
0064
0065 static void sync_print_fence(struct seq_file *s,
0066 struct dma_fence *fence, bool show)
0067 {
0068 struct sync_timeline *parent = dma_fence_parent(fence);
0069 int status;
0070
0071 status = dma_fence_get_status_locked(fence);
0072
0073 seq_printf(s, " %s%sfence %s",
0074 show ? parent->name : "",
0075 show ? "_" : "",
0076 sync_status_str(status));
0077
0078 if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags)) {
0079 struct timespec64 ts64 =
0080 ktime_to_timespec64(fence->timestamp);
0081
0082 seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
0083 }
0084
0085 if (fence->ops->timeline_value_str &&
0086 fence->ops->fence_value_str) {
0087 char value[64];
0088 bool success;
0089
0090 fence->ops->fence_value_str(fence, value, sizeof(value));
0091 success = strlen(value);
0092
0093 if (success) {
0094 seq_printf(s, ": %s", value);
0095
0096 fence->ops->timeline_value_str(fence, value,
0097 sizeof(value));
0098
0099 if (strlen(value))
0100 seq_printf(s, " / %s", value);
0101 }
0102 }
0103
0104 seq_putc(s, '\n');
0105 }
0106
0107 static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
0108 {
0109 struct list_head *pos;
0110
0111 seq_printf(s, "%s: %d\n", obj->name, obj->value);
0112
0113 spin_lock_irq(&obj->lock);
0114 list_for_each(pos, &obj->pt_list) {
0115 struct sync_pt *pt = container_of(pos, struct sync_pt, link);
0116 sync_print_fence(s, &pt->base, false);
0117 }
0118 spin_unlock_irq(&obj->lock);
0119 }
0120
0121 static void sync_print_sync_file(struct seq_file *s,
0122 struct sync_file *sync_file)
0123 {
0124 char buf[128];
0125 int i;
0126
0127 seq_printf(s, "[%p] %s: %s\n", sync_file,
0128 sync_file_get_name(sync_file, buf, sizeof(buf)),
0129 sync_status_str(dma_fence_get_status(sync_file->fence)));
0130
0131 if (dma_fence_is_array(sync_file->fence)) {
0132 struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
0133
0134 for (i = 0; i < array->num_fences; ++i)
0135 sync_print_fence(s, array->fences[i], true);
0136 } else {
0137 sync_print_fence(s, sync_file->fence, true);
0138 }
0139 }
0140
0141 static int sync_info_debugfs_show(struct seq_file *s, void *unused)
0142 {
0143 struct list_head *pos;
0144
0145 seq_puts(s, "objs:\n--------------\n");
0146
0147 spin_lock_irq(&sync_timeline_list_lock);
0148 list_for_each(pos, &sync_timeline_list_head) {
0149 struct sync_timeline *obj =
0150 container_of(pos, struct sync_timeline,
0151 sync_timeline_list);
0152
0153 sync_print_obj(s, obj);
0154 seq_putc(s, '\n');
0155 }
0156 spin_unlock_irq(&sync_timeline_list_lock);
0157
0158 seq_puts(s, "fences:\n--------------\n");
0159
0160 spin_lock_irq(&sync_file_list_lock);
0161 list_for_each(pos, &sync_file_list_head) {
0162 struct sync_file *sync_file =
0163 container_of(pos, struct sync_file, sync_file_list);
0164
0165 sync_print_sync_file(s, sync_file);
0166 seq_putc(s, '\n');
0167 }
0168 spin_unlock_irq(&sync_file_list_lock);
0169 return 0;
0170 }
0171
0172 DEFINE_SHOW_ATTRIBUTE(sync_info_debugfs);
0173
0174 static __init int sync_debugfs_init(void)
0175 {
0176 dbgfs = debugfs_create_dir("sync", NULL);
0177
0178
0179
0180
0181
0182
0183 debugfs_create_file_unsafe("info", 0444, dbgfs, NULL,
0184 &sync_info_debugfs_fops);
0185 debugfs_create_file_unsafe("sw_sync", 0644, dbgfs, NULL,
0186 &sw_sync_debugfs_fops);
0187
0188 return 0;
0189 }
0190 late_initcall(sync_debugfs_init);