summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/host/debug.c
diff options
context:
space:
mode:
authorAndrew Howe <ahowe@nvidia.com>2011-03-22 18:38:23 +0200
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:44:59 -0800
commit92be709bc9862ea968a1cc8ca006427bb787b57c (patch)
tree834901fd8a80711ca1420f5e2c6bca4a3bb15851 /drivers/video/tegra/host/debug.c
parent5dd93c6b6029ec95ed39b4a3dd76a0aff85c64b0 (diff)
video: tegra: host: Renovate debug code
Bring in changes to enable dumping the debug state to the kernel log (used when module suspend times out). Rewrote debug code to get that working more cleanly (no 16K buffer). Refactored & cleaned up debug code to make it easier to understand. Original-Change-Id: I22db36a627bfb1815a46866dfe23a5d3aa693edc Reviewed-on: http://git-master/r/24157 Reviewed-by: Scott Williams <scwilliams@nvidia.com> Tested-by: Scott Williams <scwilliams@nvidia.com> Original-Change-Id: I92d7dcc4ede088179a5a1bca982fdfba1eeb3553 Rebase-Id: Ra013bf33c1002d2e37a7c97b7d4b441ad51f7211
Diffstat (limited to 'drivers/video/tegra/host/debug.c')
-rw-r--r--drivers/video/tegra/host/debug.c376
1 files changed, 236 insertions, 140 deletions
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
index d17fe497022d..28dc52f75212 100644
--- a/drivers/video/tegra/host/debug.c
+++ b/drivers/video/tegra/host/debug.c
@@ -4,6 +4,8 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
@@ -22,14 +24,40 @@
#include "dev.h"
-#ifdef CONFIG_DEBUG_FS
+struct output {
+ void (*fn)(void *ctx, const char* str, size_t len);
+ void *ctx;
+ char buf[256];
+};
+
+static void write_to_seqfile(void *ctx, const char* str, size_t len)
+{
+ seq_write((struct seq_file *)ctx, str, len);
+}
+
+static void write_to_printk(void *ctx, const char* str, size_t len)
+{
+ printk("%s", str);
+}
+
+static void output(struct output *o, const char* fmt, ...)
+{
+ va_list args;
+ int len;
+
+ va_start(args, fmt);
+ len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
+ va_end(args);
+ o->fn(o->ctx, o->buf, len);
+}
enum {
NVHOST_DBG_STATE_CMD = 0,
NVHOST_DBG_STATE_DATA = 1,
+ NVHOST_DBG_STATE_GATHER = 2
};
-static int nvhost_debug_handle_cmd(struct seq_file *s, u32 val, int *count)
+static int show_channel_command(struct output *o, u32 val, int *count)
{
unsigned mask;
unsigned subop;
@@ -38,61 +66,56 @@ static int nvhost_debug_handle_cmd(struct seq_file *s, u32 val, int *count)
case 0x0:
mask = val & 0x3f;
if (mask) {
- seq_printf(s, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
+ output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
val >> 6 & 0x3ff, val >> 16 & 0xfff, mask);
*count = hweight8(mask);
return NVHOST_DBG_STATE_DATA;
} else {
- seq_printf(s, "SETCL(class=%03x)\n", val >> 6 & 0x3ff);
+ output(o, "SETCL(class=%03x)\n", val >> 6 & 0x3ff);
return NVHOST_DBG_STATE_CMD;
}
case 0x1:
- seq_printf(s, "INCR(offset=%03x, [", val >> 16 & 0xfff);
+ output(o, "INCR(offset=%03x, [", val >> 16 & 0xfff);
*count = val & 0xffff;
return NVHOST_DBG_STATE_DATA;
case 0x2:
- seq_printf(s, "NONINCR(offset=%03x, [", val >> 16 & 0xfff);
+ output(o, "NONINCR(offset=%03x, [", val >> 16 & 0xfff);
*count = val & 0xffff;
return NVHOST_DBG_STATE_DATA;
case 0x3:
mask = val & 0xffff;
- seq_printf(s, "MASK(offset=%03x, mask=%03x, [",
+ output(o, "MASK(offset=%03x, mask=%03x, [",
val >> 16 & 0xfff, mask);
*count = hweight16(mask);
return NVHOST_DBG_STATE_DATA;
case 0x4:
- seq_printf(s, "IMM(offset=%03x, data=%03x)\n",
+ output(o, "IMM(offset=%03x, data=%03x)\n",
val >> 16 & 0xfff, val & 0xffff);
return NVHOST_DBG_STATE_CMD;
case 0x5:
- seq_printf(s, "RESTART(offset=%08x)\n", val << 4);
+ output(o, "RESTART(offset=%08x)\n", val << 4);
return NVHOST_DBG_STATE_CMD;
case 0x6:
- seq_printf(s, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
- val >> 16 & 0x3ff, val >> 15 & 0x1, val >> 15 & 0x1,
+ output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
+ val >> 16 & 0xfff, val >> 15 & 0x1, val >> 14 & 0x1,
val & 0x3fff);
- *count = 1;
- return NVHOST_DBG_STATE_DATA;
+ *count = val & 0x3fff; // TODO: insert
+ return NVHOST_DBG_STATE_GATHER;
case 0xe:
subop = val >> 24 & 0xf;
if (subop == 0)
- seq_printf(s, "ACQUIRE_MLOCK(index=%d)\n", val & 0xff);
+ output(o, "ACQUIRE_MLOCK(index=%d)\n", val & 0xff);
else if (subop == 1)
- seq_printf(s, "RELEASE_MLOCK(index=%d)\n", val & 0xff);
+ output(o, "RELEASE_MLOCK(index=%d)\n", val & 0xff);
else
- seq_printf(s, "EXTEND_UNKNOWN(%08x)\n", val);
-
- return NVHOST_DBG_STATE_CMD;
-
- case 0xf:
- seq_printf(s, "DONE()\n");
+ output(o, "EXTEND_UNKNOWN(%08x)\n", val);
return NVHOST_DBG_STATE_CMD;
default:
@@ -100,174 +123,240 @@ static int nvhost_debug_handle_cmd(struct seq_file *s, u32 val, int *count)
}
}
-static void nvhost_debug_handle_word(struct seq_file *s, int *state, int *count,
- u32 addr, int channel, u32 val)
+static void show_channel_gather(struct output *o, u32 phys_addr,
+ u32 words);
+
+static void show_channel_word(struct output *o, int *state, int *count,
+ u32 addr, u32 val)
{
switch (*state) {
case NVHOST_DBG_STATE_CMD:
if (addr)
- seq_printf(s, "%d: %08lx: %08x:", channel, addr, val);
+ output(o, "%08x: %08x:", addr, val);
else
- seq_printf(s, "%d: %08x:", channel, val);
+ output(o, "%08x:", val);
- *state = nvhost_debug_handle_cmd(s, val, count);
+ *state = show_channel_command(o, val, count);
if (*state == NVHOST_DBG_STATE_DATA && *count == 0) {
*state = NVHOST_DBG_STATE_CMD;
- seq_printf(s, "])\n");
+ output(o, "])\n");
}
break;
case NVHOST_DBG_STATE_DATA:
(*count)--;
- seq_printf(s, "%08x%s", val, *count > 0 ? ", " : "])\n");
+ output(o, "%08x%s", val, *count > 0 ? ", " : "])\n");
if (*count == 0)
*state = NVHOST_DBG_STATE_CMD;
break;
+
+ case NVHOST_DBG_STATE_GATHER:
+ *state = NVHOST_DBG_STATE_CMD;
+ output(o, "%08x]):\n", val);
+ show_channel_gather(o, val, *count);
+ break;
}
}
-static void nvhost_sync_reg_dump(struct seq_file *s)
+/*
+ * TODO: This uses ioremap_xxx on memory which is deprecated.
+ * Also, it won't work properly with SMMU.
+ */
+static void show_channel_gather(struct output *o, u32 phys_addr,
+ u32 words)
{
- struct nvhost_master *m = s->private;
- int i;
+ u32 map_base = phys_addr & PAGE_MASK;
+ u32 map_end = (phys_addr + words * 4 + PAGE_SIZE - 1) & PAGE_MASK;
+ u32 map_size = map_end - map_base;
+ u32 map_offset = phys_addr - map_base;
+ void *map_addr = ioremap_nocache(map_base, map_size);
+ int state = NVHOST_DBG_STATE_CMD;
+ int count, i;
+
+ if (!map_addr)
+ return;
+ for (i = 0; i < words; i++)
+ show_channel_word(o, &state, &count, phys_addr + i * 4,
+ readl(map_addr + map_offset + i * 4));
+ iounmap(map_addr);
+}
- /* print HOST1X_SYNC regs 4 per line (from 0x3000 -> 0x31E0) */
- for (i = 0; i <= 0x1E0; i += 4) {
- if ((i & 0xF) == 0x0)
- seq_printf(s, "\n0x%08x : ", i);
- seq_printf(s, "%08x ", readl(m->sync_aperture + i));
+static void show_channel_pair(struct output *o, u32 addr,
+ u32 w0, u32 w1)
+{
+ int state = NVHOST_DBG_STATE_CMD;
+ int count;
+
+ show_channel_word(o, &state, &count, addr, w0);
+ show_channel_word(o, &state, &count, addr, w1);
+}
+
+static void show_channel_cdma(struct nvhost_master *m,
+ struct output *o, int chid)
+{
+ struct nvhost_channel *channel = m->channels + chid;
+ u32 dmaput, dmaget, dmactrl;
+ u32 cbstat, cbread;
+ u32 val, base, baseval;
+ u32 pbw[2];
+
+ dmaput = readl(channel->aperture + HOST1X_CHANNEL_DMAPUT);
+ dmaget = readl(channel->aperture + HOST1X_CHANNEL_DMAGET);
+ dmactrl = readl(channel->aperture + HOST1X_CHANNEL_DMACTRL);
+ cbread = readl(m->aperture + HOST1X_SYNC_CBREAD(chid));
+ cbstat = readl(m->aperture + HOST1X_SYNC_CBSTAT(chid));
+
+ output(o, "%d-%s (%d): ", chid,
+ channel->mod.name, atomic_read(&channel->mod.refcount));
+
+ if ((dmactrl & 1) || !channel->cdma.push_buffer.mapped) {
+ output(o, "inactive\n\n");
+ return;
}
- seq_printf(s, "\n\n");
+ switch (cbstat) {
+ case 0x00010008:
+ output(o, "waiting on syncpt %d val %d\n",
+ cbread >> 24, cbread & 0xffffff);
+ break;
+
+ case 0x00010009:
+ base = (cbread >> 16) & 0xff;
+ val = readl(m->aperture + HOST1X_SYNC_SYNCPT_BASE(base));
+ baseval = val & 0xffff;
+ val = cbread & 0xffff;
+ output(o, "waiting on syncpt %d val %d "
+ "(base %d = %d; offset = %d)\n",
+ cbread >> 24, baseval + val,
+ base, baseval, val);
+ break;
- /* print HOST1X_SYNC regs 4 per line (from 0x3340 -> 0x3774) */
- for (i = 0x340; i <= 0x774; i += 4) {
- if ((i & 0xF) == 0x0)
- seq_printf(s, "\n0x%08x : ", i);
- seq_printf(s, "%08x ", readl(m->sync_aperture + i));
+ default:
+ output(o, "active class %02x, offset %04x, val %08x\n",
+ cbstat >> 16, cbstat & 0xffff, cbread);
+ break;
}
+
+ nvhost_cdma_peek(&channel->cdma, dmaget, -1, pbw);
+ show_channel_pair(o, chid, pbw[0], pbw[1]);
+ output(o, "\n");
}
-static int nvhost_debug_show(struct seq_file *s, void *unused)
+void show_channel_fifo(struct nvhost_master *m,
+ struct output *o, int chid)
{
- struct nvhost_master *m = s->private;
- int i;
+ u32 val, rd_ptr, wr_ptr, start, end;
+ int state, count;
- nvhost_module_busy(&m->mod);
+ val = readl(m->aperture + HOST1X_CHANNEL_FIFOSTAT);
+ if (val & (1 << 10))
+ return;
- for (i = 0; i < NVHOST_NUMCHANNELS; i++) {
- void __iomem *regs = m->channels[i].aperture;
- u32 dmaput, dmaget, dmactrl;
- u32 cbstat, cbread;
- u32 fifostat;
- u32 val, base, offset;
- unsigned start, end;
- unsigned wr_ptr, rd_ptr;
- int state;
- int count;
- u32 phys_addr, size;
-
- dmaput = readl(regs + HOST1X_CHANNEL_DMAPUT);
- dmaget = readl(regs + HOST1X_CHANNEL_DMAGET);
- dmactrl = readl(regs + HOST1X_CHANNEL_DMACTRL);
- cbread = readl(m->aperture + HOST1X_SYNC_CBREAD(i));
- cbstat = readl(m->aperture + HOST1X_SYNC_CBSTAT(i));
-
- if (dmactrl != 0x0 || !m->channels[i].cdma.push_buffer.mapped) {
- seq_printf(s, "%d: inactive\n\n", i);
- continue;
- }
+ writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+ writel((1 << 31) | (chid << 16),
+ m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
- switch (cbstat) {
- case 0x00010008: /* HOST_WAIT_SYNCPT */
- seq_printf(s, "waiting on syncpt %d val %d\n",
- cbread >> 24, cbread & 0xffffff);
- break;
+ val = readl(m->aperture + HOST1X_SYNC_CFPEEK_PTRS);
+ rd_ptr = val & 0x1ff;
+ wr_ptr = (val >> 16) & 0x1ff;
- case 0x00010009: /* HOST_WAIT_SYNCPT_BASE */
- base = cbread >> 16 & 0xf;
- offset = cbread & 0xffff;
+ val = readl(m->aperture + HOST1X_SYNC_CF_SETUP(chid));
+ start = val & 0x1ff;
+ end = (val >> 16) & 0x1ff;
- val = readl(m->aperture + HOST1X_SYNC_SYNCPT_BASE(base)) & 0xffff;
- val += offset;
+ state = NVHOST_DBG_STATE_CMD;
+ output(o, "%d: fifo:\n", chid);
- seq_printf(s, "waiting on syncpt %d val %d (base %d = %d, offset %d)\n",
- cbread >> 24, val, base, val - offset, offset);
- break;
+ do {
+ writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+ writel((1 << 31) | (chid << 16) | rd_ptr,
+ m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+ val = readl(m->aperture + HOST1X_SYNC_CFPEEK_READ);
- default:
- seq_printf(s, "%d: active class %02x, offset %04x, val %08x\n",
- i, cbstat >> 16, cbstat & 0xffff, cbread);
- break;
- }
+ show_channel_word(o, &state, &count, 0, val);
- nvhost_cdma_find_gather(&m->channels[i].cdma, dmaget, &phys_addr, &size);
-
- /* If dmaget is in the pushbuffer (should always be?),
- * check if we're executing a fetch, and if so dump
- * it. */
- if (size) {
- u32 map_base = phys_addr & PAGE_MASK;
- u32 map_size = ((phys_addr + size * 4 + PAGE_SIZE - 1) & PAGE_MASK) - map_base;
- u32 map_offset = phys_addr - map_base;
- void *map_addr = ioremap_nocache(map_base, map_size);
-
- if (map_addr) {
- u32 ii;
-
- seq_printf(s, "\n%d: gather (%d words)\n", i, size);
- state = NVHOST_DBG_STATE_CMD;
- for (ii = 0; ii < size; ii++) {
- val = readl(map_addr + map_offset + ii*sizeof(u32));
- nvhost_debug_handle_word(s, &state, &count, phys_addr + ii * 4, i, val);
- }
- iounmap(map_addr);
- }
- }
+ if (rd_ptr == end)
+ rd_ptr = start;
+ else
+ rd_ptr++;
+ } while (rd_ptr != wr_ptr);
- fifostat = readl(regs + HOST1X_CHANNEL_FIFOSTAT);
- if ((fifostat & 1 << 10) == 0 ) {
+ if (state == NVHOST_DBG_STATE_DATA)
+ output(o, ", ...])\n");
+ output(o, "\n");
- seq_printf(s, "\n%d: fifo:\n", i);
- writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
- writel(1 << 31 | i << 16, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
- rd_ptr = readl(m->aperture + HOST1X_SYNC_CFPEEK_PTRS) & 0x1ff;
- wr_ptr = readl(m->aperture + HOST1X_SYNC_CFPEEK_PTRS) >> 16 & 0x1ff;
+ writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+}
- start = readl(m->aperture + HOST1X_SYNC_CF_SETUP(i)) & 0x1ff;
- end = (readl(m->aperture + HOST1X_SYNC_CF_SETUP(i)) >> 16) & 0x1ff;
+static void show_channels(struct nvhost_master *m, struct output *o)
+{
+ int i;
+ output(o, "---- channels ----\n");
+ for (i = 0; i < NVHOST_NUMCHANNELS; i++) {
+ show_channel_cdma(m, o, i);
+ show_channel_fifo(m, o, i);
+ }
+}
- state = NVHOST_DBG_STATE_CMD;
+static void show_mlocks(struct nvhost_master *m, struct output *o)
+{
+ u32 __iomem *mlo_regs = m->sync_aperture + HOST1X_SYNC_MLOCK_OWNER_0;
+ int i;
- do {
- writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
- writel(1 << 31 | i << 16 | rd_ptr, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
- val = readl(m->aperture + HOST1X_SYNC_CFPEEK_READ);
+ output(o, "---- mlocks ----\n");
+ for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
+ u32 owner = readl(mlo_regs + i);
+ if (owner & 0x1)
+ output(o, "%d: locked by channel %d\n",
+ i, (owner >> 8) & 0xf);
+ else if (owner & 0x2)
+ output(o, "%d: locked by cpu\n", i);
+ else
+ output(o, "%d: unlocked\n", i);
+ }
+ output(o, "\n");
+}
- nvhost_debug_handle_word(s, &state, &count, 0, i, val);
+static void show_syncpts(struct nvhost_master *m, struct output *o)
+{
+ int i;
- if (rd_ptr == end)
- rd_ptr = start;
- else
- rd_ptr++;
+ output(o, "---- syncpts ----\n");
+ for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
+ u32 max = nvhost_syncpt_read_max(&m->syncpt, i);
+ if (!max)
+ continue;
+ output(o, "id %d (%s) min %d max %d\n",
+ i, nvhost_syncpt_name(i),
+ nvhost_syncpt_update_min(&m->syncpt, i), max);
+ }
+ output(o, "\n");
+}
- } while (rd_ptr != wr_ptr);
+static void show_all(struct nvhost_master *m, struct output *o)
+{
+ nvhost_module_busy(&m->mod);
- if (state == NVHOST_DBG_STATE_DATA)
- seq_printf(s, ", ...])\n");
- }
+ show_mlocks(m, o);
+ show_syncpts(m, o);
+ show_channels(m, o);
- seq_printf(s, "\n");
- }
+ nvhost_module_idle(&m->mod);
+}
- nvhost_sync_reg_dump(s);
- nvhost_module_idle(&m->mod);
+#ifdef CONFIG_DEBUG_FS
+static int nvhost_debug_show(struct seq_file *s, void *unused)
+{
+ struct output o = {
+ .fn = write_to_seqfile,
+ .ctx = s
+ };
+ show_all(s->private, &o);
return 0;
}
-
static int nvhost_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, nvhost_debug_show, inode->i_private);
@@ -282,12 +371,19 @@ static const struct file_operations nvhost_debug_fops = {
void nvhost_debug_init(struct nvhost_master *master)
{
- debugfs_create_file("tegra_host", S_IRUGO, NULL, master, &nvhost_debug_fops);
+ debugfs_create_file("tegra_host", S_IRUGO, NULL,
+ master, &nvhost_debug_fops);
}
#else
-void nvhost_debug_add(struct nvhost_master *master)
+void nvhost_debug_init(struct nvhost_master *master)
{
}
-
#endif
+void nvhost_debug_dump(struct nvhost_master *master)
+{
+ struct output o = {
+ .fn = write_to_printk
+ };
+ show_all(master, &o);
+}