1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2010 Google, Inc. 4 * Author: Erik Gilling <konkers@android.com> 5 * 6 * Copyright (C) 2011-2013 NVIDIA Corporation 7 */ 8 9 #include <linux/debugfs.h> 10 #include <linux/pm_runtime.h> 11 #include <linux/seq_file.h> 12 #include <linux/uaccess.h> 13 14 #include <linux/io.h> 15 16 #include "dev.h" 17 #include "debug.h" 18 #include "channel.h" 19 20 static DEFINE_MUTEX(debug_lock); 21 22 unsigned int host1x_debug_trace_cmdbuf; 23 24 static pid_t host1x_debug_force_timeout_pid; 25 static u32 host1x_debug_force_timeout_val; 26 static u32 host1x_debug_force_timeout_channel; 27 28 void host1x_debug_output(struct output *o, const char *fmt, ...) 29 { 30 va_list args; 31 int len; 32 33 va_start(args, fmt); 34 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); 35 va_end(args); 36 37 o->fn(o->ctx, o->buf, len, false); 38 } 39 40 void host1x_debug_cont(struct output *o, const char *fmt, ...) 41 { 42 va_list args; 43 int len; 44 45 va_start(args, fmt); 46 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); 47 va_end(args); 48 49 o->fn(o->ctx, o->buf, len, true); 50 } 51 52 static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) 53 { 54 struct host1x *m = dev_get_drvdata(ch->dev->parent); 55 struct output *o = data; 56 int err; 57 58 err = pm_runtime_resume_and_get(m->dev); 59 if (err < 0) 60 return err; 61 62 mutex_lock(&ch->cdma.lock); 63 mutex_lock(&debug_lock); 64 65 if (show_fifo) 66 host1x_hw_show_channel_fifo(m, ch, o); 67 68 host1x_hw_show_channel_cdma(m, ch, o); 69 70 mutex_unlock(&debug_lock); 71 mutex_unlock(&ch->cdma.lock); 72 73 pm_runtime_put(m->dev); 74 75 return 0; 76 } 77 78 static void show_syncpts(struct host1x *m, struct output *o, bool show_all) 79 { 80 struct list_head *pos; 81 unsigned int i; 82 int err; 83 84 host1x_debug_output(o, "---- syncpts ----\n"); 85 86 err = pm_runtime_resume_and_get(m->dev); 87 if (err < 0) 88 return; 89 90 for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { 91 u32 max = host1x_syncpt_read_max(m->syncpt + i); 92 u32 min = host1x_syncpt_load(m->syncpt + i); 93 unsigned int waiters = 0; 94 95 spin_lock(&m->syncpt[i].intr.lock); 96 list_for_each(pos, &m->syncpt[i].intr.wait_head) 97 waiters++; 98 spin_unlock(&m->syncpt[i].intr.lock); 99 100 if (!kref_read(&m->syncpt[i].ref)) 101 continue; 102 103 if (!show_all && !min && !max && !waiters) 104 continue; 105 106 host1x_debug_output(o, 107 "id %u (%s) min %d max %d (%d waiters)\n", 108 i, m->syncpt[i].name, min, max, waiters); 109 } 110 111 for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { 112 u32 base_val; 113 114 base_val = host1x_syncpt_load_wait_base(m->syncpt + i); 115 if (base_val) 116 host1x_debug_output(o, "waitbase id %u val %d\n", i, 117 base_val); 118 } 119 120 pm_runtime_put(m->dev); 121 122 host1x_debug_output(o, "\n"); 123 } 124 125 static void show_all(struct host1x *m, struct output *o, bool show_fifo) 126 { 127 unsigned int i; 128 129 host1x_hw_show_mlocks(m, o); 130 show_syncpts(m, o, true); 131 host1x_debug_output(o, "---- channels ----\n"); 132 133 for (i = 0; i < m->info->nb_channels; ++i) { 134 struct host1x_channel *ch = host1x_channel_get_index(m, i); 135 136 if (ch) { 137 show_channel(ch, o, show_fifo); 138 host1x_channel_put(ch); 139 } 140 } 141 } 142 143 static int host1x_debug_all_show(struct seq_file *s, void *unused) 144 { 145 struct output o = { 146 .fn = write_to_seqfile, 147 .ctx = s 148 }; 149 150 show_all(s->private, &o, true); 151 152 return 0; 153 } 154 DEFINE_SHOW_ATTRIBUTE(host1x_debug_all); 155 156 static int host1x_debug_show(struct seq_file *s, void *unused) 157 { 158 struct output o = { 159 .fn = write_to_seqfile, 160 .ctx = s 161 }; 162 163 show_all(s->private, &o, false); 164 165 return 0; 166 } 167 DEFINE_SHOW_ATTRIBUTE(host1x_debug); 168 169 static void host1x_debugfs_init(struct host1x *host1x) 170 { 171 struct dentry *de = debugfs_create_dir("tegra-host1x", NULL); 172 173 /* Store the created entry */ 174 host1x->debugfs = de; 175 176 debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops); 177 debugfs_create_file("status_all", S_IRUGO, de, host1x, 178 &host1x_debug_all_fops); 179 180 debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de, 181 &host1x_debug_trace_cmdbuf); 182 183 host1x_hw_debug_init(host1x, de); 184 185 debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de, 186 &host1x_debug_force_timeout_pid); 187 debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de, 188 &host1x_debug_force_timeout_val); 189 debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de, 190 &host1x_debug_force_timeout_channel); 191 } 192 193 static void host1x_debugfs_exit(struct host1x *host1x) 194 { 195 debugfs_remove_recursive(host1x->debugfs); 196 } 197 198 void host1x_debug_init(struct host1x *host1x) 199 { 200 if (IS_ENABLED(CONFIG_DEBUG_FS)) 201 host1x_debugfs_init(host1x); 202 } 203 204 void host1x_debug_deinit(struct host1x *host1x) 205 { 206 if (IS_ENABLED(CONFIG_DEBUG_FS)) 207 host1x_debugfs_exit(host1x); 208 } 209 210 void host1x_debug_dump(struct host1x *host1x) 211 { 212 struct output o = { 213 .fn = write_to_printk 214 }; 215 216 show_all(host1x, &o, true); 217 } 218 219 void host1x_debug_dump_syncpts(struct host1x *host1x) 220 { 221 struct output o = { 222 .fn = write_to_printk 223 }; 224 225 show_syncpts(host1x, &o, false); 226 } 227