intel/aubinator_error_decode: Stop decoding after MI_BATCH_BUFFER_END
[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
44 #define CSI "\e["
45 #define BLUE_HEADER CSI "0;44m"
46 #define GREEN_HEADER CSI "1;42m"
47 #define NORMAL CSI "0m"
48
49 /* options */
50
51 static bool option_full_decode = true;
52 static bool option_print_offsets = true;
53 static enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color;
54 static char *xml_path = NULL;
55
56 static uint32_t
57 print_head(unsigned int reg)
58 {
59 printf(" head = 0x%08x, wraps = %d\n", reg & (0x7ffff<<2), reg >> 21);
60 return reg & (0x7ffff<<2);
61 }
62
63 static void
64 print_register(struct gen_spec *spec, const char *name, uint32_t reg)
65 {
66 struct gen_group *reg_spec = gen_spec_find_register_by_name(spec, name);
67
68 if (reg_spec)
69 gen_print_group(stdout, reg_spec, 0, &reg, option_color == COLOR_ALWAYS);
70 }
71
72 struct ring_register_mapping {
73 const char *ring_name;
74 const char *register_name;
75 };
76
77 static const struct ring_register_mapping acthd_registers[] = {
78 { "blt", "BCS_ACTHD_UDW" },
79 { "bsd", "VCS_ACTHD_UDW" },
80 { "bsd2", "VCS2_ACTHD_UDW" },
81 { "render", "ACTHD_UDW" },
82 { "vebox", "VECS_ACTHD_UDW" },
83 };
84
85 static const struct ring_register_mapping ctl_registers[] = {
86 { "blt", "BCS_RING_BUFFER_CTL" },
87 { "bsd", "VCS_RING_BUFFER_CTL" },
88 { "bsd2", "VCS2_RING_BUFFER_CTL" },
89 { "render", "RCS_RING_BUFFER_CTL" },
90 { "vebox", "VECS_RING_BUFFER_CTL" },
91 };
92
93 static const struct ring_register_mapping fault_registers[] = {
94 { "blt", "BCS_FAULT_REG" },
95 { "bsd", "VCS_FAULT_REG" },
96 { "render", "RCS_FAULT_REG" },
97 { "vebox", "VECS_FAULT_REG" },
98 };
99
100 static const char *
101 register_name_from_ring(const struct ring_register_mapping *mapping,
102 unsigned nb_mapping,
103 const char *ring_name)
104 {
105 for (unsigned i = 0; i < nb_mapping; i++) {
106 if (strcmp(mapping[i].ring_name, ring_name) == 0)
107 return mapping[i].register_name;
108 }
109 return NULL;
110 }
111
112 static const char *
113 instdone_register_for_ring(const struct gen_device_info *devinfo,
114 const char *ring_name)
115 {
116 if (strcmp(ring_name, "blt") == 0)
117 return "BCS_INSTDONE";
118 else if (strcmp(ring_name, "vebox") == 0)
119 return "VECS_INSTDONE";
120 else if (strcmp(ring_name, "bsd") == 0)
121 return "VCS_INSTDONE";
122 else if (strcmp(ring_name, "render") == 0) {
123 if (devinfo->gen == 6)
124 return "INSTDONE_2";
125 return "INSTDONE_1";
126 }
127
128 return NULL;
129 }
130
131 static void
132 print_pgtbl_err(unsigned int reg, struct gen_device_info *devinfo)
133 {
134 if (reg & (1 << 26))
135 printf(" Invalid Sampler Cache GTT entry\n");
136 if (reg & (1 << 24))
137 printf(" Invalid Render Cache GTT entry\n");
138 if (reg & (1 << 23))
139 printf(" Invalid Instruction/State Cache GTT entry\n");
140 if (reg & (1 << 22))
141 printf(" There is no ROC, this cannot occur!\n");
142 if (reg & (1 << 21))
143 printf(" Invalid GTT entry during Vertex Fetch\n");
144 if (reg & (1 << 20))
145 printf(" Invalid GTT entry during Command Fetch\n");
146 if (reg & (1 << 19))
147 printf(" Invalid GTT entry during CS\n");
148 if (reg & (1 << 18))
149 printf(" Invalid GTT entry during Cursor Fetch\n");
150 if (reg & (1 << 17))
151 printf(" Invalid GTT entry during Overlay Fetch\n");
152 if (reg & (1 << 8))
153 printf(" Invalid GTT entry during Display B Fetch\n");
154 if (reg & (1 << 4))
155 printf(" Invalid GTT entry during Display A Fetch\n");
156 if (reg & (1 << 1))
157 printf(" Valid PTE references illegal memory\n");
158 if (reg & (1 << 0))
159 printf(" Invalid GTT entry during fetch for host\n");
160 }
161
162 static void
163 print_snb_fence(struct gen_device_info *devinfo, uint64_t fence)
164 {
165 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
166 fence & 1 ? "" : "in",
167 fence & (1<<1) ? 'y' : 'x',
168 (int)(((fence>>32)&0xfff)+1)*128,
169 (uint32_t)fence & 0xfffff000,
170 (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
171 }
172
173 static void
174 print_i965_fence(struct gen_device_info *devinfo, uint64_t fence)
175 {
176 printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
177 fence & 1 ? "" : "in",
178 fence & (1<<1) ? 'y' : 'x',
179 (int)(((fence>>2)&0x1ff)+1)*128,
180 (uint32_t)fence & 0xfffff000,
181 (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
182 }
183
184 static void
185 print_fence(struct gen_device_info *devinfo, uint64_t fence)
186 {
187 if (devinfo->gen == 6 || devinfo->gen == 7) {
188 return print_snb_fence(devinfo, fence);
189 } else if (devinfo->gen == 4 || devinfo->gen == 5) {
190 return print_i965_fence(devinfo, fence);
191 }
192 }
193
194 static void
195 print_fault_data(struct gen_device_info *devinfo, uint32_t data1, uint32_t data0)
196 {
197 uint64_t address;
198
199 if (devinfo->gen < 8)
200 return;
201
202 address = ((uint64_t)(data0) << 12) | ((uint64_t)data1 & 0xf) << 44;
203 printf(" Address 0x%016" PRIx64 " %s\n", address,
204 data1 & (1 << 4) ? "GGTT" : "PPGTT");
205 }
206
207 #define MAX_RINGS 10 /* I really hope this never... */
208
209 #define CSI "\e["
210 #define NORMAL CSI "0m"
211
212 static void decode(struct gen_spec *spec,
213 const char *buffer_name,
214 const char *ring_name,
215 uint64_t gtt_offset,
216 uint32_t *data,
217 int *count)
218 {
219 uint32_t *p, *end = (data + *count);
220 int length;
221 struct gen_group *inst;
222
223 for (p = data; p < end; p += length) {
224 const char *color = option_full_decode ? BLUE_HEADER : NORMAL,
225 *reset_color = NORMAL;
226 uint64_t offset = gtt_offset + 4 * (p - data);
227
228 inst = gen_spec_find_instruction(spec, p);
229 length = gen_group_get_length(inst, p);
230 assert(inst == NULL || length > 0);
231 length = MAX2(1, length);
232 if (inst == NULL) {
233 printf("unknown instruction %08x\n", p[0]);
234 continue;
235 }
236 if (option_color == COLOR_NEVER) {
237 color = "";
238 reset_color = "";
239 }
240
241 printf("%s0x%08"PRIx64": 0x%08x: %-80s%s\n",
242 color, offset, p[0], gen_group_get_name(inst), reset_color);
243
244 gen_print_group(stdout, inst, offset, p,
245 option_color == COLOR_ALWAYS);
246
247 if (strcmp(inst->name, "MI_BATCH_BUFFER_END") == 0)
248 break;
249 }
250 }
251
252 static int zlib_inflate(uint32_t **ptr, int len)
253 {
254 struct z_stream_s zstream;
255 void *out;
256 const uint32_t out_size = 128*4096; /* approximate obj size */
257
258 memset(&zstream, 0, sizeof(zstream));
259
260 zstream.next_in = (unsigned char *)*ptr;
261 zstream.avail_in = 4*len;
262
263 if (inflateInit(&zstream) != Z_OK)
264 return 0;
265
266 out = malloc(out_size);
267 zstream.next_out = out;
268 zstream.avail_out = out_size;
269
270 do {
271 switch (inflate(&zstream, Z_SYNC_FLUSH)) {
272 case Z_STREAM_END:
273 goto end;
274 case Z_OK:
275 break;
276 default:
277 inflateEnd(&zstream);
278 return 0;
279 }
280
281 if (zstream.avail_out)
282 break;
283
284 out = realloc(out, 2*zstream.total_out);
285 if (out == NULL) {
286 inflateEnd(&zstream);
287 return 0;
288 }
289
290 zstream.next_out = (unsigned char *)out + zstream.total_out;
291 zstream.avail_out = zstream.total_out;
292 } while (1);
293 end:
294 inflateEnd(&zstream);
295 free(*ptr);
296 *ptr = out;
297 return zstream.total_out / 4;
298 }
299
300 static int ascii85_decode(const char *in, uint32_t **out, bool inflate)
301 {
302 int len = 0, size = 1024;
303
304 *out = realloc(*out, sizeof(uint32_t)*size);
305 if (*out == NULL)
306 return 0;
307
308 while (*in >= '!' && *in <= 'z') {
309 uint32_t v = 0;
310
311 if (len == size) {
312 size *= 2;
313 *out = realloc(*out, sizeof(uint32_t)*size);
314 if (*out == NULL)
315 return 0;
316 }
317
318 if (*in == 'z') {
319 in++;
320 } else {
321 v += in[0] - 33; v *= 85;
322 v += in[1] - 33; v *= 85;
323 v += in[2] - 33; v *= 85;
324 v += in[3] - 33; v *= 85;
325 v += in[4] - 33;
326 in += 5;
327 }
328 (*out)[len++] = v;
329 }
330
331 if (!inflate)
332 return len;
333
334 return zlib_inflate(out, len);
335 }
336
337 static void
338 read_data_file(FILE *file)
339 {
340 struct gen_spec *spec = NULL;
341 uint32_t *data = NULL;
342 long long unsigned fence;
343 int data_size = 0, count = 0, line_number = 0, matched;
344 char *line = NULL;
345 size_t line_size;
346 uint32_t offset, value;
347 uint64_t gtt_offset = 0, new_gtt_offset;
348 const char *buffer_name = "batch buffer";
349 char *ring_name = NULL;
350 struct gen_device_info devinfo;
351
352 while (getline(&line, &line_size, file) > 0) {
353 char *new_ring_name = NULL;
354 char *dashes;
355 line_number++;
356
357 if (sscanf(line, "%m[^ ] command stream\n", &new_ring_name) > 0) {
358 free(ring_name);
359 ring_name = new_ring_name;
360 }
361
362 dashes = strstr(line, "---");
363 if (dashes) {
364 uint32_t lo, hi;
365 char *new_ring_name = malloc(dashes - line);
366 strncpy(new_ring_name, line, dashes - line);
367 new_ring_name[dashes - line - 1] = '\0';
368
369 printf("%s", line);
370
371 matched = sscanf(dashes, "--- gtt_offset = 0x%08x %08x\n",
372 &hi, &lo);
373 if (matched > 0) {
374 new_gtt_offset = hi;
375 if (matched == 2) {
376 new_gtt_offset <<= 32;
377 new_gtt_offset |= lo;
378 }
379
380 decode(spec,
381 buffer_name, ring_name,
382 gtt_offset, data, &count);
383 gtt_offset = new_gtt_offset;
384 free(ring_name);
385 ring_name = new_ring_name;
386 buffer_name = "batch buffer";
387 continue;
388 }
389
390 matched = sscanf(dashes, "--- ringbuffer = 0x%08x %08x\n",
391 &hi, &lo);
392 if (matched > 0) {
393 new_gtt_offset = hi;
394 if (matched == 2) {
395 new_gtt_offset <<= 32;
396 new_gtt_offset |= lo;
397 }
398
399 decode(spec,
400 buffer_name, ring_name,
401 gtt_offset, data, &count);
402 gtt_offset = new_gtt_offset;
403 free(ring_name);
404 ring_name = new_ring_name;
405 buffer_name = "ring buffer";
406 continue;
407 }
408
409 matched = sscanf(dashes, "--- HW Context = 0x%08x %08x\n",
410 &hi, &lo);
411 if (matched > 0) {
412 new_gtt_offset = hi;
413 if (matched == 2) {
414 new_gtt_offset <<= 32;
415 new_gtt_offset |= lo;
416 }
417
418 decode(spec,
419 buffer_name, ring_name,
420 gtt_offset, data, &count);
421 gtt_offset = new_gtt_offset;
422 free(ring_name);
423 ring_name = new_ring_name;
424 buffer_name = "HW Context";
425 continue;
426 }
427 }
428
429 if (line[0] == ':' || line[0] == '~') {
430 count = ascii85_decode(line+1, &data, line[0] == ':');
431 if (count == 0) {
432 fprintf(stderr, "ASCII85 decode failed.\n");
433 exit(1);
434 }
435 decode(spec,
436 buffer_name, ring_name,
437 gtt_offset, data, &count);
438 continue;
439 }
440
441 matched = sscanf(line, "%08x : %08x", &offset, &value);
442 if (matched != 2) {
443 uint32_t reg, reg2;
444
445 /* display reg section is after the ringbuffers, don't mix them */
446 decode(spec,
447 buffer_name, ring_name,
448 gtt_offset, data, &count);
449
450 printf("%s", line);
451
452 matched = sscanf(line, "PCI ID: 0x%04x\n", &reg);
453 if (matched == 0)
454 matched = sscanf(line, " PCI ID: 0x%04x\n", &reg);
455 if (matched == 0) {
456 const char *pci_id_start = strstr(line, "PCI ID");
457 if (pci_id_start)
458 matched = sscanf(pci_id_start, "PCI ID: 0x%04x\n", &reg);
459 }
460 if (matched == 1) {
461 if (!gen_get_device_info(reg, &devinfo)) {
462 printf("Unable to identify devid=%x\n", reg);
463 return;
464 }
465
466 printf("Detected GEN%i chipset\n", devinfo.gen);
467
468 if (xml_path == NULL)
469 spec = gen_spec_load(&devinfo);
470 else
471 spec = gen_spec_load_from_path(&devinfo, xml_path);
472 }
473
474 matched = sscanf(line, " CTL: 0x%08x\n", &reg);
475 if (matched == 1) {
476 print_register(spec,
477 register_name_from_ring(ctl_registers,
478 ARRAY_SIZE(ctl_registers),
479 ring_name), reg);
480 }
481
482 matched = sscanf(line, " HEAD: 0x%08x\n", &reg);
483 if (matched == 1)
484 print_head(reg);
485
486 matched = sscanf(line, " ACTHD: 0x%08x\n", &reg);
487 if (matched == 1) {
488 print_register(spec,
489 register_name_from_ring(acthd_registers,
490 ARRAY_SIZE(acthd_registers),
491 ring_name), reg);
492 }
493
494 matched = sscanf(line, " PGTBL_ER: 0x%08x\n", &reg);
495 if (matched == 1 && reg)
496 print_pgtbl_err(reg, &devinfo);
497
498 matched = sscanf(line, " ERROR: 0x%08x\n", &reg);
499 if (matched == 1 && reg) {
500 print_register(spec, "GFX_ARB_ERROR_RPT", reg);
501 }
502
503 matched = sscanf(line, " INSTDONE: 0x%08x\n", &reg);
504 if (matched == 1) {
505 const char *reg_name =
506 instdone_register_for_ring(&devinfo, ring_name);
507 if (reg_name)
508 print_register(spec, reg_name, reg);
509 }
510
511 matched = sscanf(line, " INSTDONE1: 0x%08x\n", &reg);
512 if (matched == 1)
513 print_register(spec, "INSTDONE_1", reg);
514
515 matched = sscanf(line, " fence[%i] = %Lx\n", &reg, &fence);
516 if (matched == 2)
517 print_fence(&devinfo, fence);
518
519 matched = sscanf(line, " FAULT_REG: 0x%08x\n", &reg);
520 if (matched == 1 && reg) {
521 const char *reg_name =
522 register_name_from_ring(fault_registers,
523 ARRAY_SIZE(fault_registers),
524 ring_name);
525 if (reg_name == NULL)
526 reg_name = "FAULT_REG";
527 print_register(spec, reg_name, reg);
528 }
529
530 matched = sscanf(line, " FAULT_TLB_DATA: 0x%08x 0x%08x\n", &reg, &reg2);
531 if (matched == 2)
532 print_fault_data(&devinfo, reg, reg2);
533
534 continue;
535 }
536
537 count++;
538
539 if (count > data_size) {
540 data_size = data_size ? data_size * 2 : 1024;
541 data = realloc(data, data_size * sizeof (uint32_t));
542 if (data == NULL) {
543 fprintf(stderr, "Out of memory.\n");
544 exit(1);
545 }
546 }
547
548 data[count-1] = value;
549 }
550
551 decode(spec,
552 buffer_name, ring_name,
553 gtt_offset, data, &count);
554
555 free(data);
556 free(line);
557 free(ring_name);
558 }
559
560 static void
561 setup_pager(void)
562 {
563 int fds[2];
564 pid_t pid;
565
566 if (!isatty(1))
567 return;
568
569 if (pipe(fds) == -1)
570 return;
571
572 pid = fork();
573 if (pid == -1)
574 return;
575
576 if (pid == 0) {
577 close(fds[1]);
578 dup2(fds[0], 0);
579 execlp("less", "less", "-FRSi", NULL);
580 }
581
582 close(fds[0]);
583 dup2(fds[1], 1);
584 close(fds[1]);
585 }
586
587 static void
588 print_help(const char *progname, FILE *file)
589 {
590 fprintf(file,
591 "Usage: %s [OPTION]... [FILE]\n"
592 "Parse an Intel GPU i915_error_state.\n"
593 "With no FILE, debugfs-dri-directory is probed for in /debug and \n"
594 "/sys/kernel/debug. Otherwise, it may be specified. If a file is given,\n"
595 "it is parsed as an GPU dump in the format of /debug/dri/0/i915_error_state.\n\n"
596 " --help display this help and exit\n"
597 " --headers decode only command headers\n"
598 " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
599 " if omitted), 'always', or 'never'\n"
600 " --no-pager don't launch pager\n"
601 " --no-offsets don't print instruction offsets\n"
602 " --xml=DIR load hardware xml description from directory DIR\n",
603 progname);
604 }
605
606 int
607 main(int argc, char *argv[])
608 {
609 FILE *file;
610 const char *path;
611 struct stat st;
612 int c, i, error;
613 bool help = false, pager = true;
614 const struct option aubinator_opts[] = {
615 { "help", no_argument, (int *) &help, true },
616 { "no-pager", no_argument, (int *) &pager, false },
617 { "no-offsets", no_argument, (int *) &option_print_offsets, false },
618 { "headers", no_argument, (int *) &option_full_decode, false },
619 { "color", required_argument, NULL, 'c' },
620 { "xml", required_argument, NULL, 'x' },
621 { NULL, 0, NULL, 0 }
622 };
623
624 i = 0;
625 while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) {
626 switch (c) {
627 case 'c':
628 if (optarg == NULL || strcmp(optarg, "always") == 0)
629 option_color = COLOR_ALWAYS;
630 else if (strcmp(optarg, "never") == 0)
631 option_color = COLOR_NEVER;
632 else if (strcmp(optarg, "auto") == 0)
633 option_color = COLOR_AUTO;
634 else {
635 fprintf(stderr, "invalid value for --color: %s", optarg);
636 exit(EXIT_FAILURE);
637 }
638 break;
639 case 'x':
640 xml_path = strdup(optarg);
641 break;
642 default:
643 break;
644 }
645 }
646
647 if (help || argc == 1) {
648 print_help(argv[0], stderr);
649 exit(0);
650 }
651
652 if (optind >= argc) {
653 if (isatty(0)) {
654 path = "/sys/class/drm/card0/error";
655 error = stat(path, &st);
656 if (error != 0) {
657 path = "/debug/dri";
658 error = stat(path, &st);
659 }
660 if (error != 0) {
661 path = "/sys/kernel/debug/dri";
662 error = stat(path, &st);
663 }
664 if (error != 0) {
665 errx(1,
666 "Couldn't find i915 debugfs directory.\n\n"
667 "Is debugfs mounted? You might try mounting it with a command such as:\n\n"
668 "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n");
669 }
670 } else {
671 read_data_file(stdin);
672 exit(0);
673 }
674 } else {
675 path = argv[optind];
676 error = stat(path, &st);
677 if (error != 0) {
678 fprintf(stderr, "Error opening %s: %s\n",
679 path, strerror(errno));
680 exit(1);
681 }
682 }
683
684 if (option_color == COLOR_AUTO)
685 option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER;
686
687 if (isatty(1) && pager)
688 setup_pager();
689
690 if (S_ISDIR(st.st_mode)) {
691 int ret;
692 char *filename;
693
694 ret = asprintf(&filename, "%s/i915_error_state", path);
695 assert(ret > 0);
696 file = fopen(filename, "r");
697 if (!file) {
698 int minor;
699 for (minor = 0; minor < 64; minor++) {
700 free(filename);
701 ret = asprintf(&filename, "%s/%d/i915_error_state", path, minor);
702 assert(ret > 0);
703
704 file = fopen(filename, "r");
705 if (file)
706 break;
707
708 free(filename);
709 }
710 }
711 if (!file) {
712 fprintf(stderr, "Failed to find i915_error_state beneath %s\n",
713 path);
714 return EXIT_FAILURE;
715 }
716 } else {
717 file = fopen(path, "r");
718 if (!file) {
719 fprintf(stderr, "Failed to open %s: %s\n",
720 path, strerror(errno));
721 return EXIT_FAILURE;
722 }
723 }
724
725 read_data_file(file);
726 fclose(file);
727
728 /* close the stdout which is opened to write the output */
729 fflush(stdout);
730 close(1);
731 wait(NULL);
732
733 if (xml_path)
734 free(xml_path);
735
736 return EXIT_SUCCESS;
737 }
738
739 /* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/