From: Lionel Landwerlin Date: Tue, 4 Sep 2018 13:45:37 +0000 (+0100) Subject: intel/error2aub: write GGTT buffers into the aub file X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ca0161f890cd9b22cbb1c830e835b549e3010e7b;p=mesa.git intel/error2aub: write GGTT buffers into the aub file Signed-off-by: Lionel Landwerlin Reviewed-by: Rafael Antognolli --- diff --git a/src/intel/tools/aub_write.c b/src/intel/tools/aub_write.c index e2bd0f4cede..0447bbb39c2 100644 --- a/src/intel/tools/aub_write.c +++ b/src/intel/tools/aub_write.c @@ -543,6 +543,71 @@ aub_write_default_setup(struct aub_file *aub) write_execlists_default_setup(aub); else write_legacy_default_setup(aub); + + aub->has_default_setup = true; +} + +void +aub_write_ggtt(struct aub_file *aub, uint64_t virt_addr, uint64_t size, const void *data) +{ + if (aub->verbose_log_file) { + fprintf(aub->verbose_log_file, + " Writting GGTT address: 0x%" PRIx64 ", size: %" PRIu64"\n", + virt_addr, size); + } + + /* Default setup assumes a 1 to 1 mapping between physical and virtual GGTT + * addresses. This is somewhat incompatible with the aub_write_ggtt() + * function. In practice it doesn't matter as the GGTT writes are used to + * replace the default setup and we've taken care to setup the PML4 as the + * top of the GGTT. + */ + assert(!aub->has_default_setup); + + /* Makes the code below a bit simpler. In practice all of the write we + * receive from error2aub are page aligned. + */ + assert(virt_addr % 4096 == 0); + assert((aub->phys_addrs_allocator + size) < (1UL << 32)); + + /* GGTT PT */ + uint32_t ggtt_ptes = DIV_ROUND_UP(size, 4096); + uint64_t phys_addr = aub->phys_addrs_allocator << 12; + aub->phys_addrs_allocator += ggtt_ptes; + + if (aub->verbose_log_file) { + fprintf(aub->verbose_log_file, + " Writting GGTT address: 0x%" PRIx64 ", size: %" PRIu64" phys_addr=0x%lx entries=%u\n", + virt_addr, size, phys_addr, ggtt_ptes); + } + + mem_trace_memory_write_header_out(aub, + (virt_addr >> 12) * GEN8_PTE_SIZE, + ggtt_ptes * GEN8_PTE_SIZE, + AUB_MEM_TRACE_MEMORY_ADDRESS_SPACE_GGTT_ENTRY, + "GGTT PT"); + for (uint32_t i = 0; i < ggtt_ptes; i++) { + dword_out(aub, 1 + phys_addr + i * 4096); + dword_out(aub, 0); + } + + /* We write the GGTT buffer through the GGTT aub command rather than the + * PHYSICAL aub command. This is because the Gen9 simulator seems to have 2 + * different set of memory pools for GGTT and physical (probably someone + * didn't really understand the concept?). + */ + static const char null_block[8 * 4096]; + for (uint64_t offset = 0; offset < size; offset += 4096) { + uint32_t block_size = min(4096, size - offset); + + mem_trace_memory_write_header_out(aub, virt_addr + offset, block_size, + AUB_MEM_TRACE_MEMORY_ADDRESS_SPACE_GGTT, + "GGTT buffer"); + data_out(aub, (char *) data + offset, block_size); + + /* Pad to a multiple of 4 bytes. */ + data_out(aub, null_block, -block_size & 3); + } } /** @@ -697,3 +762,12 @@ aub_write_exec(struct aub_file *aub, uint64_t batch_addr, } fflush(aub->file); } + +void +aub_write_context_execlists(struct aub_file *aub, uint64_t context_addr, + enum drm_i915_gem_engine_class engine_class) +{ + const struct engine *cs = engine_from_engine_class(engine_class); + uint64_t descriptor = ((uint64_t)1 << 62 | context_addr | CONTEXT_FLAGS); + aub_dump_execlist(aub, cs, descriptor); +} diff --git a/src/intel/tools/aub_write.h b/src/intel/tools/aub_write.h index 604dfbc8cc5..bdd1045e650 100644 --- a/src/intel/tools/aub_write.h +++ b/src/intel/tools/aub_write.h @@ -45,6 +45,8 @@ struct aub_ppgtt_table { struct aub_file { FILE *file; + bool has_default_setup; + /* Set if you want extra logging */ FILE *verbose_log_file; @@ -85,11 +87,14 @@ aub_write_reloc(const struct gen_device_info *devinfo, void *p, uint64_t v) void aub_write_default_setup(struct aub_file *aub); void aub_map_ppgtt(struct aub_file *aub, uint64_t start, uint64_t size); +void aub_write_ggtt(struct aub_file *aub, uint64_t virt_addr, uint64_t size, const void *data); void aub_write_trace_block(struct aub_file *aub, uint32_t type, void *virtual, uint32_t size, uint64_t gtt_offset); void aub_write_exec(struct aub_file *aub, uint64_t batch_addr, uint64_t offset, enum drm_i915_gem_engine_class engine_class); +void aub_write_context_execlists(struct aub_file *aub, uint64_t context_addr, + enum drm_i915_gem_engine_class engine_class); #ifdef __cplusplus } diff --git a/src/intel/tools/error2aub.c b/src/intel/tools/error2aub.c index 1b1f8d9c5f9..e2dded29c2c 100644 --- a/src/intel/tools/error2aub.c +++ b/src/intel/tools/error2aub.c @@ -308,8 +308,6 @@ main(int argc, char *argv[]) NULL, pci_id, "error_state"); fail_if(!aub_use_execlists(&aub), "%s currently only works on gen8+\n", argv[0]); - - aub_write_default_setup(&aub); continue; } @@ -425,7 +423,18 @@ main(int argc, char *argv[]) } } + /* Find the batch that trigger the hang */ + struct bo *batch_bo = NULL; + list_for_each_entry(struct bo, bo_entry, &bo_list, link) { + if (bo_entry->type == BO_TYPE_BATCH) { + batch_bo = bo_entry; + break; + } + } + fail_if(!batch_bo, "Failed to find batch buffer.\n"); + /* Add all the BOs to the aub file */ + struct bo *hwsp_bo = NULL; list_for_each_entry(struct bo, bo_entry, &bo_list, link) { switch (bo_entry->type) { case BO_TYPE_BATCH: @@ -437,21 +446,70 @@ main(int argc, char *argv[]) aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size); aub_write_trace_block(&aub, AUB_TRACE_TYPE_NOTYPE, bo_entry->data, bo_entry->size, bo_entry->addr); - default: break; - } - } + case BO_TYPE_CONTEXT: + if (bo_entry->engine_class == batch_bo->engine_class && + bo_entry->engine_instance == batch_bo->engine_instance) { + hwsp_bo = bo_entry; + + uint32_t *context = (uint32_t *) (bo_entry->data + 4096 /* GuC */ + 4096 /* HWSP */); + + if (context[1] == 0) { + fprintf(stderr, + "Invalid context image data.\n" + "This is likely a kernel issue : https://bugs.freedesktop.org/show_bug.cgi?id=107691\n"); + } + + /* Update the ring buffer at the last known location. */ + context[5] = engines[bo_entry->engine_class].instances[bo_entry->engine_instance].ring_buffer_head; + context[7] = engines[bo_entry->engine_class].instances[bo_entry->engine_instance].ring_buffer_tail; + fprintf(stdout, "engine start=0x%x head/tail=0x%x/0x%x\n", + context[9], context[5], context[7]); + + /* The error state doesn't provide a dump of the page tables, so + * we have to provide our own, that's easy enough. + */ + context[49] = aub.pml4.phys_addr >> 32; + context[51] = aub.pml4.phys_addr & 0xffffffff; + + fprintf(stdout, "context dump:\n"); + for (int i = 0; i < 60; i++) { + if (i % 4 == 0) + fprintf(stdout, "\n 0x%08lx: ", bo_entry->addr + 8192 + i * 4); + fprintf(stdout, "0x%08x ", context[i]); + } + fprintf(stdout, "\n"); - /* Finally exec the batch BO */ - bool batch_found = false; - list_for_each_entry(struct bo, bo_entry, &bo_list, link) { - if (bo_entry->type == BO_TYPE_BATCH) { - aub_write_exec(&aub, bo_entry->addr, aub_gtt_size(&aub), bo_entry->engine_class); - batch_found = true; + } + aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data); + break; + case BO_TYPE_RINGBUFFER: + case BO_TYPE_STATUS: + case BO_TYPE_CONTEXT_WA: + aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, bo_entry->data); + break; + case BO_TYPE_UNKNOWN: + if (bo_entry->gtt == PPGTT) { + aub_map_ppgtt(&aub, bo_entry->addr, bo_entry->size); + if (bo_entry->data) { + aub_write_trace_block(&aub, AUB_TRACE_TYPE_NOTYPE, + bo_entry->data, bo_entry->size, bo_entry->addr); + } + } else { + if (bo_entry->size > 0) { + void *zero_data = calloc(1, bo_entry->size); + aub_write_ggtt(&aub, bo_entry->addr, bo_entry->size, zero_data); + free(zero_data); + } + } + break; + default: break; } } - fail_if(!batch_found, "Failed to find batch buffer.\n"); + + fail_if(!hwsp_bo, "Failed to find Context buffer.\n"); + aub_write_context_execlists(&aub, hwsp_bo->addr + 4096 /* skip GuC page */, hwsp_bo->engine_class); /* Cleanup */ list_for_each_entry_safe(struct bo, bo_entry, &bo_list, link) {