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
)
43 unsigned int mask
, subop
;
46 case HOST1X_OPCODE_SETCLASS
:
49 host1x_debug_output(o
, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
51 val
>> 16 & 0xfff, mask
);
52 return hweight8(mask
);
55 host1x_debug_output(o
, "SETCL(class=%03x)\n", val
>> 6 & 0x3ff);
58 case HOST1X_OPCODE_INCR
:
59 host1x_debug_output(o
, "INCR(offset=%03x, [",
63 case HOST1X_OPCODE_NONINCR
:
64 host1x_debug_output(o
, "NONINCR(offset=%03x, [",
68 case HOST1X_OPCODE_MASK
:
70 host1x_debug_output(o
, "MASK(offset=%03x, mask=%03x, [",
71 val
>> 16 & 0xfff, mask
);
72 return hweight16(mask
);
74 case HOST1X_OPCODE_IMM
:
75 host1x_debug_output(o
, "IMM(offset=%03x, data=%03x)\n",
76 val
>> 16 & 0xfff, val
& 0xffff);
79 case HOST1X_OPCODE_RESTART
:
80 host1x_debug_output(o
, "RESTART(offset=%08x)\n", val
<< 4);
83 case HOST1X_OPCODE_GATHER
:
84 host1x_debug_output(o
, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
85 val
>> 16 & 0xfff, val
>> 15 & 0x1,
86 val
>> 14 & 0x1, val
& 0x3fff);
89 case HOST1X_OPCODE_EXTEND
:
90 subop
= val
>> 24 & 0xf;
91 if (subop
== HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK
)
92 host1x_debug_output(o
, "ACQUIRE_MLOCK(index=%d)\n",
94 else if (subop
== HOST1X_OPCODE_EXTEND_RELEASE_MLOCK
)
95 host1x_debug_output(o
, "RELEASE_MLOCK(index=%d)\n",
98 host1x_debug_output(o
, "EXTEND_UNKNOWN(%08x)\n", val
);
106 static void show_gather(struct output
*o
, phys_addr_t phys_addr
,
107 unsigned int words
, struct host1x_cdma
*cdma
,
108 phys_addr_t pin_addr
, u32
*map_addr
)
110 /* Map dmaget cursor to corresponding mem handle */
111 u32 offset
= phys_addr
- pin_addr
;
112 unsigned int data_count
= 0, i
;
115 * Sometimes we're given different hardware address to the same
116 * page - in these cases the offset will get an invalid number and
117 * we just have to bail out.
119 if (offset
> HOST1X_DEBUG_MAX_PAGE_OFFSET
) {
120 host1x_debug_output(o
, "[address mismatch]\n");
124 for (i
= 0; i
< words
; i
++) {
125 u32 addr
= phys_addr
+ i
* 4;
126 u32 val
= *(map_addr
+ offset
/ 4 + i
);
129 host1x_debug_output(o
, "%08x: %08x:", addr
, val
);
130 data_count
= show_channel_command(o
, val
);
132 host1x_debug_output(o
, "%08x%s", val
,
133 data_count
> 0 ? ", " : "])\n");
139 static void show_channel_gathers(struct output
*o
, struct host1x_cdma
*cdma
)
141 struct host1x_job
*job
;
143 list_for_each_entry(job
, &cdma
->sync_queue
, list
) {
146 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",
147 job
, job
->syncpt_id
, job
->syncpt_end
,
148 job
->first_get
, job
->timeout
,
149 job
->num_slots
, job
->num_unpins
);
151 for (i
= 0; i
< job
->num_gathers
; i
++) {
152 struct host1x_job_gather
*g
= &job
->gathers
[i
];
155 if (job
->gather_copy_mapped
)
156 mapped
= (u32
*)job
->gather_copy_mapped
;
158 mapped
= host1x_bo_mmap(g
->bo
);
161 host1x_debug_output(o
, "[could not mmap]\n");
165 host1x_debug_output(o
, " GATHER at %pad+%#x, %d words\n",
166 &g
->base
, g
->offset
, g
->words
);
168 show_gather(o
, g
->base
+ g
->offset
, g
->words
, cdma
,
171 if (!job
->gather_copy_mapped
)
172 host1x_bo_munmap(g
->bo
, mapped
);
177 static void host1x_debug_show_channel_cdma(struct host1x
*host
,
178 struct host1x_channel
*ch
,
181 struct host1x_cdma
*cdma
= &ch
->cdma
;
182 u32 dmaput
, dmaget
, dmactrl
;
184 u32 val
, base
, baseval
;
186 dmaput
= host1x_ch_readl(ch
, HOST1X_CHANNEL_DMAPUT
);
187 dmaget
= host1x_ch_readl(ch
, HOST1X_CHANNEL_DMAGET
);
188 dmactrl
= host1x_ch_readl(ch
, HOST1X_CHANNEL_DMACTRL
);
189 cbread
= host1x_sync_readl(host
, HOST1X_SYNC_CBREAD(ch
->id
));
190 cbstat
= host1x_sync_readl(host
, HOST1X_SYNC_CBSTAT(ch
->id
));
192 host1x_debug_output(o
, "%u-%s: ", ch
->id
, dev_name(ch
->dev
));
194 if (HOST1X_CHANNEL_DMACTRL_DMASTOP_V(dmactrl
) ||
195 !ch
->cdma
.push_buffer
.mapped
) {
196 host1x_debug_output(o
, "inactive\n\n");
200 if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat
) == HOST1X_CLASS_HOST1X
&&
201 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat
) ==
202 HOST1X_UCLASS_WAIT_SYNCPT
)
203 host1x_debug_output(o
, "waiting on syncpt %d val %d\n",
204 cbread
>> 24, cbread
& 0xffffff);
205 else if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat
) ==
206 HOST1X_CLASS_HOST1X
&&
207 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat
) ==
208 HOST1X_UCLASS_WAIT_SYNCPT_BASE
) {
209 base
= (cbread
>> 16) & 0xff;
211 host1x_sync_readl(host
, HOST1X_SYNC_SYNCPT_BASE(base
));
212 val
= cbread
& 0xffff;
213 host1x_debug_output(o
, "waiting on syncpt %d val %d (base %d = %d; offset = %d)\n",
214 cbread
>> 24, baseval
+ val
, base
,
217 host1x_debug_output(o
, "active class %02x, offset %04x, val %08x\n",
218 HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat
),
219 HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat
),
222 host1x_debug_output(o
, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n",
223 dmaput
, dmaget
, dmactrl
);
224 host1x_debug_output(o
, "CBREAD %08x, CBSTAT %08x\n", cbread
, cbstat
);
226 show_channel_gathers(o
, cdma
);
227 host1x_debug_output(o
, "\n");
230 static void host1x_debug_show_channel_fifo(struct host1x
*host
,
231 struct host1x_channel
*ch
,
234 u32 val
, rd_ptr
, wr_ptr
, start
, end
;
235 unsigned int data_count
= 0;
237 host1x_debug_output(o
, "%u: fifo:\n", ch
->id
);
239 val
= host1x_ch_readl(ch
, HOST1X_CHANNEL_FIFOSTAT
);
240 host1x_debug_output(o
, "FIFOSTAT %08x\n", val
);
241 if (HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(val
)) {
242 host1x_debug_output(o
, "[empty]\n");
246 host1x_sync_writel(host
, 0x0, HOST1X_SYNC_CFPEEK_CTRL
);
247 host1x_sync_writel(host
, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
248 HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch
->id
),
249 HOST1X_SYNC_CFPEEK_CTRL
);
251 val
= host1x_sync_readl(host
, HOST1X_SYNC_CFPEEK_PTRS
);
252 rd_ptr
= HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(val
);
253 wr_ptr
= HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(val
);
255 val
= host1x_sync_readl(host
, HOST1X_SYNC_CF_SETUP(ch
->id
));
256 start
= HOST1X_SYNC_CF_SETUP_BASE_V(val
);
257 end
= HOST1X_SYNC_CF_SETUP_LIMIT_V(val
);
260 host1x_sync_writel(host
, 0x0, HOST1X_SYNC_CFPEEK_CTRL
);
261 host1x_sync_writel(host
, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
262 HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch
->id
) |
263 HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(rd_ptr
),
264 HOST1X_SYNC_CFPEEK_CTRL
);
265 val
= host1x_sync_readl(host
, HOST1X_SYNC_CFPEEK_READ
);
268 host1x_debug_output(o
, "%08x:", val
);
269 data_count
= show_channel_command(o
, val
);
271 host1x_debug_output(o
, "%08x%s", val
,
272 data_count
> 0 ? ", " : "])\n");
280 } while (rd_ptr
!= wr_ptr
);
283 host1x_debug_output(o
, ", ...])\n");
284 host1x_debug_output(o
, "\n");
286 host1x_sync_writel(host
, 0x0, HOST1X_SYNC_CFPEEK_CTRL
);
289 static void host1x_debug_show_mlocks(struct host1x
*host
, struct output
*o
)
293 host1x_debug_output(o
, "---- mlocks ----\n");
295 for (i
= 0; i
< host1x_syncpt_nb_mlocks(host
); i
++) {
297 host1x_sync_readl(host
, HOST1X_SYNC_MLOCK_OWNER(i
));
298 if (HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(owner
))
299 host1x_debug_output(o
, "%u: locked by channel %u\n",
300 i
, HOST1X_SYNC_MLOCK_OWNER_CHID_V(owner
));
301 else if (HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(owner
))
302 host1x_debug_output(o
, "%u: locked by cpu\n", i
);
304 host1x_debug_output(o
, "%u: 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
,