summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom St Denis <tom.stdenis@amd.com>2019-01-17 09:52:17 -0500
committerTom St Denis <tom.stdenis@amd.com>2019-01-19 15:32:45 -0500
commita3af62e397451c832da834feb070b3d25a8306b2 (patch)
treeb284fa84aca704a27d330dafd2e4a3aadbdeab97
parentd17db20f8f22607d4102a71de2655342d2130b80 (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.txt2
-rw-r--r--src/lib/ring_decode.c34
-rw-r--r--src/lib/umr_read_sdma_stream.c228
-rw-r--r--src/lib/umr_sdma_decode_opcodes.c395
-rw-r--r--src/umr.h66
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
diff --git a/src/umr.h b/src/umr.h
index 49da519..6563730 100644
--- a/src/umr.h
+++ b/src/umr.h
@@ -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);