2 * Copyright (C) 2010 Google, Inc.
3 * Author: Erik Gilling <konkers@android.com>
5 * Copyright (C) 2011-2013 NVIDIA Corporation
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.
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.
21 #include "../channel.h"
23 #define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400
26 HOST1X_OPCODE_SETCLASS
= 0x00,
27 HOST1X_OPCODE_INCR
= 0x01,
28 HOST1X_OPCODE_NONINCR
= 0x02,
29 HOST1X_OPCODE_MASK
= 0x03,
30 HOST1X_OPCODE_IMM
= 0x04,
31 HOST1X_OPCODE_RESTART
= 0x05,
32 HOST1X_OPCODE_GATHER
= 0x06,
33 HOST1X_OPCODE_EXTEND
= 0x0e,
37 HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK
= 0x00,
38 HOST1X_OPCODE_EXTEND_RELEASE_MLOCK
= 0x01,
41 static unsigned int show_channel_command(struct output
*o
, u32 val
)
47 case HOST1X_OPCODE_SETCLASS
:
50 host1x_debug_output(o
, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
52 val
>> 16 & 0xfff, mask
);
53 return hweight8(mask
);
55 host1x_debug_output(o
, "SETCL(class=%03x)\n",
60 case HOST1X_OPCODE_INCR
:
61 host1x_debug_output(o
, "INCR(offset=%03x, [",
65 case HOST1X_OPCODE_NONINCR
:
66 host1x_debug_output(o
, "NONINCR(offset=%03x, [",
70 case HOST1X_OPCODE_MASK
:
72 host1x_debug_output(o
, "MASK(offset=%03x, mask=%03x, [",
73 val
>> 16 & 0xfff, mask
);
74 return hweight16(mask
);
76 case HOST1X_OPCODE_IMM
:
77 host1x_debug_output(o
, "IMM(offset=%03x, data=%03x)\n",
78 val
>> 16 & 0xfff, val
& 0xffff);
81 case HOST1X_OPCODE_RESTART
:
82 host1x_debug_output(o
, "RESTART(offset=%08x)\n", val
<< 4);
85 case HOST1X_OPCODE_GATHER
:
86 host1x_debug_output(o
, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
87 val
>> 16 & 0xfff, val
>> 15 & 0x1,
88 val
>> 14 & 0x1, val
& 0x3fff);
91 case HOST1X_OPCODE_EXTEND
:
92 subop
= val
>> 24 & 0xf;
93 if (subop
== HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK
)
94 host1x_debug_output(o
, "ACQUIRE_MLOCK(index=%d)\n",
96 else if (subop
== HOST1X_OPCODE_EXTEND_RELEASE_MLOCK
)
97 host1x_debug_output(o
, "RELEASE_MLOCK(index=%d)\n",
100 host1x_debug_output(o
, "EXTEND_UNKNOWN(%08x)\n", val
);
108 static void show_gather(struct output
*o
, phys_addr_t phys_addr
,
109 unsigned int words
, struct host1x_cdma
*cdma
,
110 phys_addr_t pin_addr
, u32
*map_addr
)
112 /* Map dmaget cursor to corresponding mem handle */
113 u32 offset
= phys_addr
- pin_addr
;
114 unsigned int data_count
= 0, i
;
117 * Sometimes we're given different hardware address to the same
118 * page - in these cases the offset will get an invalid number and
119 * we just have to bail out.
121 if (offset
> HOST1X_DEBUG_MAX_PAGE_OFFSET
) {
122 host1x_debug_output(o
, "[address mismatch]\n");
126 for (i
= 0; i
< words
; i
++) {
127 u32 addr
= phys_addr
+ i
* 4;
128 u32 val
= *(map_addr
+ offset
/ 4 + i
);
131 host1x_debug_output(o
, "%08x: %08x:", addr
, val
);
132 data_count
= show_channel_command(o
, val
);
134 host1x_debug_output(o
, "%08x%s", val
,
135 data_count
> 0 ? ", " : "])\n");
141 static void show_channel_gathers(struct output
*o
, struct host1x_cdma
*cdma
)
143 struct host1x_job
*job
;
145 list_for_each_entry(job
, &cdma
->sync_queue
, list
) {
147 host1x_debug_output(o
, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n",
148 job
, job
->syncpt_id
, job
->syncpt_end
,
149 job
->first_get
, job
->timeout
,
150 job
->num_slots
, job
->num_unpins
);
152 for (i
= 0; i
< job
->num_gathers
; i
++) {
153 struct host1x_job_gather
*g
= &job
->gathers
[i
];
156 if (job
->gather_copy_mapped
)
157 mapped
= (u32
*)job
->gather_copy_mapped
;
159 mapped
= host1x_bo_mmap(g
->bo
);
162 host1x_debug_output(o
, "[could not mmap]\n");
166 host1x_debug_output(o
, " GATHER at %#llx+%04x, %d words\n",
167 (u64
)g
->base
, g
->offset
, g
->words
);
169 show_gather(o
, g
->base
+ g
->offset
, g
->words
, cdma
,
172 if (!job
->gather_copy_mapped
)
173 host1x_bo_munmap(g
->bo
, mapped
);
178 static void host1x_debug_show_channel_cdma(struct host1x
*host
,
179 struct host1x_channel
*ch
,
182 struct host1x_cdma
*cdma
= &ch
->cdma
;
183 u32 dmaput
, dmaget
, dmactrl
;
185 u32 val
, base
, baseval
;
187 dmaput
= host1x_ch_readl(ch
, HOST1X_CHANNEL_DMAPUT
);
188 dmaget
= host1x_ch_readl(ch
, HOST1X_CHANNEL_DMAGET
);
189 dmactrl
= host1x_ch_readl(ch
, HOST1X_CHANNEL_DMACTRL
);
190 cbread
= host1x_sync_readl(host
, HOST1X_SYNC_CBREAD(ch
->id
));
191 cbstat
= host1x_sync_readl(host
, HOST1X_SYNC_CBSTAT(ch
->id
));
193 host1x_debug_output(o
, "%d-%s: ", ch
->id
, dev_name(ch
->dev
));
195 if (HOST1X_CHANNEL_DMACTRL_DMASTOP_V(dmactrl
) ||
196 !ch
->cdma
.push_buffer
.mapped
) {
197 host1x_debug_output(o
, "inactive\n\n");
201 if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat
) == HOST1X_CLASS_HOST1X
&&
202 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat
) ==
203 HOST1X_UCLASS_WAIT_SYNCPT
)
204 host1x_debug_output(o
, "waiting on syncpt %d val %d\n",
205 cbread
>> 24, cbread
& 0xffffff);
206 else if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat
) ==
207 HOST1X_CLASS_HOST1X
&&
208 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat
) ==
209 HOST1X_UCLASS_WAIT_SYNCPT_BASE
) {
211 base
= (cbread
>> 16) & 0xff;
213 host1x_sync_readl(host
, HOST1X_SYNC_SYNCPT_BASE(base
));
214 val
= cbread
& 0xffff;
215 host1x_debug_output(o
, "waiting on syncpt %d val %d (base %d = %d; offset = %d)\n",
216 cbread
>> 24, baseval
+ val
, base
,
219 host1x_debug_output(o
, "active class %02x, offset %04x, val %08x\n",
220 HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat
),
221 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat
),
224 host1x_debug_output(o
, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n",
225 dmaput
, dmaget
, dmactrl
);
226 host1x_debug_output(o
, "CBREAD %08x, CBSTAT %08x\n", cbread
, cbstat
);
228 show_channel_gathers(o
, cdma
);
229 host1x_debug_output(o
, "\n");
232 static void host1x_debug_show_channel_fifo(struct host1x
*host
,
233 struct host1x_channel
*ch
,
236 u32 val
, rd_ptr
, wr_ptr
, start
, end
;
237 unsigned int data_count
= 0;
239 host1x_debug_output(o
, "%d: fifo:\n", ch
->id
);
241 val
= host1x_ch_readl(ch
, HOST1X_CHANNEL_FIFOSTAT
);
242 host1x_debug_output(o
, "FIFOSTAT %08x\n", val
);
243 if (HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(val
)) {
244 host1x_debug_output(o
, "[empty]\n");
248 host1x_sync_writel(host
, 0x0, HOST1X_SYNC_CFPEEK_CTRL
);
249 host1x_sync_writel(host
, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
250 HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch
->id
),
251 HOST1X_SYNC_CFPEEK_CTRL
);
253 val
= host1x_sync_readl(host
, HOST1X_SYNC_CFPEEK_PTRS
);
254 rd_ptr
= HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(val
);
255 wr_ptr
= HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(val
);
257 val
= host1x_sync_readl(host
, HOST1X_SYNC_CF_SETUP(ch
->id
));
258 start
= HOST1X_SYNC_CF_SETUP_BASE_V(val
);
259 end
= HOST1X_SYNC_CF_SETUP_LIMIT_V(val
);
262 host1x_sync_writel(host
, 0x0, HOST1X_SYNC_CFPEEK_CTRL
);
263 host1x_sync_writel(host
, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
264 HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch
->id
) |
265 HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(rd_ptr
),
266 HOST1X_SYNC_CFPEEK_CTRL
);
267 val
= host1x_sync_readl(host
, HOST1X_SYNC_CFPEEK_READ
);
270 host1x_debug_output(o
, "%08x:", val
);
271 data_count
= show_channel_command(o
, val
);
273 host1x_debug_output(o
, "%08x%s", val
,
274 data_count
> 0 ? ", " : "])\n");
282 } while (rd_ptr
!= wr_ptr
);
285 host1x_debug_output(o
, ", ...])\n");
286 host1x_debug_output(o
, "\n");
288 host1x_sync_writel(host
, 0x0, HOST1X_SYNC_CFPEEK_CTRL
);
291 static void host1x_debug_show_mlocks(struct host1x
*host
, struct output
*o
)
295 host1x_debug_output(o
, "---- mlocks ----\n");
296 for (i
= 0; i
< host1x_syncpt_nb_mlocks(host
); i
++) {
298 host1x_sync_readl(host
, HOST1X_SYNC_MLOCK_OWNER(i
));
299 if (HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(owner
))
300 host1x_debug_output(o
, "%d: locked by channel %d\n",
301 i
, HOST1X_SYNC_MLOCK_OWNER_CHID_F(owner
));
302 else if (HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(owner
))
303 host1x_debug_output(o
, "%d: locked by cpu\n", i
);
305 host1x_debug_output(o
, "%d: unlocked\n", i
);
307 host1x_debug_output(o
, "\n");
310 static const struct host1x_debug_ops host1x_debug_ops
= {
311 .show_channel_cdma
= host1x_debug_show_channel_cdma
,
312 .show_channel_fifo
= host1x_debug_show_channel_fifo
,
313 .show_mlocks
= host1x_debug_show_mlocks
,