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