ecc01b55e7f8166665c613c970b4ebe6cd2d8522
[mesa.git] / src / intel / tools / aubinator_error_decode.c
1 /*
2 * Copyright © 2007-2017 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <inttypes.h>
32 #include <errno.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <err.h>
37 #include <assert.h>
38 #include <getopt.h>
39 #include <zlib.h>
40
41 #include "common/gen_decoder.h"
42 #include "util/macros.h"
43 #include "gen_disasm.h"
44
45 #define CSI "\e["
46 #define BLUE_HEADER CSI "0;44m"
47 #define GREEN_HEADER CSI "1;42m"
48 #define NORMAL CSI "0m"
49
50 #define MIN(a, b) ((a) < (b) ? (a) : (b))
51
52 /* options */
53
54 static bool option_full_decode = true;
55 static bool option_print_offsets = true;
56 static enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color;
57 static char *xml_path = NULL;
58
59 static uint32_t
60 print_head(unsigned int reg)
61 {
62 printf(" head = 0x%08x, wraps = %d\n", reg & (0x7ffff<<2), reg >> 21);
63 return reg & (0x7ffff<<2);
64 }
65
66 static void
67 print_register(struct gen_spec *spec, const char *name, uint32_t reg)
68 {
69 struct gen_group *reg_spec = gen_spec_find_register_by_name(spec, name);
70
71 if (reg_spec) {
72 gen_print_group(stdout, reg_spec, 0, &reg, 0,
73 option_color == COLOR_ALWAYS);
74 }
75 }
76
77 struct ring_register_mapping {
78 const char *ring_name;
79 const char *register_name;
80 };
81
82 static const struct ring_register_mapping acthd_registers[] = {
83 { "blt", "BCS_ACTHD_UDW" },
84 { "bsd", "VCS_ACTHD_UDW" },
85 { "bsd2", "VCS2_ACTHD_UDW" },
86 { "render", "ACTHD_UDW" },
87 { "vebox", "VECS_ACTHD_UDW" },
88 };
89
90 static const struct ring_register_mapping ctl_registers[] = {
91 { "blt", "BCS_RING_BUFFER_CTL" },
92 { "bsd", "VCS_RING_BUFFER_CTL" },
93 { "bsd2", "VCS2_RING_BUFFER_CTL" },
94 { "render", "RCS_RING_BUFFER_CTL" },
95 { "vebox", "VECS_RING_BUFFER_CTL" },
96 };
97
98 static const struct ring_register_mapping fault_registers[] = {
99 { "blt", "BCS_FAULT_REG" },
100 { "bsd", "VCS_FAULT_REG" },
101 { "render", "RCS_FAULT_REG" },
102 { "vebox", "VECS_FAULT_REG" },
103 };
104
105 static const char *
106 register_name_from_ring(const struct ring_register_mapping *mapping,
107 unsigned nb_mapping,
108 const char *ring_name)
109 {
110 for (unsigned i = 0; i < nb_mapping; i++) {
111 if (strcmp(mapping[i].ring_name, ring_name) == 0)
112 return mapping[i].register_name;
113 }
114 return NULL;
115 }
116
117 static const char *
118 instdone_register_for_ring(const struct gen_device_info *devinfo,
119 const char *ring_name)
120 {
121 if (strcmp(ring_name, "blt") == 0)
122 return "BCS_INSTDONE";
123 else if (strcmp(ring_name, "vebox") == 0)
124 return "VECS_INSTDONE";
125 else if (strcmp(ring_name, "bsd") == 0)
126 return "VCS_INSTDONE";
127 else if (strcmp(ring_name, "render") == 0) {
128 if (devinfo->gen == 6)
129 return "INSTDONE_2";
130 return "INSTDONE_1";
131 }
132
133 return NULL;
134 }
135
136 static void
137 print_pgtbl_err(unsigned int reg, struct gen_device_info *devinfo)
138 {
139 if (reg & (1 << 26))
140 printf(" Invalid Sampler Cache GTT entry\n");
141 if (reg & (1 << 24))
142 printf(" Invalid Render Cache GTT entry\n");
143 if (reg & (1 << 23))
144 printf(" Invalid Instruction/State Cache GTT entry\n");
145 if (reg & (1 << 22))
146 printf(" There is no ROC, this cannot occur!\n");
147 if (reg & (1 << 21))
148 printf(" Invalid GTT entry during Vertex Fetch\n");
149 if (reg & (1 << 20))
150 printf(" Invalid GTT entry during Command Fetch\n");
151 if (reg & (1 << 19))
152 printf(" Invalid GTT entry during CS\n");
153 if (reg & (1 << 18))
154 printf(" Invalid GTT entry during Cursor Fetch\n");
155 if (reg & (1 << 17))
156 printf(" Invalid GTT entry during Overlay Fetch\n");
157 if (reg & (1 << 8))
158 printf(" Invalid GTT entry during Display B Fetch\n");
159 if (reg & (1 << 4))
160 printf(" Invalid GTT entry during Display A Fetch\n");
161 if (reg & (1 << 1))
162 printf(" Valid PTE references illegal memory\n");
163 if (reg & (1 << 0))
164 printf(" Invalid GTT entry during fetch for host\n");
165 }
166
167 static void
168 print_snb_fence(struct gen_device_info *devinfo, uint64_t fence)
169 {
170 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
171 fence & 1 ? "" : "in",
172 fence & (1<<1) ? 'y' : 'x',
173 (int)(((fence>>32)&0xfff)+1)*128,
174 (uint32_t)fence & 0xfffff000,
175 (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
176 }
177
178 static void
179 print_i965_fence(struct gen_device_info *devinfo, uint64_t fence)
180 {
181 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
182 fence & 1 ? "" : "in",
183 fence & (1<<1) ? 'y' : 'x',
184 (int)(((fence>>2)&0x1ff)+1)*128,
185 (uint32_t)fence & 0xfffff000,
186 (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
187 }
188
189 static void
190 print_fence(struct gen_device_info *devinfo, uint64_t fence)
191 {
192 if (devinfo->gen == 6 || devinfo->gen == 7) {
193 return print_snb_fence(devinfo, fence);
194 } else if (devinfo->gen == 4 || devinfo->gen == 5) {
195 return print_i965_fence(devinfo, fence);
196 }
197 }
198
199 static void
200 print_fault_data(struct gen_device_info *devinfo, uint32_t data1, uint32_t data0)
201 {
202 uint64_t address;
203
204 if (devinfo->gen < 8)
205 return;
206
207 address = ((uint64_t)(data0) << 12) | ((uint64_t)data1 & 0xf) << 44;
208 printf(" Address 0x%016" PRIx64 " %s\n", address,
209 data1 & (1 << 4) ? "GGTT" : "PPGTT");
210 }
211
212 #define CSI "\e["
213 #define NORMAL CSI "0m"
214
215 struct section {
216 uint64_t gtt_offset;
217 char *ring_name;
218 const char *buffer_name;
219 uint32_t *data;
220 int count;
221 };
222
223 #define MAX_SECTIONS 30
224 static struct section sections[MAX_SECTIONS];
225
226 static void
227 disassemble_program(struct gen_disasm *disasm, const char *type,
228 const struct section *instruction_section,
229 uint64_t ksp)
230 {
231 if (!instruction_section)
232 return;
233
234 printf("\nReferenced %s:\n", type);
235 gen_disasm_disassemble(disasm, instruction_section->data, ksp, stdout);
236 }
237
238 static const struct section *
239 find_section(const char *str_base_address)
240 {
241 uint64_t base_address = strtol(str_base_address, NULL, 16);
242 for (int s = 0; s < MAX_SECTIONS; s++) {
243 if (sections[s].gtt_offset == base_address)
244 return &sections[s];
245 }
246 return NULL;
247 }
248
249 static void
250 decode(struct gen_spec *spec, struct gen_disasm *disasm,
251 const struct section *section)
252 {
253 uint64_t gtt_offset = section->gtt_offset;
254 uint32_t *data = section->data;
255 uint32_t *p, *end = (data + section->count);
256 int length;
257 struct gen_group *inst;
258 const struct section *current_instruction_buffer = NULL;
259 const struct section *current_dynamic_state_buffer = NULL;
260
261 for (p = data; p < end; p += length) {
262 const char *color = option_full_decode ? BLUE_HEADER : NORMAL,
263 *reset_color = NORMAL;
264 uint64_t offset = gtt_offset + 4 * (p - data);
265
266 inst = gen_spec_find_instruction(spec, p);
267 length = gen_group_get_length(inst, p);
268 assert(inst == NULL || length > 0);
269 length = MAX2(1, length);
270 if (inst == NULL) {
271 printf("unknown instruction %08x\n", p[0]);
272 continue;
273 }
274 if (option_color == COLOR_NEVER) {
275 color = "";
276 reset_color = "";
277 }
278
279 printf("%s0x%08"PRIx64": 0x%08x: %-80s%s\n",
280 color, offset, p[0], gen_group_get_name(inst), reset_color);
281
282 gen_print_group(stdout, inst, offset, p, 0,
283 option_color == COLOR_ALWAYS);
284
285 if (strcmp(inst->name, "MI_BATCH_BUFFER_END") == 0)
286 break;
287
288 if (strcmp(inst->name, "STATE_BASE_ADDRESS") == 0) {
289 struct gen_field_iterator iter;
290 gen_field_iterator_init(&iter, inst, p, 0, false);
291
292 do {
293 if (strcmp(iter.name, "Instruction Base Address") == 0) {
294 current_instruction_buffer = find_section(iter.value);
295 } else if (strcmp(iter.name, "Dynamic State Base Address") == 0) {
296 current_dynamic_state_buffer = find_section(iter.value);
297 }
298 } while (gen_field_iterator_next(&iter));
299 } else if (strcmp(inst->name, "WM_STATE") == 0 ||
300 strcmp(inst->name, "3DSTATE_PS") == 0 ||
301 strcmp(inst->name, "3DSTATE_WM") == 0) {
302 struct gen_field_iterator iter;
303 gen_field_iterator_init(&iter, inst, p, 0, false);
304 uint64_t ksp[3] = {0, 0, 0};
305 bool enabled[3] = {false, false, false};
306
307 do {
308 if (strncmp(iter.name, "Kernel Start Pointer ",
309 strlen("Kernel Start Pointer ")) == 0) {
310 int idx = iter.name[strlen("Kernel Start Pointer ")] - '0';
311 ksp[idx] = strtol(iter.value, NULL, 16);
312 } else if (strcmp(iter.name, "8 Pixel Dispatch Enable") == 0) {
313 enabled[0] = strcmp(iter.value, "true") == 0;
314 } else if (strcmp(iter.name, "16 Pixel Dispatch Enable") == 0) {
315 enabled[1] = strcmp(iter.value, "true") == 0;
316 } else if (strcmp(iter.name, "32 Pixel Dispatch Enable") == 0) {
317 enabled[2] = strcmp(iter.value, "true") == 0;
318 }
319 } while (gen_field_iterator_next(&iter));
320
321 /* Reorder KSPs to be [8, 16, 32] instead of the hardware order. */
322 if (enabled[0] + enabled[1] + enabled[2] == 1) {
323 if (enabled[1]) {
324 ksp[1] = ksp[0];
325 ksp[0] = 0;
326 } else if (enabled[2]) {
327 ksp[2] = ksp[0];
328 ksp[0] = 0;
329 }
330 } else {
331 uint64_t tmp = ksp[1];
332 ksp[1] = ksp[2];
333 ksp[2] = tmp;
334 }
335
336 /* FINISHME: Broken for multi-program WM_STATE,
337 * which Mesa does not use
338 */
339 if (enabled[0]) {
340 disassemble_program(disasm, "SIMD8 fragment shader",
341 current_instruction_buffer, ksp[0]);
342 }
343 if (enabled[1]) {
344 disassemble_program(disasm, "SIMD16 fragment shader",
345 current_instruction_buffer, ksp[1]);
346 }
347 if (enabled[2]) {
348 disassemble_program(disasm, "SIMD32 fragment shader",
349 current_instruction_buffer, ksp[2]);
350 }
351 printf("\n");
352 } else if (strcmp(inst->name, "VS_STATE") == 0 ||
353 strcmp(inst->name, "GS_STATE") == 0 ||
354 strcmp(inst->name, "SF_STATE") == 0 ||
355 strcmp(inst->name, "CLIP_STATE") == 0 ||
356 strcmp(inst->name, "3DSTATE_DS") == 0 ||
357 strcmp(inst->name, "3DSTATE_HS") == 0 ||
358 strcmp(inst->name, "3DSTATE_GS") == 0 ||
359 strcmp(inst->name, "3DSTATE_VS") == 0) {
360 struct gen_field_iterator iter;
361 gen_field_iterator_init(&iter, inst, p, 0, false);
362 uint64_t ksp = 0;
363 bool is_simd8 = false; /* vertex shaders on Gen8+ only */
364 bool is_enabled = true;
365
366 do {
367 if (strcmp(iter.name, "Kernel Start Pointer") == 0) {
368 ksp = strtol(iter.value, NULL, 16);
369 } else if (strcmp(iter.name, "SIMD8 Dispatch Enable") == 0) {
370 is_simd8 = strcmp(iter.value, "true") == 0;
371 } else if (strcmp(iter.name, "Dispatch Enable") == 0) {
372 is_simd8 = strcmp(iter.value, "SIMD8") == 0;
373 } else if (strcmp(iter.name, "Enable") == 0) {
374 is_enabled = strcmp(iter.value, "true") == 0;
375 }
376 } while (gen_field_iterator_next(&iter));
377
378 const char *type =
379 strcmp(inst->name, "VS_STATE") == 0 ? "vertex shader" :
380 strcmp(inst->name, "GS_STATE") == 0 ? "geometry shader" :
381 strcmp(inst->name, "SF_STATE") == 0 ? "strips and fans shader" :
382 strcmp(inst->name, "CLIP_STATE") == 0 ? "clip shader" :
383 strcmp(inst->name, "3DSTATE_DS") == 0 ? "tessellation control shader" :
384 strcmp(inst->name, "3DSTATE_HS") == 0 ? "tessellation evaluation shader" :
385 strcmp(inst->name, "3DSTATE_VS") == 0 ? (is_simd8 ? "SIMD8 vertex shader" : "vec4 vertex shader") :
386 strcmp(inst->name, "3DSTATE_GS") == 0 ? (is_simd8 ? "SIMD8 geometry shader" : "vec4 geometry shader") :
387 NULL;
388
389 if (is_enabled) {
390 disassemble_program(disasm, type, current_instruction_buffer, ksp);
391 printf("\n");
392 }
393 } else if (strcmp(inst->name, "MEDIA_INTERFACE_DESCRIPTOR_LOAD") == 0) {
394 struct gen_field_iterator iter;
395 gen_field_iterator_init(&iter, inst, p, 0, false);
396 uint64_t interface_offset = 0;
397 do {
398 if (strcmp(iter.name, "Interface Descriptor Data Start Address") == 0) {
399 interface_offset = strtol(iter.value, NULL, 16);
400 break;
401 }
402 } while (gen_field_iterator_next(&iter));
403
404 if (current_dynamic_state_buffer && interface_offset != 0) {
405 struct gen_group *desc =
406 gen_spec_find_struct(spec, "INTERFACE_DESCRIPTOR_DATA");
407 uint32_t *desc_p =
408 ((void *)current_dynamic_state_buffer->data) + interface_offset;
409 gen_field_iterator_init(&iter, desc, desc_p, 0, false);
410 do {
411 if (strcmp(iter.name, "Kernel Start Pointer") == 0) {
412 uint64_t ksp = strtol(iter.value, NULL, 16);
413 disassemble_program(disasm, "compute shader",
414 current_instruction_buffer, ksp);
415 printf("\n");
416 break;
417 }
418 } while (gen_field_iterator_next(&iter));
419 }
420 }
421 }
422 }
423
424 static int zlib_inflate(uint32_t **ptr, int len)
425 {
426 struct z_stream_s zstream;
427 void *out;
428 const uint32_t out_size = 128*4096; /* approximate obj size */
429
430 memset(&zstream, 0, sizeof(zstream));
431
432 zstream.next_in = (unsigned char *)*ptr;
433 zstream.avail_in = 4*len;
434
435 if (inflateInit(&zstream) != Z_OK)
436 return 0;
437
438 out = malloc(out_size);
439 zstream.next_out = out;
440 zstream.avail_out = out_size;
441
442 do {
443 switch (inflate(&zstream, Z_SYNC_FLUSH)) {
444 case Z_STREAM_END:
445 goto end;
446 case Z_OK:
447 break;
448 default:
449 inflateEnd(&zstream);
450 return 0;
451 }
452
453 if (zstream.avail_out)
454 break;
455
456 out = realloc(out, 2*zstream.total_out);
457 if (out == NULL) {
458 inflateEnd(&zstream);
459 return 0;
460 }
461
462 zstream.next_out = (unsigned char *)out + zstream.total_out;
463 zstream.avail_out = zstream.total_out;
464 } while (1);
465 end:
466 inflateEnd(&zstream);
467 free(*ptr);
468 *ptr = out;
469 return zstream.total_out / 4;
470 }
471
472 static int ascii85_decode(const char *in, uint32_t **out, bool inflate)
473 {
474 int len = 0, size = 1024;
475
476 *out = realloc(*out, sizeof(uint32_t)*size);
477 if (*out == NULL)
478 return 0;
479
480 while (*in >= '!' && *in <= 'z') {
481 uint32_t v = 0;
482
483 if (len == size) {
484 size *= 2;
485 *out = realloc(*out, sizeof(uint32_t)*size);
486 if (*out == NULL)
487 return 0;
488 }
489
490 if (*in == 'z') {
491 in++;
492 } else {
493 v += in[0] - 33; v *= 85;
494 v += in[1] - 33; v *= 85;
495 v += in[2] - 33; v *= 85;
496 v += in[3] - 33; v *= 85;
497 v += in[4] - 33;
498 in += 5;
499 }
500 (*out)[len++] = v;
501 }
502
503 if (!inflate)
504 return len;
505
506 return zlib_inflate(out, len);
507 }
508
509 static void
510 read_data_file(FILE *file)
511 {
512 struct gen_spec *spec = NULL;
513 long long unsigned fence;
514 int matched;
515 char *line = NULL;
516 size_t line_size;
517 uint32_t offset, value;
518 char *ring_name = NULL;
519 struct gen_device_info devinfo;
520 struct gen_disasm *disasm = NULL;
521 int sect_num = 0;
522
523 while (getline(&line, &line_size, file) > 0) {
524 char *new_ring_name = NULL;
525 char *dashes;
526
527 if (sscanf(line, "%m[^ ] command stream\n", &new_ring_name) > 0) {
528 free(ring_name);
529 ring_name = new_ring_name;
530 }
531
532 if (line[0] == ':' || line[0] == '~') {
533 uint32_t *data = NULL;
534 int count = ascii85_decode(line+1, &data, line[0] == ':');
535 if (count == 0) {
536 fprintf(stderr, "ASCII85 decode failed.\n");
537 exit(EXIT_FAILURE);
538 }
539 sections[sect_num].data = data;
540 sections[sect_num].count = count;
541 sect_num++;
542 continue;
543 }
544
545 dashes = strstr(line, "---");
546 if (dashes) {
547 const struct {
548 const char *match;
549 const char *name;
550 } buffers[] = {
551 { "ringbuffer", "ring buffer" },
552 { "gtt_offset", "batch buffer" },
553 { "hw context", "HW Context" },
554 { "hw status", "HW status" },
555 { "wa context", "WA context" },
556 { "wa batchbuffer", "WA batch" },
557 { "user", "user" },
558 { "semaphores", "semaphores", },
559 { "guc log buffer", "GuC log", },
560 { NULL, "unknown" },
561 }, *b;
562
563 free(ring_name);
564 ring_name = malloc(dashes - line);
565 strncpy(ring_name, line, dashes - line);
566 ring_name[dashes - line - 1] = '\0';
567
568 dashes += 4;
569 for (b = buffers; b->match; b++) {
570 if (strncasecmp(dashes, b->match, strlen(b->match)) == 0)
571 break;
572 }
573
574 sections[sect_num].buffer_name = b->name;
575 sections[sect_num].ring_name = strdup(ring_name);
576
577 uint32_t hi, lo;
578 dashes = strchr(dashes, '=');
579 if (dashes && sscanf(dashes, "= 0x%08x %08x\n", &hi, &lo))
580 sections[sect_num].gtt_offset = ((uint64_t) hi) << 32 | lo;
581
582 continue;
583 }
584
585 matched = sscanf(line, "%08x : %08x", &offset, &value);
586 if (matched != 2) {
587 uint32_t reg, reg2;
588
589 /* display reg section is after the ringbuffers, don't mix them */
590 printf("%s", line);
591
592 matched = sscanf(line, "PCI ID: 0x%04x\n", &reg);
593 if (matched == 0)
594 matched = sscanf(line, " PCI ID: 0x%04x\n", &reg);
595 if (matched == 0) {
596 const char *pci_id_start = strstr(line, "PCI ID");
597 if (pci_id_start)
598 matched = sscanf(pci_id_start, "PCI ID: 0x%04x\n", &reg);
599 }
600 if (matched == 1) {
601 if (!gen_get_device_info(reg, &devinfo)) {
602 printf("Unable to identify devid=%x\n", reg);
603 exit(EXIT_FAILURE);
604 }
605
606 disasm = gen_disasm_create(reg);
607
608 printf("Detected GEN%i chipset\n", devinfo.gen);
609
610 if (xml_path == NULL)
611 spec = gen_spec_load(&devinfo);
612 else
613 spec = gen_spec_load_from_path(&devinfo, xml_path);
614 }
615
616 matched = sscanf(line, " CTL: 0x%08x\n", &reg);
617 if (matched == 1) {
618 print_register(spec,
619 register_name_from_ring(ctl_registers,
620 ARRAY_SIZE(ctl_registers),
621 ring_name), reg);
622 }
623
624 matched = sscanf(line, " HEAD: 0x%08x\n", &reg);
625 if (matched == 1)
626 print_head(reg);
627
628 matched = sscanf(line, " ACTHD: 0x%08x\n", &reg);
629 if (matched == 1) {
630 print_register(spec,
631 register_name_from_ring(acthd_registers,
632 ARRAY_SIZE(acthd_registers),
633 ring_name), reg);
634 }
635
636 matched = sscanf(line, " PGTBL_ER: 0x%08x\n", &reg);
637 if (matched == 1 && reg)
638 print_pgtbl_err(reg, &devinfo);
639
640 matched = sscanf(line, " ERROR: 0x%08x\n", &reg);
641 if (matched == 1 && reg) {
642 print_register(spec, "GFX_ARB_ERROR_RPT", reg);
643 }
644
645 matched = sscanf(line, " INSTDONE: 0x%08x\n", &reg);
646 if (matched == 1) {
647 const char *reg_name =
648 instdone_register_for_ring(&devinfo, ring_name);
649 if (reg_name)
650 print_register(spec, reg_name, reg);
651 }
652
653 matched = sscanf(line, " INSTDONE1: 0x%08x\n", &reg);
654 if (matched == 1)
655 print_register(spec, "INSTDONE_1", reg);
656
657 matched = sscanf(line, " fence[%i] = %Lx\n", &reg, &fence);
658 if (matched == 2)
659 print_fence(&devinfo, fence);
660
661 matched = sscanf(line, " FAULT_REG: 0x%08x\n", &reg);
662 if (matched == 1 && reg) {
663 const char *reg_name =
664 register_name_from_ring(fault_registers,
665 ARRAY_SIZE(fault_registers),
666 ring_name);
667 if (reg_name == NULL)
668 reg_name = "FAULT_REG";
669 print_register(spec, reg_name, reg);
670 }
671
672 matched = sscanf(line, " FAULT_TLB_DATA: 0x%08x 0x%08x\n", &reg, &reg2);
673 if (matched == 2)
674 print_fault_data(&devinfo, reg, reg2);
675
676 continue;
677 }
678 }
679
680 free(line);
681 free(ring_name);
682
683 for (int s = 0; s < sect_num; s++) {
684 printf("--- %s (%s) at 0x%08x %08x\n",
685 sections[s].buffer_name, sections[s].ring_name,
686 (unsigned) (sections[s].gtt_offset >> 32),
687 (unsigned) sections[s].gtt_offset);
688
689 if (strcmp(sections[s].buffer_name, "batch buffer") == 0 ||
690 strcmp(sections[s].buffer_name, "ring buffer") == 0 ||
691 strcmp(sections[s].buffer_name, "HW Context") == 0) {
692 decode(spec, disasm, &sections[s]);
693 }
694
695 free(sections[s].ring_name);
696 free(sections[s].data);
697 }
698
699 gen_disasm_destroy(disasm);
700 }
701
702 static void
703 setup_pager(void)
704 {
705 int fds[2];
706 pid_t pid;
707
708 if (!isatty(1))
709 return;
710
711 if (pipe(fds) == -1)
712 return;
713
714 pid = fork();
715 if (pid == -1)
716 return;
717
718 if (pid == 0) {
719 close(fds[1]);
720 dup2(fds[0], 0);
721 execlp("less", "less", "-FRSi", NULL);
722 }
723
724 close(fds[0]);
725 dup2(fds[1], 1);
726 close(fds[1]);
727 }
728
729 static void
730 print_help(const char *progname, FILE *file)
731 {
732 fprintf(file,
733 "Usage: %s [OPTION]... [FILE]\n"
734 "Parse an Intel GPU i915_error_state.\n"
735 "With no FILE, debugfs-dri-directory is probed for in /debug and \n"
736 "/sys/kernel/debug. Otherwise, it may be specified. If a file is given,\n"
737 "it is parsed as an GPU dump in the format of /debug/dri/0/i915_error_state.\n\n"
738 " --help display this help and exit\n"
739 " --headers decode only command headers\n"
740 " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
741 " if omitted), 'always', or 'never'\n"
742 " --no-pager don't launch pager\n"
743 " --no-offsets don't print instruction offsets\n"
744 " --xml=DIR load hardware xml description from directory DIR\n",
745 progname);
746 }
747
748 int
749 main(int argc, char *argv[])
750 {
751 FILE *file;
752 const char *path;
753 struct stat st;
754 int c, i, error;
755 bool help = false, pager = true;
756 const struct option aubinator_opts[] = {
757 { "help", no_argument, (int *) &help, true },
758 { "no-pager", no_argument, (int *) &pager, false },
759 { "no-offsets", no_argument, (int *) &option_print_offsets, false },
760 { "headers", no_argument, (int *) &option_full_decode, false },
761 { "color", required_argument, NULL, 'c' },
762 { "xml", required_argument, NULL, 'x' },
763 { NULL, 0, NULL, 0 }
764 };
765
766 i = 0;
767 while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) {
768 switch (c) {
769 case 'c':
770 if (optarg == NULL || strcmp(optarg, "always") == 0)
771 option_color = COLOR_ALWAYS;
772 else if (strcmp(optarg, "never") == 0)
773 option_color = COLOR_NEVER;
774 else if (strcmp(optarg, "auto") == 0)
775 option_color = COLOR_AUTO;
776 else {
777 fprintf(stderr, "invalid value for --color: %s", optarg);
778 exit(EXIT_FAILURE);
779 }
780 break;
781 case 'x':
782 xml_path = strdup(optarg);
783 break;
784 default:
785 break;
786 }
787 }
788
789 if (help || argc == 1) {
790 print_help(argv[0], stderr);
791 exit(EXIT_SUCCESS);
792 }
793
794 if (optind >= argc) {
795 if (isatty(0)) {
796 path = "/sys/class/drm/card0/error";
797 error = stat(path, &st);
798 if (error != 0) {
799 path = "/debug/dri";
800 error = stat(path, &st);
801 }
802 if (error != 0) {
803 path = "/sys/kernel/debug/dri";
804 error = stat(path, &st);
805 }
806 if (error != 0) {
807 errx(1,
808 "Couldn't find i915 debugfs directory.\n\n"
809 "Is debugfs mounted? You might try mounting it with a command such as:\n\n"
810 "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n");
811 }
812 } else {
813 read_data_file(stdin);
814 exit(EXIT_SUCCESS);
815 }
816 } else {
817 path = argv[optind];
818 error = stat(path, &st);
819 if (error != 0) {
820 fprintf(stderr, "Error opening %s: %s\n",
821 path, strerror(errno));
822 exit(EXIT_FAILURE);
823 }
824 }
825
826 if (option_color == COLOR_AUTO)
827 option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER;
828
829 if (isatty(1) && pager)
830 setup_pager();
831
832 if (S_ISDIR(st.st_mode)) {
833 int ret;
834 char *filename;
835
836 ret = asprintf(&filename, "%s/i915_error_state", path);
837 assert(ret > 0);
838 file = fopen(filename, "r");
839 if (!file) {
840 int minor;
841 free(filename);
842 for (minor = 0; minor < 64; minor++) {
843 ret = asprintf(&filename, "%s/%d/i915_error_state", path, minor);
844 assert(ret > 0);
845
846 file = fopen(filename, "r");
847 if (file)
848 break;
849
850 free(filename);
851 }
852 }
853 if (!file) {
854 fprintf(stderr, "Failed to find i915_error_state beneath %s\n",
855 path);
856 return EXIT_FAILURE;
857 }
858 } else {
859 file = fopen(path, "r");
860 if (!file) {
861 fprintf(stderr, "Failed to open %s: %s\n",
862 path, strerror(errno));
863 return EXIT_FAILURE;
864 }
865 }
866
867 read_data_file(file);
868 fclose(file);
869
870 /* close the stdout which is opened to write the output */
871 fflush(stdout);
872 close(1);
873 wait(NULL);
874
875 if (xml_path)
876 free(xml_path);
877
878 return EXIT_SUCCESS;
879 }
880
881 /* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/