1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2018 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci */
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci#include <assert.h>
26bf215546Sopenharmony_ci#include <getopt.h>
27bf215546Sopenharmony_ci#include <inttypes.h>
28bf215546Sopenharmony_ci#include <signal.h>
29bf215546Sopenharmony_ci#include <stdio.h>
30bf215546Sopenharmony_ci#include <stdlib.h>
31bf215546Sopenharmony_ci#include <string.h>
32bf215546Sopenharmony_ci#include <stdarg.h>
33bf215546Sopenharmony_ci#include <zlib.h>
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#include "util/list.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#include "aub_write.h"
38bf215546Sopenharmony_ci#include "drm-uapi/i915_drm.h"
39bf215546Sopenharmony_ci#include "intel_aub.h"
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#define fail_if(cond, ...) _fail_if(cond, NULL, __VA_ARGS__)
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci#define fail(...) fail_if(true, __VA_ARGS__)
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_cistatic int zlib_inflate(uint32_t **ptr, int len)
46bf215546Sopenharmony_ci{
47bf215546Sopenharmony_ci   struct z_stream_s zstream;
48bf215546Sopenharmony_ci   void *out;
49bf215546Sopenharmony_ci   const uint32_t out_size = 128*4096;  /* approximate obj size */
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci   memset(&zstream, 0, sizeof(zstream));
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci   zstream.next_in = (unsigned char *)*ptr;
54bf215546Sopenharmony_ci   zstream.avail_in = 4*len;
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   if (inflateInit(&zstream) != Z_OK)
57bf215546Sopenharmony_ci      return 0;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   out = malloc(out_size);
60bf215546Sopenharmony_ci   zstream.next_out = out;
61bf215546Sopenharmony_ci   zstream.avail_out = out_size;
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci   do {
64bf215546Sopenharmony_ci      switch (inflate(&zstream, Z_SYNC_FLUSH)) {
65bf215546Sopenharmony_ci      case Z_STREAM_END:
66bf215546Sopenharmony_ci         goto end;
67bf215546Sopenharmony_ci      case Z_OK:
68bf215546Sopenharmony_ci         break;
69bf215546Sopenharmony_ci      default:
70bf215546Sopenharmony_ci         inflateEnd(&zstream);
71bf215546Sopenharmony_ci         return 0;
72bf215546Sopenharmony_ci      }
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci      if (zstream.avail_out)
75bf215546Sopenharmony_ci         break;
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci      out = realloc(out, 2*zstream.total_out);
78bf215546Sopenharmony_ci      if (out == NULL) {
79bf215546Sopenharmony_ci         inflateEnd(&zstream);
80bf215546Sopenharmony_ci         return 0;
81bf215546Sopenharmony_ci      }
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci      zstream.next_out = (unsigned char *)out + zstream.total_out;
84bf215546Sopenharmony_ci      zstream.avail_out = zstream.total_out;
85bf215546Sopenharmony_ci   } while (1);
86bf215546Sopenharmony_ci end:
87bf215546Sopenharmony_ci   inflateEnd(&zstream);
88bf215546Sopenharmony_ci   free(*ptr);
89bf215546Sopenharmony_ci   *ptr = out;
90bf215546Sopenharmony_ci   return zstream.total_out / 4;
91bf215546Sopenharmony_ci}
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_cistatic int ascii85_decode(const char *in, uint32_t **out, bool inflate)
94bf215546Sopenharmony_ci{
95bf215546Sopenharmony_ci   int len = 0, size = 1024;
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   *out = realloc(*out, sizeof(uint32_t)*size);
98bf215546Sopenharmony_ci   if (*out == NULL)
99bf215546Sopenharmony_ci      return 0;
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci   while (*in >= '!' && *in <= 'z') {
102bf215546Sopenharmony_ci      uint32_t v = 0;
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci      if (len == size) {
105bf215546Sopenharmony_ci         size *= 2;
106bf215546Sopenharmony_ci         *out = realloc(*out, sizeof(uint32_t)*size);
107bf215546Sopenharmony_ci         if (*out == NULL)
108bf215546Sopenharmony_ci            return 0;
109bf215546Sopenharmony_ci      }
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci      if (*in == 'z') {
112bf215546Sopenharmony_ci         in++;
113bf215546Sopenharmony_ci      } else {
114bf215546Sopenharmony_ci         v += in[0] - 33; v *= 85;
115bf215546Sopenharmony_ci         v += in[1] - 33; v *= 85;
116bf215546Sopenharmony_ci         v += in[2] - 33; v *= 85;
117bf215546Sopenharmony_ci         v += in[3] - 33; v *= 85;
118bf215546Sopenharmony_ci         v += in[4] - 33;
119bf215546Sopenharmony_ci         in += 5;
120bf215546Sopenharmony_ci      }
121bf215546Sopenharmony_ci      (*out)[len++] = v;
122bf215546Sopenharmony_ci   }
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci   if (!inflate)
125bf215546Sopenharmony_ci      return len;
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   return zlib_inflate(out, len);
128bf215546Sopenharmony_ci}
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_cistatic void
131bf215546Sopenharmony_ciprint_help(const char *progname, FILE *file)
132bf215546Sopenharmony_ci{
133bf215546Sopenharmony_ci   fprintf(file,
134bf215546Sopenharmony_ci           "Usage: %s [OPTION]... [FILE]\n"
135bf215546Sopenharmony_ci           "Convert an Intel GPU i915 error state to an aub file.\n"
136bf215546Sopenharmony_ci           "  -h, --help          display this help and exit\n"
137bf215546Sopenharmony_ci           "  -o, --output=FILE   the output aub file (default FILE.aub)\n",
138bf215546Sopenharmony_ci           progname);
139bf215546Sopenharmony_ci}
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_cistruct bo {
142bf215546Sopenharmony_ci   enum address_space {
143bf215546Sopenharmony_ci      PPGTT,
144bf215546Sopenharmony_ci      GGTT,
145bf215546Sopenharmony_ci   } gtt;
146bf215546Sopenharmony_ci   enum bo_type {
147bf215546Sopenharmony_ci      BO_TYPE_UNKNOWN = 0,
148bf215546Sopenharmony_ci      BO_TYPE_BATCH,
149bf215546Sopenharmony_ci      BO_TYPE_USER,
150bf215546Sopenharmony_ci      BO_TYPE_CONTEXT,
151bf215546Sopenharmony_ci      BO_TYPE_RINGBUFFER,
152bf215546Sopenharmony_ci      BO_TYPE_STATUS,
153bf215546Sopenharmony_ci      BO_TYPE_CONTEXT_WA,
154bf215546Sopenharmony_ci   } type;
155bf215546Sopenharmony_ci   const char *name;
156bf215546Sopenharmony_ci   uint64_t addr;
157bf215546Sopenharmony_ci   uint8_t *data;
158bf215546Sopenharmony_ci   uint64_t size;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   enum drm_i915_gem_engine_class engine_class;
161bf215546Sopenharmony_ci   int engine_instance;
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci   struct list_head link;
164bf215546Sopenharmony_ci};
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_cistatic struct bo *
167bf215546Sopenharmony_cifind_or_create(struct list_head *bo_list, uint64_t addr,
168bf215546Sopenharmony_ci               enum address_space gtt,
169bf215546Sopenharmony_ci               enum drm_i915_gem_engine_class engine_class,
170bf215546Sopenharmony_ci               int engine_instance)
171bf215546Sopenharmony_ci{
172bf215546Sopenharmony_ci   list_for_each_entry(struct bo, bo_entry, bo_list, link) {
173bf215546Sopenharmony_ci      if (bo_entry->addr == addr &&
174bf215546Sopenharmony_ci          bo_entry->gtt == gtt &&
175bf215546Sopenharmony_ci          bo_entry->engine_class == engine_class &&
176bf215546Sopenharmony_ci          bo_entry->engine_instance == engine_instance)
177bf215546Sopenharmony_ci         return bo_entry;
178bf215546Sopenharmony_ci   }
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   struct bo *new_bo = calloc(1, sizeof(*new_bo));
181bf215546Sopenharmony_ci   new_bo->addr = addr;
182bf215546Sopenharmony_ci   new_bo->gtt = gtt;
183bf215546Sopenharmony_ci   new_bo->engine_class = engine_class;
184bf215546Sopenharmony_ci   new_bo->engine_instance = engine_instance;
185bf215546Sopenharmony_ci   list_addtail(&new_bo->link, bo_list);
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci   return new_bo;
188bf215546Sopenharmony_ci}
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_cistatic void
191bf215546Sopenharmony_ciengine_from_name(const char *engine_name,
192bf215546Sopenharmony_ci                 enum drm_i915_gem_engine_class *engine_class,
193bf215546Sopenharmony_ci                 int *engine_instance)
194bf215546Sopenharmony_ci{
195bf215546Sopenharmony_ci   const struct {
196bf215546Sopenharmony_ci      const char *match;
197bf215546Sopenharmony_ci      enum drm_i915_gem_engine_class engine_class;
198bf215546Sopenharmony_ci      bool parse_instance;
199bf215546Sopenharmony_ci   } rings[] = {
200bf215546Sopenharmony_ci      { "rcs", I915_ENGINE_CLASS_RENDER, true },
201bf215546Sopenharmony_ci      { "vcs", I915_ENGINE_CLASS_VIDEO, true },
202bf215546Sopenharmony_ci      { "vecs", I915_ENGINE_CLASS_VIDEO_ENHANCE, true },
203bf215546Sopenharmony_ci      { "bcs", I915_ENGINE_CLASS_COPY, true },
204bf215546Sopenharmony_ci      { "global", I915_ENGINE_CLASS_INVALID, false },
205bf215546Sopenharmony_ci      { "render command stream", I915_ENGINE_CLASS_RENDER, false },
206bf215546Sopenharmony_ci      { "blt command stream", I915_ENGINE_CLASS_COPY, false },
207bf215546Sopenharmony_ci      { "bsd command stream", I915_ENGINE_CLASS_VIDEO, false },
208bf215546Sopenharmony_ci      { "vebox command stream", I915_ENGINE_CLASS_VIDEO_ENHANCE, false },
209bf215546Sopenharmony_ci      { NULL, I915_ENGINE_CLASS_INVALID },
210bf215546Sopenharmony_ci   }, *r;
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci   for (r = rings; r->match; r++) {
213bf215546Sopenharmony_ci      if (strncasecmp(engine_name, r->match, strlen(r->match)) == 0) {
214bf215546Sopenharmony_ci         *engine_class = r->engine_class;
215bf215546Sopenharmony_ci         if (r->parse_instance)
216bf215546Sopenharmony_ci            *engine_instance = strtol(engine_name + strlen(r->match), NULL, 10);
217bf215546Sopenharmony_ci         else
218bf215546Sopenharmony_ci            *engine_instance = 0;
219bf215546Sopenharmony_ci         return;
220bf215546Sopenharmony_ci      }
221bf215546Sopenharmony_ci   }
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci   fail("Unknown engine %s\n", engine_name);
224bf215546Sopenharmony_ci}
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ciint
227bf215546Sopenharmony_cimain(int argc, char *argv[])
228bf215546Sopenharmony_ci{
229bf215546Sopenharmony_ci   int i, c;
230bf215546Sopenharmony_ci   bool help = false, verbose = false;
231bf215546Sopenharmony_ci   char *out_filename = NULL, *in_filename = NULL;
232bf215546Sopenharmony_ci   const struct option aubinator_opts[] = {
233bf215546Sopenharmony_ci      { "help",       no_argument,       NULL,     'h' },
234bf215546Sopenharmony_ci      { "output",     required_argument, NULL,     'o' },
235bf215546Sopenharmony_ci      { "verbose",    no_argument,       NULL,     'v' },
236bf215546Sopenharmony_ci      { NULL,         0,                 NULL,     0 }
237bf215546Sopenharmony_ci   };
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci   i = 0;
240bf215546Sopenharmony_ci   while ((c = getopt_long(argc, argv, "ho:v", aubinator_opts, &i)) != -1) {
241bf215546Sopenharmony_ci      switch (c) {
242bf215546Sopenharmony_ci      case 'h':
243bf215546Sopenharmony_ci         help = true;
244bf215546Sopenharmony_ci         break;
245bf215546Sopenharmony_ci      case 'o':
246bf215546Sopenharmony_ci         out_filename = strdup(optarg);
247bf215546Sopenharmony_ci         break;
248bf215546Sopenharmony_ci      case 'v':
249bf215546Sopenharmony_ci         verbose = true;
250bf215546Sopenharmony_ci         break;
251bf215546Sopenharmony_ci      default:
252bf215546Sopenharmony_ci         break;
253bf215546Sopenharmony_ci      }
254bf215546Sopenharmony_ci   }
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   if (optind < argc)
257bf215546Sopenharmony_ci      in_filename = argv[optind++];
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci   if (help || argc == 1 || !in_filename) {
260bf215546Sopenharmony_ci      print_help(argv[0], stderr);
261bf215546Sopenharmony_ci      return in_filename ? EXIT_SUCCESS : EXIT_FAILURE;
262bf215546Sopenharmony_ci   }
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   if (out_filename == NULL) {
265bf215546Sopenharmony_ci      int out_filename_size = strlen(in_filename) + 5;
266bf215546Sopenharmony_ci      out_filename = malloc(out_filename_size);
267bf215546Sopenharmony_ci      snprintf(out_filename, out_filename_size, "%s.aub", in_filename);
268bf215546Sopenharmony_ci   }
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   FILE *err_file = fopen(in_filename, "r");
271bf215546Sopenharmony_ci   fail_if(!err_file, "Failed to open error file \"%s\": %m\n", in_filename);
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci   FILE *aub_file = fopen(out_filename, "w");
274bf215546Sopenharmony_ci   fail_if(!aub_file, "Failed to open aub file \"%s\": %m\n", in_filename);
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   struct aub_file aub = {};
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   enum drm_i915_gem_engine_class active_engine_class = I915_ENGINE_CLASS_INVALID;
279bf215546Sopenharmony_ci   int active_engine_instance = -1;
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   enum address_space active_gtt = PPGTT;
282bf215546Sopenharmony_ci   enum address_space default_gtt = PPGTT;
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci   struct {
285bf215546Sopenharmony_ci      struct {
286bf215546Sopenharmony_ci         uint32_t ring_buffer_head;
287bf215546Sopenharmony_ci         uint32_t ring_buffer_tail;
288bf215546Sopenharmony_ci      } instances[3];
289bf215546Sopenharmony_ci   } engines[I915_ENGINE_CLASS_VIDEO_ENHANCE + 1];
290bf215546Sopenharmony_ci   memset(engines, 0, sizeof(engines));
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   int num_ring_bos = 0;
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   struct list_head bo_list;
295bf215546Sopenharmony_ci   list_inithead(&bo_list);
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   struct bo *last_bo = NULL;
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci   char *line = NULL;
300bf215546Sopenharmony_ci   size_t line_size;
301bf215546Sopenharmony_ci   while (getline(&line, &line_size, err_file) > 0) {
302bf215546Sopenharmony_ci      const char *pci_id_start = strstr(line, "PCI ID");
303bf215546Sopenharmony_ci      if (pci_id_start) {
304bf215546Sopenharmony_ci         int pci_id;
305bf215546Sopenharmony_ci         int matched = sscanf(line, "PCI ID: 0x%04x\n", &pci_id);
306bf215546Sopenharmony_ci         fail_if(!matched, "Invalid error state file!\n");
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci         aub_file_init(&aub, aub_file,
309bf215546Sopenharmony_ci                       NULL, pci_id, "error_state");
310bf215546Sopenharmony_ci         if (verbose)
311bf215546Sopenharmony_ci            aub.verbose_log_file = stdout;
312bf215546Sopenharmony_ci         default_gtt = active_gtt = aub_use_execlists(&aub) ? PPGTT : GGTT;
313bf215546Sopenharmony_ci         continue;
314bf215546Sopenharmony_ci      }
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_ci      if (strstr(line, " command stream:")) {
317bf215546Sopenharmony_ci         engine_from_name(line, &active_engine_class, &active_engine_instance);
318bf215546Sopenharmony_ci         continue;
319bf215546Sopenharmony_ci      }
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci      if (sscanf(line, "  ring->head: 0x%x\n",
322bf215546Sopenharmony_ci                 &engines[
323bf215546Sopenharmony_ci                    active_engine_class].instances[
324bf215546Sopenharmony_ci                       active_engine_instance].ring_buffer_head) == 1) {
325bf215546Sopenharmony_ci         continue;
326bf215546Sopenharmony_ci      }
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci      if (sscanf(line, "  ring->tail: 0x%x\n",
329bf215546Sopenharmony_ci                 &engines[
330bf215546Sopenharmony_ci                    active_engine_class].instances[
331bf215546Sopenharmony_ci                       active_engine_instance].ring_buffer_tail) == 1) {
332bf215546Sopenharmony_ci         continue;
333bf215546Sopenharmony_ci      }
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci      const char *active_start = "Active (";
336bf215546Sopenharmony_ci      if (strncmp(line, active_start, strlen(active_start)) == 0) {
337bf215546Sopenharmony_ci         char *ring = line + strlen(active_start);
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_ci         engine_from_name(ring, &active_engine_class, &active_engine_instance);
340bf215546Sopenharmony_ci         active_gtt = default_gtt;
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci         char *count = strchr(ring, '[');
343bf215546Sopenharmony_ci         fail_if(!count || sscanf(count, "[%d]:", &num_ring_bos) < 1,
344bf215546Sopenharmony_ci                 "Failed to parse BO table header\n");
345bf215546Sopenharmony_ci         continue;
346bf215546Sopenharmony_ci      }
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci      const char *global_start = "Pinned (global) [";
349bf215546Sopenharmony_ci      if (strncmp(line, global_start, strlen(global_start)) == 0) {
350bf215546Sopenharmony_ci         active_engine_class = I915_ENGINE_CLASS_INVALID;
351bf215546Sopenharmony_ci         active_engine_instance = -1;
352bf215546Sopenharmony_ci         active_gtt = GGTT;
353bf215546Sopenharmony_ci         continue;
354bf215546Sopenharmony_ci      }
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci      if (num_ring_bos > 0) {
357bf215546Sopenharmony_ci         unsigned hi, lo, size;
358bf215546Sopenharmony_ci         if (sscanf(line, " %x_%x %d", &hi, &lo, &size) == 3) {
359bf215546Sopenharmony_ci            struct bo *bo_entry = find_or_create(&bo_list, ((uint64_t)hi) << 32 | lo,
360bf215546Sopenharmony_ci                                                 active_gtt,
361bf215546Sopenharmony_ci                                                 active_engine_class,
362bf215546Sopenharmony_ci                                                 active_engine_instance);
363bf215546Sopenharmony_ci            bo_entry->size = size;
364bf215546Sopenharmony_ci            num_ring_bos--;
365bf215546Sopenharmony_ci         } else {
366bf215546Sopenharmony_ci            fail("Not enough BO entries in the active table\n");
367bf215546Sopenharmony_ci         }
368bf215546Sopenharmony_ci         continue;
369bf215546Sopenharmony_ci      }
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci      if (line[0] == ':' || line[0] == '~') {
372bf215546Sopenharmony_ci         if (!last_bo || last_bo->type == BO_TYPE_UNKNOWN)
373bf215546Sopenharmony_ci            continue;
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci         int count = ascii85_decode(line+1, (uint32_t **) &last_bo->data, line[0] == ':');
376bf215546Sopenharmony_ci         fail_if(count == 0, "ASCII85 decode failed.\n");
377bf215546Sopenharmony_ci         last_bo->size = count * 4;
378bf215546Sopenharmony_ci         continue;
379bf215546Sopenharmony_ci      }
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci      char *dashes = strstr(line, " --- ");
382bf215546Sopenharmony_ci      if (dashes) {
383bf215546Sopenharmony_ci         dashes += 5;
384bf215546Sopenharmony_ci
385bf215546Sopenharmony_ci         engine_from_name(line, &active_engine_class, &active_engine_instance);
386bf215546Sopenharmony_ci
387bf215546Sopenharmony_ci         uint32_t hi, lo;
388bf215546Sopenharmony_ci         char *bo_address_str = strchr(dashes, '=');
389bf215546Sopenharmony_ci         if (!bo_address_str || sscanf(bo_address_str, "= 0x%08x %08x\n", &hi, &lo) != 2)
390bf215546Sopenharmony_ci            continue;
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_ci         const struct {
393bf215546Sopenharmony_ci            const char *match;
394bf215546Sopenharmony_ci            enum bo_type type;
395bf215546Sopenharmony_ci            enum address_space gtt;
396bf215546Sopenharmony_ci         } bo_types[] = {
397bf215546Sopenharmony_ci            { "gtt_offset", BO_TYPE_BATCH,      default_gtt },
398bf215546Sopenharmony_ci            { "user",       BO_TYPE_USER,       default_gtt },
399bf215546Sopenharmony_ci            { "HW context", BO_TYPE_CONTEXT,    GGTT },
400bf215546Sopenharmony_ci            { "ringbuffer", BO_TYPE_RINGBUFFER, GGTT },
401bf215546Sopenharmony_ci            { "HW Status",  BO_TYPE_STATUS,     GGTT },
402bf215546Sopenharmony_ci            { "WA context", BO_TYPE_CONTEXT_WA, GGTT },
403bf215546Sopenharmony_ci            { "unknown",    BO_TYPE_UNKNOWN,    GGTT },
404bf215546Sopenharmony_ci         }, *b;
405bf215546Sopenharmony_ci
406bf215546Sopenharmony_ci         for (b = bo_types; b->type != BO_TYPE_UNKNOWN; b++) {
407bf215546Sopenharmony_ci            if (strncasecmp(dashes, b->match, strlen(b->match)) == 0)
408bf215546Sopenharmony_ci               break;
409bf215546Sopenharmony_ci         }
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci         last_bo = find_or_create(&bo_list, ((uint64_t) hi) << 32 | lo,
412bf215546Sopenharmony_ci                                  b->gtt,
413bf215546Sopenharmony_ci                                  active_engine_class, active_engine_instance);
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci         /* The batch buffer will appear twice as gtt_offset and user. Only
416bf215546Sopenharmony_ci          * keep the batch type.
417bf215546Sopenharmony_ci          */
418bf215546Sopenharmony_ci         if (last_bo->type == BO_TYPE_UNKNOWN) {
419bf215546Sopenharmony_ci            last_bo->type = b->type;
420bf215546Sopenharmony_ci            last_bo->name = b->match;
421bf215546Sopenharmony_ci         }
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci         continue;
424bf215546Sopenharmony_ci      }
425bf215546Sopenharmony_ci   }
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci   if (verbose) {
428bf215546Sopenharmony_ci      fprintf(stdout, "BOs found:\n");
429bf215546Sopenharmony_ci      list_for_each_entry(struct bo, bo_entry, &bo_list, link) {
430bf215546Sopenharmony_ci         fprintf(stdout, "\t type=%i addr=0x%016" PRIx64 " size=%" PRIu64 "\n",
431bf215546Sopenharmony_ci                 bo_entry->type, bo_entry->addr, bo_entry->size);
432bf215546Sopenharmony_ci      }
433bf215546Sopenharmony_ci   }
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci   /* Find the batch that trigger the hang */
436bf215546Sopenharmony_ci   struct bo *batch_bo = NULL;
437bf215546Sopenharmony_ci   list_for_each_entry(struct bo, bo_entry, &bo_list, link) {
438bf215546Sopenharmony_ci      if (bo_entry->type == BO_TYPE_BATCH) {
439bf215546Sopenharmony_ci         batch_bo = bo_entry;
440bf215546Sopenharmony_ci         break;
441bf215546Sopenharmony_ci      }
442bf215546Sopenharmony_ci   }
443bf215546Sopenharmony_ci   fail_if(!batch_bo, "Failed to find batch buffer.\n");
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   /* Add all the BOs to the aub file */
446bf215546Sopenharmony_ci   struct bo *hwsp_bo = NULL;
447bf215546Sopenharmony_ci   list_for_each_entry(struct bo, bo_entry, &bo_list, link) {
448bf215546Sopenharmony_ci      switch (bo_entry->type) {
449bf215546Sopenharmony_ci      case BO_TYPE_BATCH:
450bf215546Sopenharmony_ci         if (bo_entry->gtt == PPGTT) {
451bf215546Sopenharmony_ci            aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size);
452bf215546Sopenharmony_ci            aub_write_trace_block(&aub, AUB_TRACE_TYPE_BATCH,
453bf215546Sopenharmony_ci                                  bo_entry->data, bo_entry->size, bo_entry->addr);
454bf215546Sopenharmony_ci         } else
455bf215546Sopenharmony_ci            aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
456bf215546Sopenharmony_ci         break;
457bf215546Sopenharmony_ci      case BO_TYPE_USER:
458bf215546Sopenharmony_ci         if (bo_entry->gtt == PPGTT) {
459bf215546Sopenharmony_ci            aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size);
460bf215546Sopenharmony_ci            aub_write_trace_block(&aub, AUB_TRACE_TYPE_NOTYPE,
461bf215546Sopenharmony_ci                                  bo_entry->data, bo_entry->size, bo_entry->addr);
462bf215546Sopenharmony_ci         } else
463bf215546Sopenharmony_ci            aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
464bf215546Sopenharmony_ci         break;
465bf215546Sopenharmony_ci      case BO_TYPE_CONTEXT:
466bf215546Sopenharmony_ci         if (bo_entry->engine_class == batch_bo->engine_class &&
467bf215546Sopenharmony_ci             bo_entry->engine_instance == batch_bo->engine_instance &&
468bf215546Sopenharmony_ci             aub_use_execlists(&aub)) {
469bf215546Sopenharmony_ci            hwsp_bo = bo_entry;
470bf215546Sopenharmony_ci
471bf215546Sopenharmony_ci            uint32_t *context = (uint32_t *) (bo_entry->data + 4096 /* GuC */ + 4096 /* HWSP */);
472bf215546Sopenharmony_ci
473bf215546Sopenharmony_ci            if (context[1] == 0) {
474bf215546Sopenharmony_ci               fprintf(stderr,
475bf215546Sopenharmony_ci                       "Invalid context image data.\n"
476bf215546Sopenharmony_ci                       "This is likely a kernel issue : https://bugs.freedesktop.org/show_bug.cgi?id=107691\n");
477bf215546Sopenharmony_ci            }
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci            /* Update the ring buffer at the last known location. */
480bf215546Sopenharmony_ci            context[5] = engines[bo_entry->engine_class].instances[bo_entry->engine_instance].ring_buffer_head;
481bf215546Sopenharmony_ci            context[7] = engines[bo_entry->engine_class].instances[bo_entry->engine_instance].ring_buffer_tail;
482bf215546Sopenharmony_ci            fprintf(stdout, "engine start=0x%x head/tail=0x%x/0x%x\n",
483bf215546Sopenharmony_ci                    context[9], context[5], context[7]);
484bf215546Sopenharmony_ci
485bf215546Sopenharmony_ci            /* The error state doesn't provide a dump of the page tables, so
486bf215546Sopenharmony_ci             * we have to provide our own, that's easy enough.
487bf215546Sopenharmony_ci             */
488bf215546Sopenharmony_ci            context[49] = aub.pml4.phys_addr >> 32;
489bf215546Sopenharmony_ci            context[51] = aub.pml4.phys_addr & 0xffffffff;
490bf215546Sopenharmony_ci
491bf215546Sopenharmony_ci            fprintf(stdout, "context dump:\n");
492bf215546Sopenharmony_ci            for (int i = 0; i < 60; i++) {
493bf215546Sopenharmony_ci               if (i % 4 == 0)
494bf215546Sopenharmony_ci                  fprintf(stdout, "\n 0x%08" PRIx64 ": ", bo_entry->addr + 8192 + i * 4);
495bf215546Sopenharmony_ci               fprintf(stdout, "0x%08x ", context[i]);
496bf215546Sopenharmony_ci            }
497bf215546Sopenharmony_ci            fprintf(stdout, "\n");
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_ci         }
500bf215546Sopenharmony_ci         aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
501bf215546Sopenharmony_ci         break;
502bf215546Sopenharmony_ci      case BO_TYPE_RINGBUFFER:
503bf215546Sopenharmony_ci      case BO_TYPE_STATUS:
504bf215546Sopenharmony_ci      case BO_TYPE_CONTEXT_WA:
505bf215546Sopenharmony_ci         aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data);
506bf215546Sopenharmony_ci         break;
507bf215546Sopenharmony_ci      case BO_TYPE_UNKNOWN:
508bf215546Sopenharmony_ci         if (bo_entry->gtt == PPGTT) {
509bf215546Sopenharmony_ci            aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size);
510bf215546Sopenharmony_ci            if (bo_entry->data) {
511bf215546Sopenharmony_ci               aub_write_trace_block(&aub, AUB_TRACE_TYPE_NOTYPE,
512bf215546Sopenharmony_ci                                     bo_entry->data, bo_entry->size, bo_entry->addr);
513bf215546Sopenharmony_ci            }
514bf215546Sopenharmony_ci         } else {
515bf215546Sopenharmony_ci            if (bo_entry->size > 0) {
516bf215546Sopenharmony_ci               void *zero_data = calloc(1, bo_entry->size);
517bf215546Sopenharmony_ci               aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, zero_data);
518bf215546Sopenharmony_ci               free(zero_data);
519bf215546Sopenharmony_ci            }
520bf215546Sopenharmony_ci         }
521bf215546Sopenharmony_ci         break;
522bf215546Sopenharmony_ci      default:
523bf215546Sopenharmony_ci         break;
524bf215546Sopenharmony_ci      }
525bf215546Sopenharmony_ci   }
526bf215546Sopenharmony_ci
527bf215546Sopenharmony_ci   if (aub_use_execlists(&aub)) {
528bf215546Sopenharmony_ci      fail_if(!hwsp_bo, "Failed to find Context buffer.\n");
529bf215546Sopenharmony_ci      aub_write_context_execlists(&aub, hwsp_bo->addr + 4096 /* skip GuC page */, hwsp_bo->engine_class);
530bf215546Sopenharmony_ci   } else {
531bf215546Sopenharmony_ci      /* Use context id 0 -- if we are not using execlists it doesn't matter
532bf215546Sopenharmony_ci       * anyway
533bf215546Sopenharmony_ci       */
534bf215546Sopenharmony_ci      aub_write_exec(&aub, 0, batch_bo->addr, 0, I915_ENGINE_CLASS_RENDER);
535bf215546Sopenharmony_ci   }
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   /* Cleanup */
538bf215546Sopenharmony_ci   list_for_each_entry_safe(struct bo, bo_entry, &bo_list, link) {
539bf215546Sopenharmony_ci      list_del(&bo_entry->link);
540bf215546Sopenharmony_ci      free(bo_entry->data);
541bf215546Sopenharmony_ci      free(bo_entry);
542bf215546Sopenharmony_ci   }
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_ci   free(out_filename);
545bf215546Sopenharmony_ci   free(line);
546bf215546Sopenharmony_ci   if(err_file) {
547bf215546Sopenharmony_ci      fclose(err_file);
548bf215546Sopenharmony_ci   }
549bf215546Sopenharmony_ci   if(aub.file) {
550bf215546Sopenharmony_ci      aub_file_finish(&aub);
551bf215546Sopenharmony_ci   } else if(aub_file) {
552bf215546Sopenharmony_ci      fclose(aub_file);
553bf215546Sopenharmony_ci   }
554bf215546Sopenharmony_ci   return EXIT_SUCCESS;
555bf215546Sopenharmony_ci}
556bf215546Sopenharmony_ci
557bf215546Sopenharmony_ci/* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/
558