Mesa (main): freedreno/crashdec: HFI queue decoding
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Wed Dec 1 18:20:52 UTC 2021
Module: Mesa
Branch: main
Commit: f33d5256dd15dbbe9ebea9c2efe554f2e595de21
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=f33d5256dd15dbbe9ebea9c2efe554f2e595de21
Author: Rob Clark <robdclark at chromium.org>
Date: Mon Nov 22 15:21:08 2021 -0800
freedreno/crashdec: HFI queue decoding
Signed-off-by: Rob Clark <robdclark at chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13937>
---
src/freedreno/decode/crashdec-hfi.c | 523 ++++++++++++++++++++++++++++++++++++
src/freedreno/decode/crashdec.c | 47 ++++
src/freedreno/decode/crashdec.h | 21 ++
src/freedreno/decode/meson.build | 1 +
4 files changed, 592 insertions(+)
diff --git a/src/freedreno/decode/crashdec-hfi.c b/src/freedreno/decode/crashdec-hfi.c
new file mode 100644
index 00000000000..f777ece3d25
--- /dev/null
+++ b/src/freedreno/decode/crashdec-hfi.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright © 2021 Google, 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 (including the next
+ * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include "util/macros.h"
+#include "crashdec.h"
+
+static const char *hfi_msg_name(unsigned msgid);
+
+/*
+ * Decode HFI queues
+ */
+
+/* HFI message types */
+
+#define HFI_MSG_CMD 0
+#define HFI_MSG_ACK 1
+#define HFI_MSG_ACK_V1 2
+
+#define HFI_HEADER_ID(msg) ((msg) & 0xff)
+/* Note that header size includes the header itself: */
+#define HFI_HEADER_SIZE(msg) (((msg) >> 8) & 0xff)
+#define HFI_HEADER_TYPE(msg) (((msg) >> 16) & 0xf)
+#define HFI_HEADER_SEQNUM(msg) (((msg) >> 20) & 0xfff)
+
+struct a6xx_hfi_queue_header {
+ uint32_t status;
+ uint32_t iova;
+ uint32_t type;
+ uint32_t size;
+ uint32_t msg_size;
+ uint32_t dropped;
+ uint32_t rx_watermark;
+ uint32_t tx_watermark;
+ uint32_t rx_request;
+ uint32_t tx_request;
+ uint32_t read_index;
+ uint32_t write_index;
+};
+
+struct a6xx_hfi_queue_table_header {
+ uint32_t version;
+ uint32_t size; /* Size of the queue table in dwords */
+ uint32_t qhdr0_offset; /* Offset of the first queue header */
+ uint32_t qhdr_size; /* Size of the queue headers */
+ uint32_t num_queues; /* Number of total queues */
+ uint32_t active_queues; /* Number of active queues */
+ struct a6xx_hfi_queue_header queue[];
+};
+
+/*
+ * HFI message definitions:
+ */
+
+#define HFI_F2H_MSG_ACK 126
+
+struct a6xx_hfi_msg_response {
+ uint32_t header;
+ uint32_t ret_header;
+ uint32_t error;
+ uint32_t payload[16];
+};
+
+static void
+decode_F2H_MSG_ACK(struct a6xx_hfi_msg_response *msg)
+{
+ unsigned msgid = HFI_HEADER_ID(msg->ret_header);
+
+ printf("\t\t\t\tret_header: %s (id=%u, size=%u, type=%u, seqnum=%u)\n",
+ hfi_msg_name(msgid), msgid, HFI_HEADER_SIZE(msg->ret_header),
+ HFI_HEADER_TYPE(msg->ret_header), HFI_HEADER_SEQNUM(msg->ret_header));
+ printf("\t\t\t\terror: %u\n", msg->error);
+}
+
+#define HFI_F2H_MSG_ERROR 100
+
+struct a6xx_hfi_msg_error {
+ uint32_t header;
+ uint32_t code;
+ uint32_t payload[2];
+};
+
+static void
+decode_F2H_MSG_ERROR(struct a6xx_hfi_msg_error *msg)
+{
+ printf("\t\t\t\tcode: %u\n", msg->code);
+}
+
+#define HFI_H2F_MSG_INIT 0
+
+struct a6xx_hfi_msg_gmu_init_cmd {
+ uint32_t header;
+ uint32_t seg_id;
+ uint32_t dbg_buffer_addr;
+ uint32_t dbg_buffer_size;
+ uint32_t boot_state;
+};
+
+static void
+decode_H2F_MSG_INIT(struct a6xx_hfi_msg_gmu_init_cmd *msg)
+{
+ printf("\t\t\t\tseg_id: %u\n", msg->seg_id);
+ printf("\t\t\t\tdbg_buffer_addr: 0x%08x\n", msg->dbg_buffer_addr);
+ printf("\t\t\t\tdbg_buffer_size: %u\n", msg->dbg_buffer_size);
+ printf("\t\t\t\tboot_state: %u\n", msg->boot_state);
+}
+
+#define HFI_H2F_MSG_FW_VERSION 1
+
+struct a6xx_hfi_msg_fw_version {
+ uint32_t header;
+ uint32_t supported_version;
+};
+
+static void
+decode_H2F_MSG_FW_VERSION(struct a6xx_hfi_msg_fw_version *msg)
+{
+ printf("\t\t\t\tsupported_version: 0x%x\n", msg->supported_version);
+}
+
+#define HFI_H2F_MSG_PERF_TABLE 4
+
+struct perf_level {
+ uint32_t vote;
+ uint32_t freq;
+};
+
+struct perf_gx_level {
+ uint32_t vote;
+ uint32_t acd;
+ uint32_t freq;
+};
+
+struct a6xx_hfi_msg_perf_table_v1 {
+ uint32_t header;
+ uint32_t num_gpu_levels;
+ uint32_t num_gmu_levels;
+
+ struct perf_level gx_votes[16];
+ struct perf_level cx_votes[4];
+};
+
+struct a6xx_hfi_msg_perf_table {
+ uint32_t header;
+ uint32_t num_gpu_levels;
+ uint32_t num_gmu_levels;
+
+ struct perf_gx_level gx_votes[16];
+ struct perf_level cx_votes[4];
+};
+
+static void
+decode_H2F_MSG_PERF_TABLE(void *_msg)
+{
+ if (is_gmu_legacy()) {
+ struct a6xx_hfi_msg_perf_table_v1 *msg = _msg;
+ unsigned i;
+
+ printf("\t\t\t\tnum_gpu_levels: %u\n", msg->num_gpu_levels);
+ printf("\t\t\t\tnum_gmu_levels: %u\n", msg->num_gmu_levels);
+
+ assert(msg->num_gpu_levels <= ARRAY_SIZE(msg->gx_votes));
+ for (i = 0; i < msg->num_gpu_levels; i++) {
+ printf("\t\t\t\tgx_vote[%u]: vote=%u, freq=%u\n", i,
+ msg->gx_votes[i].vote, msg->gx_votes[i].freq);
+ }
+
+ for (; i < ARRAY_SIZE(msg->gx_votes); i++) {
+ assert(!msg->gx_votes[i].vote);
+ assert(!msg->gx_votes[i].freq);
+ }
+
+ assert(msg->num_gmu_levels <= ARRAY_SIZE(msg->cx_votes));
+ for (i = 0; i < msg->num_gmu_levels; i++) {
+ printf("\t\t\t\tcx_vote[%u]: vote=%u, freq=%u\n", i,
+ msg->cx_votes[i].vote, msg->cx_votes[i].freq);
+ }
+
+ for (; i < ARRAY_SIZE(msg->cx_votes); i++) {
+ assert(!msg->cx_votes[i].vote);
+ assert(!msg->cx_votes[i].freq);
+ }
+ } else {
+ struct a6xx_hfi_msg_perf_table *msg = _msg;
+ unsigned i;
+
+ printf("\t\t\t\tnum_gpu_levels: %u\n", msg->num_gpu_levels);
+ printf("\t\t\t\tnum_gmu_levels: %u\n", msg->num_gmu_levels);
+
+ assert(msg->num_gpu_levels <= ARRAY_SIZE(msg->gx_votes));
+ for (i = 0; i < msg->num_gpu_levels; i++) {
+ printf("\t\t\t\tgx_vote[%u]: vote=%u, acd=%u, freq=%u\n", i,
+ msg->gx_votes[i].vote, msg->gx_votes[i].acd,
+ msg->gx_votes[i].freq);
+ }
+
+ for (; i < ARRAY_SIZE(msg->gx_votes); i++) {
+ assert(!msg->gx_votes[i].vote);
+ assert(!msg->gx_votes[i].acd);
+ assert(!msg->gx_votes[i].freq);
+ }
+
+ assert(msg->num_gmu_levels <= ARRAY_SIZE(msg->cx_votes));
+ for (i = 0; i < msg->num_gmu_levels; i++) {
+ printf("\t\t\t\tcx_vote[%u]: vote=%u, freq=%u\n", i,
+ msg->cx_votes[i].vote, msg->cx_votes[i].freq);
+ }
+
+ for (; i < ARRAY_SIZE(msg->cx_votes); i++) {
+ assert(!msg->cx_votes[i].vote);
+ assert(!msg->cx_votes[i].freq);
+ }
+ }
+}
+
+#define HFI_H2F_MSG_BW_TABLE 3
+
+struct a6xx_hfi_msg_bw_table {
+ uint32_t header;
+ uint32_t bw_level_num;
+ uint32_t cnoc_cmds_num;
+ uint32_t ddr_cmds_num;
+ uint32_t cnoc_wait_bitmask;
+ uint32_t ddr_wait_bitmask;
+ uint32_t cnoc_cmds_addrs[6];
+ uint32_t cnoc_cmds_data[2][6];
+ uint32_t ddr_cmds_addrs[8];
+ uint32_t ddr_cmds_data[16][8];
+};
+
+static void
+decode_H2F_MSG_BW_TABLE(struct a6xx_hfi_msg_bw_table *msg)
+{
+ printf("\t\t\t\tbw_level_num: %u\n", msg->bw_level_num);
+ printf("\t\t\t\tcnoc_cmds_num: %u\n", msg->cnoc_cmds_num);
+ printf("\t\t\t\tddr_cmds_num: %u\n", msg->ddr_cmds_num);
+ printf("\t\t\t\tcnoc_wait_bitmask: 0x%x\n", msg->cnoc_wait_bitmask);
+ printf("\t\t\t\tddr_wait_bitmask: 0x%x\n", msg->ddr_wait_bitmask);
+ printf("\t\t\t\tcnoc_cmds_addrs: %08x %08x %08x %08x %08x %08x\n",
+ msg->cnoc_cmds_addrs[0], msg->cnoc_cmds_addrs[1], msg->cnoc_cmds_addrs[2],
+ msg->cnoc_cmds_addrs[3], msg->cnoc_cmds_addrs[4], msg->cnoc_cmds_addrs[5]);
+ for (unsigned i = 0; i < ARRAY_SIZE(msg->cnoc_cmds_data); i++) {
+ printf("\t\t\t\tcnoc_cmds_data[%u]: %08x %08x %08x %08x %08x %08x\n", i,
+ msg->cnoc_cmds_data[i][0], msg->cnoc_cmds_data[i][1], msg->cnoc_cmds_data[i][2],
+ msg->cnoc_cmds_data[i][3], msg->cnoc_cmds_data[i][4], msg->cnoc_cmds_data[i][5]);
+ }
+ printf("\t\t\t\tddr_cmds_addrs: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ msg->ddr_cmds_addrs[0], msg->ddr_cmds_addrs[1], msg->ddr_cmds_addrs[2],
+ msg->ddr_cmds_addrs[3], msg->ddr_cmds_addrs[4], msg->ddr_cmds_addrs[5],
+ msg->ddr_cmds_addrs[6], msg->ddr_cmds_addrs[7]);
+ for (unsigned i = 0; i < ARRAY_SIZE(msg->ddr_cmds_data); i++) {
+ printf("\t\t\t\tddr_cmds_data[%u]: %08x %08x %08x %08x %08x %08x %08x %08x\n", i,
+ msg->ddr_cmds_data[i][0], msg->ddr_cmds_data[i][1], msg->ddr_cmds_data[i][2],
+ msg->ddr_cmds_data[i][3], msg->ddr_cmds_data[i][4], msg->ddr_cmds_data[i][5],
+ msg->ddr_cmds_data[i][6], msg->ddr_cmds_data[i][7]);
+ }
+}
+
+#define HFI_H2F_MSG_TEST 5
+
+struct a6xx_hfi_msg_test {
+ uint32_t header;
+};
+
+static void
+decode_H2F_MSG_TEST(struct a6xx_hfi_msg_test *msg)
+{
+}
+
+#define HFI_H2F_MSG_START 10
+
+struct a6xx_hfi_msg_start {
+ uint32_t header;
+};
+
+static void
+decode_H2F_MSG_START(struct a6xx_hfi_msg_start *msg)
+{
+}
+
+#define HFI_H2F_MSG_CORE_FW_START 14
+
+struct a6xx_hfi_msg_core_fw_start {
+ uint32_t header;
+ uint32_t handle;
+};
+
+static void
+decode_H2F_MSG_CORE_FW_START(struct a6xx_hfi_msg_core_fw_start *msg)
+{
+ printf("\t\t\t\thandle: %u\n", msg->handle);
+}
+
+#define HFI_H2F_MSG_GX_BW_PERF_VOTE 30
+
+struct a6xx_hfi_gx_bw_perf_vote_cmd {
+ uint32_t header;
+ uint32_t ack_type;
+ uint32_t freq;
+ uint32_t bw;
+};
+
+static void
+decode_H2F_MSG_GX_BW_PERF_VOTE(struct a6xx_hfi_gx_bw_perf_vote_cmd *msg)
+{
+ printf("\t\t\t\tack_type: %u\n", msg->ack_type);
+ printf("\t\t\t\tfreq: %u\n", msg->freq);
+ printf("\t\t\t\tbw: %u\n", msg->bw);
+}
+
+#define HFI_H2F_MSG_PREPARE_SLUMBER 33
+
+struct a6xx_hfi_prep_slumber_cmd {
+ uint32_t header;
+ uint32_t bw;
+ uint32_t freq;
+};
+
+static void
+decode_H2F_MSG_PREPARE_SLUMBER(struct a6xx_hfi_prep_slumber_cmd *msg)
+{
+ printf("\t\t\t\tbw: %u\n", msg->bw);
+ printf("\t\t\t\tfreq: %u\n", msg->freq);
+}
+
+static struct {
+ const char *name;
+ void (*decode)(void *);
+} hfi_msgs[] = {
+#define HFI_MSG(name) [HFI_ ## name] = { #name, (void (*)(void *))decode_ ## name }
+ HFI_MSG(F2H_MSG_ACK),
+ HFI_MSG(F2H_MSG_ERROR),
+ HFI_MSG(H2F_MSG_INIT),
+ HFI_MSG(H2F_MSG_FW_VERSION),
+ HFI_MSG(H2F_MSG_PERF_TABLE),
+ HFI_MSG(H2F_MSG_BW_TABLE),
+ HFI_MSG(H2F_MSG_TEST),
+ HFI_MSG(H2F_MSG_START),
+ HFI_MSG(H2F_MSG_CORE_FW_START),
+ HFI_MSG(H2F_MSG_GX_BW_PERF_VOTE),
+ HFI_MSG(H2F_MSG_PREPARE_SLUMBER),
+};
+
+static bool
+is_valid_msg_type(unsigned type)
+{
+ switch (type) {
+ case HFI_MSG_CMD:
+ case HFI_MSG_ACK:
+ case HFI_MSG_ACK_V1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const char *
+hfi_msg_name(unsigned msgid)
+{
+ if (msgid < ARRAY_SIZE(hfi_msgs))
+ return hfi_msgs[msgid].name;
+ return NULL;
+}
+
+static bool
+is_valid_decode_start(struct a6xx_hfi_state *hfi, unsigned qidx, int32_t read_index)
+{
+ struct a6xx_hfi_queue_table_header *table = hfi->buf;
+ struct a6xx_hfi_queue_header *queue = &table->queue[qidx];
+ uint32_t offset = queue->iova - hfi->iova;
+ uint32_t *dw = (uint32_t *)(((uint8_t *)hfi->buf) + offset);
+ int last_seqno = -1;
+
+ if (read_index < 0)
+ return false;
+
+ while (read_index != queue->write_index) {
+ uint32_t hdr = dw[read_index];
+
+ if (!is_valid_msg_type(HFI_HEADER_TYPE(hdr)))
+ return false;
+
+ if (!hfi_msg_name(HFI_HEADER_ID(hdr)))
+ return false;
+
+ /* Header size should be at least 1, and not extend past the write_index: */
+ unsigned sz = HFI_HEADER_SIZE(hdr);
+ if (!is_gmu_legacy())
+ sz = ALIGN_POT(sz, 4);
+ int remaining = ((read_index + sz) + (queue->size - 1) -
+ queue->write_index) % queue->size;
+ if ((sz == 0) || (remaining < 0))
+ return false;
+
+ /* Seqno should be one more than previous seqno: */
+ unsigned seqno = HFI_HEADER_SEQNUM(hdr);
+ if ((last_seqno != -1) && (((last_seqno + 1) & 0xfff) != seqno))
+ return false;
+
+ last_seqno = seqno;
+
+ read_index = (read_index + sz) % queue->size;
+ }
+
+ return true;
+}
+
+static void
+decode_hfi(struct a6xx_hfi_state *hfi, unsigned qidx, int32_t read_index)
+{
+ struct a6xx_hfi_queue_table_header *table = hfi->buf;
+ struct a6xx_hfi_queue_header *queue = &table->queue[qidx];
+ uint32_t offset = queue->iova - hfi->iova;
+ uint32_t *dw = (uint32_t *)(((uint8_t *)hfi->buf) + offset);
+
+ while (read_index != queue->write_index) {
+ uint32_t hdr = dw[read_index];
+ unsigned msgid = HFI_HEADER_ID(hdr);
+ unsigned sz = HFI_HEADER_SIZE(hdr);
+ unsigned type = HFI_HEADER_TYPE(hdr);
+ unsigned seqno = HFI_HEADER_SEQNUM(hdr);
+
+ assert(is_valid_msg_type(type));
+ assert(hfi_msg_name(msgid));
+
+ printf("\t\t\t------ %s (id=%u, size=%u, type=%u, seqnum=%u)\n",
+ hfi_msg_name(msgid), msgid, sz, type, seqno);
+
+ if (!is_gmu_legacy())
+ sz = ALIGN_POT(sz, 4);
+
+ uint32_t buf[sz];
+ for (unsigned i = 0; i < sz; i++) {
+ buf[i] = dw[(read_index + i) % queue->size];
+ }
+
+ if (type == HFI_MSG_CMD)
+ hfi_msgs[msgid].decode(buf);
+
+ dump_hex_ascii(buf, sz*4, 4);
+
+ read_index = (read_index + sz) % queue->size;
+ }
+}
+
+/* Search backwards from the most recent (last) history entry to try to
+ * find start of the oldest HFI message which has not been overwritten
+ * due to ringbuffer wraparound.
+ */
+static int32_t
+find_decode_start(struct a6xx_hfi_state *hfi, unsigned qidx)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(hfi->history[qidx]) - 1; i >= 0; i--) {
+ if (!is_valid_decode_start(hfi, qidx, hfi->history[qidx][i]))
+ break;
+ }
+
+ /* Last entry was invalid, or we decremented below zero, so advance
+ * the index by one:
+ */
+ i++;
+
+ if (i >= ARRAY_SIZE(hfi->history[qidx]))
+ return -1;
+
+ return hfi->history[qidx][i];
+}
+
+void
+dump_gmu_hfi(struct a6xx_hfi_state *hfi)
+{
+ struct a6xx_hfi_queue_table_header *table = hfi->buf;
+
+ printf("\tversion: %u\n", table->version);
+ printf("\tsize: %u\n", table->size);
+ printf("\tqhdr0_offset: %u\n", table->qhdr0_offset);
+ printf("\tqhdr_size: %u\n", table->qhdr_size);
+ printf("\tnum_queues: %u\n", table->num_queues);
+ printf("\tactive_queues: %u\n", table->active_queues);
+
+ for (unsigned i = 0; i < table->num_queues; i++) {
+ struct a6xx_hfi_queue_header *queue = &table->queue[i];
+
+ printf("\tqueue[%u]:\n", i);
+ printf("\t\tstatus: 0x%x\n", queue->status);
+ printf("\t\tiova: 0x%x\n", queue->iova);
+ printf("\t\ttype: 0x%x\n", queue->type);
+ printf("\t\tsize: %u\n", queue->size);
+ printf("\t\tmsg_size: %u\n", queue->msg_size);
+ printf("\t\tdropped: %u\n", queue->dropped);
+ printf("\t\trx_watermark: 0x%x\n", queue->rx_watermark);
+ printf("\t\ttx_watermark: 0x%x\n", queue->tx_watermark);
+ printf("\t\trx_request: 0x%x\n", queue->rx_request);
+ printf("\t\ttx_request: 0x%x\n", queue->tx_request);
+ printf("\t\tread_index: %u\n", queue->read_index);
+ printf("\t\twrite_index: %u\n", queue->write_index);
+
+ int32_t read_index = find_decode_start(hfi, i);
+ if (read_index >= 0)
+ decode_hfi(hfi, i, read_index);
+ }
+}
diff --git a/src/freedreno/decode/crashdec.c b/src/freedreno/decode/crashdec.c
index 0fb8874f332..19d110b2b48 100644
--- a/src/freedreno/decode/crashdec.c
+++ b/src/freedreno/decode/crashdec.c
@@ -248,6 +248,51 @@ decode_ringbuffer(void)
}
}
+/*
+ * Decode HFI queues
+ */
+
+static void
+decode_gmu_hfi(void)
+{
+ struct a6xx_hfi_state hfi = {};
+
+ /* Initialize the history buffers with invalid entries (-1): */
+ memset(&hfi.history, 0xff, sizeof(hfi.history));
+
+ foreach_line_in_section (line) {
+ if (startswith(line, " iova:")) {
+ parseline(line, " iova: %" PRIx64, &hfi.iova);
+ } else if (startswith(line, " size:")) {
+ parseline(line, " size: %u", &hfi.size);
+ } else if (startswith(line, " queue-history")) {
+ unsigned qidx, dummy;
+
+ parseline(line, " queue-history[%u]:", &qidx);
+ assert(qidx < ARRAY_SIZE(hfi.history));
+
+ parseline(line, " queue-history[%u]: %d %d %d %d %d %d %d %d", &dummy,
+ &hfi.history[qidx][0], &hfi.history[qidx][1],
+ &hfi.history[qidx][2], &hfi.history[qidx][3],
+ &hfi.history[qidx][4], &hfi.history[qidx][5],
+ &hfi.history[qidx][6], &hfi.history[qidx][7]);
+ } else if (startswith(line, " data: !!ascii85 |")) {
+ hfi.buf = popline_ascii85(hfi.size / 4);
+
+ if (verbose)
+ dump_hex_ascii(hfi.buf, hfi.size, 1);
+
+ dump_gmu_hfi(&hfi);
+
+ free(hfi.buf);
+
+ continue;
+ }
+
+ printf("%s", line);
+ }
+}
+
static bool
valid_header(uint32_t pkt)
{
@@ -693,6 +738,8 @@ decode(void)
decode_bos();
} else if (startswith(line, "ringbuffer:")) {
decode_ringbuffer();
+ } else if (startswith(line, "gmu-hfi:")) {
+ decode_gmu_hfi();
} else if (startswith(line, "registers:")) {
decode_registers();
diff --git a/src/freedreno/decode/crashdec.h b/src/freedreno/decode/crashdec.h
index cb767e67637..c92afacce12 100644
--- a/src/freedreno/decode/crashdec.h
+++ b/src/freedreno/decode/crashdec.h
@@ -71,7 +71,28 @@ is_64b(void)
return options.gpu_id >= 500;
}
+static inline bool
+is_gmu_legacy(void)
+{
+ switch (options.gpu_id) {
+ case 615:
+ case 618:
+ case 630:
+ return true;
+ default:
+ return false;
+ }
+}
+
void dump_register(struct rnn *rnn, uint32_t offset, uint32_t value);
void dump_cp_mem_pool(uint32_t *mempool);
+struct a6xx_hfi_state {
+ uint64_t iova;
+ void *buf;
+ uint32_t size;
+ int32_t history[2][8];
+};
+void dump_gmu_hfi(struct a6xx_hfi_state *hfi);
+
#endif /* __CRASHDEC_H__ */
diff --git a/src/freedreno/decode/meson.build b/src/freedreno/decode/meson.build
index 58810d07438..1d820048525 100644
--- a/src/freedreno/decode/meson.build
+++ b/src/freedreno/decode/meson.build
@@ -135,6 +135,7 @@ crashdec = executable(
[
'crashdec.c',
'crashdec.h',
+ 'crashdec-hfi.c',
'crashdec-mempool.c',
],
include_directories: [
More information about the mesa-commit
mailing list