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