aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/host/host1x/host1x_debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/host/host1x/host1x_debug.c')
-rw-r--r--drivers/video/tegra/host/host1x/host1x_debug.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/host1x/host1x_debug.c b/drivers/video/tegra/host/host1x/host1x_debug.c
new file mode 100644
index 00000000000..1a1d764bbd6
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_debug.c
@@ -0,0 +1,404 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_debug.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * Copyright (C) 2011 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/debugfs.h>
21#include <linux/seq_file.h>
22#include <linux/mm.h>
23
24#include <linux/io.h>
25
26#include "dev.h"
27#include "debug.h"
28#include "nvhost_cdma.h"
29#include "../../nvmap/nvmap.h"
30
31#include "host1x_hardware.h"
32#include "host1x_cdma.h"
33
34#define NVHOST_DEBUG_MAX_PAGE_OFFSET 102400
35
36enum {
37 NVHOST_DBG_STATE_CMD = 0,
38 NVHOST_DBG_STATE_DATA = 1,
39 NVHOST_DBG_STATE_GATHER = 2
40};
41
42static int show_channel_command(struct output *o, u32 addr, u32 val, int *count)
43{
44 unsigned mask;
45 unsigned subop;
46
47 switch (val >> 28) {
48 case 0x0:
49 mask = val & 0x3f;
50 if (mask) {
51 nvhost_debug_output(o,
52 "SETCL(class=%03x, offset=%03x, mask=%02x, [",
53 val >> 6 & 0x3ff, val >> 16 & 0xfff, mask);
54 *count = hweight8(mask);
55 return NVHOST_DBG_STATE_DATA;
56 } else {
57 nvhost_debug_output(o, "SETCL(class=%03x)\n",
58 val >> 6 & 0x3ff);
59 return NVHOST_DBG_STATE_CMD;
60 }
61
62 case 0x1:
63 nvhost_debug_output(o, "INCR(offset=%03x, [",
64 val >> 16 & 0xfff);
65 *count = val & 0xffff;
66 return NVHOST_DBG_STATE_DATA;
67
68 case 0x2:
69 nvhost_debug_output(o, "NONINCR(offset=%03x, [",
70 val >> 16 & 0xfff);
71 *count = val & 0xffff;
72 return NVHOST_DBG_STATE_DATA;
73
74 case 0x3:
75 mask = val & 0xffff;
76 nvhost_debug_output(o, "MASK(offset=%03x, mask=%03x, [",
77 val >> 16 & 0xfff, mask);
78 *count = hweight16(mask);
79 return NVHOST_DBG_STATE_DATA;
80
81 case 0x4:
82 nvhost_debug_output(o, "IMM(offset=%03x, data=%03x)\n",
83 val >> 16 & 0xfff, val & 0xffff);
84 return NVHOST_DBG_STATE_CMD;
85
86 case 0x5:
87 nvhost_debug_output(o, "RESTART(offset=%08x)\n", val << 4);
88 return NVHOST_DBG_STATE_CMD;
89
90 case 0x6:
91 nvhost_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
92 val >> 16 & 0xfff, val >> 15 & 0x1, val >> 14 & 0x1,
93 val & 0x3fff);
94 *count = val & 0x3fff; /* TODO: insert */
95 return NVHOST_DBG_STATE_GATHER;
96
97 case 0xe:
98 subop = val >> 24 & 0xf;
99 if (subop == 0)
100 nvhost_debug_output(o, "ACQUIRE_MLOCK(index=%d)\n",
101 val & 0xff);
102 else if (subop == 1)
103 nvhost_debug_output(o, "RELEASE_MLOCK(index=%d)\n",
104 val & 0xff);
105 else
106 nvhost_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val);
107 return NVHOST_DBG_STATE_CMD;
108
109 default:
110 return NVHOST_DBG_STATE_CMD;
111 }
112}
113
114static void show_channel_gather(struct output *o, u32 addr,
115 phys_addr_t phys_addr, u32 words, struct nvhost_cdma *cdma);
116
117static void show_channel_word(struct output *o, int *state, int *count,
118 u32 addr, u32 val, struct nvhost_cdma *cdma)
119{
120 static int start_count, dont_print;
121
122 switch (*state) {
123 case NVHOST_DBG_STATE_CMD:
124 if (addr)
125 nvhost_debug_output(o, "%08x: %08x:", addr, val);
126 else
127 nvhost_debug_output(o, "%08x:", val);
128
129 *state = show_channel_command(o, addr, val, count);
130 dont_print = 0;
131 start_count = *count;
132 if (*state == NVHOST_DBG_STATE_DATA && *count == 0) {
133 *state = NVHOST_DBG_STATE_CMD;
134 nvhost_debug_output(o, "])\n");
135 }
136 break;
137
138 case NVHOST_DBG_STATE_DATA:
139 (*count)--;
140 if (start_count - *count < 64)
141 nvhost_debug_output(o, "%08x%s",
142 val, *count > 0 ? ", " : "])\n");
143 else if (!dont_print && (*count > 0)) {
144 nvhost_debug_output(o, "[truncated; %d more words]\n",
145 *count);
146 dont_print = 1;
147 }
148 if (*count == 0)
149 *state = NVHOST_DBG_STATE_CMD;
150 break;
151
152 case NVHOST_DBG_STATE_GATHER:
153 *state = NVHOST_DBG_STATE_CMD;
154 nvhost_debug_output(o, "%08x]):\n", val);
155 if (cdma) {
156 show_channel_gather(o, addr, val,
157 *count, cdma);
158 }
159 break;
160 }
161}
162
163static void show_channel_gather(struct output *o, u32 addr,
164 phys_addr_t phys_addr,
165 u32 words, struct nvhost_cdma *cdma)
166{
167#if defined(CONFIG_TEGRA_NVMAP)
168 /* Map dmaget cursor to corresponding nvmap_handle */
169 struct push_buffer *pb = &cdma->push_buffer;
170 u32 cur = addr - pb->phys;
171 struct nvmap_client_handle *nvmap = &pb->nvmap[cur/8];
172 struct nvmap_handle_ref ref;
173 u32 *map_addr, offset;
174 phys_addr_t pin_addr;
175 int state, count, i;
176
177 if ((u32)nvmap->handle == NVHOST_CDMA_PUSH_GATHER_CTXSAVE) {
178 nvhost_debug_output(o, "[context save]\n");
179 return;
180 }
181
182 if (!nvmap->handle || !nvmap->client
183 || atomic_read(&nvmap->handle->ref) < 1) {
184 nvhost_debug_output(o, "[already deallocated]\n");
185 return;
186 }
187
188 /* Create a fake nvmap_handle_ref - nvmap requires it
189 * but accesses only the first field - nvmap_handle */
190 ref.handle = nvmap->handle;
191
192 map_addr = nvmap_mmap(&ref);
193 if (!map_addr) {
194 nvhost_debug_output(o, "[could not mmap]\n");
195 return;
196 }
197
198 /* Get base address from nvmap */
199 pin_addr = nvmap_pin(nvmap->client, &ref);
200 if (IS_ERR_VALUE(pin_addr)) {
201 nvhost_debug_output(o, "[couldn't pin]\n");
202 nvmap_munmap(&ref, map_addr);
203 return;
204 }
205
206 offset = phys_addr - pin_addr;
207 /*
208 * Sometimes we're given different hardware address to the same
209 * page - in these cases the offset will get an invalid number and
210 * we just have to bail out.
211 */
212 if (offset > NVHOST_DEBUG_MAX_PAGE_OFFSET) {
213 nvhost_debug_output(o, "[address mismatch]\n");
214 } else {
215 /* GATHER buffer starts always with commands */
216 state = NVHOST_DBG_STATE_CMD;
217 for (i = 0; i < words; i++)
218 show_channel_word(o, &state, &count,
219 phys_addr + i * 4,
220 *(map_addr + offset/4 + i),
221 cdma);
222 }
223 nvmap_unpin(nvmap->client, &ref);
224 nvmap_munmap(&ref, map_addr);
225#endif
226}
227
228static void show_channel_pair(struct output *o, u32 addr,
229 u32 w0, u32 w1, struct nvhost_cdma *cdma)
230{
231 int state = NVHOST_DBG_STATE_CMD;
232 int count;
233
234 show_channel_word(o, &state, &count, addr, w0, cdma);
235 show_channel_word(o, &state, &count, addr+4, w1, cdma);
236}
237
238/**
239 * Retrieve the op pair at a slot offset from a DMA address
240 */
241static void cdma_peek(struct nvhost_cdma *cdma,
242 u32 dmaget, int slot, u32 *out)
243{
244 u32 offset = dmaget - cdma->push_buffer.phys;
245 u32 *p = cdma->push_buffer.mapped;
246
247 offset = ((offset + slot * 8) & (PUSH_BUFFER_SIZE - 1)) >> 2;
248 out[0] = p[offset];
249 out[1] = p[offset + 1];
250}
251
252u32 previous_oppair(struct nvhost_cdma *cdma, u32 cur)
253{
254 u32 pb = cdma->push_buffer.phys;
255 u32 prev = cur-8;
256 if (prev < pb)
257 prev += PUSH_BUFFER_SIZE;
258 return prev;
259}
260
261static void t20_debug_show_channel_cdma(struct nvhost_master *m,
262 struct nvhost_channel *ch, struct output *o, int chid)
263{
264 struct nvhost_channel *channel = ch;
265 struct nvhost_cdma *cdma = &channel->cdma;
266 u32 dmaput, dmaget, dmactrl;
267 u32 cbstat, cbread;
268 u32 val, base, baseval;
269 u32 pbw[2];
270
271 dmaput = readl(channel->aperture + HOST1X_CHANNEL_DMAPUT);
272 dmaget = readl(channel->aperture + HOST1X_CHANNEL_DMAGET);
273 dmactrl = readl(channel->aperture + HOST1X_CHANNEL_DMACTRL);
274 cbread = readl(m->sync_aperture + HOST1X_SYNC_CBREAD_x(chid));
275 cbstat = readl(m->sync_aperture + HOST1X_SYNC_CBSTAT_x(chid));
276
277 nvhost_debug_output(o, "%d-%s (%d): ", chid,
278 channel->dev->name,
279 channel->dev->refcount);
280
281 if (HOST1X_VAL(CHANNEL_DMACTRL, DMASTOP, dmactrl)
282 || !channel->cdma.push_buffer.mapped) {
283 nvhost_debug_output(o, "inactive\n\n");
284 return;
285 }
286
287 switch (cbstat) {
288 case 0x00010008:
289 nvhost_debug_output(o, "waiting on syncpt %d val %d\n",
290 cbread >> 24, cbread & 0xffffff);
291 break;
292
293 case 0x00010009:
294 base = (cbread >> 16) & 0xff;
295 val = readl(m->sync_aperture +
296 HOST1X_SYNC_SYNCPT_BASE_x(base));
297 baseval = HOST1X_VAL(SYNC_SYNCPT_BASE_0, BASE, val);
298 val = cbread & 0xffff;
299 nvhost_debug_output(o, "waiting on syncpt %d val %d "
300 "(base %d = %d; offset = %d)\n",
301 cbread >> 24, baseval + val,
302 base, baseval, val);
303 break;
304
305 default:
306 nvhost_debug_output(o,
307 "active class %02x, offset %04x, val %08x\n",
308 HOST1X_VAL(SYNC_CBSTAT_0, CBCLASS0, cbstat),
309 HOST1X_VAL(SYNC_CBSTAT_0, CBOFFSET0, cbstat),
310 cbread);
311 break;
312 }
313
314 nvhost_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n",
315 dmaput, dmaget, dmactrl);
316 nvhost_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat);
317
318 cdma_peek(cdma, dmaget, -1, pbw);
319 show_channel_pair(o, previous_oppair(cdma, dmaget),
320 pbw[0], pbw[1], &channel->cdma);
321 nvhost_debug_output(o, "\n");
322}
323
324void t20_debug_show_channel_fifo(struct nvhost_master *m,
325 struct nvhost_channel *ch, struct output *o, int chid)
326{
327 u32 val, rd_ptr, wr_ptr, start, end;
328 struct nvhost_channel *channel = ch;
329 int state, count;
330
331 nvhost_debug_output(o, "%d: fifo:\n", chid);
332
333 val = readl(channel->aperture + HOST1X_CHANNEL_FIFOSTAT);
334 nvhost_debug_output(o, "FIFOSTAT %08x\n", val);
335 if (HOST1X_VAL(CHANNEL_FIFOSTAT, CFEMPTY, val)) {
336 nvhost_debug_output(o, "[empty]\n");
337 return;
338 }
339
340 writel(0x0, m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
341 writel(HOST1X_CREATE(SYNC_CFPEEK_CTRL, ENA, 1)
342 | HOST1X_CREATE(SYNC_CFPEEK_CTRL, CHANNR, chid),
343 m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
344
345 val = readl(m->sync_aperture + HOST1X_SYNC_CFPEEK_PTRS);
346 rd_ptr = HOST1X_VAL(SYNC_CFPEEK_PTRS, CF_RD_PTR, val);
347 wr_ptr = HOST1X_VAL(SYNC_CFPEEK_PTRS, CF_WR_PTR, val);
348
349 val = readl(m->sync_aperture + HOST1X_SYNC_CFx_SETUP(chid));
350 start = HOST1X_VAL(SYNC_CF0_SETUP, BASE, val);
351 end = HOST1X_VAL(SYNC_CF0_SETUP, LIMIT, val);
352
353 state = NVHOST_DBG_STATE_CMD;
354
355 do {
356 writel(0x0, m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
357 writel(HOST1X_CREATE(SYNC_CFPEEK_CTRL, ENA, 1)
358 | HOST1X_CREATE(SYNC_CFPEEK_CTRL, CHANNR, chid)
359 | HOST1X_CREATE(SYNC_CFPEEK_CTRL, ADDR, rd_ptr),
360 m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
361 val = readl(m->sync_aperture + HOST1X_SYNC_CFPEEK_READ);
362
363 show_channel_word(o, &state, &count, 0, val, NULL);
364
365 if (rd_ptr == end)
366 rd_ptr = start;
367 else
368 rd_ptr++;
369 } while (rd_ptr != wr_ptr);
370
371 if (state == NVHOST_DBG_STATE_DATA)
372 nvhost_debug_output(o, ", ...])\n");
373 nvhost_debug_output(o, "\n");
374
375 writel(0x0, m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
376}
377
378static void t20_debug_show_mlocks(struct nvhost_master *m, struct output *o)
379{
380 u32 __iomem *mlo_regs = m->sync_aperture + HOST1X_SYNC_MLOCK_OWNER_0;
381 int i;
382
383 nvhost_debug_output(o, "---- mlocks ----\n");
384 for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
385 u32 owner = readl(mlo_regs + i);
386 if (HOST1X_VAL(SYNC_MLOCK_OWNER_0, CH_OWNS, owner))
387 nvhost_debug_output(o, "%d: locked by channel %d\n",
388 i, HOST1X_VAL(SYNC_MLOCK_OWNER_0, CHID, owner));
389 else if (HOST1X_VAL(SYNC_MLOCK_OWNER_0, CPU_OWNS, owner))
390 nvhost_debug_output(o, "%d: locked by cpu\n", i);
391 else
392 nvhost_debug_output(o, "%d: unlocked\n", i);
393 }
394 nvhost_debug_output(o, "\n");
395}
396
397int nvhost_init_t20_debug_support(struct nvhost_master *host)
398{
399 host->op.debug.show_channel_cdma = t20_debug_show_channel_cdma;
400 host->op.debug.show_channel_fifo = t20_debug_show_channel_fifo;
401 host->op.debug.show_mlocks = t20_debug_show_mlocks;
402
403 return 0;
404}