Commit | Line | Data |
---|---|---|
6236451d TB |
1 | /* |
2 | * Copyright (C) 2010 Google, Inc. | |
3 | * Author: Erik Gilling <konkers@android.com> | |
4 | * | |
5 | * Copyright (C) 2011-2013 NVIDIA Corporation | |
6 | * | |
7 | * This software is licensed under the terms of the GNU General Public | |
8 | * License version 2, as published by the Free Software Foundation, and | |
9 | * may be copied, distributed, and modified under those terms. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | */ | |
17 | ||
18 | #include <linux/debugfs.h> | |
19 | #include <linux/seq_file.h> | |
20 | #include <linux/uaccess.h> | |
21 | ||
22 | #include <linux/io.h> | |
23 | ||
24 | #include "dev.h" | |
25 | #include "debug.h" | |
26 | #include "channel.h" | |
27 | ||
28 | unsigned int host1x_debug_trace_cmdbuf; | |
29 | ||
30 | static pid_t host1x_debug_force_timeout_pid; | |
31 | static u32 host1x_debug_force_timeout_val; | |
32 | static u32 host1x_debug_force_timeout_channel; | |
33 | ||
34 | void host1x_debug_output(struct output *o, const char *fmt, ...) | |
35 | { | |
36 | va_list args; | |
37 | int len; | |
38 | ||
39 | va_start(args, fmt); | |
40 | len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); | |
41 | va_end(args); | |
0b8070d1 | 42 | |
6236451d TB |
43 | o->fn(o->ctx, o->buf, len); |
44 | } | |
45 | ||
46 | static int show_channels(struct host1x_channel *ch, void *data, bool show_fifo) | |
47 | { | |
48 | struct host1x *m = dev_get_drvdata(ch->dev->parent); | |
49 | struct output *o = data; | |
50 | ||
51 | mutex_lock(&ch->reflock); | |
0b8070d1 | 52 | |
6236451d TB |
53 | if (ch->refcount) { |
54 | mutex_lock(&ch->cdma.lock); | |
0b8070d1 | 55 | |
6236451d TB |
56 | if (show_fifo) |
57 | host1x_hw_show_channel_fifo(m, ch, o); | |
0b8070d1 | 58 | |
6236451d TB |
59 | host1x_hw_show_channel_cdma(m, ch, o); |
60 | mutex_unlock(&ch->cdma.lock); | |
61 | } | |
0b8070d1 | 62 | |
6236451d TB |
63 | mutex_unlock(&ch->reflock); |
64 | ||
65 | return 0; | |
66 | } | |
67 | ||
68 | static void show_syncpts(struct host1x *m, struct output *o) | |
69 | { | |
14c95fc8 | 70 | unsigned int i; |
6df633d0 | 71 | |
6236451d | 72 | host1x_debug_output(o, "---- syncpts ----\n"); |
0b8070d1 | 73 | |
6236451d TB |
74 | for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { |
75 | u32 max = host1x_syncpt_read_max(m->syncpt + i); | |
76 | u32 min = host1x_syncpt_load(m->syncpt + i); | |
6df633d0 | 77 | |
6236451d TB |
78 | if (!min && !max) |
79 | continue; | |
14c95fc8 TR |
80 | |
81 | host1x_debug_output(o, "id %u (%s) min %d max %d\n", | |
6236451d TB |
82 | i, m->syncpt[i].name, min, max); |
83 | } | |
84 | ||
85 | for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { | |
86 | u32 base_val; | |
6df633d0 | 87 | |
6236451d TB |
88 | base_val = host1x_syncpt_load_wait_base(m->syncpt + i); |
89 | if (base_val) | |
14c95fc8 | 90 | host1x_debug_output(o, "waitbase id %u val %d\n", i, |
6236451d TB |
91 | base_val); |
92 | } | |
93 | ||
94 | host1x_debug_output(o, "\n"); | |
95 | } | |
96 | ||
97 | static void show_all(struct host1x *m, struct output *o) | |
98 | { | |
99 | struct host1x_channel *ch; | |
100 | ||
101 | host1x_hw_show_mlocks(m, o); | |
102 | show_syncpts(m, o); | |
103 | host1x_debug_output(o, "---- channels ----\n"); | |
104 | ||
105 | host1x_for_each_channel(m, ch) | |
106 | show_channels(ch, o, true); | |
107 | } | |
108 | ||
6236451d TB |
109 | static void show_all_no_fifo(struct host1x *host1x, struct output *o) |
110 | { | |
111 | struct host1x_channel *ch; | |
112 | ||
113 | host1x_hw_show_mlocks(host1x, o); | |
114 | show_syncpts(host1x, o); | |
115 | host1x_debug_output(o, "---- channels ----\n"); | |
116 | ||
117 | host1x_for_each_channel(host1x, ch) | |
118 | show_channels(ch, o, false); | |
119 | } | |
120 | ||
121 | static int host1x_debug_show_all(struct seq_file *s, void *unused) | |
122 | { | |
123 | struct output o = { | |
124 | .fn = write_to_seqfile, | |
125 | .ctx = s | |
126 | }; | |
0b8070d1 | 127 | |
6236451d | 128 | show_all(s->private, &o); |
0b8070d1 | 129 | |
6236451d TB |
130 | return 0; |
131 | } | |
132 | ||
133 | static int host1x_debug_show(struct seq_file *s, void *unused) | |
134 | { | |
135 | struct output o = { | |
136 | .fn = write_to_seqfile, | |
137 | .ctx = s | |
138 | }; | |
0b8070d1 | 139 | |
6236451d | 140 | show_all_no_fifo(s->private, &o); |
0b8070d1 | 141 | |
6236451d TB |
142 | return 0; |
143 | } | |
144 | ||
145 | static int host1x_debug_open_all(struct inode *inode, struct file *file) | |
146 | { | |
147 | return single_open(file, host1x_debug_show_all, inode->i_private); | |
148 | } | |
149 | ||
150 | static const struct file_operations host1x_debug_all_fops = { | |
0b8070d1 TR |
151 | .open = host1x_debug_open_all, |
152 | .read = seq_read, | |
153 | .llseek = seq_lseek, | |
154 | .release = single_release, | |
6236451d TB |
155 | }; |
156 | ||
157 | static int host1x_debug_open(struct inode *inode, struct file *file) | |
158 | { | |
159 | return single_open(file, host1x_debug_show, inode->i_private); | |
160 | } | |
161 | ||
162 | static const struct file_operations host1x_debug_fops = { | |
0b8070d1 TR |
163 | .open = host1x_debug_open, |
164 | .read = seq_read, | |
165 | .llseek = seq_lseek, | |
166 | .release = single_release, | |
6236451d TB |
167 | }; |
168 | ||
8e0d788c | 169 | static void host1x_debugfs_init(struct host1x *host1x) |
6236451d TB |
170 | { |
171 | struct dentry *de = debugfs_create_dir("tegra-host1x", NULL); | |
172 | ||
173 | if (!de) | |
174 | return; | |
175 | ||
176 | /* Store the created entry */ | |
177 | host1x->debugfs = de; | |
178 | ||
179 | debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops); | |
180 | debugfs_create_file("status_all", S_IRUGO, de, host1x, | |
181 | &host1x_debug_all_fops); | |
182 | ||
183 | debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de, | |
184 | &host1x_debug_trace_cmdbuf); | |
185 | ||
186 | host1x_hw_debug_init(host1x, de); | |
187 | ||
188 | debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de, | |
189 | &host1x_debug_force_timeout_pid); | |
190 | debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de, | |
191 | &host1x_debug_force_timeout_val); | |
192 | debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de, | |
193 | &host1x_debug_force_timeout_channel); | |
194 | } | |
195 | ||
8e0d788c | 196 | static void host1x_debugfs_exit(struct host1x *host1x) |
6236451d TB |
197 | { |
198 | debugfs_remove_recursive(host1x->debugfs); | |
199 | } | |
8e0d788c | 200 | |
6236451d TB |
201 | void host1x_debug_init(struct host1x *host1x) |
202 | { | |
8e0d788c TR |
203 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
204 | host1x_debugfs_init(host1x); | |
6236451d | 205 | } |
8e0d788c | 206 | |
6236451d TB |
207 | void host1x_debug_deinit(struct host1x *host1x) |
208 | { | |
8e0d788c TR |
209 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
210 | host1x_debugfs_exit(host1x); | |
6236451d | 211 | } |
6236451d TB |
212 | |
213 | void host1x_debug_dump(struct host1x *host1x) | |
214 | { | |
215 | struct output o = { | |
216 | .fn = write_to_printk | |
217 | }; | |
0b8070d1 | 218 | |
6236451d TB |
219 | show_all(host1x, &o); |
220 | } | |
221 | ||
222 | void host1x_debug_dump_syncpts(struct host1x *host1x) | |
223 | { | |
224 | struct output o = { | |
225 | .fn = write_to_printk | |
226 | }; | |
0b8070d1 | 227 | |
6236451d TB |
228 | show_syncpts(host1x, &o); |
229 | } |