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