intel/gen_decoder: return -1 for unknown command formats
[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 }
248
249 static int zlib_inflate(uint32_t **ptr, int len)
250 {
251 struct z_stream_s zstream;
252 void *out;
253 const uint32_t out_size = 128*4096; /* approximate obj size */
254
255 memset(&zstream, 0, sizeof(zstream));
256
257 zstream.next_in = (unsigned char *)*ptr;
258 zstream.avail_in = 4*len;
259
260 if (inflateInit(&zstream) != Z_OK)
261 return 0;
262
263 out = malloc(out_size);
264 zstream.next_out = out;
265 zstream.avail_out = out_size;
266
267 do {
268 switch (inflate(&zstream, Z_SYNC_FLUSH)) {
269 case Z_STREAM_END:
270 goto end;
271 case Z_OK:
272 break;
273 default:
274 inflateEnd(&zstream);
275 return 0;
276 }
277
278 if (zstream.avail_out)
279 break;
280
281 out = realloc(out, 2*zstream.total_out);
282 if (out == NULL) {
283 inflateEnd(&zstream);
284 return 0;
285 }
286
287 zstream.next_out = (unsigned char *)out + zstream.total_out;
288 zstream.avail_out = zstream.total_out;
289 } while (1);
290 end:
291 inflateEnd(&zstream);
292 free(*ptr);
293 *ptr = out;
294 return zstream.total_out / 4;
295 }
296
297 static int ascii85_decode(const char *in, uint32_t **out, bool inflate)
298 {
299 int len = 0, size = 1024;
300
301 *out = realloc(*out, sizeof(uint32_t)*size);
302 if (*out == NULL)
303 return 0;
304
305 while (*in >= '!' && *in <= 'z') {
306 uint32_t v = 0;
307
308 if (len == size) {
309 size *= 2;
310 *out = realloc(*out, sizeof(uint32_t)*size);
311 if (*out == NULL)
312 return 0;
313 }
314
315 if (*in == 'z') {
316 in++;
317 } else {
318 v += in[0] - 33; v *= 85;
319 v += in[1] - 33; v *= 85;
320 v += in[2] - 33; v *= 85;
321 v += in[3] - 33; v *= 85;
322 v += in[4] - 33;
323 in += 5;
324 }
325 (*out)[len++] = v;
326 }
327
328 if (!inflate)
329 return len;
330
331 return zlib_inflate(out, len);
332 }
333
334 static void
335 read_data_file(FILE *file)
336 {
337 struct gen_spec *spec = NULL;
338 uint32_t *data = NULL;
339 long long unsigned fence;
340 int data_size = 0, count = 0, line_number = 0, matched;
341 char *line = NULL;
342 size_t line_size;
343 uint32_t offset, value;
344 uint64_t gtt_offset = 0, new_gtt_offset;
345 const char *buffer_name = "batch buffer";
346 char *ring_name = NULL;
347 struct gen_device_info devinfo;
348
349 while (getline(&line, &line_size, file) > 0) {
350 char *new_ring_name = NULL;
351 char *dashes;
352 line_number++;
353
354 if (sscanf(line, "%m[^ ] command stream\n", &new_ring_name) > 0) {
355 free(ring_name);
356 ring_name = new_ring_name;
357 }
358
359 dashes = strstr(line, "---");
360 if (dashes) {
361 uint32_t lo, hi;
362 char *new_ring_name = malloc(dashes - line);
363 strncpy(new_ring_name, line, dashes - line);
364 new_ring_name[dashes - line - 1] = '\0';
365
366 printf("%s", line);
367
368 matched = sscanf(dashes, "--- gtt_offset = 0x%08x %08x\n",
369 &hi, &lo);
370 if (matched > 0) {
371 new_gtt_offset = hi;
372 if (matched == 2) {
373 new_gtt_offset <<= 32;
374 new_gtt_offset |= lo;
375 }
376
377 decode(spec,
378 buffer_name, ring_name,
379 gtt_offset, data, &count);
380 gtt_offset = new_gtt_offset;
381 free(ring_name);
382 ring_name = new_ring_name;
383 buffer_name = "batch buffer";
384 continue;
385 }
386
387 matched = sscanf(dashes, "--- ringbuffer = 0x%08x %08x\n",
388 &hi, &lo);
389 if (matched > 0) {
390 new_gtt_offset = hi;
391 if (matched == 2) {
392 new_gtt_offset <<= 32;
393 new_gtt_offset |= lo;
394 }
395
396 decode(spec,
397 buffer_name, ring_name,
398 gtt_offset, data, &count);
399 gtt_offset = new_gtt_offset;
400 free(ring_name);
401 ring_name = new_ring_name;
402 buffer_name = "ring buffer";
403 continue;
404 }
405
406 matched = sscanf(dashes, "--- HW Context = 0x%08x %08x\n",
407 &hi, &lo);
408 if (matched > 0) {
409 new_gtt_offset = hi;
410 if (matched == 2) {
411 new_gtt_offset <<= 32;
412 new_gtt_offset |= lo;
413 }
414
415 decode(spec,
416 buffer_name, ring_name,
417 gtt_offset, data, &count);
418 gtt_offset = new_gtt_offset;
419 free(ring_name);
420 ring_name = new_ring_name;
421 buffer_name = "HW Context";
422 continue;
423 }
424 }
425
426 if (line[0] == ':' || line[0] == '~') {
427 count = ascii85_decode(line+1, &data, line[0] == ':');
428 if (count == 0) {
429 fprintf(stderr, "ASCII85 decode failed.\n");
430 exit(1);
431 }
432 decode(spec,
433 buffer_name, ring_name,
434 gtt_offset, data, &count);
435 continue;
436 }
437
438 matched = sscanf(line, "%08x : %08x", &offset, &value);
439 if (matched != 2) {
440 uint32_t reg, reg2;
441
442 /* display reg section is after the ringbuffers, don't mix them */
443 decode(spec,
444 buffer_name, ring_name,
445 gtt_offset, data, &count);
446
447 printf("%s", line);
448
449 matched = sscanf(line, "PCI ID: 0x%04x\n", &reg);
450 if (matched == 0)
451 matched = sscanf(line, " PCI ID: 0x%04x\n", &reg);
452 if (matched == 0) {
453 const char *pci_id_start = strstr(line, "PCI ID");
454 if (pci_id_start)
455 matched = sscanf(pci_id_start, "PCI ID: 0x%04x\n", &reg);
456 }
457 if (matched == 1) {
458 if (!gen_get_device_info(reg, &devinfo)) {
459 printf("Unable to identify devid=%x\n", reg);
460 return;
461 }
462
463 printf("Detected GEN%i chipset\n", devinfo.gen);
464
465 if (xml_path == NULL)
466 spec = gen_spec_load(&devinfo);
467 else
468 spec = gen_spec_load_from_path(&devinfo, xml_path);
469 }
470
471 matched = sscanf(line, " CTL: 0x%08x\n", &reg);
472 if (matched == 1) {
473 print_register(spec,
474 register_name_from_ring(ctl_registers,
475 ARRAY_SIZE(ctl_registers),
476 ring_name), reg);
477 }
478
479 matched = sscanf(line, " HEAD: 0x%08x\n", &reg);
480 if (matched == 1)
481 print_head(reg);
482
483 matched = sscanf(line, " ACTHD: 0x%08x\n", &reg);
484 if (matched == 1) {
485 print_register(spec,
486 register_name_from_ring(acthd_registers,
487 ARRAY_SIZE(acthd_registers),
488 ring_name), reg);
489 }
490
491 matched = sscanf(line, " PGTBL_ER: 0x%08x\n", &reg);
492 if (matched == 1 && reg)
493 print_pgtbl_err(reg, &devinfo);
494
495 matched = sscanf(line, " ERROR: 0x%08x\n", &reg);
496 if (matched == 1 && reg) {
497 print_register(spec, "GFX_ARB_ERROR_RPT", reg);
498 }
499
500 matched = sscanf(line, " INSTDONE: 0x%08x\n", &reg);
501 if (matched == 1) {
502 const char *reg_name =
503 instdone_register_for_ring(&devinfo, ring_name);
504 if (reg_name)
505 print_register(spec, reg_name, reg);
506 }
507
508 matched = sscanf(line, " INSTDONE1: 0x%08x\n", &reg);
509 if (matched == 1)
510 print_register(spec, "INSTDONE_1", reg);
511
512 matched = sscanf(line, " fence[%i] = %Lx\n", &reg, &fence);
513 if (matched == 2)
514 print_fence(&devinfo, fence);
515
516 matched = sscanf(line, " FAULT_REG: 0x%08x\n", &reg);
517 if (matched == 1 && reg) {
518 const char *reg_name =
519 register_name_from_ring(fault_registers,
520 ARRAY_SIZE(fault_registers),
521 ring_name);
522 if (reg_name == NULL)
523 reg_name = "FAULT_REG";
524 print_register(spec, reg_name, reg);
525 }
526
527 matched = sscanf(line, " FAULT_TLB_DATA: 0x%08x 0x%08x\n", &reg, &reg2);
528 if (matched == 2)
529 print_fault_data(&devinfo, reg, reg2);
530
531 continue;
532 }
533
534 count++;
535
536 if (count > data_size) {
537 data_size = data_size ? data_size * 2 : 1024;
538 data = realloc(data, data_size * sizeof (uint32_t));
539 if (data == NULL) {
540 fprintf(stderr, "Out of memory.\n");
541 exit(1);
542 }
543 }
544
545 data[count-1] = value;
546 }
547
548 decode(spec,
549 buffer_name, ring_name,
550 gtt_offset, data, &count);
551
552 free(data);
553 free(line);
554 free(ring_name);
555 }
556
557 static void
558 setup_pager(void)
559 {
560 int fds[2];
561 pid_t pid;
562
563 if (!isatty(1))
564 return;
565
566 if (pipe(fds) == -1)
567 return;
568
569 pid = fork();
570 if (pid == -1)
571 return;
572
573 if (pid == 0) {
574 close(fds[1]);
575 dup2(fds[0], 0);
576 execlp("less", "less", "-FRSi", NULL);
577 }
578
579 close(fds[0]);
580 dup2(fds[1], 1);
581 close(fds[1]);
582 }
583
584 static void
585 print_help(const char *progname, FILE *file)
586 {
587 fprintf(file,
588 "Usage: %s [OPTION]... [FILE]\n"
589 "Parse an Intel GPU i915_error_state.\n"
590 "With no FILE, debugfs-dri-directory is probed for in /debug and \n"
591 "/sys/kernel/debug. Otherwise, it may be specified. If a file is given,\n"
592 "it is parsed as an GPU dump in the format of /debug/dri/0/i915_error_state.\n\n"
593 " --help display this help and exit\n"
594 " --headers decode only command headers\n"
595 " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
596 " if omitted), 'always', or 'never'\n"
597 " --no-pager don't launch pager\n"
598 " --no-offsets don't print instruction offsets\n"
599 " --xml=DIR load hardware xml description from directory DIR\n",
600 progname);
601 }
602
603 int
604 main(int argc, char *argv[])
605 {
606 FILE *file;
607 const char *path;
608 struct stat st;
609 int c, i, error;
610 bool help = false, pager = true;
611 const struct option aubinator_opts[] = {
612 { "help", no_argument, (int *) &help, true },
613 { "no-pager", no_argument, (int *) &pager, false },
614 { "no-offsets", no_argument, (int *) &option_print_offsets, false },
615 { "headers", no_argument, (int *) &option_full_decode, false },
616 { "color", required_argument, NULL, 'c' },
617 { "xml", required_argument, NULL, 'x' },
618 { NULL, 0, NULL, 0 }
619 };
620
621 i = 0;
622 while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) {
623 switch (c) {
624 case 'c':
625 if (optarg == NULL || strcmp(optarg, "always") == 0)
626 option_color = COLOR_ALWAYS;
627 else if (strcmp(optarg, "never") == 0)
628 option_color = COLOR_NEVER;
629 else if (strcmp(optarg, "auto") == 0)
630 option_color = COLOR_AUTO;
631 else {
632 fprintf(stderr, "invalid value for --color: %s", optarg);
633 exit(EXIT_FAILURE);
634 }
635 break;
636 case 'x':
637 xml_path = strdup(optarg);
638 break;
639 default:
640 break;
641 }
642 }
643
644 if (help || argc == 1) {
645 print_help(argv[0], stderr);
646 exit(0);
647 }
648
649 if (optind >= argc) {
650 if (isatty(0)) {
651 path = "/sys/class/drm/card0/error";
652 error = stat(path, &st);
653 if (error != 0) {
654 path = "/debug/dri";
655 error = stat(path, &st);
656 }
657 if (error != 0) {
658 path = "/sys/kernel/debug/dri";
659 error = stat(path, &st);
660 }
661 if (error != 0) {
662 errx(1,
663 "Couldn't find i915 debugfs directory.\n\n"
664 "Is debugfs mounted? You might try mounting it with a command such as:\n\n"
665 "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n");
666 }
667 } else {
668 read_data_file(stdin);
669 exit(0);
670 }
671 } else {
672 path = argv[optind];
673 error = stat(path, &st);
674 if (error != 0) {
675 fprintf(stderr, "Error opening %s: %s\n",
676 path, strerror(errno));
677 exit(1);
678 }
679 }
680
681 if (option_color == COLOR_AUTO)
682 option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER;
683
684 if (isatty(1) && pager)
685 setup_pager();
686
687 if (S_ISDIR(st.st_mode)) {
688 int ret;
689 char *filename;
690
691 ret = asprintf(&filename, "%s/i915_error_state", path);
692 assert(ret > 0);
693 file = fopen(filename, "r");
694 if (!file) {
695 int minor;
696 for (minor = 0; minor < 64; minor++) {
697 free(filename);
698 ret = asprintf(&filename, "%s/%d/i915_error_state", path, minor);
699 assert(ret > 0);
700
701 file = fopen(filename, "r");
702 if (file)
703 break;
704
705 free(filename);
706 }
707 }
708 if (!file) {
709 fprintf(stderr, "Failed to find i915_error_state beneath %s\n",
710 path);
711 return EXIT_FAILURE;
712 }
713 } else {
714 file = fopen(path, "r");
715 if (!file) {
716 fprintf(stderr, "Failed to open %s: %s\n",
717 path, strerror(errno));
718 return EXIT_FAILURE;
719 }
720 }
721
722 read_data_file(file);
723 fclose(file);
724
725 /* close the stdout which is opened to write the output */
726 fflush(stdout);
727 close(1);
728 wait(NULL);
729
730 if (xml_path)
731 free(xml_path);
732
733 return EXIT_SUCCESS;
734 }
735
736 /* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/