• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/intel_decoder.h"
42 #include "compiler/brw_compiler.h"
43 #include "dev/intel_debug.h"
44 #include "util/macros.h"
45 
46 #define MIN(a, b) ((a) < (b) ? (a) : (b))
47 
48 /* options */
49 
50 static bool option_full_decode = true;
51 static bool option_print_all_bb = false;
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
print_head(unsigned int reg)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
print_register(struct intel_spec * spec,const char * name,uint32_t reg)64 print_register(struct intel_spec *spec, const char *name, uint32_t reg)
65 {
66    struct intel_group *reg_spec =
67       name ? intel_spec_find_register_by_name(spec, name) : NULL;
68 
69    if (reg_spec) {
70       intel_print_group(stdout, reg_spec, 0, &reg, 0,
71                         option_color == COLOR_ALWAYS);
72    }
73 }
74 
75 struct ring_register_mapping {
76    enum drm_i915_gem_engine_class ring_class;
77    unsigned ring_instance;
78    const char *register_name;
79 };
80 
81 static const struct ring_register_mapping acthd_registers[] = {
82    { I915_ENGINE_CLASS_COPY, 0, "BCS_ACTHD_UDW" },
83    { I915_ENGINE_CLASS_VIDEO, 0, "VCS_ACTHD_UDW" },
84    { I915_ENGINE_CLASS_VIDEO, 1, "VCS2_ACTHD_UDW" },
85    { I915_ENGINE_CLASS_RENDER, 0, "ACTHD_UDW" },
86    { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_ACTHD_UDW" },
87 };
88 
89 static const struct ring_register_mapping ctl_registers[] = {
90    { I915_ENGINE_CLASS_COPY, 0, "BCS_RING_BUFFER_CTL" },
91    { I915_ENGINE_CLASS_VIDEO, 0, "VCS_RING_BUFFER_CTL" },
92    { I915_ENGINE_CLASS_VIDEO, 1, "VCS2_RING_BUFFER_CTL" },
93    { I915_ENGINE_CLASS_RENDER, 0, "RCS_RING_BUFFER_CTL" },
94    { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0,  "VECS_RING_BUFFER_CTL" },
95 };
96 
97 static const struct ring_register_mapping fault_registers[] = {
98    { I915_ENGINE_CLASS_COPY, 0, "BCS_FAULT_REG" },
99    { I915_ENGINE_CLASS_VIDEO, 0, "VCS_FAULT_REG" },
100    { I915_ENGINE_CLASS_RENDER, 0, "RCS_FAULT_REG" },
101    { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_FAULT_REG" },
102 };
103 
ring_name_to_class(const char * ring_name,enum drm_i915_gem_engine_class * class)104 static int ring_name_to_class(const char *ring_name,
105                               enum drm_i915_gem_engine_class *class)
106 {
107    static const char *class_names[] = {
108       [I915_ENGINE_CLASS_RENDER] = "rcs",
109       [I915_ENGINE_CLASS_COPY] = "bcs",
110       [I915_ENGINE_CLASS_VIDEO] = "vcs",
111       [I915_ENGINE_CLASS_VIDEO_ENHANCE] = "vecs",
112    };
113    for (size_t i = 0; i < ARRAY_SIZE(class_names); i++) {
114       if (strncmp(ring_name, class_names[i], strlen(class_names[i])))
115          continue;
116 
117       *class = i;
118       return atoi(ring_name + strlen(class_names[i]));
119    }
120 
121    static const struct {
122       const char *name;
123       unsigned int class;
124       int instance;
125    } legacy_names[] = {
126       { "render", I915_ENGINE_CLASS_RENDER, 0 },
127       { "blt", I915_ENGINE_CLASS_COPY, 0 },
128       { "bsd", I915_ENGINE_CLASS_VIDEO, 0 },
129       { "bsd2", I915_ENGINE_CLASS_VIDEO, 1 },
130       { "vebox", I915_ENGINE_CLASS_VIDEO_ENHANCE, 0 },
131    };
132    for (size_t i = 0; i < ARRAY_SIZE(legacy_names); i++) {
133       if (strcmp(ring_name, legacy_names[i].name))
134          continue;
135 
136       *class = legacy_names[i].class;
137       return legacy_names[i].instance;
138    }
139 
140    return -1;
141 }
142 
143 static const char *
register_name_from_ring(const struct ring_register_mapping * mapping,unsigned nb_mapping,const char * ring_name)144 register_name_from_ring(const struct ring_register_mapping *mapping,
145                         unsigned nb_mapping,
146                         const char *ring_name)
147 {
148    enum drm_i915_gem_engine_class class;
149    int instance;
150 
151    instance = ring_name_to_class(ring_name, &class);
152    if (instance < 0)
153       return NULL;
154 
155    for (unsigned i = 0; i < nb_mapping; i++) {
156       if (mapping[i].ring_class == class &&
157           mapping[i].ring_instance == instance)
158          return mapping[i].register_name;
159    }
160    return NULL;
161 }
162 
163 static const char *
instdone_register_for_ring(const struct intel_device_info * devinfo,const char * ring_name)164 instdone_register_for_ring(const struct intel_device_info *devinfo,
165                            const char *ring_name)
166 {
167    enum drm_i915_gem_engine_class class;
168    int instance;
169 
170    instance = ring_name_to_class(ring_name, &class);
171    if (instance < 0)
172       return NULL;
173 
174    switch (class) {
175    case I915_ENGINE_CLASS_RENDER:
176       if (devinfo->ver == 6)
177          return "INSTDONE_2";
178       else
179          return "INSTDONE_1";
180 
181    case I915_ENGINE_CLASS_COPY:
182       return "BCS_INSTDONE";
183 
184    case I915_ENGINE_CLASS_VIDEO:
185       switch (instance) {
186       case 0:
187          return "VCS_INSTDONE";
188       case 1:
189          return "VCS2_INSTDONE";
190       default:
191          return NULL;
192       }
193 
194    case I915_ENGINE_CLASS_VIDEO_ENHANCE:
195       return "VECS_INSTDONE";
196 
197    default:
198       return NULL;
199    }
200 
201    return NULL;
202 }
203 
204 static void
print_pgtbl_err(unsigned int reg,struct intel_device_info * devinfo)205 print_pgtbl_err(unsigned int reg, struct intel_device_info *devinfo)
206 {
207    if (reg & (1 << 26))
208       printf("    Invalid Sampler Cache GTT entry\n");
209    if (reg & (1 << 24))
210       printf("    Invalid Render Cache GTT entry\n");
211    if (reg & (1 << 23))
212       printf("    Invalid Instruction/State Cache GTT entry\n");
213    if (reg & (1 << 22))
214       printf("    There is no ROC, this cannot occur!\n");
215    if (reg & (1 << 21))
216       printf("    Invalid GTT entry during Vertex Fetch\n");
217    if (reg & (1 << 20))
218       printf("    Invalid GTT entry during Command Fetch\n");
219    if (reg & (1 << 19))
220       printf("    Invalid GTT entry during CS\n");
221    if (reg & (1 << 18))
222       printf("    Invalid GTT entry during Cursor Fetch\n");
223    if (reg & (1 << 17))
224       printf("    Invalid GTT entry during Overlay Fetch\n");
225    if (reg & (1 << 8))
226       printf("    Invalid GTT entry during Display B Fetch\n");
227    if (reg & (1 << 4))
228       printf("    Invalid GTT entry during Display A Fetch\n");
229    if (reg & (1 << 1))
230       printf("    Valid PTE references illegal memory\n");
231    if (reg & (1 << 0))
232       printf("    Invalid GTT entry during fetch for host\n");
233 }
234 
235 static void
print_snb_fence(struct intel_device_info * devinfo,uint64_t fence)236 print_snb_fence(struct intel_device_info *devinfo, uint64_t fence)
237 {
238    printf("    %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
239           fence & 1 ? "" : "in",
240           fence & (1<<1) ? 'y' : 'x',
241           (int)(((fence>>32)&0xfff)+1)*128,
242           (uint32_t)fence & 0xfffff000,
243           (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
244 }
245 
246 static void
print_i965_fence(struct intel_device_info * devinfo,uint64_t fence)247 print_i965_fence(struct intel_device_info *devinfo, uint64_t fence)
248 {
249    printf("    %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n",
250           fence & 1 ? "" : "in",
251           fence & (1<<1) ? 'y' : 'x',
252           (int)(((fence>>2)&0x1ff)+1)*128,
253           (uint32_t)fence & 0xfffff000,
254           (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096));
255 }
256 
257 static void
print_fence(struct intel_device_info * devinfo,uint64_t fence)258 print_fence(struct intel_device_info *devinfo, uint64_t fence)
259 {
260    if (devinfo->ver == 6 || devinfo->ver == 7) {
261       return print_snb_fence(devinfo, fence);
262    } else if (devinfo->ver == 4 || devinfo->ver == 5) {
263       return print_i965_fence(devinfo, fence);
264    }
265 }
266 
267 static void
print_fault_data(struct intel_device_info * devinfo,uint32_t data1,uint32_t data0)268 print_fault_data(struct intel_device_info *devinfo, uint32_t data1, uint32_t data0)
269 {
270    uint64_t address;
271 
272    if (devinfo->ver < 8)
273       return;
274 
275    address = ((uint64_t)(data0) << 12) | ((uint64_t)data1 & 0xf) << 44;
276    printf("    Address 0x%016" PRIx64 " %s\n", address,
277           data1 & (1 << 4) ? "GGTT" : "PPGTT");
278 }
279 
280 #define CSI "\e["
281 #define NORMAL       CSI "0m"
282 
283 struct section {
284    uint64_t gtt_offset;
285    char *ring_name;
286    const char *buffer_name;
287    uint32_t *data;
288    int dword_count;
289    size_t data_offset;
290 };
291 
292 #define MAX_SECTIONS 256
293 static unsigned num_sections;
294 static struct section sections[MAX_SECTIONS];
295 
zlib_inflate(uint32_t ** ptr,int len)296 static int zlib_inflate(uint32_t **ptr, int len)
297 {
298    struct z_stream_s zstream;
299    void *out;
300    const uint32_t out_size = 128*4096;  /* approximate obj size */
301 
302    memset(&zstream, 0, sizeof(zstream));
303 
304    zstream.next_in = (unsigned char *)*ptr;
305    zstream.avail_in = 4*len;
306 
307    if (inflateInit(&zstream) != Z_OK)
308       return 0;
309 
310    out = malloc(out_size);
311    zstream.next_out = out;
312    zstream.avail_out = out_size;
313 
314    do {
315       switch (inflate(&zstream, Z_SYNC_FLUSH)) {
316       case Z_STREAM_END:
317          goto end;
318       case Z_OK:
319          break;
320       default:
321          inflateEnd(&zstream);
322          return 0;
323       }
324 
325       if (zstream.avail_out)
326          break;
327 
328       out = realloc(out, 2*zstream.total_out);
329       if (out == NULL) {
330          inflateEnd(&zstream);
331          return 0;
332       }
333 
334       zstream.next_out = (unsigned char *)out + zstream.total_out;
335       zstream.avail_out = zstream.total_out;
336    } while (1);
337  end:
338    inflateEnd(&zstream);
339    free(*ptr);
340    *ptr = out;
341    return zstream.total_out / 4;
342 }
343 
ascii85_decode(const char * in,uint32_t ** out,bool inflate)344 static int ascii85_decode(const char *in, uint32_t **out, bool inflate)
345 {
346    int len = 0, size = 1024;
347 
348    *out = realloc(*out, sizeof(uint32_t)*size);
349    if (*out == NULL)
350       return 0;
351 
352    while (*in >= '!' && *in <= 'z') {
353       uint32_t v = 0;
354 
355       if (len == size) {
356          size *= 2;
357          *out = realloc(*out, sizeof(uint32_t)*size);
358          if (*out == NULL)
359             return 0;
360       }
361 
362       if (*in == 'z') {
363          in++;
364       } else {
365          v += in[0] - 33; v *= 85;
366          v += in[1] - 33; v *= 85;
367          v += in[2] - 33; v *= 85;
368          v += in[3] - 33; v *= 85;
369          v += in[4] - 33;
370          in += 5;
371       }
372       (*out)[len++] = v;
373    }
374 
375    if (!inflate)
376       return len;
377 
378    return zlib_inflate(out, len);
379 }
380 
qsort_hw_context_first(const void * a,const void * b)381 static int qsort_hw_context_first(const void *a, const void *b)
382 {
383    const struct section *sa = a, *sb = b;
384    if (strcmp(sa->buffer_name, "HW Context") == 0)
385       return -1;
386    if (strcmp(sb->buffer_name, "HW Context") == 0)
387       return 1;
388    else
389       return 0;
390 }
391 
392 static struct intel_batch_decode_bo
get_intel_batch_bo(void * user_data,bool ppgtt,uint64_t address)393 get_intel_batch_bo(void *user_data, bool ppgtt, uint64_t address)
394 {
395    for (int s = 0; s < num_sections; s++) {
396       if (sections[s].gtt_offset <= address &&
397           address < sections[s].gtt_offset + sections[s].dword_count * 4) {
398          return (struct intel_batch_decode_bo) {
399             .addr = sections[s].gtt_offset,
400             .map = sections[s].data,
401             .size = sections[s].dword_count * 4,
402          };
403       }
404    }
405 
406    return (struct intel_batch_decode_bo) { .map = NULL };
407 }
408 
409 static void
read_data_file(FILE * file)410 read_data_file(FILE *file)
411 {
412    struct intel_spec *spec = NULL;
413    long long unsigned fence;
414    int matched;
415    char *line = NULL;
416    size_t line_size;
417    uint32_t offset, value;
418    uint32_t ring_head = UINT32_MAX, ring_tail = UINT32_MAX;
419    bool ring_wraps = false;
420    char *ring_name = NULL;
421    struct intel_device_info devinfo;
422    struct brw_isa_info isa;
423    uint64_t acthd = 0;
424 
425    while (getline(&line, &line_size, file) > 0) {
426       char *new_ring_name = NULL;
427       char *dashes;
428 
429       if (sscanf(line, "%m[^ ] command stream\n", &new_ring_name) > 0) {
430          free(ring_name);
431          ring_name = new_ring_name;
432       }
433 
434       if (line[0] == ':' || line[0] == '~') {
435          uint32_t *data = NULL;
436          int dword_count = ascii85_decode(line+1, &data, line[0] == ':');
437          if (dword_count == 0) {
438             fprintf(stderr, "ASCII85 decode failed.\n");
439             exit(EXIT_FAILURE);
440          }
441          assert(num_sections < MAX_SECTIONS);
442          sections[num_sections].data = data;
443          sections[num_sections].dword_count = dword_count;
444          num_sections++;
445          continue;
446       }
447 
448       dashes = strstr(line, "---");
449       if (dashes) {
450          const struct {
451             const char *match;
452             const char *name;
453          } buffers[] = {
454             { "ringbuffer", "ring buffer" },
455             { "ring", "ring buffer" },
456             { "gtt_offset", "batch buffer" },
457             { "batch", "batch buffer" },
458             { "hw context", "HW Context" },
459             { "hw status", "HW status" },
460             { "wa context", "WA context" },
461             { "wa batchbuffer", "WA batch" },
462             { "NULL context", "Kernel context" },
463             { "user", "user" },
464             { "semaphores", "semaphores", },
465             { "guc log buffer", "GuC log", },
466             { NULL, "unknown" },
467          }, *b;
468 
469          free(ring_name);
470          ring_name = malloc(dashes - line);
471          strncpy(ring_name, line, dashes - line);
472          ring_name[dashes - line - 1] = '\0';
473 
474          dashes += 4;
475          for (b = buffers; b->match; b++) {
476             if (strncasecmp(dashes, b->match, strlen(b->match)) == 0)
477                break;
478          }
479 
480          assert(num_sections < MAX_SECTIONS);
481          sections[num_sections].buffer_name = b->name;
482          sections[num_sections].ring_name = strdup(ring_name);
483 
484          uint32_t hi, lo;
485          dashes = strchr(dashes, '=');
486          if (dashes && sscanf(dashes, "= 0x%08x %08x\n", &hi, &lo))
487             sections[num_sections].gtt_offset = ((uint64_t) hi) << 32 | lo;
488 
489          continue;
490       }
491 
492       matched = sscanf(line, "%08x : %08x", &offset, &value);
493       if (matched != 2) {
494          uint32_t reg, reg2;
495 
496          /* display reg section is after the ringbuffers, don't mix them */
497          printf("%s", line);
498 
499          matched = sscanf(line, "PCI ID: 0x%04x\n", &reg);
500          if (matched == 0)
501             matched = sscanf(line, " PCI ID: 0x%04x\n", &reg);
502          if (matched == 0) {
503             const char *pci_id_start = strstr(line, "PCI ID");
504             if (pci_id_start)
505                matched = sscanf(pci_id_start, "PCI ID: 0x%04x\n", &reg);
506          }
507          if (matched == 1) {
508             if (!intel_get_device_info_from_pci_id(reg, &devinfo)) {
509                printf("Unable to identify devid=%x\n", reg);
510                exit(EXIT_FAILURE);
511             }
512 
513             printf("Detected GEN%i chipset\n", devinfo.ver);
514 
515             brw_init_isa_info(&isa, &devinfo);
516 
517             if (xml_path == NULL)
518                spec = intel_spec_load(&devinfo);
519             else
520                spec = intel_spec_load_from_path(&devinfo, xml_path);
521          }
522 
523          matched = sscanf(line, "  CTL: 0x%08x\n", &reg);
524          if (matched == 1) {
525             print_register(spec,
526                            register_name_from_ring(ctl_registers,
527                                                    ARRAY_SIZE(ctl_registers),
528                                                    ring_name), reg);
529          }
530 
531          matched = sscanf(line, "  HEAD: 0x%08x\n", &reg);
532          if (matched == 1)
533             print_head(reg);
534 
535          sscanf(line, "  HEAD: 0x%08x [0x%08X]\n", &reg, &ring_head);
536          sscanf(line, "  TAIL: 0x%08x\n", &ring_tail);
537 
538          matched = sscanf(line, "  ACTHD: 0x%08x\n", &reg);
539          if (matched == 1) {
540             print_register(spec,
541                            register_name_from_ring(acthd_registers,
542                                                    ARRAY_SIZE(acthd_registers),
543                                                    ring_name), reg);
544          }
545 
546          matched = sscanf(line, "  ACTHD: 0x%08x %08x\n", &reg, &reg2);
547          if (matched == 2)
548             acthd = ((uint64_t)reg << 32) | reg2;
549 
550          matched = sscanf(line, "  PGTBL_ER: 0x%08x\n", &reg);
551          if (matched == 1 && reg)
552             print_pgtbl_err(reg, &devinfo);
553 
554          matched = sscanf(line, "  ERROR: 0x%08x\n", &reg);
555          if (matched == 1 && reg) {
556             print_register(spec, "GFX_ARB_ERROR_RPT", reg);
557          }
558 
559          matched = sscanf(line, "  INSTDONE: 0x%08x\n", &reg);
560          if (matched == 1) {
561             const char *reg_name =
562                instdone_register_for_ring(&devinfo, ring_name);
563             if (reg_name)
564                print_register(spec, reg_name, reg);
565          }
566 
567          matched = sscanf(line, "  SC_INSTDONE: 0x%08x\n", &reg);
568          if (matched == 1)
569             print_register(spec, "SC_INSTDONE", reg);
570 
571          matched = sscanf(line, "  SC_INSTDONE_EXTRA: 0x%08x\n", &reg);
572          if (matched == 1)
573             print_register(spec, "SC_INSTDONE_EXTRA", reg);
574 
575          matched = sscanf(line, "  SC_INSTDONE_EXTRA2: 0x%08x\n", &reg);
576          if (matched == 1)
577             print_register(spec, "SC_INSTDONE_EXTRA2", reg);
578 
579          matched = sscanf(line, "  SAMPLER_INSTDONE[%*d][%*d]: 0x%08x\n", &reg);
580          if (matched == 1)
581             print_register(spec, "SAMPLER_INSTDONE", reg);
582 
583          matched = sscanf(line, "  ROW_INSTDONE[%*d][%*d]: 0x%08x\n", &reg);
584          if (matched == 1)
585             print_register(spec, "ROW_INSTDONE", reg);
586 
587          matched = sscanf(line, "  GEOM_SVGUNIT_INSTDONE[%*d][%*d]: 0x%08x\n", &reg);
588          if (matched == 1)
589             print_register(spec, "INSTDONE_GEOM", reg);
590 
591          matched = sscanf(line, "  INSTDONE1: 0x%08x\n", &reg);
592          if (matched == 1)
593             print_register(spec, "INSTDONE_1", reg);
594 
595          matched = sscanf(line, "  fence[%i] = %Lx\n", &reg, &fence);
596          if (matched == 2)
597             print_fence(&devinfo, fence);
598 
599          matched = sscanf(line, "  FAULT_REG: 0x%08x\n", &reg);
600          if (matched == 1 && reg) {
601             const char *reg_name =
602                register_name_from_ring(fault_registers,
603                                        ARRAY_SIZE(fault_registers),
604                                        ring_name);
605             if (reg_name == NULL)
606                reg_name = "FAULT_REG";
607             print_register(spec, reg_name, reg);
608          }
609 
610          matched = sscanf(line, "  FAULT_TLB_DATA: 0x%08x 0x%08x\n", &reg, &reg2);
611          if (matched == 2)
612             print_fault_data(&devinfo, reg, reg2);
613 
614          continue;
615       }
616    }
617 
618    free(line);
619    free(ring_name);
620 
621    /*
622     * Order sections so that the hardware context section is visited by the
623     * decoder before other command buffers. This will allow the decoder to see
624     * persistent state that was set before the current batch.
625     */
626    qsort(sections, num_sections, sizeof(sections[0]), qsort_hw_context_first);
627 
628    for (int s = 0; s < num_sections; s++) {
629       if (strcmp(sections[s].buffer_name, "ring buffer") != 0)
630          continue;
631       if (ring_head == UINT32_MAX) {
632          ring_head = 0;
633          ring_tail = UINT32_MAX;
634       }
635       if (ring_tail == UINT32_MAX)
636          ring_tail = (ring_head - sizeof(uint32_t)) %
637             (sections[s].dword_count * sizeof(uint32_t));
638       if (ring_head > ring_tail) {
639          size_t total_size = sections[s].dword_count * sizeof(uint32_t) -
640             ring_head + ring_tail;
641          size_t size1 = total_size - ring_tail;
642          uint32_t *new_data = calloc(total_size, 1);
643          memcpy(new_data, (uint8_t *)sections[s].data + ring_head, size1);
644          memcpy((uint8_t *)new_data + size1, sections[s].data, ring_tail);
645          free(sections[s].data);
646          sections[s].data = new_data;
647          ring_head = 0;
648          ring_tail = total_size;
649          ring_wraps = true;
650       }
651       sections[s].data_offset = ring_head;
652       sections[s].dword_count = (ring_tail - ring_head) / sizeof(uint32_t);
653    }
654 
655    for (int s = 0; s < num_sections; s++) {
656       if (sections[s].dword_count * 4 > intel_debug_identifier_size() &&
657           memcmp(sections[s].data, intel_debug_identifier(),
658                  intel_debug_identifier_size()) == 0) {
659          const struct intel_debug_block_driver *driver_desc =
660             intel_debug_get_identifier_block(sections[s].data,
661                                              sections[s].dword_count * 4,
662                                              INTEL_DEBUG_BLOCK_TYPE_DRIVER);
663          if (driver_desc) {
664             printf("Driver identifier: %s\n",
665                    (const char *) driver_desc->description);
666          }
667          break;
668       }
669    }
670 
671    enum intel_batch_decode_flags batch_flags = 0;
672    if (option_color == COLOR_ALWAYS)
673       batch_flags |= INTEL_BATCH_DECODE_IN_COLOR;
674    if (option_full_decode)
675       batch_flags |= INTEL_BATCH_DECODE_FULL;
676    if (option_print_offsets)
677       batch_flags |= INTEL_BATCH_DECODE_OFFSETS;
678    batch_flags |= INTEL_BATCH_DECODE_FLOATS;
679 
680    struct intel_batch_decode_ctx batch_ctx;
681    intel_batch_decode_ctx_init(&batch_ctx, &isa, &devinfo, stdout,
682                                batch_flags, xml_path, get_intel_batch_bo,
683                                NULL, NULL);
684    batch_ctx.acthd = acthd;
685 
686 
687    for (int s = 0; s < num_sections; s++) {
688       enum drm_i915_gem_engine_class class;
689       ring_name_to_class(sections[s].ring_name, &class);
690 
691       printf("--- %s (%s) at 0x%08x %08x\n",
692              sections[s].buffer_name, sections[s].ring_name,
693              (unsigned) (sections[s].gtt_offset >> 32),
694              (unsigned) sections[s].gtt_offset);
695 
696       bool is_ring_buffer = strcmp(sections[s].buffer_name, "ring buffer") == 0;
697       if (option_print_all_bb || is_ring_buffer ||
698           strcmp(sections[s].buffer_name, "batch buffer") == 0 ||
699           strcmp(sections[s].buffer_name, "HW Context") == 0) {
700          if (is_ring_buffer && ring_wraps)
701             batch_ctx.flags &= ~INTEL_BATCH_DECODE_OFFSETS;
702          batch_ctx.engine = class;
703          uint8_t *data = (uint8_t *)sections[s].data + sections[s].data_offset;
704          uint64_t batch_addr = sections[s].gtt_offset + sections[s].data_offset;
705          intel_print_batch(&batch_ctx, (uint32_t *)data,
706                            sections[s].dword_count * 4, batch_addr,
707                            is_ring_buffer);
708          batch_ctx.flags = batch_flags;
709       }
710    }
711 
712    intel_batch_decode_ctx_finish(&batch_ctx);
713 
714    for (int s = 0; s < num_sections; s++) {
715       free(sections[s].ring_name);
716       free(sections[s].data);
717    }
718 }
719 
720 static void
setup_pager(void)721 setup_pager(void)
722 {
723    int fds[2];
724    pid_t pid;
725 
726    if (!isatty(1))
727       return;
728 
729    if (pipe(fds) == -1)
730       return;
731 
732    pid = fork();
733    if (pid == -1)
734       return;
735 
736    if (pid == 0) {
737       close(fds[1]);
738       dup2(fds[0], 0);
739       execlp("less", "less", "-FRSi", NULL);
740    }
741 
742    close(fds[0]);
743    dup2(fds[1], 1);
744    close(fds[1]);
745 }
746 
747 static void
print_help(const char * progname,FILE * file)748 print_help(const char *progname, FILE *file)
749 {
750    fprintf(file,
751            "Usage: %s [OPTION]... [FILE]\n"
752            "Parse an Intel GPU i915_error_state.\n"
753            "With no FILE, debugfs-dri-directory is probed for in /debug and \n"
754            "/sys/kernel/debug.  Otherwise, it may be specified. If a file is given,\n"
755            "it is parsed as an GPU dump in the format of /debug/dri/0/i915_error_state.\n\n"
756            "      --help          display this help and exit\n"
757            "      --headers       decode only command headers\n"
758            "      --color[=WHEN]  colorize the output; WHEN can be 'auto' (default\n"
759            "                        if omitted), 'always', or 'never'\n"
760            "      --no-pager      don't launch pager\n"
761            "      --no-offsets    don't print instruction offsets\n"
762            "      --xml=DIR       load hardware xml description from directory DIR\n"
763            "      --all-bb        print out all batchbuffers\n",
764            progname);
765 }
766 
767 static FILE *
open_error_state_file(const char * path)768 open_error_state_file(const char *path)
769 {
770    FILE *file;
771    struct stat st;
772 
773    if (stat(path, &st))
774       return NULL;
775 
776    if (S_ISDIR(st.st_mode)) {
777       ASSERTED int ret;
778       char *filename;
779 
780       ret = asprintf(&filename, "%s/i915_error_state", path);
781       assert(ret > 0);
782       file = fopen(filename, "r");
783       free(filename);
784       if (!file) {
785          int minor;
786          for (minor = 0; minor < 64; minor++) {
787             ret = asprintf(&filename, "%s/%d/i915_error_state", path, minor);
788             assert(ret > 0);
789 
790             file = fopen(filename, "r");
791             free(filename);
792             if (file)
793                break;
794          }
795       }
796       if (!file) {
797          fprintf(stderr, "Failed to find i915_error_state beneath %s\n",
798                  path);
799          exit(EXIT_FAILURE);
800       }
801    } else {
802       file = fopen(path, "r");
803       if (!file) {
804          fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
805          exit(EXIT_FAILURE);
806       }
807    }
808 
809    return file;
810 }
811 
812 int
main(int argc,char * argv[])813 main(int argc, char *argv[])
814 {
815    FILE *file;
816    int c, i;
817    bool help = false, pager = true;
818    const struct option aubinator_opts[] = {
819       { "help",       no_argument,       (int *) &help,                 true },
820       { "no-pager",   no_argument,       (int *) &pager,                false },
821       { "no-offsets", no_argument,       (int *) &option_print_offsets, false },
822       { "headers",    no_argument,       (int *) &option_full_decode,   false },
823       { "color",      optional_argument, NULL,                          'c' },
824       { "xml",        required_argument, NULL,                          'x' },
825       { "all-bb",     no_argument,       (int *) &option_print_all_bb,  true },
826       { NULL,         0,                 NULL,                          0 }
827    };
828 
829    i = 0;
830    while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) {
831       switch (c) {
832       case 'c':
833          if (optarg == NULL || strcmp(optarg, "always") == 0)
834             option_color = COLOR_ALWAYS;
835          else if (strcmp(optarg, "never") == 0)
836             option_color = COLOR_NEVER;
837          else if (strcmp(optarg, "auto") == 0)
838             option_color = COLOR_AUTO;
839          else {
840             fprintf(stderr, "invalid value for --color: %s", optarg);
841             exit(EXIT_FAILURE);
842          }
843          break;
844       case 'x':
845          xml_path = strdup(optarg);
846          break;
847       case '?':
848          print_help(argv[0], stderr);
849          exit(EXIT_FAILURE);
850       default:
851          break;
852       }
853    }
854 
855    if (help) {
856       print_help(argv[0], stderr);
857       exit(EXIT_SUCCESS);
858    }
859 
860    if (optind >= argc) {
861       if (isatty(0)) {
862          file = open_error_state_file("/sys/class/drm/card0/error");
863          if (!file)
864             file = open_error_state_file("/debug/dri");
865          if (!file)
866             file = open_error_state_file("/sys/kernel/debug/dri");
867 
868          if (file == NULL) {
869             errx(1,
870                  "Couldn't find i915 debugfs directory.\n\n"
871                  "Is debugfs mounted? You might try mounting it with a command such as:\n\n"
872                  "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n");
873          }
874       } else {
875          file = stdin;
876       }
877    } else {
878       const char *path = argv[optind];
879       if (strcmp(path, "-") == 0) {
880          file = stdin;
881       } else {
882          file = open_error_state_file(path);
883          if (file == NULL) {
884             fprintf(stderr, "Error opening %s: %s\n", path, strerror(errno));
885             exit(EXIT_FAILURE);
886          }
887       }
888    }
889 
890    if (option_color == COLOR_AUTO)
891       option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER;
892 
893    if (isatty(1) && pager)
894       setup_pager();
895 
896    read_data_file(file);
897    fclose(file);
898 
899    /* close the stdout which is opened to write the output */
900    fflush(stdout);
901    close(1);
902    wait(NULL);
903 
904    if (xml_path)
905       free(xml_path);
906 
907    return EXIT_SUCCESS;
908 }
909 
910 /* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/
911