diff options
author | Tom St Denis <tom.stdenis@amd.com> | 2019-01-17 09:52:17 -0500 |
---|---|---|
committer | Tom St Denis <tom.stdenis@amd.com> | 2019-01-19 15:32:45 -0500 |
commit | a3af62e397451c832da834feb070b3d25a8306b2 (patch) | |
tree | b284fa84aca704a27d330dafd2e4a3aadbdeab97 | |
parent | d17db20f8f22607d4102a71de2655342d2130b80 (diff) |
Add SDMA stream decoder API
As well add a few opcodes to the ring decoder side of the SDMA decoder.
Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
-rw-r--r-- | src/lib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/lib/ring_decode.c | 34 | ||||
-rw-r--r-- | src/lib/umr_read_sdma_stream.c | 228 | ||||
-rw-r--r-- | src/lib/umr_sdma_decode_opcodes.c | 395 | ||||
-rw-r--r-- | src/umr.h | 66 |
5 files changed, 723 insertions, 2 deletions
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 8330865..016997e 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -25,7 +25,9 @@ add_library(umrcore STATIC umr_llvm_disasm.c umr_read_ring_data.c umr_read_pm4_stream.c + umr_read_sdma_stream.c umr_pm4_decode_opcodes.c + umr_sdma_decode_opcodes.c update.c version.c $<TARGET_OBJECTS:asic> $<TARGET_OBJECTS:ip> diff --git a/src/lib/ring_decode.c b/src/lib/ring_decode.c index f07caf0..63273cc 100644 --- a/src/lib/ring_decode.c +++ b/src/lib/ring_decode.c @@ -1537,6 +1537,14 @@ static void parse_next_sdma_pkt(struct umr_asic *asic, struct umr_ring_decoder * break; } break; + case 7: // SEM + switch (decoder->sdma.cur_word) { + case 1: printf("SEMAPHORE_ADDR_LO: %s0x%08lx%s", YELLOW, (unsigned long)ib, RST); + break; + case 2: printf("SEMAPHORE_ADDR_HI: %s0x%08lx%s", YELLOW, (unsigned long)ib, RST); + break; + } + break; case 8: // POLL_REGMEM switch (decoder->sdma.cur_sub_opcode) { case 0: // WAIT_REG_MEM @@ -1580,6 +1588,24 @@ static void parse_next_sdma_pkt(struct umr_asic *asic, struct umr_ring_decoder * break; } break; + case 10: // ATOMIC + switch (decoder->sdma.cur_word) { + case 1: printf("ADDR_LO: %s0x%08lx%s", YELLOW, (unsigned long)ib, RST); + break; + case 2: printf("ADDR_HI: %s0x%08lx%s", YELLOW, (unsigned long)ib, RST); + break; + case 3: printf("SRC_DATA_LO: %s0x%08lx%s", BLUE, (unsigned long)ib, RST); + break; + case 4: printf("SRC_DATA_HI: %s0x%08lx%s", BLUE, (unsigned long)ib, RST); + break; + case 5: printf("CMP_DATA_LO: %s0x%08lx%s", BLUE, (unsigned long)ib, RST); + break; + case 6: printf("CMP_DATA_HI: %s0x%08lx%s", BLUE, (unsigned long)ib, RST); + break; + case 7: printf("LOOP_INTERVAL: %s0x%08lx%s", BLUE, (unsigned long)ib & 0x1FFF, RST); + break; + } + break; case 11: // CONST_FILL switch (decoder->sdma.cur_word) { case 1: printf("CONST_FILL_DST_LO: %s0x%08lx%s", YELLOW, (unsigned long)ib, RST); @@ -1620,7 +1646,7 @@ static void parse_next_sdma_pkt(struct umr_asic *asic, struct umr_ring_decoder * if (asic->family <= FAMILY_VI) printf("SRBM_WRITE_ADDR: %s0x%08lx%s(%s)", YELLOW, (unsigned long)ib & 0xFFFF, RST, umr_reg_name(asic, ib & 0xFFFF)); else - printf("SRBM_WRITE_ADDR: %s0x%08lx%s(%s)", YELLOW, (unsigned long)ib & 0xFFFF, RST, umr_reg_name(asic, ib & 0x3FFFF)); + printf("SRBM_WRITE_ADDR: %s0x%08lx%s(%s)", YELLOW, (unsigned long)ib & 0x3FFFF, RST, umr_reg_name(asic, ib & 0x3FFFF)); decoder->sdma.next_write_mem = ib; break; case 2: printf("SRBM_WRITE_DATA: %s0x%08lx%s", BLUE, (unsigned long)ib, RST); @@ -1628,6 +1654,11 @@ static void parse_next_sdma_pkt(struct umr_asic *asic, struct umr_ring_decoder * break; } break; + case 15: // PRE_EXE + switch (decoder->sdma.cur_word) { + case 1: printf("COUNT: %s0x%08lu%s", BLUE, (unsigned long)ib & 0x3FFF, RST); + break; + } } decoder->sdma.cur_word++; @@ -1719,7 +1750,6 @@ static void print_decode_sdma(struct umr_asic *asic, struct umr_ring_decoder *de case 6: // TRAP decoder->sdma.n_words = 2; break; - break; case 7: // SEM printf(", WRITE_ONE: %s%u%s, SIGNAL: %s%u%s, MAILBOX: %s%u%s", BLUE, (unsigned)((ib >> 29) & 1), RST, diff --git a/src/lib/umr_read_sdma_stream.c b/src/lib/umr_read_sdma_stream.c new file mode 100644 index 0000000..4300b72 --- /dev/null +++ b/src/lib/umr_read_sdma_stream.c @@ -0,0 +1,228 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Tom St Denis <tom.stdenis@amd.com> + * + */ +#include "umr.h" +#include <inttypes.h> + +/** + * umr_sdma_decode_ring - Read a GPU ring and decode into a sdma stream + * + * @ringname - Common name of the ring, e.g., 'gfx' or 'comp_1.0.0' + * @no_halt - Set to 0 to issue an SQ_CMD halt command + * + * Return a sdma stream if successful. + */ +struct umr_sdma_stream *umr_sdma_decode_ring(struct umr_asic *asic, char *ringname) +{ + void *ps; + uint32_t *ringdata, ringsize; + + // read ring data and reduce indeices modulo ring size + // since the kernel returned values might be unwrapped. + ringdata = umr_read_ring_data(asic, ringname, &ringsize); + ringsize /= 4; + ringdata[0] %= ringsize; + ringdata[1] %= ringsize; + + // only proceed if there is data to read + // and then linearize it so that the stream + // decoder can do it's thing + if (ringdata[0] != ringdata[1]) { // rptr != wptr + uint32_t *lineardata, linearsize; + + // copy ring data into linear array + lineardata = calloc(ringsize, sizeof(*lineardata)); + linearsize = 0; + while (ringdata[0] != ringdata[1]) { + lineardata[linearsize++] = ringdata[3 + ringdata[0]]; // first 3 words are rptr/wptr/dwptr + ringdata[0] = (ringdata[0] + 1) % ringsize; + } + + ps = umr_sdma_decode_stream(asic, 0, lineardata, linearsize); + free(lineardata); + free(ringdata); + } else { + ps = NULL; + } + + return ps; +} + +/** + * umr_sdma_decode_stream - Decode an array of sdma packets into a sdma stream + * + * @vmid: The VMID (or zero) that this array comes from (if say an IB) + * @stream: An array of DWORDS which contain the sdma packets + * @nwords: The number of words in the stream + * + * Returns a sdma stream if successfully decoded. + */ +struct umr_sdma_stream *umr_sdma_decode_stream(struct umr_asic *asic, int vmid, uint32_t *stream, uint32_t nwords) +{ + struct umr_sdma_stream *ops, *ps; + + ps = ops = calloc(1, sizeof *ops); + if (!ps) { + fprintf(stderr, "[ERROR]: Out of memory\n"); + return NULL; + } + + while (nwords) { + ps->opcode = *stream & 0xFF; + ps->sub_opcode = (*stream >> 8) & 0xFF; + ps->header_dw = *stream++; + + switch (ps->opcode) { + case 0: // NOP + ps->nwords = 0; // no words other than header + break; + case 1: // COPY + switch (ps->sub_opcode) { + case 0: // LINEAR + ps->nwords = 6; + + // BROADCAST + if (ps->header_dw & (1UL << 27)) { + ps->nwords += 2; + } + break; + case 1: // TILED + ps->nwords = 11; + break; + case 3: // STRUCTURE/SOA + ps->nwords = 7; + break; + case 4: // LINEAR_SUB_WINDOW + ps->nwords = 12; + break; + case 5: // TILED_SUB_WINDOW + ps->nwords = 13; + break; + case 6: // T2T_SUB_WIND + ps->nwords = 14; + break; + } + break; + case 2: // WRITE + switch (ps->sub_opcode) { + case 0: // LINEAR + ps->nwords = 4; + ps->nwords += stream[2] - 1; + break; + case 1: // TILED + ps->nwords = 9; + break; + } + break; + case 4: // INDIRECT + ps->ib.vmid = (ps->header_dw >> 16) & 0xF; + ps->ib.addr = ((uint64_t)stream[1] << 32) | stream[0]; + ps->ib.size = stream[2]; + if (asic->family >= FAMILY_AI) + ps->ib.vmid |= UMR_MM_HUB; + ps->nwords = 5; + + { + uint32_t *data = calloc(sizeof(*data), ps->ib.size); + if (umr_read_vram(asic, ps->ib.vmid, ps->ib.addr, ps->ib.size * sizeof(*data), data) == 0) + ps->next_ib = umr_sdma_decode_stream(asic, ps->ib.vmid, data, ps->ib.size); + free(data); + } + break; + case 5: // FENCE + ps->nwords = 3; + break; + case 6: // TRAP + ps->nwords = 1; + break; + case 7: // SEM + ps->nwords = 2; + break; + case 8: // POLL_REGMEM + ps->nwords = ps->sub_opcode ? 3 : 5; + break; + case 9: // COND_EXE + ps->nwords = 4; + break; + case 10: // ATOMIC + ps->nwords = 7; + break; + case 11: // CONST_FILL + ps->nwords = 4; + break; + case 12: // GEN_PTEPDE + ps->nwords = 9; + break; + case 13: // TIMESTAMP + switch (ps->sub_opcode) { + case 0: + ps->nwords = 2; + break; + case 1: + ps->nwords = 2; + break; + case 2: + ps->nwords = 2; + break; + } + break; + case 14: // SRBM_WRITE + ps->nwords = 2; + break; + case 15: // PRE_EXE + ps->nwords = 1; + break; + } + + ps->words = calloc(ps->nwords, sizeof(ps->words[0])); + memcpy(ps->words, stream, ps->nwords * sizeof(ps->words[0])); + + stream += ps->nwords; + if (nwords <= 1 + ps->nwords) { + fprintf(stderr, "[WARNING]: Ran out of stream words in SDMA stream decode\n"); + return ops; + } + nwords -= 1 + ps->nwords; + + ps->next = calloc(1, sizeof(ps->next[0])); + ps = ps->next; + } + return ops; +} + +/** + * umr_free_sdma_stream - Free a sdma stream object + */ +void umr_free_sdma_stream(struct umr_sdma_stream *stream) +{ + while (stream) { + struct umr_sdma_stream *n; + n = stream->next; + if (stream->next_ib) + umr_free_sdma_stream(stream->next_ib); + free(stream->words); + free(stream); + stream = n; + } +} diff --git a/src/lib/umr_sdma_decode_opcodes.c b/src/lib/umr_sdma_decode_opcodes.c new file mode 100644 index 0000000..6f74618 --- /dev/null +++ b/src/lib/umr_sdma_decode_opcodes.c @@ -0,0 +1,395 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Tom St Denis <tom.stdenis@amd.com> + * + */ +#include "umr.h" +#include <inttypes.h> + +struct umr_sdma_stream *umr_sdma_decode_stream_opcodes(struct umr_asic *asic, struct umr_sdma_stream_decode_ui *ui, struct umr_sdma_stream *stream, + uint64_t ib_addr, uint32_t ib_vmid, uint64_t from_addr, uint64_t from_vmid, unsigned long opcodes, int follow) +{ + uint32_t n; + struct umr_sdma_stream *os = stream; + static const char *poll_regmem_funcs[] = { "always", "<", "<=", "==", "!=", ">=", ">", "N/A" }; + + n = 0; + while (os) { + n += os->nwords; + os = os->next; + } + + ui->start_ib(ui, ib_addr, ib_vmid, from_addr, from_vmid, n); + while (stream && opcodes--) { + switch (stream->opcode) { + case 0: + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "NOP"); + break; + case 1: // COPY + switch (stream->sub_opcode) { + case 0: // LINEAR + switch (stream->header_dw & (1UL << 27)) { + case 0: // not broadcast + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "COPY (LINEAR)"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "COPY_COUNT", stream->words[0], NULL, 10); + ui->add_field(ui, ib_addr + 8, ib_vmid, "DST_SW", (stream->words[1] >> 16) & 3, NULL, 10); + ui->add_field(ui, ib_addr + 8, ib_vmid, "DST_HA", (stream->words[1] >> 22) & 1, NULL, 10); + ui->add_field(ui, ib_addr + 8, ib_vmid, "SRC_SW", (stream->words[1] >> 24) & 3, NULL, 10); + ui->add_field(ui, ib_addr + 8, ib_vmid, "SRC_HA", (stream->words[1] >> 30) & 1, NULL, 10); + ui->add_field(ui, ib_addr + 12, ib_vmid, "SRC_ADDR_LO", stream->words[2], NULL, 16); + ui->add_field(ui, ib_addr + 16, ib_vmid, "SRC_ADDR_HI", stream->words[3], NULL, 16); + ui->add_field(ui, ib_addr + 20, ib_vmid, "DST_ADDR_LO", stream->words[4], NULL, 16); + ui->add_field(ui, ib_addr + 24, ib_vmid, "DST_ADDR_HI", stream->words[5], NULL, 16); + break; + default: // broadcast + break; + } + break; + case 1: // TILED + break; + case 3: // SOA + break; + case 4: // LINEAR_SUB_WINDOW + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "COPY (LINEAR_SUB_WINDOW)"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "SRC_ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "SRC_ADDR_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "SRC_X", (stream->words[2] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 12, ib_vmid, "SRC_X", (stream->words[2] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 16, ib_vmid, "SRC_Z", (stream->words[3] >> 0) & 0x7FF, NULL, 10); + ui->add_field(ui, ib_addr + 16, ib_vmid, "SRC_PITCH", (stream->words[3] >> 16) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 20, ib_vmid, "SRC_SLICE_PITCH", stream->words[4] & 0xFFFFFFF, NULL, 10); + + ui->add_field(ui, ib_addr + 24, ib_vmid, "DST_ADDR_LO", stream->words[5], NULL, 16); + ui->add_field(ui, ib_addr + 28, ib_vmid, "DST_ADDR_HI", stream->words[6], NULL, 16); + ui->add_field(ui, ib_addr + 32, ib_vmid, "DST_X", (stream->words[7] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 32, ib_vmid, "DST_X", (stream->words[7] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 36, ib_vmid, "DST_Z", (stream->words[8] >> 0) & 0x7FF, NULL, 10); + ui->add_field(ui, ib_addr + 36, ib_vmid, "DST_PITCH", (stream->words[8] >> 16) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 40, ib_vmid, "DST_SLICE_PITCH", stream->words[9] & 0xFFFFFFF, NULL, 10); + + ui->add_field(ui, ib_addr + 44, ib_vmid, "RECT_X", (stream->words[10] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 44, ib_vmid, "RECT_Y", (stream->words[10] >> 16) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "RECT_Z", (stream->words[11] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "DST_SW", (stream->words[11] >> 16) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "DST_HA", (stream->words[11] >> 22) & 0x1, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "SRC_SW", (stream->words[11] >> 24) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "SRC_HA", (stream->words[11] >> 30) & 0x1, NULL, 10); + break; + case 5: // TILED_SUB_WINDOW (TODO bitfields) + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "COPY (TILED_SUB_WINDOW)"); + ui->add_field(ui, ib_addr + 0, ib_vmid, "DETILED", stream->header_dw >> 31, NULL, 16); + ui->add_field(ui, ib_addr + 4, ib_vmid, "TILED_ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "TILED_ADDR_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "TILED_X", (stream->words[2] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 12, ib_vmid, "TILED_X", (stream->words[2] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 16, ib_vmid, "TILED_Z", (stream->words[3] >> 0) & 0x7FF, NULL, 10); + ui->add_field(ui, ib_addr + 16, ib_vmid, "TILED_PITCH", (stream->words[3] >> 16) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 20, ib_vmid, "PITCH_IN_TILE", stream->words[4] & 0xFFFFFFF, NULL, 10); + + ui->add_field(ui, ib_addr + 24, ib_vmid, "ELEMENT_SIZE", (stream->words[5] >> 0) & 0x7, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "ARRAY_MODE", (stream->words[5] >> 3) & 0xF, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "MIT_MODE", (stream->words[5] >> 8) & 0x7, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "TILESPLIT_SIZE", (stream->words[5] >> 11) & 0x7, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "BANK_W", (stream->words[5] >> 15) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "BANK_H", (stream->words[5] >> 18) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "NUM_BANK", (stream->words[5] >> 21) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "MAT_ASPT", (stream->words[5] >> 24) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "PIPE_CONFIG", (stream->words[5] >> 26) & 0x1F, NULL, 10); + + ui->add_field(ui, ib_addr + 28, ib_vmid, "LINEAR_ADDR_LO", stream->words[6], NULL, 16); + ui->add_field(ui, ib_addr + 32, ib_vmid, "LINEAR_ADDR_HI", stream->words[7], NULL, 16); + + ui->add_field(ui, ib_addr + 36, ib_vmid, "LINEAR_X", (stream->words[8] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 36, ib_vmid, "LINEAR_Y", (stream->words[8] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 40, ib_vmid, "LINEAR_Z", (stream->words[9] >> 0) & 0x7FF, NULL, 10); + ui->add_field(ui, ib_addr + 40, ib_vmid, "LINEAR_PITCH", (stream->words[9] >> 16) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 44, ib_vmid, "LINEAR_SLICE_PITCH", stream->words[10] & 0xFFFFFFF, NULL, 10); + + ui->add_field(ui, ib_addr + 48, ib_vmid, "RECT_X", (stream->words[11] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "RECT_Y", (stream->words[11] >> 16) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 52, ib_vmid, "RECT_Z", (stream->words[12] >> 0) & 0x7FF, NULL, 10); + ui->add_field(ui, ib_addr + 52, ib_vmid, "LINEAR_SW", (stream->words[12] >> 16) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 52, ib_vmid, "TILE_SW", (stream->words[12] >> 22) & 0x3, NULL, 10); + break; + case 6: // T2T_SUB_WINDOW + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "COPY (T2T_SUB_WINDOW)"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "SRC_ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "SRC_ADDR_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "SRC_X", (stream->words[2] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 12, ib_vmid, "SRC_X", (stream->words[2] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 16, ib_vmid, "SRC_Z", (stream->words[3] >> 0) & 0x7FF, NULL, 10); + ui->add_field(ui, ib_addr + 16, ib_vmid, "SRC_PITCH", (stream->words[3] >> 16) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 20, ib_vmid, "SRC_SLICE_PITCH", stream->words[4] & 0xFFFFFFF, NULL, 10); + + ui->add_field(ui, ib_addr + 24, ib_vmid, "SRC_ELEMENT_SIZE", (stream->words[5] >> 0) & 0x7, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "SRC_ARRAY_MODE", (stream->words[5] >> 3) & 0xF, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "SRC_MIT_MODE", (stream->words[5] >> 8) & 0x7, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "SRC_TILESPLIT_SIZE", (stream->words[5] >> 11) & 0x7, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "SRC_BANK_W", (stream->words[5] >> 15) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "SRC_BANK_H", (stream->words[5] >> 18) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "NUM_BANKS", (stream->words[5] >> 21) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "MAT_ASPT", (stream->words[5] >> 24) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 24, ib_vmid, "PIPE_CONFIG", (stream->words[5] >> 26) & 0x1F, NULL, 10); + + ui->add_field(ui, ib_addr + 28, ib_vmid, "DST_ADDR_LO", stream->words[6], NULL, 16); + ui->add_field(ui, ib_addr + 32, ib_vmid, "DST_ADDR_HI", stream->words[7], NULL, 16); + ui->add_field(ui, ib_addr + 36, ib_vmid, "DW9", stream->words[8], NULL, 16); + + ui->add_field(ui, ib_addr + 40, ib_vmid, "DST_Z", (stream->words[9] >> 0) & 0x7FF, NULL, 10); + ui->add_field(ui, ib_addr + 40, ib_vmid, "DST_PITCH", (stream->words[9] >> 16) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 44, ib_vmid, "DST_SLICE_PITCH", stream->words[10] & 0xFFFFFFF, NULL, 10); + + ui->add_field(ui, ib_addr + 48, ib_vmid, "ARRAY_MODE", (stream->words[11] >> 3) & 0xF, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "MIT_MODE", (stream->words[11] >> 8) & 0x7, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "TILESPLIT_SIZE", (stream->words[11] >> 11) & 0x7, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "BANK_W", (stream->words[11] >> 15) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "BANK_H", (stream->words[11] >> 18) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "NUM_BANK", (stream->words[11] >> 21) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "MAT_ASPT", (stream->words[11] >> 24) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 48, ib_vmid, "PIPE_CONFIG", (stream->words[11] >> 26) & 0x1F, NULL, 10); + + ui->add_field(ui, ib_addr + 52, ib_vmid, "RECT_X", (stream->words[12] >> 0) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 52, ib_vmid, "RECT_Y", (stream->words[12] >> 16) & 0x3FFF, NULL, 10); + ui->add_field(ui, ib_addr + 56, ib_vmid, "RECT_Z", (stream->words[13] >> 0) & 0x7FF, NULL, 10); + ui->add_field(ui, ib_addr + 56, ib_vmid, "DST_SW", (stream->words[13] >> 16) & 0x3, NULL, 10); + ui->add_field(ui, ib_addr + 56, ib_vmid, "SRC_SW", (stream->words[13] >> 22) & 0x3, NULL, 10); + break; + } + break; + case 2: // WRITE + switch (stream->sub_opcode) { + case 0: // LINEAR + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "WRITE (LINEAR)"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "DST_ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "DST_ADDR_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "COUNT", stream->words[2], NULL, 10); + for (n = 3; n < stream->nwords; n++) + ui->add_field(ui, ib_addr + 16 + 4 * (n - 3), ib_vmid, "DATA", stream->words[n], NULL, 16); + break; + case 1: // TILED (TODO bit decodings...) + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "WRITE (TILED)"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "DST_ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "DST_ADDR_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "DW3", stream->words[2], NULL, 16); + ui->add_field(ui, ib_addr + 16, ib_vmid, "DW4", stream->words[3], NULL, 16); + ui->add_field(ui, ib_addr + 20, ib_vmid, "DW5", stream->words[4], NULL, 16); + ui->add_field(ui, ib_addr + 24, ib_vmid, "DW6", stream->words[5], NULL, 16); + ui->add_field(ui, ib_addr + 28, ib_vmid, "DW7", stream->words[6], NULL, 16); + break; + } + break; + case 4: // INDIRECT + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "INDIRECT_BUFFER"); + ui->add_field(ui, ib_addr + 0, ib_vmid, "VMID", (stream->header_dw >> 16) & 0xF, NULL, 16); + ui->add_field(ui, ib_addr + 4, ib_vmid, "IB_BASE_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "IB_BASE_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "IB_BASE_SIZE", stream->words[2], NULL, 10); + ui->add_field(ui, ib_addr + 16, ib_vmid, "IB_CSA_ADDR_LO", stream->words[3], NULL, 16); + ui->add_field(ui, ib_addr + 20, ib_vmid, "IB_CSA_ADDR_HI", stream->words[4], NULL, 16); + if (follow && stream->next_ib) + umr_sdma_decode_stream_opcodes(asic, ui, stream->next_ib, stream->ib.addr, stream->ib.vmid, ib_addr, ib_vmid, ~0UL, 1); + break; + case 5: // FENCE + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "FENCE"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "FENCE_ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "FENCE_ADDR_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "FENCE_DATA", stream->words[2], NULL, 16); + break; + case 6: // TRAP + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "TRAP"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "TRAP_INT_CONTEXT", stream->words[0] & 0xFFFFFF, NULL, 16); + break; + case 7: // SEM + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "SEM"); + ui->add_field(ui, ib_addr + 0, ib_vmid, "WRITE_ONE", (stream->header_dw >> 29) & 1, NULL, 16); + ui->add_field(ui, ib_addr + 0, ib_vmid, "SIGNAL", (stream->header_dw >> 30) & 1, NULL, 16); + ui->add_field(ui, ib_addr + 0, ib_vmid, "MAILBOX", (stream->header_dw >> 31) & 1, NULL, 16); + ui->add_field(ui, ib_addr + 4, ib_vmid, "SEMAPHORE_ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "SEMAPHORE_ADDR_HI", stream->words[1], NULL, 16); + break; + case 8: // POLL_REGMEM + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "WAIT_REG_MEM"); + ui->add_field(ui, ib_addr + 0, ib_vmid, "HDP_FLUSH", (stream->header_dw >> 26) & 1, NULL, 16); + ui->add_field(ui, ib_addr + 0, ib_vmid, "FUNCTION", 0, poll_regmem_funcs[(stream->header_dw >> 28) & 7], 0); + ui->add_field(ui, ib_addr + 0, ib_vmid, "MEM_POLL", (stream->header_dw >> 31) & 1, NULL, 16); + switch (stream->sub_opcode) { + case 0: // WAIT_REG_MEM + if (!(stream->header_dw & (1UL << 31))) { + ui->add_field(ui, ib_addr + 4, ib_vmid, "POLL_REGMEM_ADDR_LO", 0, umr_reg_name(asic, stream->words[0]), 0); + ui->add_field(ui, ib_addr + 8, ib_vmid, "POLL_REGMEM_ADDR_HI", 0, umr_reg_name(asic, stream->words[1]), 0); + } else { + ui->add_field(ui, ib_addr + 4, ib_vmid, "POLL_REGMEM_ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "POLL_REGMEM_ADDR_HI", stream->words[1], NULL, 16); + } + ui->add_field(ui, ib_addr + 8, ib_vmid, "POLL_REGMEM_ADDR_VALUE", stream->words[2], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "POLL_REGMEM_ADDR_MASK", stream->words[3], NULL, 16); + ui->add_field(ui, ib_addr + 16, ib_vmid, "POLL_REGMEM_ADDR_DW5", stream->words[4], NULL, 16); + break; + case 1: // WRITE WAIT_REG_MEM + ui->add_field(ui, ib_addr + 4, ib_vmid, "SRC_ADDR", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "DST_ADDR_LO", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "DST_ADDR_HI", stream->words[2], NULL, 16); + break; + } + break; + case 9: // COND_EXE + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "COND_EXE"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "ADDR_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "REFERENCE", stream->words[2], NULL, 16); + ui->add_field(ui, ib_addr + 16, ib_vmid, "EXEC_COUNT", stream->words[3], NULL, 10); + break; + case 10: // ATOMIC + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "ATOMIC"); + ui->add_field(ui, ib_addr + 0, ib_vmid, "LOOP", (stream->header_dw >> 16) & 1, NULL, 16); + ui->add_field(ui, ib_addr + 0, ib_vmid, "OP", (stream->header_dw >> 25) & 0x7F, NULL, 16); + ui->add_field(ui, ib_addr + 4, ib_vmid, "ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "ADDR_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "SRC_DATA_LO", stream->words[2], NULL, 16); + ui->add_field(ui, ib_addr + 16, ib_vmid, "SRC_DATA_HI", stream->words[3], NULL, 16); + ui->add_field(ui, ib_addr + 20, ib_vmid, "CMP_DATA_LO", stream->words[4], NULL, 16); + ui->add_field(ui, ib_addr + 24, ib_vmid, "CMP_DATA_HI", stream->words[5], NULL, 16); + ui->add_field(ui, ib_addr + 28, ib_vmid, "LOOP_INTERVAL", stream->words[6] & 0x1FFF, NULL, 16); + break; + case 11: // CONST_FILL + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "CONST_FILL"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "CONST_FILL_DST_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "CONST_FILL_DST_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "CONST_FILL_DATA", stream->words[2], NULL, 16); + ui->add_field(ui, ib_addr + 16, ib_vmid, "CONST_FILL_BYTE_COUNT", stream->words[3], NULL, 10); + break; + case 12: // GEN_PTEPDE + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "GEN_PTEPDE"); + ui->add_field(ui, ib_addr + 4, ib_vmid, "GEN_PTEPDE_PE_ADDR_LO", stream->words[0], NULL, 16); + ui->add_field(ui, ib_addr + 8, ib_vmid, "GEN_PTEPDE_PE_ADDR_HI", stream->words[1], NULL, 16); + ui->add_field(ui, ib_addr + 12, ib_vmid, "GEN_PTEPDE_FLAGS_LO", stream->words[2], NULL, 16); + ui->add_field(ui, ib_addr + 16, ib_vmid, "GEN_PTEPDE_FLAGS_HI", stream->words[3], NULL, 16); + ui->add_field(ui, ib_addr + 20, ib_vmid, "GEN_PTEPDE_ADDR_LO", stream->words[4], NULL, 16); + ui->add_field(ui, ib_addr + 24, ib_vmid, "GEN_PTEPDE_ADDR_HI", stream->words[5], NULL, 16); + ui->add_field(ui, ib_addr + 28, ib_vmid, "GEN_PTEPDE_INC_SIZE", stream->words[6], NULL, 16); + ui->add_field(ui, ib_addr + 32, ib_vmid, "GEN_PTEPDE_DW8", stream->words[7], NULL, 16); + ui->add_field(ui, ib_addr + 36, ib_vmid, "GEN_PTEPDE_COUNT", stream->words[8], NULL, 10); + break; + case 14: // SRBM_WRITE + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "SRBM_WRITE"); + if (asic->family <= FAMILY_VI) + ui->add_field(ui, ib_addr + 4, ib_vmid, "SRBM_WRITE_ADDR", 0, umr_reg_name(asic, stream->words[0] & 0xFFFF), 0); + else + ui->add_field(ui, ib_addr + 4, ib_vmid, "SRBM_WRITE_ADDR", 0, umr_reg_name(asic, stream->words[0] & 0x3FFFF), 0); + ui->add_field(ui, ib_addr + 8, ib_vmid, "SRBM_WRITE_DATA", stream->words[1], NULL, 16); + break; + case 15: // PRE_EXE + ui->start_opcode(ui, ib_addr, ib_vmid, stream->opcode, stream->sub_opcode, stream->nwords + 1, "PRE_EXE"); + ui->add_field(ui, ib_addr + 0, ib_vmid, "DEV_SEL", (stream->header_dw >> 16) & 0xFF, NULL, 10); + ui->add_field(ui, ib_addr + 4, ib_vmid, "EXEC_COUNT", stream->words[0] & 0x3FFF, NULL, 10); + break; + default: + if (ui->unhandled) + ui->unhandled(ui, asic, ib_addr, ib_vmid, stream); + break; + } + + ib_addr += (1 + stream->nwords) * 4; + stream = stream->next; + } + ui->done(ui); + return stream; +} + +// used for testing leave disabled for normal builds +#if 0 + +// example opaque data to keep track of offsets +struct demo_ui_data { + uint64_t off[16]; // address of start of IB so we can compute offsets when printing opcodes/fields + int i; +}; + +static void start_ib(struct umr_sdma_stream_decode_ui *ui, uint64_t ib_addr, uint32_t ib_vmid, uint64_t from_addr, uint32_t from_vmid, uint32_t size) +{ + struct demo_ui_data *data = ui->data; + data->off[data->i++] = ib_addr; + printf("Decoding IB at %lu@0x%llx from %lu@0x%llx of %lu words\n", (unsigned long)ib_vmid, (unsigned long long)ib_addr, (unsigned long)from_vmid, (unsigned long long)from_addr, (unsigned long)size); +} +static void start_opcode(struct umr_sdma_stream_decode_ui *ui, uint64_t ib_addr, uint32_t ib_vmid, uint32_t opcode, uint32_t sub_opcode, uint32_t nwords, char *opcode_name) +{ + struct demo_ui_data *data = ui->data; + printf("Opcode 0x%lx [%s] at %lu@[0x%llx + 0x%llx] (%lu words)\n", (unsigned long)opcode, opcode_name, (unsigned long)ib_vmid, (unsigned long long)data->off[data->i - 1], (unsigned long long)ib_addr - data->off[data->i - 1], (unsigned long)nwords); + fflush(stdout); +} +static void add_field(struct umr_sdma_stream_decode_ui *ui, uint64_t ib_addr, uint32_t ib_vmid, const char *field_name, uint64_t value, char *str, int ideal_radix) +{ + struct demo_ui_data *data = ui->data; + printf("\t[%lu@0x%llx + 0x%llx] -- %s == ", (unsigned long)ib_vmid, (unsigned long long)data->off[data->i - 1], (unsigned long long)ib_addr - data->off[data->i - 1], field_name); + + if (str) { + printf("[%s]", str); + } else { + switch (ideal_radix) { + case 10: printf("%llu", (unsigned long long)value); break; + case 16: printf("0x%llx", (unsigned long long)value); break; + } + } + printf("\n"); + fflush(stdout); +} + +static void unhandled(struct umr_sdma_stream_decode_ui *ui, struct umr_asic *asic, uint64_t ib_addr, uint32_t ib_vmid, struct umr_sdma_stream *stream) +{ +} + +static void done(struct umr_sdma_stream_decode_ui *ui) +{ + struct demo_ui_data *data = ui->data; + data->i--; + + printf("Done decoding IB\n"); +} + +static struct umr_sdma_stream_decode_ui demo_ui = { start_ib, start_opcode, add_field, unhandled, done, NULL }; + +/** demo */ +int umr__demo(struct umr_asic *asic) +{ + struct umr_sdma_stream *stream, *sstream; + struct umr_sdma_stream_decode_ui myui; + myui = demo_ui; + + // assign our opaque structure + myui.data = calloc(1, sizeof(struct demo_ui_data)); + +while (1) { + memset(myui.data, 0, sizeof(struct demo_ui_data)); + stream = umr_sdma_decode_ring(asic, "sdma0"); + if (stream) { + sstream = umr_sdma_decode_stream_opcodes(asic, &myui, stream, 0, 0, 0, 0, ~0UL, 1); + // printf("\nand now the rest...\n"); + // umr_sdma_decode_stream_opcodes(asic, &myui, sstream, 0, 0, 0, 0, ~0UL, 1); + umr_free_sdma_stream(stream); + } +} + + free(myui.data); +} + + +#endif @@ -685,6 +685,7 @@ void *umr_read_ring_data(struct umr_asic *asic, char *ringname, uint32_t *ringsi struct umr_pm4_stream *umr_pm4_decode_ring(struct umr_asic *asic, char *ringname, int no_halt); struct umr_pm4_stream *umr_pm4_decode_stream(struct umr_asic *asic, int vmid, uint32_t *stream, uint32_t nwords); void umr_free_pm4_stream(struct umr_pm4_stream *stream); + struct umr_shaders_pgm *umr_find_shader_in_stream(struct umr_pm4_stream *stream, unsigned vmid, uint64_t addr); struct umr_shaders_pgm *umr_find_shader_in_ring(struct umr_asic *asic, char *ringname, unsigned vmid, uint64_t addr, int no_halt); int umr_pm4_decode_ring_is_halted(struct umr_asic *asic, char *ringname); @@ -742,6 +743,71 @@ struct umr_pm4_stream_decode_ui { struct umr_pm4_stream *umr_pm4_decode_stream_opcodes(struct umr_asic *asic, struct umr_pm4_stream_decode_ui *ui, struct umr_pm4_stream *stream, uint64_t ib_addr, uint32_t ib_vmid, uint64_t from_addr, uint64_t from_vmid, unsigned long opcodes, int follow); int umr_pm4_decode_opcodes_ib(struct umr_asic *asic, struct umr_pm4_stream_decode_ui *ui, uint64_t ib_addr, uint32_t ib_vmid, uint32_t nwords, uint64_t from_addr, uint64_t from_ib, unsigned long opcodes, int follow); +/* SDMA decoding */ +struct umr_sdma_stream { + uint32_t + opcode, + sub_opcode, + nwords, + header_dw, + *words; + + struct { + uint32_t vmid, size; + uint64_t addr; + } ib; + + struct umr_sdma_stream *next, *next_ib; +}; + +struct umr_sdma_stream *umr_sdma_decode_ring(struct umr_asic *asic, char *ringname); +struct umr_sdma_stream *umr_sdma_decode_stream(struct umr_asic *asic, int vmid, uint32_t *stream, uint32_t nwords); +void umr_free_sdma_stream(struct umr_sdma_stream *stream); + +struct umr_sdma_stream_decode_ui { + + /** start_ib -- Start a new IB + * ib_addr/ib_vmid: Address of the IB + * from_addr/from_vmid: Where does this reference come from? + * size: size of IB in DWORDs + */ + void (*start_ib)(struct umr_sdma_stream_decode_ui *ui, uint64_t ib_addr, uint32_t ib_vmid, uint64_t from_addr, uint32_t from_vmid, uint32_t size); + + /** start_opcode -- Start a new opcode + * ib_addr/ib_vmid: Address of where packet is found + * opcode: The numeric value of the ocpode + * nwords: number of DWORDS in this opcode + * opcode_name: Printable string name of opcode + */ + void (*start_opcode)(struct umr_sdma_stream_decode_ui *ui, uint64_t ib_addr, uint32_t ib_vmid, uint32_t opcode, uint32_t sub_opcode, uint32_t nwords, char *opcode_name); + + /** add_field -- Add a decoded field to a specific DWORD + * ib_addr/ib_vmid: Address of the word from which the field comes + * field_name: printable name of the field + * value: Value of the field + * ideal_radix: (10 decimal, 16 hex) + */ + void (*add_field)(struct umr_sdma_stream_decode_ui *ui, uint64_t ib_addr, uint32_t ib_vmid, const char *field_name, uint64_t value, char *str, int ideal_radix); + + /** unhandled -- Decoder for unhandled (private) opcodes + * asic: The ASIC the IB stream is bound to + * ib_addr:ib_vmid: The address where the sdma opcode comes from + * stream: The pointer to the current stream opcode being handled + * + * Can be NULL to drop support for unhandled opcodes. + */ + void (*unhandled)(struct umr_sdma_stream_decode_ui *ui, struct umr_asic *asic, uint64_t ib_addr, uint32_t ib_vmid, struct umr_sdma_stream *stream); + + void (*done)(struct umr_sdma_stream_decode_ui *ui); + + /** data -- opaque pointer that can be used to track state information */ + void *data; +}; + +struct umr_sdma_stream *umr_sdma_decode_stream_opcodes(struct umr_asic *asic, struct umr_sdma_stream_decode_ui *ui, struct umr_sdma_stream *stream, uint64_t ib_addr, uint32_t ib_vmid, uint64_t from_addr, uint64_t from_vmid, unsigned long opcodes, int follow); + +// various low level functions + void umr_print_decode(struct umr_asic *asic, struct umr_ring_decoder *decoder, uint32_t ib); void umr_dump_ib(struct umr_asic *asic, struct umr_ring_decoder *decoder); void umr_dump_shaders(struct umr_asic *asic, struct umr_ring_decoder *decoder, struct umr_wave_data *wd); |