X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=blobdiff_plain;f=src%2Famd%2Fvulkan%2Fradv_debug.c;h=ce68c2ddb02f68244e5d0b16a0af9f55e5585108;hp=6ce76b77eaaa133c9cb410524032951b795b2f2d;hb=48a910d1f9344ed46822b9a969c200e606613cf3;hpb=8e97a61cfbb50e427159877a2b8110ec0f5ce8ef;ds=sidebyside diff --git a/src/amd/vulkan/radv_debug.c b/src/amd/vulkan/radv_debug.c index 6ce76b77eaa..ce68c2ddb02 100644 --- a/src/amd/vulkan/radv_debug.c +++ b/src/amd/vulkan/radv_debug.c @@ -734,3 +734,142 @@ radv_trap_handler_finish(struct radv_device *device) if (unlikely(device->tma_bo)) ws->buffer_destroy(device->tma_bo); } + +static struct radv_shader_variant * +radv_get_faulty_shader(struct radv_device *device, uint64_t faulty_pc) +{ + struct radv_shader_variant *shader = NULL; + + mtx_lock(&device->shader_slab_mutex); + list_for_each_entry(struct radv_shader_slab, slab, &device->shader_slabs, slabs) { + list_for_each_entry(struct radv_shader_variant, s, &slab->shaders, slab_list) { + uint64_t offset = align_u64(s->bo_offset + s->code_size, 256); + uint64_t va = radv_buffer_get_va(s->bo); + + if (faulty_pc >= va + s->bo_offset && faulty_pc < va + offset) { + mtx_unlock(&device->shader_slab_mutex); + return s; + } + } + } + mtx_unlock(&device->shader_slab_mutex); + + return shader; +} + +static void +radv_dump_faulty_shader(struct radv_device *device, uint64_t faulty_pc) +{ + struct radv_shader_variant *shader; + uint64_t start_addr, end_addr; + uint32_t instr_offset; + + shader = radv_get_faulty_shader(device, faulty_pc); + if (!shader) + return; + + start_addr = radv_buffer_get_va(shader->bo) + shader->bo_offset; + end_addr = start_addr + shader->code_size; + instr_offset = faulty_pc - start_addr; + + fprintf(stderr, "Faulty shader found " + "VA=[0x%"PRIx64"-0x%"PRIx64"], instr_offset=%d\n", + start_addr, end_addr, instr_offset); + + /* Get the list of instructions. + * Buffer size / 4 is the upper bound of the instruction count. + */ + unsigned num_inst = 0; + struct radv_shader_inst *instructions = + calloc(shader->code_size / 4, sizeof(struct radv_shader_inst)); + + /* Split the disassembly string into instructions. */ + si_add_split_disasm(shader->disasm_string, start_addr, &num_inst, instructions); + + /* Print instructions with annotations. */ + for (unsigned i = 0; i < num_inst; i++) { + struct radv_shader_inst *inst = &instructions[i]; + + if (start_addr + inst->offset == faulty_pc) { + fprintf(stderr, "\n!!! Faulty instruction below !!!\n"); + fprintf(stderr, "%s\n", inst->text); + fprintf(stderr, "\n"); + } else { + fprintf(stderr, "%s\n", inst->text); + } + } + + free(instructions); +} + +struct radv_sq_hw_reg { + uint32_t status; + uint32_t trap_sts; + uint32_t hw_id; + uint32_t ib_sts; +}; + +static void +radv_dump_sq_hw_regs(struct radv_device *device) +{ + struct radv_sq_hw_reg *regs = (struct radv_sq_hw_reg *)&device->tma_ptr[6]; + + fprintf(stderr, "\nHardware registers:\n"); + ac_dump_reg(stderr, device->physical_device->rad_info.chip_class, + R_000002_SQ_HW_REG_STATUS, regs->status, ~0); + ac_dump_reg(stderr, device->physical_device->rad_info.chip_class, + R_000003_SQ_HW_REG_TRAP_STS, regs->trap_sts, ~0); + ac_dump_reg(stderr, device->physical_device->rad_info.chip_class, + R_000004_SQ_HW_REG_HW_ID, regs->hw_id, ~0); + ac_dump_reg(stderr, device->physical_device->rad_info.chip_class, + R_000007_SQ_HW_REG_IB_STS, regs->ib_sts, ~0); + fprintf(stderr, "\n\n"); +} + +void +radv_check_trap_handler(struct radv_queue *queue) +{ + enum ring_type ring = radv_queue_family_to_ring(queue->queue_family_index); + struct radv_device *device = queue->device; + struct radeon_winsys *ws = device->ws; + + /* Wait for the context to be idle in a finite time. */ + ws->ctx_wait_idle(queue->hw_ctx, ring, queue->queue_idx); + + /* Try to detect if the trap handler has been reached by the hw by + * looking at ttmp0 which should be non-zero if a shader exception + * happened. + */ + if (!device->tma_ptr[4]) + return; + +#if 0 + fprintf(stderr, "tma_ptr:\n"); + for (unsigned i = 0; i < 10; i++) + fprintf(stderr, "tma_ptr[%d]=0x%x\n", i, device->tma_ptr[i]); +#endif + + radv_dump_sq_hw_regs(device); + + uint32_t ttmp0 = device->tma_ptr[4]; + uint32_t ttmp1 = device->tma_ptr[5]; + + /* According to the ISA docs, 3.10 Trap and Exception Registers: + * + * "{ttmp1, ttmp0} = {3'h0, pc_rewind[3:0], HT[0], trapID[7:0], PC[47:0]}" + * + * "When the trap handler is entered, the PC of the faulting + * instruction is: (PC - PC_rewind * 4)." + * */ + uint8_t trap_id = (ttmp1 >> 16) & 0xff; + uint8_t ht = (ttmp1 >> 24) & 0x1; + uint8_t pc_rewind = (ttmp1 >> 25) & 0xf; + uint64_t pc = (ttmp0 | ((ttmp1 & 0x0000ffffull) << 32)) - (pc_rewind * 4); + + fprintf(stderr, "PC=0x%"PRIx64", trapID=%d, HT=%d, PC_rewind=%d\n", + pc, trap_id, ht, pc_rewind); + + radv_dump_faulty_shader(device, pc); + + abort(); +}