101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2018 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg *
2301e04c3fSmrg */
2401e04c3fSmrg
2501e04c3fSmrg#include <assert.h>
2601e04c3fSmrg#include <getopt.h>
2701e04c3fSmrg#include <inttypes.h>
2801e04c3fSmrg#include <signal.h>
2901e04c3fSmrg#include <stdio.h>
3001e04c3fSmrg#include <stdlib.h>
3101e04c3fSmrg#include <string.h>
3201e04c3fSmrg#include <stdarg.h>
3301e04c3fSmrg#include <zlib.h>
3401e04c3fSmrg
359f464c52Smaya#include "util/list.h"
369f464c52Smaya
3701e04c3fSmrg#include "aub_write.h"
389f464c52Smaya#include "drm-uapi/i915_drm.h"
3901e04c3fSmrg#include "intel_aub.h"
4001e04c3fSmrg
417ec681f3Smrg#define fail_if(cond, ...) _fail_if(cond, NULL, __VA_ARGS__)
4201e04c3fSmrg
4301e04c3fSmrg#define fail(...) fail_if(true, __VA_ARGS__)
4401e04c3fSmrg
4501e04c3fSmrgstatic int zlib_inflate(uint32_t **ptr, int len)
4601e04c3fSmrg{
4701e04c3fSmrg   struct z_stream_s zstream;
4801e04c3fSmrg   void *out;
4901e04c3fSmrg   const uint32_t out_size = 128*4096;  /* approximate obj size */
5001e04c3fSmrg
5101e04c3fSmrg   memset(&zstream, 0, sizeof(zstream));
5201e04c3fSmrg
5301e04c3fSmrg   zstream.next_in = (unsigned char *)*ptr;
5401e04c3fSmrg   zstream.avail_in = 4*len;
5501e04c3fSmrg
5601e04c3fSmrg   if (inflateInit(&zstream) != Z_OK)
5701e04c3fSmrg      return 0;
5801e04c3fSmrg
5901e04c3fSmrg   out = malloc(out_size);
6001e04c3fSmrg   zstream.next_out = out;
6101e04c3fSmrg   zstream.avail_out = out_size;
6201e04c3fSmrg
6301e04c3fSmrg   do {
6401e04c3fSmrg      switch (inflate(&zstream, Z_SYNC_FLUSH)) {
6501e04c3fSmrg      case Z_STREAM_END:
6601e04c3fSmrg         goto end;
6701e04c3fSmrg      case Z_OK:
6801e04c3fSmrg         break;
6901e04c3fSmrg      default:
7001e04c3fSmrg         inflateEnd(&zstream);
7101e04c3fSmrg         return 0;
7201e04c3fSmrg      }
7301e04c3fSmrg
7401e04c3fSmrg      if (zstream.avail_out)
7501e04c3fSmrg         break;
7601e04c3fSmrg
7701e04c3fSmrg      out = realloc(out, 2*zstream.total_out);
7801e04c3fSmrg      if (out == NULL) {
7901e04c3fSmrg         inflateEnd(&zstream);
8001e04c3fSmrg         return 0;
8101e04c3fSmrg      }
8201e04c3fSmrg
8301e04c3fSmrg      zstream.next_out = (unsigned char *)out + zstream.total_out;
8401e04c3fSmrg      zstream.avail_out = zstream.total_out;
8501e04c3fSmrg   } while (1);
8601e04c3fSmrg end:
8701e04c3fSmrg   inflateEnd(&zstream);
8801e04c3fSmrg   free(*ptr);
8901e04c3fSmrg   *ptr = out;
9001e04c3fSmrg   return zstream.total_out / 4;
9101e04c3fSmrg}
9201e04c3fSmrg
9301e04c3fSmrgstatic int ascii85_decode(const char *in, uint32_t **out, bool inflate)
9401e04c3fSmrg{
9501e04c3fSmrg   int len = 0, size = 1024;
9601e04c3fSmrg
9701e04c3fSmrg   *out = realloc(*out, sizeof(uint32_t)*size);
9801e04c3fSmrg   if (*out == NULL)
9901e04c3fSmrg      return 0;
10001e04c3fSmrg
10101e04c3fSmrg   while (*in >= '!' && *in <= 'z') {
10201e04c3fSmrg      uint32_t v = 0;
10301e04c3fSmrg
10401e04c3fSmrg      if (len == size) {
10501e04c3fSmrg         size *= 2;
10601e04c3fSmrg         *out = realloc(*out, sizeof(uint32_t)*size);
10701e04c3fSmrg         if (*out == NULL)
10801e04c3fSmrg            return 0;
10901e04c3fSmrg      }
11001e04c3fSmrg
11101e04c3fSmrg      if (*in == 'z') {
11201e04c3fSmrg         in++;
11301e04c3fSmrg      } else {
11401e04c3fSmrg         v += in[0] - 33; v *= 85;
11501e04c3fSmrg         v += in[1] - 33; v *= 85;
11601e04c3fSmrg         v += in[2] - 33; v *= 85;
11701e04c3fSmrg         v += in[3] - 33; v *= 85;
11801e04c3fSmrg         v += in[4] - 33;
11901e04c3fSmrg         in += 5;
12001e04c3fSmrg      }
12101e04c3fSmrg      (*out)[len++] = v;
12201e04c3fSmrg   }
12301e04c3fSmrg
12401e04c3fSmrg   if (!inflate)
12501e04c3fSmrg      return len;
12601e04c3fSmrg
12701e04c3fSmrg   return zlib_inflate(out, len);
12801e04c3fSmrg}
12901e04c3fSmrg
13001e04c3fSmrgstatic void
13101e04c3fSmrgprint_help(const char *progname, FILE *file)
13201e04c3fSmrg{
13301e04c3fSmrg   fprintf(file,
13401e04c3fSmrg           "Usage: %s [OPTION]... [FILE]\n"
13501e04c3fSmrg           "Convert an Intel GPU i915 error state to an aub file.\n"
13601e04c3fSmrg           "  -h, --help          display this help and exit\n"
13701e04c3fSmrg           "  -o, --output=FILE   the output aub file (default FILE.aub)\n",
13801e04c3fSmrg           progname);
13901e04c3fSmrg}
14001e04c3fSmrg
1419f464c52Smayastruct bo {
1429f464c52Smaya   enum address_space {
1439f464c52Smaya      PPGTT,
1449f464c52Smaya      GGTT,
1459f464c52Smaya   } gtt;
1469f464c52Smaya   enum bo_type {
1479f464c52Smaya      BO_TYPE_UNKNOWN = 0,
1489f464c52Smaya      BO_TYPE_BATCH,
1499f464c52Smaya      BO_TYPE_USER,
1509f464c52Smaya      BO_TYPE_CONTEXT,
1519f464c52Smaya      BO_TYPE_RINGBUFFER,
1529f464c52Smaya      BO_TYPE_STATUS,
1539f464c52Smaya      BO_TYPE_CONTEXT_WA,
1549f464c52Smaya   } type;
1559f464c52Smaya   const char *name;
1569f464c52Smaya   uint64_t addr;
1579f464c52Smaya   uint8_t *data;
1589f464c52Smaya   uint64_t size;
1599f464c52Smaya
1609f464c52Smaya   enum drm_i915_gem_engine_class engine_class;
1619f464c52Smaya   int engine_instance;
1629f464c52Smaya
1639f464c52Smaya   struct list_head link;
1649f464c52Smaya};
1659f464c52Smaya
1669f464c52Smayastatic struct bo *
1679f464c52Smayafind_or_create(struct list_head *bo_list, uint64_t addr,
1689f464c52Smaya               enum address_space gtt,
1699f464c52Smaya               enum drm_i915_gem_engine_class engine_class,
1709f464c52Smaya               int engine_instance)
1719f464c52Smaya{
1729f464c52Smaya   list_for_each_entry(struct bo, bo_entry, bo_list, link) {
1739f464c52Smaya      if (bo_entry->addr == addr &&
1749f464c52Smaya          bo_entry->gtt == gtt &&
1759f464c52Smaya          bo_entry->engine_class == engine_class &&
1769f464c52Smaya          bo_entry->engine_instance == engine_instance)
1779f464c52Smaya         return bo_entry;
1789f464c52Smaya   }
1799f464c52Smaya
1809f464c52Smaya   struct bo *new_bo = calloc(1, sizeof(*new_bo));
1819f464c52Smaya   new_bo->addr = addr;
1829f464c52Smaya   new_bo->gtt = gtt;
1839f464c52Smaya   new_bo->engine_class = engine_class;
1849f464c52Smaya   new_bo->engine_instance = engine_instance;
1859f464c52Smaya   list_addtail(&new_bo->link, bo_list);
1869f464c52Smaya
1879f464c52Smaya   return new_bo;
1889f464c52Smaya}
1899f464c52Smaya
1909f464c52Smayastatic void
1919f464c52Smayaengine_from_name(const char *engine_name,
1929f464c52Smaya                 enum drm_i915_gem_engine_class *engine_class,
1939f464c52Smaya                 int *engine_instance)
1949f464c52Smaya{
1959f464c52Smaya   const struct {
1969f464c52Smaya      const char *match;
1979f464c52Smaya      enum drm_i915_gem_engine_class engine_class;
1989f464c52Smaya      bool parse_instance;
1999f464c52Smaya   } rings[] = {
2009f464c52Smaya      { "rcs", I915_ENGINE_CLASS_RENDER, true },
2019f464c52Smaya      { "vcs", I915_ENGINE_CLASS_VIDEO, true },
2029f464c52Smaya      { "vecs", I915_ENGINE_CLASS_VIDEO_ENHANCE, true },
2039f464c52Smaya      { "bcs", I915_ENGINE_CLASS_COPY, true },
2049f464c52Smaya      { "global", I915_ENGINE_CLASS_INVALID, false },
2059f464c52Smaya      { "render command stream", I915_ENGINE_CLASS_RENDER, false },
2069f464c52Smaya      { "blt command stream", I915_ENGINE_CLASS_COPY, false },
2079f464c52Smaya      { "bsd command stream", I915_ENGINE_CLASS_VIDEO, false },
2089f464c52Smaya      { "vebox command stream", I915_ENGINE_CLASS_VIDEO_ENHANCE, false },
2099f464c52Smaya      { NULL, I915_ENGINE_CLASS_INVALID },
2109f464c52Smaya   }, *r;
2119f464c52Smaya
2129f464c52Smaya   for (r = rings; r->match; r++) {
2139f464c52Smaya      if (strncasecmp(engine_name, r->match, strlen(r->match)) == 0) {
2149f464c52Smaya         *engine_class = r->engine_class;
2159f464c52Smaya         if (r->parse_instance)
2169f464c52Smaya            *engine_instance = strtol(engine_name + strlen(r->match), NULL, 10);
2179f464c52Smaya         else
2189f464c52Smaya            *engine_instance = 0;
2199f464c52Smaya         return;
2209f464c52Smaya      }
2219f464c52Smaya   }
2229f464c52Smaya
2239f464c52Smaya   fail("Unknown engine %s\n", engine_name);
2249f464c52Smaya}
2259f464c52Smaya
22601e04c3fSmrgint
22701e04c3fSmrgmain(int argc, char *argv[])
22801e04c3fSmrg{
22901e04c3fSmrg   int i, c;
2307ec681f3Smrg   bool help = false, verbose = false;
23101e04c3fSmrg   char *out_filename = NULL, *in_filename = NULL;
23201e04c3fSmrg   const struct option aubinator_opts[] = {
23301e04c3fSmrg      { "help",       no_argument,       NULL,     'h' },
23401e04c3fSmrg      { "output",     required_argument, NULL,     'o' },
2359f464c52Smaya      { "verbose",    no_argument,       NULL,     'v' },
23601e04c3fSmrg      { NULL,         0,                 NULL,     0 }
23701e04c3fSmrg   };
23801e04c3fSmrg
23901e04c3fSmrg   i = 0;
2409f464c52Smaya   while ((c = getopt_long(argc, argv, "ho:v", aubinator_opts, &i)) != -1) {
24101e04c3fSmrg      switch (c) {
24201e04c3fSmrg      case 'h':
24301e04c3fSmrg         help = true;
24401e04c3fSmrg         break;
24501e04c3fSmrg      case 'o':
24601e04c3fSmrg         out_filename = strdup(optarg);
24701e04c3fSmrg         break;
2489f464c52Smaya      case 'v':
2499f464c52Smaya         verbose = true;
2509f464c52Smaya         break;
25101e04c3fSmrg      default:
25201e04c3fSmrg         break;
25301e04c3fSmrg      }
25401e04c3fSmrg   }
25501e04c3fSmrg
25601e04c3fSmrg   if (optind < argc)
25701e04c3fSmrg      in_filename = argv[optind++];
25801e04c3fSmrg
25901e04c3fSmrg   if (help || argc == 1 || !in_filename) {
26001e04c3fSmrg      print_help(argv[0], stderr);
26101e04c3fSmrg      return in_filename ? EXIT_SUCCESS : EXIT_FAILURE;
26201e04c3fSmrg   }
26301e04c3fSmrg
26401e04c3fSmrg   if (out_filename == NULL) {
26501e04c3fSmrg      int out_filename_size = strlen(in_filename) + 5;
26601e04c3fSmrg      out_filename = malloc(out_filename_size);
26701e04c3fSmrg      snprintf(out_filename, out_filename_size, "%s.aub", in_filename);
26801e04c3fSmrg   }
26901e04c3fSmrg
27001e04c3fSmrg   FILE *err_file = fopen(in_filename, "r");
27101e04c3fSmrg   fail_if(!err_file, "Failed to open error file \"%s\": %m\n", in_filename);
27201e04c3fSmrg
27301e04c3fSmrg   FILE *aub_file = fopen(out_filename, "w");
27401e04c3fSmrg   fail_if(!aub_file, "Failed to open aub file \"%s\": %m\n", in_filename);
27501e04c3fSmrg
27601e04c3fSmrg   struct aub_file aub = {};
27701e04c3fSmrg
2789f464c52Smaya   enum drm_i915_gem_engine_class active_engine_class = I915_ENGINE_CLASS_INVALID;
2799f464c52Smaya   int active_engine_instance = -1;
2809f464c52Smaya
2819f464c52Smaya   enum address_space active_gtt = PPGTT;
2827ec681f3Smrg   enum address_space default_gtt = PPGTT;
2839f464c52Smaya
2849f464c52Smaya   struct {
2859f464c52Smaya      struct {
2869f464c52Smaya         uint32_t ring_buffer_head;
2879f464c52Smaya         uint32_t ring_buffer_tail;
2889f464c52Smaya      } instances[3];
2899f464c52Smaya   } engines[I915_ENGINE_CLASS_VIDEO_ENHANCE + 1];
2909f464c52Smaya   memset(engines, 0, sizeof(engines));
2919f464c52Smaya
29201e04c3fSmrg   int num_ring_bos = 0;
29301e04c3fSmrg
2949f464c52Smaya   struct list_head bo_list;
2959f464c52Smaya   list_inithead(&bo_list);
29601e04c3fSmrg
2979f464c52Smaya   struct bo *last_bo = NULL;
29801e04c3fSmrg
29901e04c3fSmrg   char *line = NULL;
30001e04c3fSmrg   size_t line_size;
30101e04c3fSmrg   while (getline(&line, &line_size, err_file) > 0) {
30201e04c3fSmrg      const char *pci_id_start = strstr(line, "PCI ID");
30301e04c3fSmrg      if (pci_id_start) {
30401e04c3fSmrg         int pci_id;
30501e04c3fSmrg         int matched = sscanf(line, "PCI ID: 0x%04x\n", &pci_id);
30601e04c3fSmrg         fail_if(!matched, "Invalid error state file!\n");
30701e04c3fSmrg
3089f464c52Smaya         aub_file_init(&aub, aub_file,
3099f464c52Smaya                       NULL, pci_id, "error_state");
3109f464c52Smaya         if (verbose)
3119f464c52Smaya            aub.verbose_log_file = stdout;
3127ec681f3Smrg         default_gtt = active_gtt = aub_use_execlists(&aub) ? PPGTT : GGTT;
3139f464c52Smaya         continue;
3149f464c52Smaya      }
3159f464c52Smaya
3169f464c52Smaya      if (strstr(line, " command stream:")) {
3179f464c52Smaya         engine_from_name(line, &active_engine_class, &active_engine_instance);
3189f464c52Smaya         continue;
3199f464c52Smaya      }
32001e04c3fSmrg
3219f464c52Smaya      if (sscanf(line, "  ring->head: 0x%x\n",
3229f464c52Smaya                 &engines[
3239f464c52Smaya                    active_engine_class].instances[
3249f464c52Smaya                       active_engine_instance].ring_buffer_head) == 1) {
3259f464c52Smaya         continue;
3269f464c52Smaya      }
3279f464c52Smaya
3289f464c52Smaya      if (sscanf(line, "  ring->tail: 0x%x\n",
3299f464c52Smaya                 &engines[
3309f464c52Smaya                    active_engine_class].instances[
3319f464c52Smaya                       active_engine_instance].ring_buffer_tail) == 1) {
33201e04c3fSmrg         continue;
33301e04c3fSmrg      }
33401e04c3fSmrg
33501e04c3fSmrg      const char *active_start = "Active (";
33601e04c3fSmrg      if (strncmp(line, active_start, strlen(active_start)) == 0) {
33701e04c3fSmrg         char *ring = line + strlen(active_start);
33801e04c3fSmrg
3399f464c52Smaya         engine_from_name(ring, &active_engine_class, &active_engine_instance);
3407ec681f3Smrg         active_gtt = default_gtt;
34101e04c3fSmrg
34201e04c3fSmrg         char *count = strchr(ring, '[');
34301e04c3fSmrg         fail_if(!count || sscanf(count, "[%d]:", &num_ring_bos) < 1,
34401e04c3fSmrg                 "Failed to parse BO table header\n");
34501e04c3fSmrg         continue;
34601e04c3fSmrg      }
34701e04c3fSmrg
3489f464c52Smaya      const char *global_start = "Pinned (global) [";
3499f464c52Smaya      if (strncmp(line, global_start, strlen(global_start)) == 0) {
3509f464c52Smaya         active_engine_class = I915_ENGINE_CLASS_INVALID;
3519f464c52Smaya         active_engine_instance = -1;
3529f464c52Smaya         active_gtt = GGTT;
3539f464c52Smaya         continue;
3549f464c52Smaya      }
3559f464c52Smaya
35601e04c3fSmrg      if (num_ring_bos > 0) {
35701e04c3fSmrg         unsigned hi, lo, size;
35801e04c3fSmrg         if (sscanf(line, " %x_%x %d", &hi, &lo, &size) == 3) {
3599f464c52Smaya            struct bo *bo_entry = find_or_create(&bo_list, ((uint64_t)hi) << 32 | lo,
3609f464c52Smaya                                                 active_gtt,
3619f464c52Smaya                                                 active_engine_class,
3629f464c52Smaya                                                 active_engine_instance);
3639f464c52Smaya            bo_entry->size = size;
36401e04c3fSmrg            num_ring_bos--;
36501e04c3fSmrg         } else {
36601e04c3fSmrg            fail("Not enough BO entries in the active table\n");
36701e04c3fSmrg         }
36801e04c3fSmrg         continue;
36901e04c3fSmrg      }
37001e04c3fSmrg
37101e04c3fSmrg      if (line[0] == ':' || line[0] == '~') {
3729f464c52Smaya         if (!last_bo || last_bo->type == BO_TYPE_UNKNOWN)
37301e04c3fSmrg            continue;
37401e04c3fSmrg
3759f464c52Smaya         int count = ascii85_decode(line+1, (uint32_t **) &last_bo->data, line[0] == ':');
37601e04c3fSmrg         fail_if(count == 0, "ASCII85 decode failed.\n");
3779f464c52Smaya         last_bo->size = count * 4;
37801e04c3fSmrg         continue;
37901e04c3fSmrg      }
38001e04c3fSmrg
3819f464c52Smaya      char *dashes = strstr(line, " --- ");
38201e04c3fSmrg      if (dashes) {
3839f464c52Smaya         dashes += 5;
3849f464c52Smaya
3859f464c52Smaya         engine_from_name(line, &active_engine_class, &active_engine_instance);
3869f464c52Smaya
3879f464c52Smaya         uint32_t hi, lo;
3889f464c52Smaya         char *bo_address_str = strchr(dashes, '=');
3899f464c52Smaya         if (!bo_address_str || sscanf(bo_address_str, "= 0x%08x %08x\n", &hi, &lo) != 2)
3909f464c52Smaya            continue;
39101e04c3fSmrg
39201e04c3fSmrg         const struct {
39301e04c3fSmrg            const char *match;
39401e04c3fSmrg            enum bo_type type;
3959f464c52Smaya            enum address_space gtt;
39601e04c3fSmrg         } bo_types[] = {
3977ec681f3Smrg            { "gtt_offset", BO_TYPE_BATCH,      default_gtt },
3987ec681f3Smrg            { "user",       BO_TYPE_USER,       default_gtt },
3999f464c52Smaya            { "HW context", BO_TYPE_CONTEXT,    GGTT },
4009f464c52Smaya            { "ringbuffer", BO_TYPE_RINGBUFFER, GGTT },
4019f464c52Smaya            { "HW Status",  BO_TYPE_STATUS,     GGTT },
4029f464c52Smaya            { "WA context", BO_TYPE_CONTEXT_WA, GGTT },
4039f464c52Smaya            { "unknown",    BO_TYPE_UNKNOWN,    GGTT },
40401e04c3fSmrg         }, *b;
40501e04c3fSmrg
4069f464c52Smaya         for (b = bo_types; b->type != BO_TYPE_UNKNOWN; b++) {
4079f464c52Smaya            if (strncasecmp(dashes, b->match, strlen(b->match)) == 0)
40801e04c3fSmrg               break;
40901e04c3fSmrg         }
41001e04c3fSmrg
4119f464c52Smaya         last_bo = find_or_create(&bo_list, ((uint64_t) hi) << 32 | lo,
4129f464c52Smaya                                  b->gtt,
4139f464c52Smaya                                  active_engine_class, active_engine_instance);
4149f464c52Smaya
4159f464c52Smaya         /* The batch buffer will appear twice as gtt_offset and user. Only
4169f464c52Smaya          * keep the batch type.
4179f464c52Smaya          */
4189f464c52Smaya         if (last_bo->type == BO_TYPE_UNKNOWN) {
4199f464c52Smaya            last_bo->type = b->type;
4209f464c52Smaya            last_bo->name = b->match;
42101e04c3fSmrg         }
4229f464c52Smaya
42301e04c3fSmrg         continue;
42401e04c3fSmrg      }
42501e04c3fSmrg   }
42601e04c3fSmrg
4279f464c52Smaya   if (verbose) {
4289f464c52Smaya      fprintf(stdout, "BOs found:\n");
4299f464c52Smaya      list_for_each_entry(struct bo, bo_entry, &bo_list, link) {
4309f464c52Smaya         fprintf(stdout, "\t type=%i addr=0x%016" PRIx64 " size=%" PRIu64 "\n",
4319f464c52Smaya                 bo_entry->type, bo_entry->addr, bo_entry->size);
4329f464c52Smaya      }
4339f464c52Smaya   }
4349f464c52Smaya
4359f464c52Smaya   /* Find the batch that trigger the hang */
4369f464c52Smaya   struct bo *batch_bo = NULL;
4379f464c52Smaya   list_for_each_entry(struct bo, bo_entry, &bo_list, link) {
4389f464c52Smaya      if (bo_entry->type == BO_TYPE_BATCH) {
4399f464c52Smaya         batch_bo = bo_entry;
4409f464c52Smaya         break;
4419f464c52Smaya      }
4429f464c52Smaya   }
4439f464c52Smaya   fail_if(!batch_bo, "Failed to find batch buffer.\n");
4449f464c52Smaya
4459f464c52Smaya   /* Add all the BOs to the aub file */
4469f464c52Smaya   struct bo *hwsp_bo = NULL;
4479f464c52Smaya   list_for_each_entry(struct bo, bo_entry, &bo_list, link) {
4489f464c52Smaya      switch (bo_entry->type) {
4499f464c52Smaya      case BO_TYPE_BATCH:
4507ec681f3Smrg         if (bo_entry->gtt == PPGTT) {
4517ec681f3Smrg            aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size);
4527ec681f3Smrg            aub_write_trace_block(&aub, AUB_TRACE_TYPE_BATCH,
4537ec681f3Smrg                                  bo_entry->data, bo_entry->size, bo_entry->addr);
4547ec681f3Smrg         } else
4557ec681f3Smrg            aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
4569f464c52Smaya         break;
4579f464c52Smaya      case BO_TYPE_USER:
4587ec681f3Smrg         if (bo_entry->gtt == PPGTT) {
4597ec681f3Smrg            aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size);
4607ec681f3Smrg            aub_write_trace_block(&aub, AUB_TRACE_TYPE_NOTYPE,
4617ec681f3Smrg                                  bo_entry->data, bo_entry->size, bo_entry->addr);
4627ec681f3Smrg         } else
4637ec681f3Smrg            aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
4649f464c52Smaya         break;
4659f464c52Smaya      case BO_TYPE_CONTEXT:
4669f464c52Smaya         if (bo_entry->engine_class == batch_bo->engine_class &&
4677ec681f3Smrg             bo_entry->engine_instance == batch_bo->engine_instance &&
4687ec681f3Smrg             aub_use_execlists(&aub)) {
4699f464c52Smaya            hwsp_bo = bo_entry;
47001e04c3fSmrg
4719f464c52Smaya            uint32_t *context = (uint32_t *) (bo_entry->data + 4096 /* GuC */ + 4096 /* HWSP */);
4729f464c52Smaya
4739f464c52Smaya            if (context[1] == 0) {
4749f464c52Smaya               fprintf(stderr,
4759f464c52Smaya                       "Invalid context image data.\n"
4769f464c52Smaya                       "This is likely a kernel issue : https://bugs.freedesktop.org/show_bug.cgi?id=107691\n");
4779f464c52Smaya            }
4789f464c52Smaya
4799f464c52Smaya            /* Update the ring buffer at the last known location. */
4809f464c52Smaya            context[5] = engines[bo_entry->engine_class].instances[bo_entry->engine_instance].ring_buffer_head;
4819f464c52Smaya            context[7] = engines[bo_entry->engine_class].instances[bo_entry->engine_instance].ring_buffer_tail;
4829f464c52Smaya            fprintf(stdout, "engine start=0x%x head/tail=0x%x/0x%x\n",
4839f464c52Smaya                    context[9], context[5], context[7]);
4849f464c52Smaya
4859f464c52Smaya            /* The error state doesn't provide a dump of the page tables, so
4869f464c52Smaya             * we have to provide our own, that's easy enough.
4879f464c52Smaya             */
4889f464c52Smaya            context[49] = aub.pml4.phys_addr >> 32;
4899f464c52Smaya            context[51] = aub.pml4.phys_addr & 0xffffffff;
4909f464c52Smaya
4919f464c52Smaya            fprintf(stdout, "context dump:\n");
4929f464c52Smaya            for (int i = 0; i < 60; i++) {
4939f464c52Smaya               if (i % 4 == 0)
4947ec681f3Smrg                  fprintf(stdout, "\n 0x%08" PRIx64 ": ", bo_entry->addr + 8192 + i * 4);
4959f464c52Smaya               fprintf(stdout, "0x%08x ", context[i]);
4969f464c52Smaya            }
4979f464c52Smaya            fprintf(stdout, "\n");
4989f464c52Smaya
4999f464c52Smaya         }
5009f464c52Smaya         aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
5019f464c52Smaya         break;
5029f464c52Smaya      case BO_TYPE_RINGBUFFER:
5039f464c52Smaya      case BO_TYPE_STATUS:
5049f464c52Smaya      case BO_TYPE_CONTEXT_WA:
5059f464c52Smaya         aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
5069f464c52Smaya         break;
5079f464c52Smaya      case BO_TYPE_UNKNOWN:
5089f464c52Smaya         if (bo_entry->gtt == PPGTT) {
5099f464c52Smaya            aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size);
5109f464c52Smaya            if (bo_entry->data) {
5119f464c52Smaya               aub_write_trace_block(&aub, AUB_TRACE_TYPE_NOTYPE,
5129f464c52Smaya                                     bo_entry->data, bo_entry->size, bo_entry->addr);
5139f464c52Smaya            }
5149f464c52Smaya         } else {
5159f464c52Smaya            if (bo_entry->size > 0) {
5169f464c52Smaya               void *zero_data = calloc(1, bo_entry->size);
5179f464c52Smaya               aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, zero_data);
5189f464c52Smaya               free(zero_data);
5199f464c52Smaya            }
5209f464c52Smaya         }
5219f464c52Smaya         break;
5229f464c52Smaya      default:
5239f464c52Smaya         break;
5249f464c52Smaya      }
5259f464c52Smaya   }
5269f464c52Smaya
5277ec681f3Smrg   if (aub_use_execlists(&aub)) {
5287ec681f3Smrg      fail_if(!hwsp_bo, "Failed to find Context buffer.\n");
5297ec681f3Smrg      aub_write_context_execlists(&aub, hwsp_bo->addr + 4096 /* skip GuC page */, hwsp_bo->engine_class);
5307ec681f3Smrg   } else {
5317ec681f3Smrg      /* Use context id 0 -- if we are not using execlists it doesn't matter
5327ec681f3Smrg       * anyway
5337ec681f3Smrg       */
5347ec681f3Smrg      aub_write_exec(&aub, 0, batch_bo->addr, 0, I915_ENGINE_CLASS_RENDER);
5357ec681f3Smrg   }
5369f464c52Smaya
5379f464c52Smaya   /* Cleanup */
5389f464c52Smaya   list_for_each_entry_safe(struct bo, bo_entry, &bo_list, link) {
5399f464c52Smaya      list_del(&bo_entry->link);
5409f464c52Smaya      free(bo_entry->data);
5419f464c52Smaya      free(bo_entry);
5429f464c52Smaya   }
54301e04c3fSmrg
54401e04c3fSmrg   free(out_filename);
54501e04c3fSmrg   free(line);
54601e04c3fSmrg   if(err_file) {
54701e04c3fSmrg      fclose(err_file);
54801e04c3fSmrg   }
54901e04c3fSmrg   if(aub.file) {
55001e04c3fSmrg      aub_file_finish(&aub);
55101e04c3fSmrg   } else if(aub_file) {
55201e04c3fSmrg      fclose(aub_file);
55301e04c3fSmrg   }
55401e04c3fSmrg   return EXIT_SUCCESS;
55501e04c3fSmrg}
55601e04c3fSmrg
55701e04c3fSmrg/* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/
558