4cb946409e6da19ae9812f4ef7f30ea76f5d0925
[linux-3.10.git] / drivers / video / tegra / host / host1x / host1x_debug.c
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 #include <linux/scatterlist.h>
24
25 #include <linux/io.h>
26
27 #include "dev.h"
28 #include "debug.h"
29 #include "nvhost_cdma.h"
30 #include "nvhost_channel.h"
31 #include "nvhost_job.h"
32 #include "chip_support.h"
33 #include "nvhost_memmgr.h"
34
35 #define NVHOST_DEBUG_MAX_PAGE_OFFSET 102400
36
37 enum {
38         NVHOST_DBG_STATE_CMD = 0,
39         NVHOST_DBG_STATE_DATA = 1,
40         NVHOST_DBG_STATE_GATHER = 2
41 };
42
43 static void do_show_channel_gather(struct output *o,
44                 phys_addr_t phys_addr,
45                 u32 words, struct nvhost_cdma *cdma,
46                 phys_addr_t pin_addr, u32 *map_addr)
47 {
48         /* Map dmaget cursor to corresponding nvmap_handle */
49         u32 offset;
50         int state, i;
51
52         offset = phys_addr - pin_addr;
53         /*
54          * Sometimes we're given different hardware address to the same
55          * page - in these cases the offset will get an invalid number and
56          * we just have to bail out.
57          */
58         if (offset > NVHOST_DEBUG_MAX_PAGE_OFFSET) {
59                 nvhost_debug_output(o, "[address mismatch]\n");
60         } else {
61                 /* GATHER buffer starts always with commands */
62                 state = NVHOST_DBG_STATE_CMD;
63                 for (i = 0; i < words; i++)
64                         nvhost_debug_output(o,
65                                         "%08x ", *(map_addr + offset/4 + i));
66                 nvhost_debug_output(o, "\n");
67         }
68 }
69
70 static void show_channel_gathers(struct output *o, struct nvhost_cdma *cdma)
71 {
72         struct nvhost_job *job =
73                 list_first_entry(&cdma->sync_queue, struct nvhost_job, list);
74         int i;
75         nvhost_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d,"
76                         " first_get=%08x, timeout=%d, ctx=%p,"
77                         " num_slots=%d, num_handles=%d\n",
78                         job,
79                         job->syncpt_id,
80                         job->syncpt_end,
81                         job->first_get,
82                         job->timeout,
83                         job->hwctx,
84                         job->num_slots,
85                         job->num_unpins);
86
87         for (i = 0; i < job->num_gathers; i++) {
88                 struct nvhost_job_gather *g = &job->gathers[i];
89                 u32 *mapped = nvhost_memmgr_mmap(g->ref);
90                 if (!mapped) {
91                         nvhost_debug_output(o, "[could not mmap]\n");
92                         continue;
93                 }
94
95                 nvhost_debug_output(o,
96                         "    GATHER at %08x+%04x, %d words\n",
97                         g->mem_base, g->offset, g->words);
98
99                 do_show_channel_gather(o, g->mem_base + g->offset,
100                                 g->words, cdma, g->mem_base, mapped);
101                 nvhost_memmgr_munmap(g->ref, mapped);
102         }
103 }
104
105 static void t20_debug_show_channel_cdma(struct nvhost_master *m,
106         struct nvhost_channel *ch, struct output *o, int chid)
107 {
108         struct nvhost_channel *channel = ch;
109         struct nvhost_cdma *cdma = &channel->cdma;
110         u32 dmaput, dmaget, dmactrl;
111         u32 cbstat, cbread, cmdstat;
112         u32 val, base, baseval;
113         struct nvhost_device_data *pdata = platform_get_drvdata(channel->dev);
114
115         dmaput = readl(channel->aperture + host1x_channel_dmaput_r());
116         dmaget = readl(channel->aperture + host1x_channel_dmaget_r());
117         dmactrl = readl(channel->aperture + host1x_channel_dmactrl_r());
118         cbread = readl(m->sync_aperture + host1x_sync_cbread0_r() + 4 * chid);
119         cbstat = readl(m->sync_aperture + host1x_sync_cbstat_0_r() + 4 * chid);
120         cmdstat = readl(m->sync_aperture + host1x_sync_cmdproc_stat_r());
121
122         nvhost_debug_output(o, "%d-%s (%d): ", chid,
123                             channel->dev->name,
124                             pdata->refcount);
125
126         if (host1x_channel_dmactrl_dmastop_v(dmactrl)
127                 || !channel->cdma.push_buffer.mapped) {
128                 nvhost_debug_output(o, "inactive\n\n");
129                 return;
130         }
131
132         if (cmdstat & BIT(chid))
133                 nvhost_debug_output(o, "bad opcode observed, ");
134
135         switch (cbstat) {
136         case 0x00010008:
137                 nvhost_debug_output(o, "waiting on syncpt %d val %d\n",
138                         cbread >> 24, cbread & 0xffffff);
139                 break;
140
141         case 0x00010009:
142                 base = (cbread >> 16) & 0xff;
143                 baseval = readl(m->sync_aperture +
144                                 host1x_sync_syncpt_base_0_r() + 4 * base);
145                 val = cbread & 0xffff;
146                 nvhost_debug_output(o, "waiting on syncpt %d val %d "
147                           "(base %d = %d; offset = %d)\n",
148                         cbread >> 24, baseval + val,
149                         base, baseval, val);
150                 break;
151
152         default:
153                 nvhost_debug_output(o,
154                                 "active class %02x, offset %04x, val %08x\n",
155                                 host1x_sync_cbstat_0_cbclass0_v(cbstat),
156                                 host1x_sync_cbstat_0_cboffset0_v(cbstat),
157                                 cbread);
158                 break;
159         }
160
161         nvhost_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n",
162                 dmaput, dmaget, dmactrl);
163         nvhost_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat);
164
165         show_channel_gathers(o, cdma);
166         nvhost_debug_output(o, "\n");
167 }
168
169 static void t20_debug_show_channel_fifo(struct nvhost_master *m,
170         struct nvhost_channel *ch, struct output *o, int chid)
171 {
172         u32 val, rd_ptr, wr_ptr, start, end, max = 64;
173         struct nvhost_channel *channel = ch;
174
175         nvhost_debug_output(o, "%d: fifo:\n", chid);
176
177         writel(host1x_sync_cfpeek_ctrl_cfpeek_ena_f(1)
178                         | host1x_sync_cfpeek_ctrl_cfpeek_channr_f(chid),
179                 m->sync_aperture + host1x_sync_cfpeek_ctrl_r());
180         wmb();
181
182         val = readl(channel->aperture + host1x_channel_fifostat_r());
183         if (host1x_channel_fifostat_cfempty_v(val)) {
184                 writel(0x0, m->sync_aperture + host1x_sync_cfpeek_ctrl_r());
185                 nvhost_debug_output(o, "FIFOSTAT %08x\n[empty]\n",
186                                 val);
187                 return;
188         }
189
190         val = readl(m->sync_aperture + host1x_sync_cfpeek_ptrs_r());
191         rd_ptr = host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(val);
192         wr_ptr = host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(val);
193
194         val = readl(m->sync_aperture + host1x_sync_cf0_setup_r() + 4 * chid);
195         start = host1x_sync_cf0_setup_cf0_base_v(val);
196         end = host1x_sync_cf0_setup_cf0_limit_v(val);
197
198         nvhost_debug_output(o, "FIFOSTAT %08x, %03x - %03x, RD %03x, WR %03x\n",
199                         val, start, end, rd_ptr, wr_ptr);
200         do {
201                 writel(host1x_sync_cfpeek_ctrl_cfpeek_ena_f(1)
202                                 | host1x_sync_cfpeek_ctrl_cfpeek_channr_f(chid)
203                                 | host1x_sync_cfpeek_ctrl_cfpeek_addr_f(rd_ptr),
204                         m->sync_aperture + host1x_sync_cfpeek_ctrl_r());
205                 wmb();
206                 val = readl(m->sync_aperture + host1x_sync_cfpeek_read_r());
207                 rmb();
208
209                 nvhost_debug_output(o, "%08x ", val);
210
211                 if (rd_ptr == end)
212                         rd_ptr = start;
213                 else
214                         rd_ptr++;
215
216                 max--;
217         } while (max && rd_ptr != wr_ptr);
218
219         nvhost_debug_output(o, "\n");
220
221         writel(0x0, m->sync_aperture + host1x_sync_cfpeek_ctrl_r());
222 }
223
224 static void t20_debug_show_mlocks(struct nvhost_master *m, struct output *o)
225 {
226         u32 __iomem *mlo_regs = m->sync_aperture +
227                 host1x_sync_mlock_owner_0_r();
228         int i;
229
230         nvhost_debug_output(o, "---- mlocks ----\n");
231         for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
232                 u32 owner = readl(mlo_regs + i);
233                 if (host1x_sync_mlock_owner_0_mlock_ch_owns_0_v(owner))
234                         nvhost_debug_output(o, "%d: locked by channel %d\n",
235                                 i,
236                                 host1x_sync_mlock_owner_0_mlock_owner_chid_0_v(
237                                         owner));
238                 else if (host1x_sync_mlock_owner_0_mlock_cpu_owns_0_v(owner))
239                         nvhost_debug_output(o, "%d: locked by cpu\n", i);
240         }
241         nvhost_debug_output(o, "\n");
242 }
243
244 static const struct nvhost_debug_ops host1x_debug_ops = {
245         .show_channel_cdma = t20_debug_show_channel_cdma,
246         .show_channel_fifo = t20_debug_show_channel_fifo,
247         .show_mlocks = t20_debug_show_mlocks,
248 };