0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/debugfs.h>
0010 #include <linux/pm_runtime.h>
0011 #include <linux/seq_file.h>
0012 #include <linux/uaccess.h>
0013
0014 #include <linux/io.h>
0015
0016 #include "dev.h"
0017 #include "debug.h"
0018 #include "channel.h"
0019
0020 static DEFINE_MUTEX(debug_lock);
0021
0022 unsigned int host1x_debug_trace_cmdbuf;
0023
0024 static pid_t host1x_debug_force_timeout_pid;
0025 static u32 host1x_debug_force_timeout_val;
0026 static u32 host1x_debug_force_timeout_channel;
0027
0028 void host1x_debug_output(struct output *o, const char *fmt, ...)
0029 {
0030 va_list args;
0031 int len;
0032
0033 va_start(args, fmt);
0034 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
0035 va_end(args);
0036
0037 o->fn(o->ctx, o->buf, len, false);
0038 }
0039
0040 void host1x_debug_cont(struct output *o, const char *fmt, ...)
0041 {
0042 va_list args;
0043 int len;
0044
0045 va_start(args, fmt);
0046 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
0047 va_end(args);
0048
0049 o->fn(o->ctx, o->buf, len, true);
0050 }
0051
0052 static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
0053 {
0054 struct host1x *m = dev_get_drvdata(ch->dev->parent);
0055 struct output *o = data;
0056 int err;
0057
0058 err = pm_runtime_resume_and_get(m->dev);
0059 if (err < 0)
0060 return err;
0061
0062 mutex_lock(&ch->cdma.lock);
0063 mutex_lock(&debug_lock);
0064
0065 if (show_fifo)
0066 host1x_hw_show_channel_fifo(m, ch, o);
0067
0068 host1x_hw_show_channel_cdma(m, ch, o);
0069
0070 mutex_unlock(&debug_lock);
0071 mutex_unlock(&ch->cdma.lock);
0072
0073 pm_runtime_put(m->dev);
0074
0075 return 0;
0076 }
0077
0078 static void show_syncpts(struct host1x *m, struct output *o, bool show_all)
0079 {
0080 struct list_head *pos;
0081 unsigned int i;
0082 int err;
0083
0084 host1x_debug_output(o, "---- syncpts ----\n");
0085
0086 err = pm_runtime_resume_and_get(m->dev);
0087 if (err < 0)
0088 return;
0089
0090 for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {
0091 u32 max = host1x_syncpt_read_max(m->syncpt + i);
0092 u32 min = host1x_syncpt_load(m->syncpt + i);
0093 unsigned int waiters = 0;
0094
0095 spin_lock(&m->syncpt[i].intr.lock);
0096 list_for_each(pos, &m->syncpt[i].intr.wait_head)
0097 waiters++;
0098 spin_unlock(&m->syncpt[i].intr.lock);
0099
0100 if (!kref_read(&m->syncpt[i].ref))
0101 continue;
0102
0103 if (!show_all && !min && !max && !waiters)
0104 continue;
0105
0106 host1x_debug_output(o,
0107 "id %u (%s) min %d max %d (%d waiters)\n",
0108 i, m->syncpt[i].name, min, max, waiters);
0109 }
0110
0111 for (i = 0; i < host1x_syncpt_nb_bases(m); i++) {
0112 u32 base_val;
0113
0114 base_val = host1x_syncpt_load_wait_base(m->syncpt + i);
0115 if (base_val)
0116 host1x_debug_output(o, "waitbase id %u val %d\n", i,
0117 base_val);
0118 }
0119
0120 pm_runtime_put(m->dev);
0121
0122 host1x_debug_output(o, "\n");
0123 }
0124
0125 static void show_all(struct host1x *m, struct output *o, bool show_fifo)
0126 {
0127 unsigned int i;
0128
0129 host1x_hw_show_mlocks(m, o);
0130 show_syncpts(m, o, true);
0131 host1x_debug_output(o, "---- channels ----\n");
0132
0133 for (i = 0; i < m->info->nb_channels; ++i) {
0134 struct host1x_channel *ch = host1x_channel_get_index(m, i);
0135
0136 if (ch) {
0137 show_channel(ch, o, show_fifo);
0138 host1x_channel_put(ch);
0139 }
0140 }
0141 }
0142
0143 static int host1x_debug_show_all(struct seq_file *s, void *unused)
0144 {
0145 struct output o = {
0146 .fn = write_to_seqfile,
0147 .ctx = s
0148 };
0149
0150 show_all(s->private, &o, true);
0151
0152 return 0;
0153 }
0154
0155 static int host1x_debug_show(struct seq_file *s, void *unused)
0156 {
0157 struct output o = {
0158 .fn = write_to_seqfile,
0159 .ctx = s
0160 };
0161
0162 show_all(s->private, &o, false);
0163
0164 return 0;
0165 }
0166
0167 static int host1x_debug_open_all(struct inode *inode, struct file *file)
0168 {
0169 return single_open(file, host1x_debug_show_all, inode->i_private);
0170 }
0171
0172 static const struct file_operations host1x_debug_all_fops = {
0173 .open = host1x_debug_open_all,
0174 .read = seq_read,
0175 .llseek = seq_lseek,
0176 .release = single_release,
0177 };
0178
0179 static int host1x_debug_open(struct inode *inode, struct file *file)
0180 {
0181 return single_open(file, host1x_debug_show, inode->i_private);
0182 }
0183
0184 static const struct file_operations host1x_debug_fops = {
0185 .open = host1x_debug_open,
0186 .read = seq_read,
0187 .llseek = seq_lseek,
0188 .release = single_release,
0189 };
0190
0191 static void host1x_debugfs_init(struct host1x *host1x)
0192 {
0193 struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);
0194
0195
0196 host1x->debugfs = de;
0197
0198 debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops);
0199 debugfs_create_file("status_all", S_IRUGO, de, host1x,
0200 &host1x_debug_all_fops);
0201
0202 debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
0203 &host1x_debug_trace_cmdbuf);
0204
0205 host1x_hw_debug_init(host1x, de);
0206
0207 debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
0208 &host1x_debug_force_timeout_pid);
0209 debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,
0210 &host1x_debug_force_timeout_val);
0211 debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,
0212 &host1x_debug_force_timeout_channel);
0213 }
0214
0215 static void host1x_debugfs_exit(struct host1x *host1x)
0216 {
0217 debugfs_remove_recursive(host1x->debugfs);
0218 }
0219
0220 void host1x_debug_init(struct host1x *host1x)
0221 {
0222 if (IS_ENABLED(CONFIG_DEBUG_FS))
0223 host1x_debugfs_init(host1x);
0224 }
0225
0226 void host1x_debug_deinit(struct host1x *host1x)
0227 {
0228 if (IS_ENABLED(CONFIG_DEBUG_FS))
0229 host1x_debugfs_exit(host1x);
0230 }
0231
0232 void host1x_debug_dump(struct host1x *host1x)
0233 {
0234 struct output o = {
0235 .fn = write_to_printk
0236 };
0237
0238 show_all(host1x, &o, true);
0239 }
0240
0241 void host1x_debug_dump_syncpts(struct host1x *host1x)
0242 {
0243 struct output o = {
0244 .fn = write_to_printk
0245 };
0246
0247 show_syncpts(host1x, &o, false);
0248 }