xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/r600/eg_debug.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2015 Advanced Micro Devices, Inc.
3  * Authors:
4  *      Marek Olšák <[email protected]>
5  * SPDX-License-Identifier: MIT
6  */
7 #include "r600_pipe.h"
8 #include "evergreend.h"
9 
10 #include "egd_tables.h"
11 
12 #define AC_IS_TRACE_POINT(x)            (((x) & 0xcafe0000) == 0xcafe0000)
13 #define AC_GET_TRACE_POINT_ID(x)        ((x) & 0xffff)
14 
15 /* Parsed IBs are difficult to read without colors. Use "less -R file" to
16  * read them, or use "aha -b -f file" to convert them to html.
17  */
18 #define COLOR_RESET	"\033[0m"
19 #define COLOR_RED	"\033[31m"
20 #define COLOR_GREEN	"\033[1;32m"
21 #define COLOR_YELLOW	"\033[1;33m"
22 #define COLOR_CYAN	"\033[1;36m"
23 
24 #define INDENT_PKT 8
25 
26 typedef void *(*ac_debug_addr_callback)(void *data, uint64_t addr);
print_spaces(FILE * f,unsigned num)27 static void print_spaces(FILE *f, unsigned num)
28 {
29 	fprintf(f, "%*s", num, "");
30 }
31 
print_value(FILE * file,uint32_t value,int bits)32 static void print_value(FILE *file, uint32_t value, int bits)
33 {
34 	/* Guess if it's int or float */
35 	if (value <= (1 << 15)) {
36 		if (value <= 9)
37 			fprintf(file, "%u\n", value);
38 		else
39 			fprintf(file, "%u (0x%0*x)\n", value, bits / 4, value);
40 	} else {
41 		float f = uif(value);
42 
43 		if (fabs(f) < 100000 && f*10 == floor(f*10))
44 			fprintf(file, "%.1ff (0x%0*x)\n", f, bits / 4, value);
45 		else
46 			/* Don't print more leading zeros than there are bits. */
47 			fprintf(file, "0x%0*x\n", bits / 4, value);
48 	}
49 }
50 
print_named_value(FILE * file,const char * name,uint32_t value,int bits)51 static void print_named_value(FILE *file, const char *name, uint32_t value,
52 			      int bits)
53 {
54 	print_spaces(file, INDENT_PKT);
55 	fprintf(file, COLOR_YELLOW "%s" COLOR_RESET " <- ", name);
56 	print_value(file, value, bits);
57 }
58 
eg_dump_reg(FILE * file,unsigned offset,uint32_t value,uint32_t field_mask)59 static void eg_dump_reg(FILE *file, unsigned offset, uint32_t value,
60 			uint32_t field_mask)
61 {
62 	unsigned r, f;
63 
64 	for (r = 0; r < ARRAY_SIZE(egd_reg_table); r++) {
65 		const struct eg_reg *reg = &egd_reg_table[r];
66 		const char *reg_name = egd_strings + reg->name_offset;
67 
68 		if (reg->offset == offset) {
69 			bool first_field = true;
70 
71 			print_spaces(file, INDENT_PKT);
72 			fprintf(file, COLOR_YELLOW "%s" COLOR_RESET " <- ",
73 				reg_name);
74 
75 			if (!reg->num_fields) {
76 				print_value(file, value, 32);
77 				return;
78 			}
79 
80 			for (f = 0; f < reg->num_fields; f++) {
81 				const struct eg_field *field = egd_fields_table + reg->fields_offset + f;
82 				const int *values_offsets = egd_strings_offsets + field->values_offset;
83 				uint32_t val = (value & field->mask) >>
84 					       (ffs(field->mask) - 1);
85 
86 				if (!(field->mask & field_mask))
87 					continue;
88 
89 				/* Indent the field. */
90 				if (!first_field)
91 					print_spaces(file,
92 						     INDENT_PKT + strlen(reg_name) + 4);
93 
94 				/* Print the field. */
95 				fprintf(file, "%s = ", egd_strings + field->name_offset);
96 
97 				if (val < field->num_values && values_offsets[val] >= 0)
98 					fprintf(file, "%s\n", egd_strings + values_offsets[val]);
99 				else
100 					print_value(file, val,
101 						    util_bitcount(field->mask));
102 
103 				first_field = false;
104 			}
105 			return;
106 		}
107 	}
108 
109 	print_spaces(file, INDENT_PKT);
110 	fprintf(file, COLOR_YELLOW "0x%05x" COLOR_RESET " <- 0x%08x\n", offset, value);
111 }
112 
113 
ac_parse_set_reg_packet(FILE * f,uint32_t * ib,unsigned count,unsigned reg_offset)114 static void ac_parse_set_reg_packet(FILE *f, uint32_t *ib, unsigned count,
115 				    unsigned reg_offset)
116 {
117 	unsigned reg = (ib[1] << 2) + reg_offset;
118 	unsigned i;
119 
120 	for (i = 0; i < count; i++)
121 		eg_dump_reg(f, reg + i*4, ib[2+i], ~0);
122 }
123 
ac_parse_packet3(FILE * f,uint32_t * ib,int * num_dw,int trace_id,enum amd_gfx_level gfx_level,ac_debug_addr_callback addr_callback,void * addr_callback_data)124 static uint32_t *ac_parse_packet3(FILE *f, uint32_t *ib, int *num_dw,
125 				  int trace_id, enum amd_gfx_level gfx_level,
126 				  ac_debug_addr_callback addr_callback,
127 				  void *addr_callback_data)
128 {
129 	unsigned count = PKT_COUNT_G(ib[0]);
130 	unsigned op = PKT3_IT_OPCODE_G(ib[0]);
131 	const char *predicate = PKT3_PREDICATE(ib[0]) ? "(predicate)" : "";
132 	const char *compute_mode = (ib[0] & 0x2) ? "(C)" : "";
133 	unsigned i;
134 
135 	/* Print the name first. */
136 	for (i = 0; i < ARRAY_SIZE(packet3_table); i++)
137 		if (packet3_table[i].op == op)
138 			break;
139 
140 	if (i < ARRAY_SIZE(packet3_table)) {
141 		const char *name = egd_strings + packet3_table[i].name_offset;
142 
143 		if (op == PKT3_SET_CONTEXT_REG ||
144 		    op == PKT3_SET_CONFIG_REG ||
145 		    op == PKT3_SET_UCONFIG_REG ||
146 		    op == PKT3_SET_SH_REG)
147 			fprintf(f, COLOR_CYAN "%s%s%s" COLOR_CYAN ":\n",
148 				name, compute_mode, predicate);
149 		else
150 			fprintf(f, COLOR_GREEN "%s%s%s" COLOR_RESET ":\n",
151 				name, compute_mode, predicate);
152 	} else
153 		fprintf(f, COLOR_RED "PKT3_UNKNOWN 0x%x%s%s" COLOR_RESET ":\n",
154 			op, compute_mode, predicate);
155 
156 	/* Print the contents. */
157 	switch (op) {
158 	case PKT3_SET_CONTEXT_REG:
159 		ac_parse_set_reg_packet(f, ib, count, EVERGREEN_CONTEXT_REG_OFFSET);
160 		break;
161 	case PKT3_SET_CONFIG_REG:
162 		ac_parse_set_reg_packet(f, ib, count, EVERGREEN_CONFIG_REG_OFFSET);
163 		break;
164 	case PKT3_SURFACE_SYNC:
165 		eg_dump_reg(f, R_0085F0_CP_COHER_CNTL, ib[1], ~0);
166 		eg_dump_reg(f, R_0085F4_CP_COHER_SIZE, ib[2], ~0);
167 		eg_dump_reg(f, R_0085F8_CP_COHER_BASE, ib[3], ~0);
168 		print_named_value(f, "POLL_INTERVAL", ib[4], 16);
169 		break;
170 	case PKT3_EVENT_WRITE:
171 		/* TODO dump VGT_EVENT_INITIATOR */
172 #if 0
173 		eg_dump_reg(f, R_028A90_VGT_EVENT_INITIATOR, ib[1],
174 			    S_028A90_EVENT_TYPE(~0));
175 #endif
176 		print_named_value(f, "EVENT_TYPE", ib[1] & 0xff, 8);
177 		print_named_value(f, "EVENT_INDEX", (ib[1] >> 8) & 0xf, 4);
178 		print_named_value(f, "INV_L2", (ib[1] >> 20) & 0x1, 1);
179 		if (count > 0) {
180 			print_named_value(f, "ADDRESS_LO", ib[2], 32);
181 			print_named_value(f, "ADDRESS_HI", ib[3], 16);
182 		}
183 		break;
184 	case PKT3_DRAW_INDEX_AUTO:
185 		eg_dump_reg(f, R_008970_VGT_NUM_INDICES, ib[1], ~0);
186 		eg_dump_reg(f, R_0287F0_VGT_DRAW_INITIATOR, ib[2], ~0);
187 		break;
188 	case PKT3_DRAW_INDEX_2:
189 		eg_dump_reg(f, R_028A78_VGT_DMA_MAX_SIZE, ib[1], ~0);
190 		eg_dump_reg(f, R_0287E8_VGT_DMA_BASE, ib[2], ~0);
191 		eg_dump_reg(f, R_0287E4_VGT_DMA_BASE_HI, ib[3], ~0);
192 		eg_dump_reg(f, R_008970_VGT_NUM_INDICES, ib[4], ~0);
193 		eg_dump_reg(f, R_0287F0_VGT_DRAW_INITIATOR, ib[5], ~0);
194 		break;
195 	case PKT3_INDEX_TYPE:
196 		eg_dump_reg(f, R_028A7C_VGT_DMA_INDEX_TYPE, ib[1], ~0);
197 		break;
198 	case PKT3_NUM_INSTANCES:
199 		eg_dump_reg(f, R_028A88_VGT_NUM_INSTANCES, ib[1], ~0);
200 		break;
201 	case PKT3_INDIRECT_BUFFER:
202 		break;
203 	case PKT3_PFP_SYNC_ME:
204 		break;
205 	case PKT3_NOP:
206 		if (ib[0] == 0xffff1000) {
207 			count = -1; /* One dword NOP. */
208 			break;
209 		} else if (count == 0 && AC_IS_TRACE_POINT(ib[1])) {
210 			unsigned packet_id = AC_GET_TRACE_POINT_ID(ib[1]);
211 
212 			print_spaces(f, INDENT_PKT);
213 			fprintf(f, COLOR_RED "Trace point ID: %u\n", packet_id);
214 
215 			if (trace_id == -1)
216 				break; /* tracing was disabled */
217 
218 			print_spaces(f, INDENT_PKT);
219 			if (packet_id < trace_id)
220 				fprintf(f, COLOR_RED
221 					"This trace point was reached by the CP."
222 					COLOR_RESET "\n");
223 			else if (packet_id == trace_id)
224 				fprintf(f, COLOR_RED
225 					"!!!!! This is the last trace point that "
226 					"was reached by the CP !!!!!"
227 					COLOR_RESET "\n");
228 			else if (packet_id+1 == trace_id)
229 				fprintf(f, COLOR_RED
230 					"!!!!! This is the first trace point that "
231 					"was NOT been reached by the CP !!!!!"
232 					COLOR_RESET "\n");
233 			else
234 				fprintf(f, COLOR_RED
235 					"!!!!! This trace point was NOT reached "
236 					"by the CP !!!!!"
237 					COLOR_RESET "\n");
238 			break;
239 		}
240 		FALLTHROUGH; /* print all dwords */
241 	default:
242 		for (i = 0; i < count+1; i++) {
243 			print_spaces(f, INDENT_PKT);
244 			fprintf(f, "0x%08x\n", ib[1+i]);
245 		}
246 	}
247 
248 	ib += count + 2;
249 	*num_dw -= count + 2;
250 	return ib;
251 }
252 
253 /**
254  * Parse and print an IB into a file.
255  *
256  * \param f		file
257  * \param ib		IB
258  * \param num_dw	size of the IB
259  * \param gfx_level	gfx level
260  * \param trace_id	the last trace ID that is known to have been reached
261  *			and executed by the CP, typically read from a buffer
262  * \param addr_callback Get a mapped pointer of the IB at a given address. Can
263  *                      be NULL.
264  * \param addr_callback_data user data for addr_callback
265  */
eg_parse_ib(FILE * f,uint32_t * ib,int num_dw,int trace_id,const char * name,enum amd_gfx_level gfx_level,ac_debug_addr_callback addr_callback,void * addr_callback_data)266 static void eg_parse_ib(FILE *f, uint32_t *ib, int num_dw, int trace_id,
267 			const char *name, enum amd_gfx_level gfx_level,
268 			ac_debug_addr_callback addr_callback, void *addr_callback_data)
269 {
270 	fprintf(f, "------------------ %s begin ------------------\n", name);
271 
272 	while (num_dw > 0) {
273 		unsigned type = PKT_TYPE_G(ib[0]);
274 
275 		switch (type) {
276 		case 3:
277 			ib = ac_parse_packet3(f, ib, &num_dw, trace_id,
278 					      gfx_level, addr_callback,
279 					      addr_callback_data);
280 			break;
281 		case 2:
282 			/* type-2 nop */
283 			if (ib[0] == 0x80000000) {
284 				fprintf(f, COLOR_GREEN "NOP (type 2)" COLOR_RESET "\n");
285 				ib++;
286 				num_dw--;
287 				break;
288 			}
289 			FALLTHROUGH;
290 		default:
291 			fprintf(f, "Unknown packet type %i\n", type);
292 			return;
293 		}
294 	}
295 
296 	fprintf(f, "------------------- %s end -------------------\n", name);
297 	if (num_dw < 0) {
298 		printf("Packet ends after the end of IB.\n");
299 		exit(0);
300 	}
301 	fprintf(f, "\n");
302 }
303 
eg_dump_last_ib(struct r600_context * rctx,FILE * f)304 static void eg_dump_last_ib(struct r600_context *rctx, FILE *f)
305 {
306 	int last_trace_id = -1;
307 
308 	if (!rctx->last_gfx.ib)
309 		return;
310 
311 	if (rctx->last_trace_buf) {
312 		/* We are expecting that the ddebug pipe has already
313 		 * waited for the context, so this buffer should be idle.
314 		 * If the GPU is hung, there is no point in waiting for it.
315 		 */
316 		uint32_t *map = rctx->b.ws->buffer_map(rctx->b.ws, rctx->last_trace_buf->buf,
317 						       NULL,
318 						       PIPE_MAP_UNSYNCHRONIZED |
319 						       PIPE_MAP_READ);
320 		if (map)
321 			last_trace_id = *map;
322 	}
323 
324 	eg_parse_ib(f, rctx->last_gfx.ib, rctx->last_gfx.num_dw,
325 		    last_trace_id, "IB", rctx->b.gfx_level,
326 		     NULL, NULL);
327 }
328 
329 
eg_dump_debug_state(struct pipe_context * ctx,FILE * f,unsigned flags)330 void eg_dump_debug_state(struct pipe_context *ctx, FILE *f,
331 			 unsigned flags)
332 {
333 	struct r600_context *rctx = (struct r600_context*)ctx;
334 
335 	eg_dump_last_ib(rctx, f);
336 
337 	fprintf(f, "Done.\n");
338 
339 	/* dump only once */
340 	radeon_clear_saved_cs(&rctx->last_gfx);
341 	r600_resource_reference(&rctx->last_trace_buf, NULL);
342 }
343