summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/debug_gk20a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/debug_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/debug_gk20a.c295
1 files changed, 295 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/debug_gk20a.c b/drivers/gpu/nvgpu/gk20a/debug_gk20a.c
new file mode 100644
index 00000000..c5b6953c
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/debug_gk20a.c
@@ -0,0 +1,295 @@
1/*
2 * drivers/video/tegra/host/t20/debug_gk20a.c
3 *
4 * Copyright (C) 2011-2014 NVIDIA Corporation. All rights reserved.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/nvhost.h>
18#include <linux/debugfs.h>
19#include <linux/seq_file.h>
20
21#include <linux/io.h>
22
23#include "gk20a.h"
24#include "debug_gk20a.h"
25
26#include "hw_ram_gk20a.h"
27#include "hw_fifo_gk20a.h"
28#include "hw_ccsr_gk20a.h"
29#include "hw_pbdma_gk20a.h"
30
31unsigned int gk20a_debug_trace_cmdbuf;
32struct platform_device *gk20a_device;
33
34struct gk20a_debug_output {
35 void (*fn)(void *ctx, const char *str, size_t len);
36 void *ctx;
37 char buf[256];
38};
39
40static const char * const ccsr_chan_status_str[] = {
41 "idle",
42 "pending",
43 "pending_ctx_reload",
44 "pending_acquire",
45 "pending_acq_ctx_reload",
46 "on_pbdma",
47 "on_pbdma_and_eng",
48 "on_eng",
49 "on_eng_pending_acquire",
50 "on_eng_pending",
51 "on_pbdma_ctx_reload",
52 "on_pbdma_and_eng_ctx_reload",
53 "on_eng_ctx_reload",
54 "on_eng_pending_ctx_reload",
55 "on_eng_pending_acq_ctx_reload",
56};
57
58static const char * const chan_status_str[] = {
59 "invalid",
60 "valid",
61 "chsw_load",
62 "chsw_save",
63 "chsw_switch",
64};
65
66static const char * const ctx_status_str[] = {
67 "invalid",
68 "valid",
69 NULL,
70 NULL,
71 NULL,
72 "ctxsw_load",
73 "ctxsw_save",
74 "ctxsw_switch",
75};
76
77static inline void gk20a_debug_write_printk(void *ctx, const char *str,
78 size_t len)
79{
80 pr_info("%s", str);
81}
82
83static inline void gk20a_debug_write_to_seqfile(void *ctx, const char *str,
84 size_t len)
85{
86 seq_write((struct seq_file *)ctx, str, len);
87}
88
89void gk20a_debug_output(struct gk20a_debug_output *o, const char *fmt, ...)
90{
91 va_list args;
92 int len;
93
94 va_start(args, fmt);
95 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
96 va_end(args);
97 o->fn(o->ctx, o->buf, len);
98}
99
100static void gk20a_debug_show_channel(struct gk20a *g,
101 struct gk20a_debug_output *o,
102 struct channel_gk20a *ch)
103{
104 u32 channel = gk20a_readl(g, ccsr_channel_r(ch->hw_chid));
105 u32 status = ccsr_channel_status_v(channel);
106 u32 syncpointa, syncpointb;
107 void *inst_ptr;
108
109 inst_ptr = ch->inst_block.cpuva;
110 if (!inst_ptr)
111 return;
112
113 syncpointa = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointa_w());
114 syncpointb = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointb_w());
115
116 gk20a_debug_output(o, "%d-%s, pid %d: ", ch->hw_chid,
117 ch->g->dev->name,
118 ch->pid);
119 gk20a_debug_output(o, "%s in use %s %s\n",
120 ccsr_channel_enable_v(channel) ? "" : "not",
121 ccsr_chan_status_str[status],
122 ccsr_channel_busy_v(channel) ? "busy" : "not busy");
123 gk20a_debug_output(o, "TOP: %016llx PUT: %016llx GET: %016llx "
124 "FETCH: %016llx\nHEADER: %08x COUNT: %08x\n"
125 "SYNCPOINT %08x %08x SEMAPHORE %08x %08x %08x %08x\n",
126 (u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_top_level_get_w()) +
127 ((u64)gk20a_mem_rd32(inst_ptr,
128 ram_fc_pb_top_level_get_hi_w()) << 32ULL),
129 (u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_put_w()) +
130 ((u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_put_hi_w()) << 32ULL),
131 (u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_get_w()) +
132 ((u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_get_hi_w()) << 32ULL),
133 (u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_fetch_w()) +
134 ((u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_fetch_hi_w()) << 32ULL),
135 gk20a_mem_rd32(inst_ptr, ram_fc_pb_header_w()),
136 gk20a_mem_rd32(inst_ptr, ram_fc_pb_count_w()),
137 syncpointa,
138 syncpointb,
139 gk20a_mem_rd32(inst_ptr, ram_fc_semaphorea_w()),
140 gk20a_mem_rd32(inst_ptr, ram_fc_semaphoreb_w()),
141 gk20a_mem_rd32(inst_ptr, ram_fc_semaphorec_w()),
142 gk20a_mem_rd32(inst_ptr, ram_fc_semaphored_w()));
143
144 if ((pbdma_syncpointb_op_v(syncpointb) == pbdma_syncpointb_op_wait_v())
145 && (pbdma_syncpointb_wait_switch_v(syncpointb) ==
146 pbdma_syncpointb_wait_switch_en_v()))
147 gk20a_debug_output(o, "Waiting on syncpt %u (%s) val %u\n",
148 pbdma_syncpointb_syncpt_index_v(syncpointb),
149 nvhost_syncpt_get_name(
150 to_platform_device(g->dev->dev.parent),
151 pbdma_syncpointb_syncpt_index_v(syncpointb)),
152 pbdma_syncpointa_payload_v(syncpointa));
153
154 gk20a_debug_output(o, "\n");
155}
156
157void gk20a_debug_show_dump(struct platform_device *pdev,
158 struct gk20a_debug_output *o)
159{
160 struct gk20a_platform *platform = gk20a_get_platform(pdev);
161 struct gk20a *g = platform->g;
162 struct fifo_gk20a *f = &g->fifo;
163 u32 chid;
164 int i;
165
166 gk20a_busy(g->dev);
167 for (i = 0; i < fifo_pbdma_status__size_1_v(); i++) {
168 u32 status = gk20a_readl(g, fifo_pbdma_status_r(i));
169 u32 chan_status = fifo_pbdma_status_chan_status_v(status);
170
171 gk20a_debug_output(o, "%s pbdma %d: ", g->dev->name, i);
172 gk20a_debug_output(o,
173 "id: %d (%s), next_id: %d (%s) status: %s\n",
174 fifo_pbdma_status_id_v(status),
175 fifo_pbdma_status_id_type_v(status) ?
176 "tsg" : "channel",
177 fifo_pbdma_status_next_id_v(status),
178 fifo_pbdma_status_next_id_type_v(status) ?
179 "tsg" : "channel",
180 chan_status_str[chan_status]);
181 gk20a_debug_output(o, "PUT: %016llx GET: %016llx "
182 "FETCH: %08x HEADER: %08x\n",
183 (u64)gk20a_readl(g, pbdma_put_r(i)) +
184 ((u64)gk20a_readl(g, pbdma_put_hi_r(i)) << 32ULL),
185 (u64)gk20a_readl(g, pbdma_get_r(i)) +
186 ((u64)gk20a_readl(g, pbdma_get_hi_r(i)) << 32ULL),
187 gk20a_readl(g, pbdma_gp_fetch_r(i)),
188 gk20a_readl(g, pbdma_pb_header_r(i)));
189 }
190 gk20a_debug_output(o, "\n");
191
192 for (i = 0; i < fifo_engine_status__size_1_v(); i++) {
193 u32 status = gk20a_readl(g, fifo_engine_status_r(i));
194 u32 ctx_status = fifo_engine_status_ctx_status_v(status);
195
196 gk20a_debug_output(o, "%s eng %d: ", g->dev->name, i);
197 gk20a_debug_output(o,
198 "id: %d (%s), next_id: %d (%s), ctx: %s ",
199 fifo_engine_status_id_v(status),
200 fifo_engine_status_id_type_v(status) ?
201 "tsg" : "channel",
202 fifo_engine_status_next_id_v(status),
203 fifo_engine_status_next_id_type_v(status) ?
204 "tsg" : "channel",
205 ctx_status_str[ctx_status]);
206
207 if (fifo_engine_status_faulted_v(status))
208 gk20a_debug_output(o, "faulted ");
209 if (fifo_engine_status_engine_v(status))
210 gk20a_debug_output(o, "busy ");
211 gk20a_debug_output(o, "\n");
212 }
213 gk20a_debug_output(o, "\n");
214
215 for (chid = 0; chid < f->num_channels; chid++) {
216 if (f->channel[chid].in_use) {
217 struct channel_gk20a *gpu_ch = &f->channel[chid];
218 gk20a_debug_show_channel(g, o, gpu_ch);
219 }
220 }
221 gk20a_idle(g->dev);
222}
223
224void gk20a_debug_dump(struct platform_device *pdev)
225{
226 struct gk20a_platform *platform = gk20a_get_platform(pdev);
227 struct gk20a_debug_output o = {
228 .fn = gk20a_debug_write_printk
229 };
230
231 if (platform->dump_platform_dependencies)
232 platform->dump_platform_dependencies(pdev);
233
234 gk20a_debug_show_dump(pdev, &o);
235}
236
237void gk20a_debug_dump_device(struct platform_device *pdev)
238{
239 struct gk20a_debug_output o = {
240 .fn = gk20a_debug_write_printk
241 };
242
243 /* Dump the first device if no info is provided */
244 if (!pdev && gk20a_device)
245 pdev = gk20a_device;
246
247 gk20a_debug_show_dump(pdev, &o);
248}
249EXPORT_SYMBOL(gk20a_debug_dump_device);
250
251static int gk20a_debug_show(struct seq_file *s, void *unused)
252{
253 struct platform_device *pdev = s->private;
254 struct gk20a_debug_output o = {
255 .fn = gk20a_debug_write_to_seqfile,
256 .ctx = s,
257 };
258 gk20a_debug_show_dump(pdev, &o);
259 return 0;
260}
261
262static int gk20a_debug_open(struct inode *inode, struct file *file)
263{
264 return single_open(file, gk20a_debug_show, inode->i_private);
265}
266
267static const struct file_operations gk20a_debug_fops = {
268 .open = gk20a_debug_open,
269 .read = seq_read,
270 .llseek = seq_lseek,
271 .release = single_release,
272};
273
274void gk20a_debug_init(struct platform_device *pdev)
275{
276 struct gk20a_platform *platform = platform_get_drvdata(pdev);
277
278 /* Store the first device */
279 if (!gk20a_device)
280 gk20a_device = pdev;
281
282 platform->debugfs = debugfs_create_dir(pdev->name, NULL);
283
284 debugfs_create_file("status", S_IRUGO, platform->debugfs,
285 pdev, &gk20a_debug_fops);
286 debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, platform->debugfs,
287 &gk20a_debug_trace_cmdbuf);
288
289#if defined(GK20A_DEBUG)
290 debugfs_create_u32("dbg_mask", S_IRUGO|S_IWUSR, platform->debugfs,
291 &gk20a_dbg_mask);
292 debugfs_create_u32("dbg_ftrace", S_IRUGO|S_IWUSR, platform->debugfs,
293 &gk20a_dbg_ftrace);
294#endif
295}