xref: /aosp_15_r20/external/igt-gpu-tools/tools/intel_error_decode.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2007 Intel Corporation
3  * Copyright © 2009 Intel Corporation
4  * Copyright © 2010 Intel Corporation
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23  * IN THE SOFTWARE.
24  *
25  * Authors:
26  *    Eric Anholt <[email protected]>
27  *    Carl Worth <[email protected]>
28  *    Chris Wilson <[email protected]>
29  *
30  */
31 
32 /** @file intel_decode.c
33  * This file contains code to print out batchbuffer contents in a
34  * human-readable format.
35  *
36  * The current version only supports i915 packets, and only pretty-prints a
37  * subset of them.  The intention is for it to make just a best attempt to
38  * decode, but never crash in the process.
39  */
40 
41 #include <stdbool.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <inttypes.h>
48 #include <errno.h>
49 #include <sys/stat.h>
50 #include <err.h>
51 #include <assert.h>
52 #include <intel_bufmgr.h>
53 #include <zlib.h>
54 #include <ctype.h>
55 
56 #include "intel_chipset.h"
57 #include "intel_io.h"
58 #include "instdone.h"
59 #include "intel_reg.h"
60 #include "drmtest.h"
61 
62 static uint32_t
print_head(unsigned int reg)63 print_head(unsigned int reg)
64 {
65 	printf("    head = 0x%08x, wraps = %d\n", reg & (0x7ffff<<2), reg >> 21);
66 	return reg & (0x7ffff<<2);
67 }
68 
69 static uint32_t
print_ctl(unsigned int reg)70 print_ctl(unsigned int reg)
71 {
72 	uint32_t ring_length = 	(((reg & (0x1ff << 12)) >> 12) + 1) * 4096;
73 
74 #define BIT_STR(reg, x, on, off) ((1 << (x)) & reg) ? on : off
75 
76 	printf("    len=%d%s%s%s\n", ring_length,
77 	       BIT_STR(reg, 0, ", enabled", ", disabled"),
78 	       BIT_STR(reg, 10, ", semaphore wait ", ""),
79 	       BIT_STR(reg, 11, ", rb wait ", "")
80 		);
81 #undef BIT_STR
82 	return ring_length;
83 }
84 
85 static void
print_acthd(unsigned int reg,unsigned int ring_length)86 print_acthd(unsigned int reg, unsigned int ring_length)
87 {
88 	if ((reg & (0x7ffff << 2)) < ring_length)
89 		printf("    at ring: 0x%08x\n", reg & (0x7ffff << 2));
90 	else
91 		printf("    at batch: 0x%08x\n", reg);
92 }
93 
94 static void
print_instdone(uint32_t devid,unsigned int instdone,unsigned int instdone1)95 print_instdone(uint32_t devid, unsigned int instdone, unsigned int instdone1)
96 {
97 	int i;
98 	static int once;
99 
100 	if (!once) {
101 		if (!init_instdone_definitions(devid))
102 			return;
103 		once = 1;
104 	}
105 
106 	for (i = 0; i < num_instdone_bits; i++) {
107 		int busy = 0;
108 
109 		if (instdone_bits[i].reg == INSTDONE_1) {
110 			if (!(instdone1 & instdone_bits[i].bit))
111 				busy = 1;
112 		} else {
113 			if (!(instdone & instdone_bits[i].bit))
114 				busy = 1;
115 		}
116 
117 		if (busy)
118 			printf("    busy: %s\n", instdone_bits[i].name);
119 	}
120 }
121 
122 static void
print_i830_pgtbl_err(unsigned int reg)123 print_i830_pgtbl_err(unsigned int reg)
124 {
125 	const char *str;
126 
127 	switch((reg >> 3) & 0xf) {
128 	case 0x1: str = "Overlay TLB"; break;
129 	case 0x2: str = "Display A TLB"; break;
130 	case 0x3: str = "Host TLB"; break;
131 	case 0x4: str = "Render TLB"; break;
132 	case 0x5: str = "Display C TLB"; break;
133 	case 0x6: str = "Mapping TLB"; break;
134 	case 0x7: str = "Command Stream TLB"; break;
135 	case 0x8: str = "Vertex Buffer TLB"; break;
136 	case 0x9: str = "Display B TLB"; break;
137 	case 0xa: str = "Reserved System Memory"; break;
138 	case 0xb: str = "Compressor TLB"; break;
139 	case 0xc: str = "Binner TLB"; break;
140 	default: str = "unknown"; break;
141 	}
142 
143 	if (str)
144 		printf("    source = %s\n", str);
145 
146 	switch(reg & 0x7) {
147 	case 0x0: str  = "Invalid GTT"; break;
148 	case 0x1: str = "Invalid GTT PTE"; break;
149 	case 0x2: str = "Invalid Memory"; break;
150 	case 0x3: str = "Invalid TLB miss"; break;
151 	case 0x4: str = "Invalid PTE data"; break;
152 	case 0x5: str = "Invalid LocalMemory not present"; break;
153 	case 0x6: str = "Invalid Tiling"; break;
154 	case 0x7: str = "Host to CAM"; break;
155 	}
156 	printf("    error = %s\n", str);
157 }
158 
159 static void
print_i915_pgtbl_err(unsigned int reg)160 print_i915_pgtbl_err(unsigned int reg)
161 {
162 	if (reg & (1 << 29))
163 		printf("    Cursor A: Invalid GTT PTE\n");
164 	if (reg & (1 << 28))
165 		printf("    Cursor B: Invalid GTT PTE\n");
166 	if (reg & (1 << 27))
167 		printf("    MT: Invalid tiling\n");
168 	if (reg & (1 << 26))
169 		printf("    MT: Invalid GTT PTE\n");
170 	if (reg & (1 << 25))
171 		printf("    LC: Invalid tiling\n");
172 	if (reg & (1 << 24))
173 		printf("    LC: Invalid GTT PTE\n");
174 	if (reg & (1 << 23))
175 		printf("    BIN VertexData: Invalid GTT PTE\n");
176 	if (reg & (1 << 22))
177 		printf("    BIN Instruction: Invalid GTT PTE\n");
178 	if (reg & (1 << 21))
179 		printf("    CS VertexData: Invalid GTT PTE\n");
180 	if (reg & (1 << 20))
181 		printf("    CS Instruction: Invalid GTT PTE\n");
182 	if (reg & (1 << 19))
183 		printf("    CS: Invalid GTT\n");
184 	if (reg & (1 << 18))
185 		printf("    Overlay: Invalid tiling\n");
186 	if (reg & (1 << 16))
187 		printf("    Overlay: Invalid GTT PTE\n");
188 	if (reg & (1 << 14))
189 		printf("    Display C: Invalid tiling\n");
190 	if (reg & (1 << 12))
191 		printf("    Display C: Invalid GTT PTE\n");
192 	if (reg & (1 << 10))
193 		printf("    Display B: Invalid tiling\n");
194 	if (reg & (1 << 8))
195 		printf("    Display B: Invalid GTT PTE\n");
196 	if (reg & (1 << 6))
197 		printf("    Display A: Invalid tiling\n");
198 	if (reg & (1 << 4))
199 		printf("    Display A: Invalid GTT PTE\n");
200 	if (reg & (1 << 1))
201 		printf("    Host Invalid PTE data\n");
202 	if (reg & (1 << 0))
203 		printf("    Host Invalid GTT PTE\n");
204 }
205 
206 static void
print_i965_pgtbl_err(unsigned int reg)207 print_i965_pgtbl_err(unsigned int reg)
208 {
209 	if (reg & (1 << 26))
210 		printf("    Invalid Sampler Cache GTT entry\n");
211 	if (reg & (1 << 24))
212 		printf("    Invalid Render Cache GTT entry\n");
213 	if (reg & (1 << 23))
214 		printf("    Invalid Instruction/State Cache GTT entry\n");
215 	if (reg & (1 << 22))
216 		printf("    There is no ROC, this cannot occur!\n");
217 	if (reg & (1 << 21))
218 		printf("    Invalid GTT entry during Vertex Fetch\n");
219 	if (reg & (1 << 20))
220 		printf("    Invalid GTT entry during Command Fetch\n");
221 	if (reg & (1 << 19))
222 		printf("    Invalid GTT entry during CS\n");
223 	if (reg & (1 << 18))
224 		printf("    Invalid GTT entry during Cursor Fetch\n");
225 	if (reg & (1 << 17))
226 		printf("    Invalid GTT entry during Overlay Fetch\n");
227 	if (reg & (1 << 8))
228 		printf("    Invalid GTT entry during Display B Fetch\n");
229 	if (reg & (1 << 4))
230 		printf("    Invalid GTT entry during Display A Fetch\n");
231 	if (reg & (1 << 1))
232 		printf("    Valid PTE references illegal memory\n");
233 	if (reg & (1 << 0))
234 		printf("    Invalid GTT entry during fetch for host\n");
235 }
236 
237 static void
print_pgtbl_err(unsigned int reg,unsigned int devid)238 print_pgtbl_err(unsigned int reg, unsigned int devid)
239 {
240 	if (IS_965(devid)) {
241 		return print_i965_pgtbl_err(reg);
242 	} else if (IS_GEN3(devid)) {
243 		return print_i915_pgtbl_err(reg);
244 	} else {
245 		return print_i830_pgtbl_err(reg);
246 	}
247 }
248 
print_ivb_error(unsigned int reg,unsigned int devid)249 static void print_ivb_error(unsigned int reg, unsigned int devid)
250 {
251 	if (reg & (1 << 0))
252 		printf("    TLB page fault error (GTT entry not valid)\n");
253 	if (reg & (1 << 1))
254 		printf("    Invalid physical address in RSTRM interface (PAVP)\n");
255 	if (reg & (1 << 2))
256 		printf("    Invalid page directory entry error\n");
257 	if (reg & (1 << 3))
258 		printf("    Invalid physical address in ROSTRM interface (PAVP)\n");
259 	if (reg & (1 << 4))
260 		printf("    TLB page VTD translation generated an error\n");
261 	if (reg & (1 << 5))
262 		printf("    Invalid physical address in WRITE interface (PAVP)\n");
263 	if (reg & (1 << 6))
264 		printf("    Page directory VTD translation generated error\n");
265 	if (reg & (1 << 8))
266 		printf("    Cacheline containing a PD was marked as invalid\n");
267 	if (IS_HASWELL(devid) && (reg >> 10) & 0x1f)
268 		printf("    %d pending page faults\n", (reg >> 10) & 0x1f);
269 }
270 
print_snb_error(unsigned int reg)271 static void print_snb_error(unsigned int reg)
272 {
273 	if (reg & (1 << 0))
274 		printf("    TLB page fault error (GTT entry not valid)\n");
275 	if (reg & (1 << 1))
276 		printf("    Context page GTT translation generated a fault (GTT entry not valid)\n");
277 	if (reg & (1 << 2))
278 		printf("    Invalid page directory entry error\n");
279 	if (reg & (1 << 3))
280 		printf("    HWS page GTT translation generated a page fault (GTT entry not valid)\n");
281 	if (reg & (1 << 4))
282 		printf("    TLB page VTD translation generated an error\n");
283 	if (reg & (1 << 5))
284 		printf("    Context page VTD translation generated an error\n");
285 	if (reg & (1 << 6))
286 		printf("    Page directory VTD translation generated error\n");
287 	if (reg & (1 << 7))
288 		printf("    HWS page VTD translation generated an error\n");
289 	if (reg & (1 << 8))
290 		printf("    Cacheline containing a PD was marked as invalid\n");
291 }
292 
print_bdw_error(unsigned int reg,unsigned int devid)293 static void print_bdw_error(unsigned int reg, unsigned int devid)
294 {
295 	print_ivb_error(reg, devid);
296 
297 	if (reg & (1 << 10))
298 		printf("    Non WB memory type for Advanced Context\n");
299 	if (reg & (1 << 11))
300 		printf("    PASID not enabled\n");
301 	if (reg & (1 << 12))
302 		printf("    PASID boundary violation\n");
303 	if (reg & (1 << 13))
304 		printf("    PASID not valid\n");
305 	if (reg & (1 << 14))
306 		printf("    PASID was zero for untranslated request\n");
307 	if (reg & (1 << 15))
308 		printf("    Context was not marked as present when doing DMA\n");
309 }
310 
311 static void
print_error(unsigned int reg,unsigned int devid)312 print_error(unsigned int reg, unsigned int devid)
313 {
314 	switch (intel_gen(devid)) {
315 	case 8: return print_bdw_error(reg, devid);
316 	case 7: return print_ivb_error(reg, devid);
317 	case 6: return print_snb_error(reg);
318 	}
319 }
320 
321 static void
print_snb_fence(unsigned int devid,uint64_t fence)322 print_snb_fence(unsigned int devid, uint64_t fence)
323 {
324 	printf("    %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
325 			fence & 1 ? "" : "in",
326 			fence & (1<<1) ? 'y' : 'x',
327 			(int)(((fence>>32)&0xfff)+1)*128,
328 			(uint32_t)fence & 0xfffff000,
329 			(uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
330 }
331 
332 static void
print_i965_fence(unsigned int devid,uint64_t fence)333 print_i965_fence(unsigned int devid, uint64_t fence)
334 {
335 	printf("    %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
336 			fence & 1 ? "" : "in",
337 			fence & (1<<1) ? 'y' : 'x',
338 			(int)(((fence>>2)&0x1ff)+1)*128,
339 			(uint32_t)fence & 0xfffff000,
340 			(uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
341 }
342 
343 static void
print_i915_fence(unsigned int devid,uint64_t fence)344 print_i915_fence(unsigned int devid, uint64_t fence)
345 {
346 	unsigned tile_width;
347 	if ((fence & 12) && !IS_915(devid))
348 		tile_width = 128;
349 	else
350 		tile_width = 512;
351 
352 	printf("    %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %i\n",
353 			fence & 1 ? "" : "in",
354 			fence & (1<<12) ? 'y' : 'x',
355 			(1<<((fence>>4)&0xf))*tile_width,
356 			(uint32_t)fence & 0xff00000,
357 			1<<(20 + ((fence>>8)&0xf)));
358 }
359 
360 static void
print_i830_fence(unsigned int devid,uint64_t fence)361 print_i830_fence(unsigned int devid, uint64_t fence)
362 {
363 	printf("    %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %i\n",
364 			fence & 1 ? "" : "in",
365 			fence & (1<<12) ? 'y' : 'x',
366 			(1<<((fence>>4)&0xf))*128,
367 			(uint32_t)fence & 0x7f80000,
368 			1<<(19 + ((fence>>8)&0xf)));
369 }
370 
371 static void
print_fence(unsigned int devid,uint64_t fence)372 print_fence(unsigned int devid, uint64_t fence)
373 {
374 	if (IS_GEN6(devid) || IS_GEN7(devid)) {
375 		return print_snb_fence(devid, fence);
376 	} else if (IS_GEN4(devid) || IS_GEN5(devid)) {
377 		return print_i965_fence(devid, fence);
378 	} else if (IS_GEN3(devid)) {
379 		return print_i915_fence(devid, fence);
380 	} else {
381 		return print_i830_fence(devid, fence);
382 	}
383 }
384 
385 static void
print_fault_reg(unsigned devid,uint32_t reg)386 print_fault_reg(unsigned devid, uint32_t reg)
387 {
388 	const char *gen7_types[] = { "Page",
389 				     "Invalid PD",
390 				     "Unloaded PD",
391 				     "Invalid and Unloaded PD" };
392 
393 	const char *gen8_types[] = { "PTE",
394 				     "PDE",
395 				     "PDPE",
396 				     "PML4E" };
397 
398 	const char *engine[] = { "GFX", "MFX0", "MFX1", "VEBX",
399 				 "BLT", "Unknown", "Unknown", "Unknown" };
400 
401 	if (intel_gen(devid) < 7)
402 		return;
403 
404 	if (reg & (1 << 0))
405 		printf("    Valid\n");
406 	else
407 		return;
408 
409 	if (intel_gen(devid) < 8)
410 		printf("    %s Fault (%s)\n", gen7_types[reg >> 1 & 0x3],
411 		       reg & (1 << 11) ? "GGTT" : "PPGTT");
412 	else
413 		printf("    Invalid %s Fault\n", gen8_types[reg >> 1 & 0x3]);
414 
415 	if (intel_gen(devid) < 8)
416 		printf("    Address 0x%08x\n", reg & ~((1 << 12)-1));
417 	else
418 		printf("    Engine %s\n", engine[reg >> 12 & 0x7]);
419 
420 	printf("    Source ID %d\n", reg >> 3 & 0xff);
421 }
422 
423 static void
print_fault_data(unsigned devid,uint32_t data1,uint32_t data0)424 print_fault_data(unsigned devid, uint32_t data1, uint32_t data0)
425 {
426 	uint64_t address;
427 
428 	if (intel_gen(devid) < 8)
429 		return;
430 
431 	address = ((uint64_t)(data0) << 12) | ((uint64_t)data1 & 0xf) << 44;
432 	printf("    Address 0x%016" PRIx64 " %s\n", address,
433 	       data1 & (1 << 4) ? "GGTT" : "PPGTT");
434 }
435 
436 #define MAX_RINGS 10 /* I really hope this never... */
437 
maybe_ascii(const void * data,int check)438 static bool maybe_ascii(const void *data, int check)
439 {
440 	const char *c = data;
441 	while (check--) {
442 		if (!isprint(*c++))
443 			return false;
444 	}
445 	return true;
446 }
447 
decode(struct drm_intel_decode * ctx,const char * buffer_name,const char * ring_name,uint64_t gtt_offset,uint32_t head_offset,uint32_t * data,int * count,int decode)448 static void decode(struct drm_intel_decode *ctx,
449 		   const char *buffer_name,
450 		   const char *ring_name,
451 		   uint64_t gtt_offset,
452 		   uint32_t head_offset,
453 		   uint32_t *data, int *count,
454 		   int decode)
455 {
456 	if (!*count)
457 		return;
458 
459 	printf("%s (%s) at 0x%08x_%08x", buffer_name, ring_name,
460 	       (unsigned)(gtt_offset >> 32),
461 	       (unsigned)(gtt_offset & 0xffffffff));
462 	if (head_offset != -1)
463 		printf("; HEAD points to: 0x%08x_%08x",
464 		       (unsigned)((head_offset + gtt_offset) >> 32),
465 		       (unsigned)((head_offset + gtt_offset) & 0xffffffff));
466 	printf("\n");
467 
468 	if (decode) {
469 		drm_intel_decode_set_batch_pointer(ctx, data, gtt_offset,
470 						   *count);
471 		drm_intel_decode(ctx);
472 	} else if (maybe_ascii(data, 16)) {
473 		printf("%*s\n", 4 * *count, (char *)data);
474 	} else {
475 		for (int i = 0; i + 4 <= *count; i += 4)
476 			printf("[%04x] %08x %08x %08x %08x\n",
477 			       4*i, data[i], data[i+1], data[i+2], data[i+3]);
478 	}
479 	*count = 0;
480 }
481 
zlib_inflate(uint32_t ** ptr,int len)482 static int zlib_inflate(uint32_t **ptr, int len)
483 {
484 	struct z_stream_s zstream;
485 	void *out;
486 
487 	memset(&zstream, 0, sizeof(zstream));
488 
489 	zstream.next_in = (unsigned char *)*ptr;
490 	zstream.avail_in = 4*len;
491 
492 	if (inflateInit(&zstream) != Z_OK)
493 		return 0;
494 
495 	out = malloc(128*4096); /* approximate obj size */
496 	zstream.next_out = out;
497 	zstream.avail_out = 128*4096;
498 
499 	do {
500 		switch (inflate(&zstream, Z_SYNC_FLUSH)) {
501 		case Z_STREAM_END:
502 			goto end;
503 		case Z_OK:
504 			break;
505 		default:
506 			inflateEnd(&zstream);
507 			return 0;
508 		}
509 
510 		if (zstream.avail_out)
511 			break;
512 
513 		out = realloc(out, 2*zstream.total_out);
514 		if (out == NULL) {
515 			inflateEnd(&zstream);
516 			return 0;
517 		}
518 
519 		zstream.next_out = (unsigned char *)out + zstream.total_out;
520 		zstream.avail_out = zstream.total_out;
521 	} while (1);
522 end:
523 	inflateEnd(&zstream);
524 	free(*ptr);
525 	*ptr = out;
526 	return zstream.total_out / 4;
527 }
528 
ascii85_decode(const char * in,uint32_t ** out,bool inflate)529 static int ascii85_decode(const char *in, uint32_t **out, bool inflate)
530 {
531 	int len = 0, size = 1024;
532 
533 	*out = realloc(*out, sizeof(uint32_t)*size);
534 	if (*out == NULL)
535 		return 0;
536 
537 	while (*in >= '!' && *in <= 'z') {
538 		uint32_t v = 0;
539 
540 		if (len == size) {
541 			size *= 2;
542 			*out = realloc(*out, sizeof(uint32_t)*size);
543 			if (*out == NULL)
544 				return 0;
545 		}
546 
547 		if (*in == 'z') {
548 			in++;
549 		} else {
550 			v += in[0] - 33; v *= 85;
551 			v += in[1] - 33; v *= 85;
552 			v += in[2] - 33; v *= 85;
553 			v += in[3] - 33; v *= 85;
554 			v += in[4] - 33;
555 			in += 5;
556 		}
557 		(*out)[len++] = v;
558 	}
559 
560 	if (!inflate)
561 		return len;
562 
563 	return zlib_inflate(out, len);
564 }
565 
566 static void
read_data_file(FILE * file)567 read_data_file(FILE *file)
568 {
569 	struct drm_intel_decode *decode_ctx = NULL;
570 	uint32_t devid = PCI_CHIP_I855_GM;
571 	uint32_t *data = NULL;
572 	uint32_t head[MAX_RINGS];
573 	int head_idx = 0;
574 	int num_rings = 0;
575 	long long unsigned fence;
576 	int data_size = 0, count = 0, matched;
577 	char *line = NULL;
578 	size_t line_size;
579 	uint32_t offset, value, ring_length = 0;
580 	uint64_t gtt_offset = 0;
581 	uint32_t head_offset = -1;
582 	const char *buffer_name = "batch buffer";
583 	char *ring_name = NULL;
584 	int do_decode = 1;
585 
586 	while (getline(&line, &line_size, file) > 0) {
587 		char *dashes;
588 
589 		if (line[0] == ':' || line[0] == '~') {
590 			count = ascii85_decode(line+1, &data, line[0] == ':');
591 			if (count == 0)
592 				fprintf(stderr, "ASCII85 decode failed (%s - %s).\n",
593 					ring_name, buffer_name);
594 			decode(decode_ctx,
595 			       buffer_name, ring_name,
596 			       gtt_offset, head_offset,
597 			       data, &count, do_decode);
598 			continue;
599 		}
600 
601 		dashes = strstr(line, "---");
602 		if (dashes) {
603 			const struct {
604 				const char *match;
605 				const char *name;
606 				int do_decode;
607 			} buffers[] = {
608 				{ "ringbuffer", "ring", 1 },
609 				{ "gtt_offset", "batch", 1 },
610 				{ "hw context", "HW context", 1 },
611 				{ "hw status", "HW status", 0 },
612 				{ "wa context", "WA context", 1 },
613 				{ "wa batchbuffer", "WA batch", 1 },
614 				{ "user", "user", 0 },
615 				{ "semaphores", "semaphores", 0 },
616 				{ "guc log buffer", "GuC log", 0 },
617 				{ },
618 			}, *b;
619 			char *new_ring_name;
620 
621 			new_ring_name = malloc(dashes - line);
622 			strncpy(new_ring_name, line, dashes - line);
623 			new_ring_name[dashes - line - 1] = '\0';
624 
625 			decode(decode_ctx,
626 			       buffer_name, ring_name,
627 			       gtt_offset, head_offset,
628 			       data, &count, do_decode);
629 			gtt_offset = 0;
630 			head_offset = -1;
631 
632 			free(ring_name);
633 			ring_name = new_ring_name;
634 
635 			dashes += 4;
636 			for (b = buffers; b->match; b++) {
637 				uint32_t lo, hi;
638 
639 				if (strncasecmp(dashes, b->match,
640 						strlen(b->match)))
641 					continue;
642 
643 				dashes = strchr(dashes, '=');
644 				if (!dashes)
645 					break;
646 
647 				matched = sscanf(dashes, "= 0x%08x %08x\n",
648 						 &hi, &lo);
649 				if (matched > 0) {
650 					gtt_offset = hi;
651 					if (matched == 2) {
652 						gtt_offset <<= 32;
653 						gtt_offset |= lo;
654 					}
655 				}
656 
657 				do_decode = b->do_decode;
658 				buffer_name = b->name;
659 				if (b == buffers)
660 					head_offset = head[head_idx++];
661 				break;
662 			}
663 
664 			continue;
665 		}
666 
667 		matched = sscanf(line, "%08x : %08x", &offset, &value);
668 		if (matched != 2) {
669 			unsigned int reg, reg2;
670 
671 			/* display reg section is after the ringbuffers, don't mix them */
672 			decode(decode_ctx,
673 			       buffer_name, ring_name,
674 			       gtt_offset, head_offset,
675 			       data, &count, do_decode);
676 
677 			printf("%s", line);
678 
679 			matched = sscanf(line, "PCI ID: 0x%04x\n", &reg);
680 			if (matched == 0)
681 				matched = sscanf(line, " PCI ID: 0x%04x\n", &reg);
682 			if (matched == 0) {
683 				const char *pci_id_start = strstr(line, "PCI ID");
684 				if (pci_id_start)
685 					matched = sscanf(pci_id_start, "PCI ID: 0x%04x\n", &reg);
686 			}
687 			if (matched == 1) {
688 				devid = reg;
689 				printf("Detected GEN%i chipset\n",
690 						intel_gen(devid));
691 
692 				decode_ctx = drm_intel_decode_context_alloc(devid);
693 			}
694 
695 			matched = sscanf(line, "  CTL: 0x%08x\n", &reg);
696 			if (matched == 1)
697 				ring_length = print_ctl(reg);
698 
699 			matched = sscanf(line, "  HEAD: 0x%08x\n", &reg);
700 			if (matched == 1) {
701 				head[num_rings++] = print_head(reg);
702 			}
703 
704 			matched = sscanf(line, "  ACTHD: 0x%08x\n", &reg);
705 			if (matched == 1) {
706 				print_acthd(reg, ring_length);
707 				drm_intel_decode_set_head_tail(decode_ctx, reg, 0xffffffff);
708 			}
709 
710 			matched = sscanf(line, "  PGTBL_ER: 0x%08x\n", &reg);
711 			if (matched == 1 && reg)
712 				print_pgtbl_err(reg, devid);
713 
714 			matched = sscanf(line, "  ERROR: 0x%08x\n", &reg);
715 			if (matched == 1 && reg)
716 				print_error(reg, devid);
717 
718 			matched = sscanf(line, "  INSTDONE: 0x%08x\n", &reg);
719 			if (matched == 1)
720 				print_instdone(devid, reg, -1);
721 
722 			matched = sscanf(line, "  INSTDONE1: 0x%08x\n", &reg);
723 			if (matched == 1)
724 				print_instdone(devid, -1, reg);
725 
726 			matched = sscanf(line, "  fence[%i] = %Lx\n", &reg, &fence);
727 			if (matched == 2)
728 				print_fence(devid, fence);
729 
730 			matched = sscanf(line, "  FAULT_REG: 0x%08x\n", &reg);
731 			if (matched == 1 && reg)
732 				print_fault_reg(devid, reg);
733 
734 			matched = sscanf(line, "  FAULT_TLB_DATA: 0x%08x 0x%08x\n", &reg, &reg2);
735 			if (matched == 2)
736 				print_fault_data(devid, reg, reg2);
737 
738 			continue;
739 		}
740 
741 		count++;
742 
743 		if (count > data_size) {
744 			data_size = data_size ? data_size * 2 : 1024;
745 			data = realloc(data, data_size * sizeof (uint32_t));
746 			if (data == NULL) {
747 				fprintf(stderr, "Out of memory.\n");
748 				exit(1);
749 			}
750 		}
751 
752 		data[count-1] = value;
753 	}
754 
755 	decode(decode_ctx,
756 	       buffer_name, ring_name,
757 	       gtt_offset, head_offset,
758 	       data, &count, do_decode);
759 
760 	free(data);
761 	free(line);
762 	free(ring_name);
763 }
764 
setup_pager(void)765 static void setup_pager(void)
766 {
767 	int fds[2];
768 
769 	if (pipe(fds) == -1)
770 		return;
771 
772 	switch (fork()) {
773 	case -1:
774 		break;
775 	case 0:
776 		close(fds[1]);
777 		dup2(fds[0], 0);
778 		execlp("less", "less", "-FRSi", NULL);
779 		break;
780 
781 	default:
782 		close(fds[0]);
783 		dup2(fds[1], 1);
784 		close(fds[1]);
785 		break;
786 	}
787 }
788 
789 int
main(int argc,char * argv[])790 main(int argc, char *argv[])
791 {
792 	FILE *file;
793 	const char *path;
794 	char *filename = NULL;
795 	struct stat st;
796 	int error;
797 
798 	if (argc > 2) {
799 		fprintf(stderr,
800 				"intel_gpu_decode: Parse an Intel GPU i915_error_state\n"
801 				"Usage:\n"
802 				"\t%s [<file>]\n"
803 				"\n"
804 				"With no arguments, debugfs-dri-directory is probed for in "
805 				"/debug and \n"
806 				"/sys/kernel/debug.  Otherwise, it may be "
807 				"specified.  If a file is given,\n"
808 				"it is parsed as an GPU dump in the format of "
809 				"/debug/dri/0/i915_error_state.\n",
810 				argv[0]);
811 		return 1;
812 	}
813 
814 	if (isatty(1))
815 		setup_pager();
816 
817 	if (argc == 1) {
818 		if (isatty(0)) {
819 			path = "/sys/class/drm/card0/error";
820 			error = stat(path, &st);
821 			if (error != 0) {
822 				path = "/debug/dri";
823 				error = stat(path, &st);
824 			}
825 			if (error != 0) {
826 				path = "/sys/kernel/debug/dri";
827 				error = stat(path, &st);
828 			}
829 			if (error != 0) {
830 				errx(1,
831 				     "Couldn't find i915 debugfs directory.\n\n"
832 				     "Is debugfs mounted? You might try mounting it with a command such as:\n\n"
833 				     "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n");
834 			}
835 		} else {
836 			read_data_file(stdin);
837 			exit(0);
838 		}
839 	} else {
840 		path = argv[1];
841 		error = stat(path, &st);
842 		if (error != 0) {
843 			fprintf(stderr, "Error opening %s: %s\n",
844 					path, strerror(errno));
845 			exit(1);
846 		}
847 	}
848 
849 	if (S_ISDIR(st.st_mode)) {
850 		int ret;
851 
852 		ret = asprintf(&filename, "%s/i915_error_state", path);
853 		assert(ret > 0);
854 		file = fopen(filename, "r");
855 		if (!file) {
856 			int minor;
857 			for (minor = 0; minor < 64; minor++) {
858 				free(filename);
859 				ret = asprintf(&filename, "%s/%d/i915_error_state", path, minor);
860 				assert(ret > 0);
861 
862 				file = fopen(filename, "r");
863 				if (file)
864 					break;
865 			}
866 		}
867 		if (!file) {
868 			fprintf(stderr, "Failed to find i915_error_state beneath %s\n",
869 					path);
870 			exit (1);
871 		}
872 	} else {
873 		file = fopen(path, "r");
874 		if (!file) {
875 			fprintf(stderr, "Failed to open %s: %s\n",
876 					path, strerror(errno));
877 			exit (1);
878 		}
879 	}
880 
881 	read_data_file(file);
882 	fclose(file);
883 
884 	if (filename != path)
885 		free(filename);
886 
887 	return 0;
888 }
889 
890 /* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/
891