Path: blob/21.2-virgl/src/gallium/drivers/r600/eg_debug.c
4570 views
/*1* Copyright 2015 Advanced Micro Devices, Inc.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* on the rights to use, copy, modify, merge, publish, distribute, sub7* license, and/or sell copies of the Software, and to permit persons to whom8* the Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,18* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR19* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE20* USE OR OTHER DEALINGS IN THE SOFTWARE.21*22* Authors:23* Marek Olšák <[email protected]>24*/25#include "r600_pipe.h"26#include "evergreend.h"2728#include "egd_tables.h"2930#define AC_IS_TRACE_POINT(x) (((x) & 0xcafe0000) == 0xcafe0000)31#define AC_GET_TRACE_POINT_ID(x) ((x) & 0xffff)3233/* Parsed IBs are difficult to read without colors. Use "less -R file" to34* read them, or use "aha -b -f file" to convert them to html.35*/36#define COLOR_RESET "\033[0m"37#define COLOR_RED "\033[31m"38#define COLOR_GREEN "\033[1;32m"39#define COLOR_YELLOW "\033[1;33m"40#define COLOR_CYAN "\033[1;36m"4142#define INDENT_PKT 84344typedef void *(*ac_debug_addr_callback)(void *data, uint64_t addr);45static void print_spaces(FILE *f, unsigned num)46{47fprintf(f, "%*s", num, "");48}4950static void print_value(FILE *file, uint32_t value, int bits)51{52/* Guess if it's int or float */53if (value <= (1 << 15)) {54if (value <= 9)55fprintf(file, "%u\n", value);56else57fprintf(file, "%u (0x%0*x)\n", value, bits / 4, value);58} else {59float f = uif(value);6061if (fabs(f) < 100000 && f*10 == floor(f*10))62fprintf(file, "%.1ff (0x%0*x)\n", f, bits / 4, value);63else64/* Don't print more leading zeros than there are bits. */65fprintf(file, "0x%0*x\n", bits / 4, value);66}67}6869static void print_named_value(FILE *file, const char *name, uint32_t value,70int bits)71{72print_spaces(file, INDENT_PKT);73fprintf(file, COLOR_YELLOW "%s" COLOR_RESET " <- ", name);74print_value(file, value, bits);75}7677static void eg_dump_reg(FILE *file, unsigned offset, uint32_t value,78uint32_t field_mask)79{80unsigned r, f;8182for (r = 0; r < ARRAY_SIZE(egd_reg_table); r++) {83const struct eg_reg *reg = &egd_reg_table[r];84const char *reg_name = egd_strings + reg->name_offset;8586if (reg->offset == offset) {87bool first_field = true;8889print_spaces(file, INDENT_PKT);90fprintf(file, COLOR_YELLOW "%s" COLOR_RESET " <- ",91reg_name);9293if (!reg->num_fields) {94print_value(file, value, 32);95return;96}9798for (f = 0; f < reg->num_fields; f++) {99const struct eg_field *field = egd_fields_table + reg->fields_offset + f;100const int *values_offsets = egd_strings_offsets + field->values_offset;101uint32_t val = (value & field->mask) >>102(ffs(field->mask) - 1);103104if (!(field->mask & field_mask))105continue;106107/* Indent the field. */108if (!first_field)109print_spaces(file,110INDENT_PKT + strlen(reg_name) + 4);111112/* Print the field. */113fprintf(file, "%s = ", egd_strings + field->name_offset);114115if (val < field->num_values && values_offsets[val] >= 0)116fprintf(file, "%s\n", egd_strings + values_offsets[val]);117else118print_value(file, val,119util_bitcount(field->mask));120121first_field = false;122}123return;124}125}126127print_spaces(file, INDENT_PKT);128fprintf(file, COLOR_YELLOW "0x%05x" COLOR_RESET " <- 0x%08x\n", offset, value);129}130131132static void ac_parse_set_reg_packet(FILE *f, uint32_t *ib, unsigned count,133unsigned reg_offset)134{135unsigned reg = (ib[1] << 2) + reg_offset;136unsigned i;137138for (i = 0; i < count; i++)139eg_dump_reg(f, reg + i*4, ib[2+i], ~0);140}141142static uint32_t *ac_parse_packet3(FILE *f, uint32_t *ib, int *num_dw,143int trace_id, enum chip_class chip_class,144ac_debug_addr_callback addr_callback,145void *addr_callback_data)146{147unsigned count = PKT_COUNT_G(ib[0]);148unsigned op = PKT3_IT_OPCODE_G(ib[0]);149const char *predicate = PKT3_PREDICATE(ib[0]) ? "(predicate)" : "";150const char *compute_mode = (ib[0] & 0x2) ? "(C)" : "";151unsigned i;152153/* Print the name first. */154for (i = 0; i < ARRAY_SIZE(packet3_table); i++)155if (packet3_table[i].op == op)156break;157158if (i < ARRAY_SIZE(packet3_table)) {159const char *name = egd_strings + packet3_table[i].name_offset;160161if (op == PKT3_SET_CONTEXT_REG ||162op == PKT3_SET_CONFIG_REG ||163op == PKT3_SET_UCONFIG_REG ||164op == PKT3_SET_SH_REG)165fprintf(f, COLOR_CYAN "%s%s%s" COLOR_CYAN ":\n",166name, compute_mode, predicate);167else168fprintf(f, COLOR_GREEN "%s%s%s" COLOR_RESET ":\n",169name, compute_mode, predicate);170} else171fprintf(f, COLOR_RED "PKT3_UNKNOWN 0x%x%s%s" COLOR_RESET ":\n",172op, compute_mode, predicate);173174/* Print the contents. */175switch (op) {176case PKT3_SET_CONTEXT_REG:177ac_parse_set_reg_packet(f, ib, count, EVERGREEN_CONTEXT_REG_OFFSET);178break;179case PKT3_SET_CONFIG_REG:180ac_parse_set_reg_packet(f, ib, count, EVERGREEN_CONFIG_REG_OFFSET);181break;182case PKT3_SURFACE_SYNC:183eg_dump_reg(f, R_0085F0_CP_COHER_CNTL, ib[1], ~0);184eg_dump_reg(f, R_0085F4_CP_COHER_SIZE, ib[2], ~0);185eg_dump_reg(f, R_0085F8_CP_COHER_BASE, ib[3], ~0);186print_named_value(f, "POLL_INTERVAL", ib[4], 16);187break;188case PKT3_EVENT_WRITE:189/* TODO dump VGT_EVENT_INITIATOR */190#if 0191eg_dump_reg(f, R_028A90_VGT_EVENT_INITIATOR, ib[1],192S_028A90_EVENT_TYPE(~0));193#endif194print_named_value(f, "EVENT_TYPE", ib[1] & 0xff, 8);195print_named_value(f, "EVENT_INDEX", (ib[1] >> 8) & 0xf, 4);196print_named_value(f, "INV_L2", (ib[1] >> 20) & 0x1, 1);197if (count > 0) {198print_named_value(f, "ADDRESS_LO", ib[2], 32);199print_named_value(f, "ADDRESS_HI", ib[3], 16);200}201break;202case PKT3_DRAW_INDEX_AUTO:203eg_dump_reg(f, R_008970_VGT_NUM_INDICES, ib[1], ~0);204eg_dump_reg(f, R_0287F0_VGT_DRAW_INITIATOR, ib[2], ~0);205break;206case PKT3_DRAW_INDEX_2:207eg_dump_reg(f, R_028A78_VGT_DMA_MAX_SIZE, ib[1], ~0);208eg_dump_reg(f, R_0287E8_VGT_DMA_BASE, ib[2], ~0);209eg_dump_reg(f, R_0287E4_VGT_DMA_BASE_HI, ib[3], ~0);210eg_dump_reg(f, R_008970_VGT_NUM_INDICES, ib[4], ~0);211eg_dump_reg(f, R_0287F0_VGT_DRAW_INITIATOR, ib[5], ~0);212break;213case PKT3_INDEX_TYPE:214eg_dump_reg(f, R_028A7C_VGT_DMA_INDEX_TYPE, ib[1], ~0);215break;216case PKT3_NUM_INSTANCES:217eg_dump_reg(f, R_028A88_VGT_NUM_INSTANCES, ib[1], ~0);218break;219case PKT3_INDIRECT_BUFFER:220break;221case PKT3_PFP_SYNC_ME:222break;223case PKT3_NOP:224if (ib[0] == 0xffff1000) {225count = -1; /* One dword NOP. */226break;227} else if (count == 0 && AC_IS_TRACE_POINT(ib[1])) {228unsigned packet_id = AC_GET_TRACE_POINT_ID(ib[1]);229230print_spaces(f, INDENT_PKT);231fprintf(f, COLOR_RED "Trace point ID: %u\n", packet_id);232233if (trace_id == -1)234break; /* tracing was disabled */235236print_spaces(f, INDENT_PKT);237if (packet_id < trace_id)238fprintf(f, COLOR_RED239"This trace point was reached by the CP."240COLOR_RESET "\n");241else if (packet_id == trace_id)242fprintf(f, COLOR_RED243"!!!!! This is the last trace point that "244"was reached by the CP !!!!!"245COLOR_RESET "\n");246else if (packet_id+1 == trace_id)247fprintf(f, COLOR_RED248"!!!!! This is the first trace point that "249"was NOT been reached by the CP !!!!!"250COLOR_RESET "\n");251else252fprintf(f, COLOR_RED253"!!!!! This trace point was NOT reached "254"by the CP !!!!!"255COLOR_RESET "\n");256break;257}258FALLTHROUGH; /* print all dwords */259default:260for (i = 0; i < count+1; i++) {261print_spaces(f, INDENT_PKT);262fprintf(f, "0x%08x\n", ib[1+i]);263}264}265266ib += count + 2;267*num_dw -= count + 2;268return ib;269}270271/**272* Parse and print an IB into a file.273*274* \param f file275* \param ib IB276* \param num_dw size of the IB277* \param chip_class chip class278* \param trace_id the last trace ID that is known to have been reached279* and executed by the CP, typically read from a buffer280* \param addr_callback Get a mapped pointer of the IB at a given address. Can281* be NULL.282* \param addr_callback_data user data for addr_callback283*/284static void eg_parse_ib(FILE *f, uint32_t *ib, int num_dw, int trace_id,285const char *name, enum chip_class chip_class,286ac_debug_addr_callback addr_callback, void *addr_callback_data)287{288fprintf(f, "------------------ %s begin ------------------\n", name);289290while (num_dw > 0) {291unsigned type = PKT_TYPE_G(ib[0]);292293switch (type) {294case 3:295ib = ac_parse_packet3(f, ib, &num_dw, trace_id,296chip_class, addr_callback,297addr_callback_data);298break;299case 2:300/* type-2 nop */301if (ib[0] == 0x80000000) {302fprintf(f, COLOR_GREEN "NOP (type 2)" COLOR_RESET "\n");303ib++;304num_dw--;305break;306}307FALLTHROUGH;308default:309fprintf(f, "Unknown packet type %i\n", type);310return;311}312}313314fprintf(f, "------------------- %s end -------------------\n", name);315if (num_dw < 0) {316printf("Packet ends after the end of IB.\n");317exit(0);318}319fprintf(f, "\n");320}321322static void eg_dump_last_ib(struct r600_context *rctx, FILE *f)323{324int last_trace_id = -1;325326if (!rctx->last_gfx.ib)327return;328329if (rctx->last_trace_buf) {330/* We are expecting that the ddebug pipe has already331* waited for the context, so this buffer should be idle.332* If the GPU is hung, there is no point in waiting for it.333*/334uint32_t *map = rctx->b.ws->buffer_map(rctx->b.ws, rctx->last_trace_buf->buf,335NULL,336PIPE_MAP_UNSYNCHRONIZED |337PIPE_MAP_READ);338if (map)339last_trace_id = *map;340}341342eg_parse_ib(f, rctx->last_gfx.ib, rctx->last_gfx.num_dw,343last_trace_id, "IB", rctx->b.chip_class,344NULL, NULL);345}346347348void eg_dump_debug_state(struct pipe_context *ctx, FILE *f,349unsigned flags)350{351struct r600_context *rctx = (struct r600_context*)ctx;352353eg_dump_last_ib(rctx, f);354355fprintf(f, "Done.\n");356357/* dump only once */358radeon_clear_saved_cs(&rctx->last_gfx);359r600_resource_reference(&rctx->last_trace_buf, NULL);360}361362363