X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fintel%2Ftools%2Faubinator_error_decode.c;h=6a4d42e53c25eefc5e9dfde2763a16c4a6e5446d;hb=aff078eb5a79dc53330ee8edfc755a995a041c74;hp=8a67f4f1698f9036c8441b35afbd591a6d48a50d;hpb=e8d9b76f6390459b2f7e2aa6ae8b74275f66c791;p=mesa.git diff --git a/src/intel/tools/aubinator_error_decode.c b/src/intel/tools/aubinator_error_decode.c index 8a67f4f1698..6a4d42e53c2 100644 --- a/src/intel/tools/aubinator_error_decode.c +++ b/src/intel/tools/aubinator_error_decode.c @@ -39,6 +39,7 @@ #include #include "common/gen_decoder.h" +#include "dev/gen_debug.h" #include "util/macros.h" #define CSI "\e[" @@ -46,9 +47,12 @@ #define GREEN_HEADER CSI "1;42m" #define NORMAL CSI "0m" +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + /* options */ static bool option_full_decode = true; +static bool option_print_all_bb = false; static bool option_print_offsets = true; static enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color; static char *xml_path = NULL; @@ -63,47 +67,98 @@ print_head(unsigned int reg) static void print_register(struct gen_spec *spec, const char *name, uint32_t reg) { - struct gen_group *reg_spec = gen_spec_find_register_by_name(spec, name); + struct gen_group *reg_spec = + name ? gen_spec_find_register_by_name(spec, name) : NULL; - if (reg_spec) - gen_print_group(stdout, reg_spec, 0, ®, option_color == COLOR_ALWAYS); + if (reg_spec) { + gen_print_group(stdout, reg_spec, 0, ®, 0, + option_color == COLOR_ALWAYS); + } } struct ring_register_mapping { - const char *ring_name; + enum drm_i915_gem_engine_class ring_class; + unsigned ring_instance; const char *register_name; }; static const struct ring_register_mapping acthd_registers[] = { - { "blt", "BCS_ACTHD_UDW" }, - { "bsd", "VCS_ACTHD_UDW" }, - { "bsd2", "VCS2_ACTHD_UDW" }, - { "render", "ACTHD_UDW" }, - { "vebox", "VECS_ACTHD_UDW" }, + { I915_ENGINE_CLASS_COPY, 0, "BCS_ACTHD_UDW" }, + { I915_ENGINE_CLASS_VIDEO, 0, "VCS_ACTHD_UDW" }, + { I915_ENGINE_CLASS_VIDEO, 1, "VCS2_ACTHD_UDW" }, + { I915_ENGINE_CLASS_RENDER, 0, "ACTHD_UDW" }, + { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_ACTHD_UDW" }, }; static const struct ring_register_mapping ctl_registers[] = { - { "blt", "BCS_RING_BUFFER_CTL" }, - { "bsd", "VCS_RING_BUFFER_CTL" }, - { "bsd2", "VCS2_RING_BUFFER_CTL" }, - { "render", "RCS_RING_BUFFER_CTL" }, - { "vebox", "VECS_RING_BUFFER_CTL" }, + { I915_ENGINE_CLASS_COPY, 0, "BCS_RING_BUFFER_CTL" }, + { I915_ENGINE_CLASS_VIDEO, 0, "VCS_RING_BUFFER_CTL" }, + { I915_ENGINE_CLASS_VIDEO, 1, "VCS2_RING_BUFFER_CTL" }, + { I915_ENGINE_CLASS_RENDER, 0, "RCS_RING_BUFFER_CTL" }, + { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_RING_BUFFER_CTL" }, }; static const struct ring_register_mapping fault_registers[] = { - { "blt", "BCS_FAULT_REG" }, - { "bsd", "VCS_FAULT_REG" }, - { "render", "RCS_FAULT_REG" }, - { "vebox", "VECS_FAULT_REG" }, + { I915_ENGINE_CLASS_COPY, 0, "BCS_FAULT_REG" }, + { I915_ENGINE_CLASS_VIDEO, 0, "VCS_FAULT_REG" }, + { I915_ENGINE_CLASS_RENDER, 0, "RCS_FAULT_REG" }, + { I915_ENGINE_CLASS_VIDEO_ENHANCE, 0, "VECS_FAULT_REG" }, }; +static int ring_name_to_class(const char *ring_name, + enum drm_i915_gem_engine_class *class) +{ + static const char *class_names[] = { + [I915_ENGINE_CLASS_RENDER] = "rcs", + [I915_ENGINE_CLASS_COPY] = "bcs", + [I915_ENGINE_CLASS_VIDEO] = "vcs", + [I915_ENGINE_CLASS_VIDEO_ENHANCE] = "vecs", + }; + for (size_t i = 0; i < ARRAY_SIZE(class_names); i++) { + if (strncmp(ring_name, class_names[i], strlen(class_names[i]))) + continue; + + *class = i; + return atoi(ring_name + strlen(class_names[i])); + } + + static const struct { + const char *name; + unsigned int class; + int instance; + } legacy_names[] = { + { "render", I915_ENGINE_CLASS_RENDER, 0 }, + { "blt", I915_ENGINE_CLASS_COPY, 0 }, + { "bsd", I915_ENGINE_CLASS_VIDEO, 0 }, + { "bsd2", I915_ENGINE_CLASS_VIDEO, 1 }, + { "vebox", I915_ENGINE_CLASS_VIDEO_ENHANCE, 0 }, + }; + for (size_t i = 0; i < ARRAY_SIZE(legacy_names); i++) { + if (strcmp(ring_name, legacy_names[i].name)) + continue; + + *class = legacy_names[i].class; + return legacy_names[i].instance; + } + + return -1; +} + static const char * register_name_from_ring(const struct ring_register_mapping *mapping, unsigned nb_mapping, const char *ring_name) { + enum drm_i915_gem_engine_class class; + int instance; + + instance = ring_name_to_class(ring_name, &class); + if (instance < 0) + return NULL; + for (unsigned i = 0; i < nb_mapping; i++) { - if (strcmp(mapping[i].ring_name, ring_name) == 0) + if (mapping[i].ring_class == class && + mapping[i].ring_instance == instance) return mapping[i].register_name; } return NULL; @@ -113,16 +168,38 @@ static const char * instdone_register_for_ring(const struct gen_device_info *devinfo, const char *ring_name) { - if (strcmp(ring_name, "blt") == 0) - return "BCS_INSTDONE"; - else if (strcmp(ring_name, "vebox") == 0) - return "VECS_INSTDONE"; - else if (strcmp(ring_name, "bsd") == 0) - return "VCS_INSTDONE"; - else if (strcmp(ring_name, "render") == 0) { + enum drm_i915_gem_engine_class class; + int instance; + + instance = ring_name_to_class(ring_name, &class); + if (instance < 0) + return NULL; + + switch (class) { + case I915_ENGINE_CLASS_RENDER: if (devinfo->gen == 6) return "INSTDONE_2"; - return "INSTDONE_1"; + else + return "INSTDONE_1"; + + case I915_ENGINE_CLASS_COPY: + return "BCS_INSTDONE"; + + case I915_ENGINE_CLASS_VIDEO: + switch (instance) { + case 0: + return "VCS_INSTDONE"; + case 1: + return "VCS2_INSTDONE"; + default: + return NULL; + } + + case I915_ENGINE_CLASS_VIDEO_ENHANCE: + return "VECS_INSTDONE"; + + default: + return NULL; } return NULL; @@ -204,46 +281,21 @@ print_fault_data(struct gen_device_info *devinfo, uint32_t data1, uint32_t data0 data1 & (1 << 4) ? "GGTT" : "PPGTT"); } -#define MAX_RINGS 10 /* I really hope this never... */ - #define CSI "\e[" #define NORMAL CSI "0m" -static void decode(struct gen_spec *spec, - const char *buffer_name, - const char *ring_name, - uint64_t gtt_offset, - uint32_t *data, - int *count) -{ - uint32_t *p, *end = (data + *count); - unsigned int length; - struct gen_group *inst; - - for (p = data; p < end; p += length) { - const char *color = option_full_decode ? BLUE_HEADER : NORMAL, - *reset_color = NORMAL; - uint64_t offset = gtt_offset + 4 * (p - data); - - inst = gen_spec_find_instruction(spec, p); - if (inst == NULL) { - printf("unknown instruction %08x\n", p[0]); - length = (p[0] & 0xff) + 2; - continue; - } - if (option_color == COLOR_NEVER) { - color = ""; - reset_color = ""; - } - - printf("%s0x%08"PRIx64": 0x%08x: %-80s%s\n", - color, offset, p[0], gen_group_get_name(inst), reset_color); +struct section { + uint64_t gtt_offset; + char *ring_name; + const char *buffer_name; + uint32_t *data; + int dword_count; + size_t data_offset; +}; - gen_print_group(stdout, inst, offset, data, - option_color == COLOR_ALWAYS); - length = gen_group_get_length(inst, p); - } -} +#define MAX_SECTIONS 256 +static unsigned num_sections; +static struct section sections[MAX_SECTIONS]; static int zlib_inflate(uint32_t **ptr, int len) { @@ -330,107 +382,112 @@ static int ascii85_decode(const char *in, uint32_t **out, bool inflate) return zlib_inflate(out, len); } +static int qsort_hw_context_first(const void *a, const void *b) +{ + const struct section *sa = a, *sb = b; + if (strcmp(sa->buffer_name, "HW Context") == 0) + return -1; + if (strcmp(sb->buffer_name, "HW Context") == 0) + return 1; + else + return 0; +} + +static struct gen_batch_decode_bo +get_gen_batch_bo(void *user_data, bool ppgtt, uint64_t address) +{ + for (int s = 0; s < num_sections; s++) { + if (sections[s].gtt_offset <= address && + address < sections[s].gtt_offset + sections[s].dword_count * 4) { + return (struct gen_batch_decode_bo) { + .addr = sections[s].gtt_offset, + .map = sections[s].data, + .size = sections[s].dword_count * 4, + }; + } + } + + return (struct gen_batch_decode_bo) { .map = NULL }; +} + static void read_data_file(FILE *file) { struct gen_spec *spec = NULL; - uint32_t *data = NULL; long long unsigned fence; - int data_size = 0, count = 0, line_number = 0, matched; + int matched; char *line = NULL; size_t line_size; uint32_t offset, value; - uint64_t gtt_offset = 0, new_gtt_offset; - const char *buffer_name = "batch buffer"; + uint32_t ring_head = UINT32_MAX, ring_tail = UINT32_MAX; + bool ring_wraps = false; char *ring_name = NULL; struct gen_device_info devinfo; while (getline(&line, &line_size, file) > 0) { char *new_ring_name = NULL; char *dashes; - line_number++; if (sscanf(line, "%m[^ ] command stream\n", &new_ring_name) > 0) { free(ring_name); ring_name = new_ring_name; } + if (line[0] == ':' || line[0] == '~') { + uint32_t *data = NULL; + int dword_count = ascii85_decode(line+1, &data, line[0] == ':'); + if (dword_count == 0) { + fprintf(stderr, "ASCII85 decode failed.\n"); + exit(EXIT_FAILURE); + } + assert(num_sections < MAX_SECTIONS); + sections[num_sections].data = data; + sections[num_sections].dword_count = dword_count; + num_sections++; + continue; + } + dashes = strstr(line, "---"); if (dashes) { - uint32_t lo, hi; - char *new_ring_name = malloc(dashes - line); - strncpy(new_ring_name, line, dashes - line); - new_ring_name[dashes - line - 1] = '\0'; - - printf("%s", line); - - matched = sscanf(dashes, "--- gtt_offset = 0x%08x %08x\n", - &hi, &lo); - if (matched > 0) { - new_gtt_offset = hi; - if (matched == 2) { - new_gtt_offset <<= 32; - new_gtt_offset |= lo; - } - - decode(spec, - buffer_name, ring_name, - gtt_offset, data, &count); - gtt_offset = new_gtt_offset; - free(ring_name); - ring_name = new_ring_name; - buffer_name = "batch buffer"; - continue; - } + const struct { + const char *match; + const char *name; + } buffers[] = { + { "ringbuffer", "ring buffer" }, + { "ring", "ring buffer" }, + { "gtt_offset", "batch buffer" }, + { "batch", "batch buffer" }, + { "hw context", "HW Context" }, + { "hw status", "HW status" }, + { "wa context", "WA context" }, + { "wa batchbuffer", "WA batch" }, + { "NULL context", "Kernel context" }, + { "user", "user" }, + { "semaphores", "semaphores", }, + { "guc log buffer", "GuC log", }, + { NULL, "unknown" }, + }, *b; - matched = sscanf(dashes, "--- ringbuffer = 0x%08x %08x\n", - &hi, &lo); - if (matched > 0) { - new_gtt_offset = hi; - if (matched == 2) { - new_gtt_offset <<= 32; - new_gtt_offset |= lo; - } + free(ring_name); + ring_name = malloc(dashes - line); + strncpy(ring_name, line, dashes - line); + ring_name[dashes - line - 1] = '\0'; - decode(spec, - buffer_name, ring_name, - gtt_offset, data, &count); - gtt_offset = new_gtt_offset; - free(ring_name); - ring_name = new_ring_name; - buffer_name = "ring buffer"; - continue; + dashes += 4; + for (b = buffers; b->match; b++) { + if (strncasecmp(dashes, b->match, strlen(b->match)) == 0) + break; } - matched = sscanf(dashes, "--- HW Context = 0x%08x %08x\n", - &hi, &lo); - if (matched > 0) { - new_gtt_offset = hi; - if (matched == 2) { - new_gtt_offset <<= 32; - new_gtt_offset |= lo; - } + assert(num_sections < MAX_SECTIONS); + sections[num_sections].buffer_name = b->name; + sections[num_sections].ring_name = strdup(ring_name); - decode(spec, - buffer_name, ring_name, - gtt_offset, data, &count); - gtt_offset = new_gtt_offset; - free(ring_name); - ring_name = new_ring_name; - buffer_name = "HW Context"; - continue; - } - } + uint32_t hi, lo; + dashes = strchr(dashes, '='); + if (dashes && sscanf(dashes, "= 0x%08x %08x\n", &hi, &lo)) + sections[num_sections].gtt_offset = ((uint64_t) hi) << 32 | lo; - if (line[0] == ':' || line[0] == '~') { - count = ascii85_decode(line+1, &data, line[0] == ':'); - if (count == 0) { - fprintf(stderr, "ASCII85 decode failed.\n"); - exit(1); - } - decode(spec, - buffer_name, ring_name, - gtt_offset, data, &count); continue; } @@ -439,10 +496,6 @@ read_data_file(FILE *file) uint32_t reg, reg2; /* display reg section is after the ringbuffers, don't mix them */ - decode(spec, - buffer_name, ring_name, - gtt_offset, data, &count); - printf("%s", line); matched = sscanf(line, "PCI ID: 0x%04x\n", ®); @@ -454,9 +507,9 @@ read_data_file(FILE *file) matched = sscanf(pci_id_start, "PCI ID: 0x%04x\n", ®); } if (matched == 1) { - if (!gen_get_device_info(reg, &devinfo)) { + if (!gen_get_device_info_from_pci_id(reg, &devinfo)) { printf("Unable to identify devid=%x\n", reg); - return; + exit(EXIT_FAILURE); } printf("Detected GEN%i chipset\n", devinfo.gen); @@ -479,6 +532,9 @@ read_data_file(FILE *file) if (matched == 1) print_head(reg); + sscanf(line, " HEAD: 0x%08x [0x%08X]\n", ®, &ring_head); + sscanf(line, " TAIL: 0x%08x\n", &ring_tail); + matched = sscanf(line, " ACTHD: 0x%08x\n", ®); if (matched == 1) { print_register(spec, @@ -504,6 +560,18 @@ read_data_file(FILE *file) print_register(spec, reg_name, reg); } + matched = sscanf(line, " SC_INSTDONE: 0x%08x\n", ®); + if (matched == 1) + print_register(spec, "SC_INSTDONE", reg); + + matched = sscanf(line, " SAMPLER_INSTDONE[%*d][%*d]: 0x%08x\n", ®); + if (matched == 1) + print_register(spec, "SAMPLER_INSTDONE", reg); + + matched = sscanf(line, " ROW_INSTDONE[%*d][%*d]: 0x%08x\n", ®); + if (matched == 1) + print_register(spec, "ROW_INSTDONE", reg); + matched = sscanf(line, " INSTDONE1: 0x%08x\n", ®); if (matched == 1) print_register(spec, "INSTDONE_1", reg); @@ -529,28 +597,106 @@ read_data_file(FILE *file) continue; } + } + + free(line); + free(ring_name); - count++; + /* + * Order sections so that the hardware context section is visited by the + * decoder before other command buffers. This will allow the decoder to see + * persistent state that was set before the current batch. + */ + qsort(sections, num_sections, sizeof(sections[0]), qsort_hw_context_first); - if (count > data_size) { - data_size = data_size ? data_size * 2 : 1024; - data = realloc(data, data_size * sizeof (uint32_t)); - if (data == NULL) { - fprintf(stderr, "Out of memory.\n"); - exit(1); + for (int s = 0; s < num_sections; s++) { + if (strcmp(sections[s].buffer_name, "ring buffer") != 0) + continue; + if (ring_head == UINT32_MAX) { + ring_head = 0; + ring_tail = UINT32_MAX; + } + if (ring_tail == UINT32_MAX) + ring_tail = (ring_head - sizeof(uint32_t)) % + (sections[s].dword_count * sizeof(uint32_t)); + if (ring_head > ring_tail) { + size_t total_size = sections[s].dword_count * sizeof(uint32_t) - + ring_head + ring_tail; + size_t size1 = total_size - ring_tail; + uint32_t *new_data = calloc(total_size, 1); + memcpy(new_data, (uint8_t *)sections[s].data + ring_head, size1); + memcpy((uint8_t *)new_data + size1, sections[s].data, ring_tail); + free(sections[s].data); + sections[s].data = new_data; + ring_head = 0; + ring_tail = total_size; + ring_wraps = true; + } + sections[s].data_offset = ring_head; + sections[s].dword_count = (ring_tail - ring_head) / sizeof(uint32_t); + } + + for (int s = 0; s < num_sections; s++) { + if (sections[s].dword_count * 4 > intel_debug_identifier_size() && + memcmp(sections[s].data, intel_debug_identifier(), + intel_debug_identifier_size()) == 0) { + const struct gen_debug_block_driver *driver_desc = + intel_debug_get_identifier_block(sections[s].data, + sections[s].dword_count * 4, + GEN_DEBUG_BLOCK_TYPE_DRIVER); + if (driver_desc) { + printf("Driver identifier: %s\n", + (const char *) driver_desc->description); } + break; } + } - data[count-1] = value; + enum gen_batch_decode_flags batch_flags = 0; + if (option_color == COLOR_ALWAYS) + batch_flags |= GEN_BATCH_DECODE_IN_COLOR; + if (option_full_decode) + batch_flags |= GEN_BATCH_DECODE_FULL; + if (option_print_offsets) + batch_flags |= GEN_BATCH_DECODE_OFFSETS; + batch_flags |= GEN_BATCH_DECODE_FLOATS; + + struct gen_batch_decode_ctx batch_ctx; + gen_batch_decode_ctx_init(&batch_ctx, &devinfo, stdout, batch_flags, + xml_path, get_gen_batch_bo, NULL, NULL); + + + for (int s = 0; s < num_sections; s++) { + enum drm_i915_gem_engine_class class; + ring_name_to_class(sections[s].ring_name, &class); + + printf("--- %s (%s) at 0x%08x %08x\n", + sections[s].buffer_name, sections[s].ring_name, + (unsigned) (sections[s].gtt_offset >> 32), + (unsigned) sections[s].gtt_offset); + + bool is_ring_buffer = strcmp(sections[s].buffer_name, "ring buffer") == 0; + if (option_print_all_bb || is_ring_buffer || + strcmp(sections[s].buffer_name, "batch buffer") == 0 || + strcmp(sections[s].buffer_name, "HW Context") == 0) { + if (is_ring_buffer && ring_wraps) + batch_ctx.flags &= ~GEN_BATCH_DECODE_OFFSETS; + batch_ctx.engine = class; + uint8_t *data = (uint8_t *)sections[s].data + sections[s].data_offset; + uint64_t batch_addr = sections[s].gtt_offset + sections[s].data_offset; + gen_print_batch(&batch_ctx, (uint32_t *)data, + sections[s].dword_count * 4, batch_addr, + is_ring_buffer); + batch_ctx.flags = batch_flags; + } } - decode(spec, - buffer_name, ring_name, - gtt_offset, data, &count); + gen_batch_decode_ctx_finish(&batch_ctx); - free(data); - free(line); - free(ring_name); + for (int s = 0; s < num_sections; s++) { + free(sections[s].ring_name); + free(sections[s].data); + } } static void @@ -595,7 +741,8 @@ print_help(const char *progname, FILE *file) " if omitted), 'always', or 'never'\n" " --no-pager don't launch pager\n" " --no-offsets don't print instruction offsets\n" - " --xml=DIR load hardware xml description from directory DIR\n", + " --xml=DIR load hardware xml description from directory DIR\n" + " --all-bb print out all batchbuffers\n", progname); } @@ -614,6 +761,7 @@ main(int argc, char *argv[]) { "headers", no_argument, (int *) &option_full_decode, false }, { "color", required_argument, NULL, 'c' }, { "xml", required_argument, NULL, 'x' }, + { "all-bb", no_argument, (int *) &option_print_all_bb, true }, { NULL, 0, NULL, 0 } }; @@ -642,7 +790,7 @@ main(int argc, char *argv[]) if (help || argc == 1) { print_help(argv[0], stderr); - exit(0); + exit(EXIT_SUCCESS); } if (optind >= argc) { @@ -665,7 +813,7 @@ main(int argc, char *argv[]) } } else { read_data_file(stdin); - exit(0); + exit(EXIT_SUCCESS); } } else { path = argv[optind]; @@ -673,7 +821,7 @@ main(int argc, char *argv[]) if (error != 0) { fprintf(stderr, "Error opening %s: %s\n", path, strerror(errno)); - exit(1); + exit(EXIT_FAILURE); } } @@ -684,7 +832,7 @@ main(int argc, char *argv[]) setup_pager(); if (S_ISDIR(st.st_mode)) { - int ret; + ASSERTED int ret; char *filename; ret = asprintf(&filename, "%s/i915_error_state", path); @@ -692,8 +840,8 @@ main(int argc, char *argv[]) file = fopen(filename, "r"); if (!file) { int minor; + free(filename); for (minor = 0; minor < 64; minor++) { - free(filename); ret = asprintf(&filename, "%s/%d/i915_error_state", path, minor); assert(ret > 0);