xref: /aosp_15_r20/external/mesa3d/src/freedreno/decode/crashdec-hfi.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2021 Google, Inc.
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "util/macros.h"
7 #include "crashdec.h"
8 
9 static const char *hfi_msg_name(unsigned msgid);
10 
11 /*
12  * Decode HFI queues
13  */
14 
15 /* HFI message types */
16 
17 #define HFI_MSG_CMD 0
18 #define HFI_MSG_ACK 1
19 #define HFI_MSG_ACK_V1 2
20 
21 #define HFI_HEADER_ID(msg) ((msg) & 0xff)
22 /* Note that header size includes the header itself: */
23 #define HFI_HEADER_SIZE(msg) (((msg) >> 8) & 0xff)
24 #define HFI_HEADER_TYPE(msg)   (((msg) >> 16) & 0xf)
25 #define HFI_HEADER_SEQNUM(msg) (((msg) >> 20) & 0xfff)
26 
27 struct a6xx_hfi_queue_header {
28    uint32_t status;
29    uint32_t iova;
30    uint32_t type;
31    uint32_t size;
32    uint32_t msg_size;
33    uint32_t dropped;
34    uint32_t rx_watermark;
35    uint32_t tx_watermark;
36    uint32_t rx_request;
37    uint32_t tx_request;
38    uint32_t read_index;
39    uint32_t write_index;
40 };
41 
42 struct a6xx_hfi_queue_table_header {
43    uint32_t version;
44    uint32_t size;               /* Size of the queue table in dwords */
45    uint32_t qhdr0_offset;       /* Offset of the first queue header */
46    uint32_t qhdr_size;          /* Size of the queue headers */
47    uint32_t num_queues;         /* Number of total queues */
48    uint32_t active_queues;      /* Number of active queues */
49    struct a6xx_hfi_queue_header queue[];
50 };
51 
52 /*
53  * HFI message definitions:
54  */
55 
56 #define HFI_F2H_MSG_ACK 126
57 
58 struct a6xx_hfi_msg_response {
59    uint32_t header;
60    uint32_t ret_header;
61    uint32_t error;
62    uint32_t payload[16];
63 };
64 
65 static void
decode_F2H_MSG_ACK(struct a6xx_hfi_msg_response * msg)66 decode_F2H_MSG_ACK(struct a6xx_hfi_msg_response *msg)
67 {
68    unsigned msgid = HFI_HEADER_ID(msg->ret_header);
69 
70    printf("\t\t\t\tret_header: %s  (id=%u, size=%u, type=%u, seqnum=%u)\n",
71           hfi_msg_name(msgid), msgid, HFI_HEADER_SIZE(msg->ret_header),
72           HFI_HEADER_TYPE(msg->ret_header), HFI_HEADER_SEQNUM(msg->ret_header));
73    printf("\t\t\t\terror:      %u\n",     msg->error);
74 }
75 
76 #define HFI_F2H_MSG_ERROR 100
77 
78 struct a6xx_hfi_msg_error {
79    uint32_t header;
80    uint32_t code;
81    uint32_t payload[2];
82 };
83 
84 static void
decode_F2H_MSG_ERROR(struct a6xx_hfi_msg_error * msg)85 decode_F2H_MSG_ERROR(struct a6xx_hfi_msg_error *msg)
86 {
87    printf("\t\t\t\tcode: %u\n", msg->code);
88 }
89 
90 #define HFI_H2F_MSG_INIT 0
91 
92 struct a6xx_hfi_msg_gmu_init_cmd {
93    uint32_t header;
94    uint32_t seg_id;
95    uint32_t dbg_buffer_addr;
96    uint32_t dbg_buffer_size;
97    uint32_t boot_state;
98 };
99 
100 static void
decode_H2F_MSG_INIT(struct a6xx_hfi_msg_gmu_init_cmd * msg)101 decode_H2F_MSG_INIT(struct a6xx_hfi_msg_gmu_init_cmd *msg)
102 {
103    printf("\t\t\t\tseg_id:          %u\n",     msg->seg_id);
104    printf("\t\t\t\tdbg_buffer_addr: 0x%08x\n", msg->dbg_buffer_addr);
105    printf("\t\t\t\tdbg_buffer_size: %u\n",     msg->dbg_buffer_size);
106    printf("\t\t\t\tboot_state:      %u\n",     msg->boot_state);
107 }
108 
109 #define HFI_H2F_MSG_FW_VERSION 1
110 
111 struct a6xx_hfi_msg_fw_version {
112    uint32_t header;
113    uint32_t supported_version;
114 };
115 
116 static void
decode_H2F_MSG_FW_VERSION(struct a6xx_hfi_msg_fw_version * msg)117 decode_H2F_MSG_FW_VERSION(struct a6xx_hfi_msg_fw_version *msg)
118 {
119    printf("\t\t\t\tsupported_version: 0x%x\n", msg->supported_version);
120 }
121 
122 #define HFI_H2F_MSG_PERF_TABLE 4
123 
124 struct perf_level {
125    uint32_t vote;
126    uint32_t freq;
127 };
128 
129 struct perf_gx_level {
130    uint32_t vote;
131    uint32_t acd;
132    uint32_t freq;
133 };
134 
135 struct a6xx_hfi_msg_perf_table_v1 {
136    uint32_t header;
137    uint32_t num_gpu_levels;
138    uint32_t num_gmu_levels;
139 
140    struct perf_level gx_votes[16];
141    struct perf_level cx_votes[4];
142 };
143 
144 struct a6xx_hfi_msg_perf_table {
145    uint32_t header;
146    uint32_t num_gpu_levels;
147    uint32_t num_gmu_levels;
148 
149    struct perf_gx_level gx_votes[16];
150    struct perf_level cx_votes[4];
151 };
152 
153 static void
decode_H2F_MSG_PERF_TABLE(void * _msg)154 decode_H2F_MSG_PERF_TABLE(void *_msg)
155 {
156    if (is_gmu_legacy()) {
157       struct a6xx_hfi_msg_perf_table_v1 *msg = _msg;
158       unsigned i;
159 
160       printf("\t\t\t\tnum_gpu_levels: %u\n", msg->num_gpu_levels);
161       printf("\t\t\t\tnum_gmu_levels: %u\n", msg->num_gmu_levels);
162 
163       assert(msg->num_gpu_levels <= ARRAY_SIZE(msg->gx_votes));
164       for (i = 0; i < msg->num_gpu_levels; i++) {
165          printf("\t\t\t\tgx_vote[%u]:    vote=%u, freq=%u\n", i,
166                 msg->gx_votes[i].vote, msg->gx_votes[i].freq);
167       }
168 
169       for (; i < ARRAY_SIZE(msg->gx_votes); i++) {
170          assert(!msg->gx_votes[i].vote);
171          assert(!msg->gx_votes[i].freq);
172       }
173 
174       assert(msg->num_gmu_levels <= ARRAY_SIZE(msg->cx_votes));
175       for (i = 0; i < msg->num_gmu_levels; i++) {
176          printf("\t\t\t\tcx_vote[%u]:    vote=%u, freq=%u\n", i,
177                 msg->cx_votes[i].vote, msg->cx_votes[i].freq);
178       }
179 
180       for (; i < ARRAY_SIZE(msg->cx_votes); i++) {
181          assert(!msg->cx_votes[i].vote);
182          assert(!msg->cx_votes[i].freq);
183       }
184    } else {
185       struct a6xx_hfi_msg_perf_table *msg = _msg;
186       unsigned i;
187 
188       printf("\t\t\t\tnum_gpu_levels: %u\n", msg->num_gpu_levels);
189       printf("\t\t\t\tnum_gmu_levels: %u\n", msg->num_gmu_levels);
190 
191       assert(msg->num_gpu_levels <= ARRAY_SIZE(msg->gx_votes));
192       for (i = 0; i < msg->num_gpu_levels; i++) {
193          printf("\t\t\t\tgx_vote[%u]:    vote=%u, acd=%u, freq=%u\n", i,
194                 msg->gx_votes[i].vote, msg->gx_votes[i].acd,
195                 msg->gx_votes[i].freq);
196       }
197 
198       for (; i < ARRAY_SIZE(msg->gx_votes); i++) {
199          assert(!msg->gx_votes[i].vote);
200          assert(!msg->gx_votes[i].acd);
201          assert(!msg->gx_votes[i].freq);
202       }
203 
204       assert(msg->num_gmu_levels <= ARRAY_SIZE(msg->cx_votes));
205       for (i = 0; i < msg->num_gmu_levels; i++) {
206          printf("\t\t\t\tcx_vote[%u]:    vote=%u, freq=%u\n", i,
207                 msg->cx_votes[i].vote, msg->cx_votes[i].freq);
208       }
209 
210       for (; i < ARRAY_SIZE(msg->cx_votes); i++) {
211          assert(!msg->cx_votes[i].vote);
212          assert(!msg->cx_votes[i].freq);
213       }
214    }
215 }
216 
217 #define HFI_H2F_MSG_BW_TABLE 3
218 
219 struct a6xx_hfi_msg_bw_table {
220    uint32_t header;
221    uint32_t bw_level_num;
222    uint32_t cnoc_cmds_num;
223    uint32_t ddr_cmds_num;
224    uint32_t cnoc_wait_bitmask;
225    uint32_t ddr_wait_bitmask;
226    uint32_t cnoc_cmds_addrs[6];
227    uint32_t cnoc_cmds_data[2][6];
228    uint32_t ddr_cmds_addrs[8];
229    uint32_t ddr_cmds_data[16][8];
230 };
231 
232 static void
decode_H2F_MSG_BW_TABLE(struct a6xx_hfi_msg_bw_table * msg)233 decode_H2F_MSG_BW_TABLE(struct a6xx_hfi_msg_bw_table *msg)
234 {
235    printf("\t\t\t\tbw_level_num:       %u\n",   msg->bw_level_num);
236    printf("\t\t\t\tcnoc_cmds_num:      %u\n",   msg->cnoc_cmds_num);
237    printf("\t\t\t\tddr_cmds_num:       %u\n",   msg->ddr_cmds_num);
238    printf("\t\t\t\tcnoc_wait_bitmask:  0x%x\n", msg->cnoc_wait_bitmask);
239    printf("\t\t\t\tddr_wait_bitmask:   0x%x\n", msg->ddr_wait_bitmask);
240    printf("\t\t\t\tcnoc_cmds_addrs:    %08x %08x %08x %08x %08x %08x\n",
241           msg->cnoc_cmds_addrs[0], msg->cnoc_cmds_addrs[1], msg->cnoc_cmds_addrs[2],
242           msg->cnoc_cmds_addrs[3], msg->cnoc_cmds_addrs[4], msg->cnoc_cmds_addrs[5]);
243    for (unsigned i = 0; i < ARRAY_SIZE(msg->cnoc_cmds_data); i++) {
244       printf("\t\t\t\tcnoc_cmds_data[%u]:  %08x %08x %08x %08x %08x %08x\n", i,
245              msg->cnoc_cmds_data[i][0], msg->cnoc_cmds_data[i][1], msg->cnoc_cmds_data[i][2],
246              msg->cnoc_cmds_data[i][3], msg->cnoc_cmds_data[i][4], msg->cnoc_cmds_data[i][5]);
247    }
248    printf("\t\t\t\tddr_cmds_addrs:     %08x %08x %08x %08x %08x %08x %08x %08x\n",
249           msg->ddr_cmds_addrs[0], msg->ddr_cmds_addrs[1], msg->ddr_cmds_addrs[2],
250           msg->ddr_cmds_addrs[3], msg->ddr_cmds_addrs[4], msg->ddr_cmds_addrs[5],
251           msg->ddr_cmds_addrs[6], msg->ddr_cmds_addrs[7]);
252    for (unsigned i = 0; i < ARRAY_SIZE(msg->ddr_cmds_data); i++) {
253       printf("\t\t\t\tddr_cmds_data[%u]:   %08x %08x %08x %08x %08x %08x %08x %08x\n", i,
254              msg->ddr_cmds_data[i][0], msg->ddr_cmds_data[i][1], msg->ddr_cmds_data[i][2],
255              msg->ddr_cmds_data[i][3], msg->ddr_cmds_data[i][4], msg->ddr_cmds_data[i][5],
256              msg->ddr_cmds_data[i][6], msg->ddr_cmds_data[i][7]);
257    }
258 }
259 
260 #define HFI_H2F_MSG_TEST 5
261 
262 struct a6xx_hfi_msg_test {
263    uint32_t header;
264 };
265 
266 static void
decode_H2F_MSG_TEST(struct a6xx_hfi_msg_test * msg)267 decode_H2F_MSG_TEST(struct a6xx_hfi_msg_test *msg)
268 {
269 }
270 
271 #define HFI_H2F_MSG_START 10
272 
273 struct a6xx_hfi_msg_start {
274    uint32_t header;
275 };
276 
277 static void
decode_H2F_MSG_START(struct a6xx_hfi_msg_start * msg)278 decode_H2F_MSG_START(struct a6xx_hfi_msg_start *msg)
279 {
280 }
281 
282 #define HFI_H2F_MSG_CORE_FW_START 14
283 
284 struct a6xx_hfi_msg_core_fw_start {
285    uint32_t header;
286    uint32_t handle;
287 };
288 
289 static void
decode_H2F_MSG_CORE_FW_START(struct a6xx_hfi_msg_core_fw_start * msg)290 decode_H2F_MSG_CORE_FW_START(struct a6xx_hfi_msg_core_fw_start *msg)
291 {
292    printf("\t\t\t\thandle: %u\n", msg->handle);
293 }
294 
295 #define HFI_H2F_MSG_GX_BW_PERF_VOTE 30
296 
297 struct a6xx_hfi_gx_bw_perf_vote_cmd {
298    uint32_t header;
299    uint32_t ack_type;
300    uint32_t freq;
301    uint32_t bw;
302 };
303 
304 static void
decode_H2F_MSG_GX_BW_PERF_VOTE(struct a6xx_hfi_gx_bw_perf_vote_cmd * msg)305 decode_H2F_MSG_GX_BW_PERF_VOTE(struct a6xx_hfi_gx_bw_perf_vote_cmd *msg)
306 {
307    printf("\t\t\t\tack_type: %u\n", msg->ack_type);
308    printf("\t\t\t\tfreq:     %u\n", msg->freq);
309    printf("\t\t\t\tbw:       %u\n", msg->bw);
310 }
311 
312 #define HFI_H2F_MSG_PREPARE_SLUMBER 33
313 
314 struct a6xx_hfi_prep_slumber_cmd {
315    uint32_t header;
316    uint32_t bw;
317    uint32_t freq;
318 };
319 
320 static void
decode_H2F_MSG_PREPARE_SLUMBER(struct a6xx_hfi_prep_slumber_cmd * msg)321 decode_H2F_MSG_PREPARE_SLUMBER(struct a6xx_hfi_prep_slumber_cmd *msg)
322 {
323    printf("\t\t\t\tbw:   %u\n", msg->bw);
324    printf("\t\t\t\tfreq: %u\n", msg->freq);
325 }
326 
327 static struct {
328    const char *name;
329    void (*decode)(void *);
330 } hfi_msgs[] = {
331 #define HFI_MSG(name) [HFI_ ## name] = { #name, (void (*)(void *))decode_ ## name }
332    HFI_MSG(F2H_MSG_ACK),
333    HFI_MSG(F2H_MSG_ERROR),
334    HFI_MSG(H2F_MSG_INIT),
335    HFI_MSG(H2F_MSG_FW_VERSION),
336    HFI_MSG(H2F_MSG_PERF_TABLE),
337    HFI_MSG(H2F_MSG_BW_TABLE),
338    HFI_MSG(H2F_MSG_TEST),
339    HFI_MSG(H2F_MSG_START),
340    HFI_MSG(H2F_MSG_CORE_FW_START),
341    HFI_MSG(H2F_MSG_GX_BW_PERF_VOTE),
342    HFI_MSG(H2F_MSG_PREPARE_SLUMBER),
343 };
344 
345 static bool
is_valid_msg_type(unsigned type)346 is_valid_msg_type(unsigned type)
347 {
348    switch (type) {
349    case HFI_MSG_CMD:
350    case HFI_MSG_ACK:
351    case HFI_MSG_ACK_V1:
352       return true;
353    default:
354       return false;
355    }
356 }
357 
358 static const char *
hfi_msg_name(unsigned msgid)359 hfi_msg_name(unsigned msgid)
360 {
361    if (msgid < ARRAY_SIZE(hfi_msgs))
362       return hfi_msgs[msgid].name;
363    return NULL;
364 }
365 
366 static bool
is_valid_decode_start(struct a6xx_hfi_state * hfi,unsigned qidx,int32_t read_index)367 is_valid_decode_start(struct a6xx_hfi_state *hfi, unsigned qidx, int32_t read_index)
368 {
369    struct a6xx_hfi_queue_table_header *table = hfi->buf;
370    struct a6xx_hfi_queue_header *queue = &table->queue[qidx];
371    uint32_t offset = queue->iova - hfi->iova;
372    uint32_t *dw = (uint32_t *)(((uint8_t *)hfi->buf) + offset);
373    int last_seqno = -1;
374 
375    if (read_index < 0)
376       return false;
377 
378    while (read_index != queue->write_index) {
379       uint32_t hdr = dw[read_index];
380 
381       if (!is_valid_msg_type(HFI_HEADER_TYPE(hdr)))
382          return false;
383 
384       if (!hfi_msg_name(HFI_HEADER_ID(hdr)))
385          return false;
386 
387       /* Header size should be at least 1, and not extend past the write_index: */
388       unsigned sz = HFI_HEADER_SIZE(hdr);
389       if (!is_gmu_legacy())
390          sz = ALIGN_POT(sz, 4);
391       int remaining = ((read_index + sz) + (queue->size - 1) -
392                        queue->write_index) % queue->size;
393       if ((sz == 0) || (remaining < 0))
394          return false;
395 
396       /* Seqno should be one more than previous seqno: */
397       unsigned seqno = HFI_HEADER_SEQNUM(hdr);
398       if ((last_seqno != -1) && (((last_seqno + 1) & 0xfff) != seqno))
399          return false;
400 
401       last_seqno = seqno;
402 
403       read_index = (read_index + sz) % queue->size;
404    }
405 
406    return true;
407 }
408 
409 static void
decode_hfi(struct a6xx_hfi_state * hfi,unsigned qidx,int32_t read_index)410 decode_hfi(struct a6xx_hfi_state *hfi, unsigned qidx, int32_t read_index)
411 {
412    struct a6xx_hfi_queue_table_header *table = hfi->buf;
413    struct a6xx_hfi_queue_header *queue = &table->queue[qidx];
414    uint32_t offset = queue->iova - hfi->iova;
415    uint32_t *dw = (uint32_t *)(((uint8_t *)hfi->buf) + offset);
416 
417    while (read_index != queue->write_index) {
418       uint32_t hdr = dw[read_index];
419       unsigned msgid = HFI_HEADER_ID(hdr);
420       unsigned sz    = HFI_HEADER_SIZE(hdr);
421       unsigned type  = HFI_HEADER_TYPE(hdr);
422       unsigned seqno = HFI_HEADER_SEQNUM(hdr);
423 
424       assert(is_valid_msg_type(type));
425       assert(hfi_msg_name(msgid));
426 
427       printf("\t\t\t------ %s (id=%u, size=%u, type=%u, seqnum=%u)\n",
428              hfi_msg_name(msgid), msgid, sz, type, seqno);
429 
430       if (!is_gmu_legacy())
431          sz = ALIGN_POT(sz, 4);
432 
433       uint32_t buf[sz];
434       for (unsigned i = 0; i < sz; i++) {
435          buf[i] = dw[(read_index + i) % queue->size];
436       }
437 
438       if (type == HFI_MSG_CMD)
439          hfi_msgs[msgid].decode(buf);
440 
441       dump_hex_ascii(buf, sz*4, 4);
442 
443       read_index = (read_index + sz) % queue->size;
444    }
445 }
446 
447 /* Search backwards from the most recent (last) history entry to try to
448  * find start of the oldest HFI message which has not been overwritten
449  * due to ringbuffer wraparound.
450  */
451 static int32_t
find_decode_start(struct a6xx_hfi_state * hfi,unsigned qidx)452 find_decode_start(struct a6xx_hfi_state *hfi, unsigned qidx)
453 {
454    int i;
455 
456    for (i = ARRAY_SIZE(hfi->history[qidx]) - 1; i >= 0; i--) {
457       if (!is_valid_decode_start(hfi, qidx, hfi->history[qidx][i]))
458          break;
459    }
460 
461    /* Last entry was invalid, or we decremented below zero, so advance
462     * the index by one:
463     */
464    i++;
465 
466    if (i >= ARRAY_SIZE(hfi->history[qidx]))
467       return -1;
468 
469    return hfi->history[qidx][i];
470 }
471 
472 void
dump_gmu_hfi(struct a6xx_hfi_state * hfi)473 dump_gmu_hfi(struct a6xx_hfi_state *hfi)
474 {
475    struct a6xx_hfi_queue_table_header *table = hfi->buf;
476 
477    printf("\tversion:       %u\n", table->version);
478    printf("\tsize:          %u\n", table->size);
479    printf("\tqhdr0_offset:  %u\n", table->qhdr0_offset);
480    printf("\tqhdr_size:     %u\n", table->qhdr_size);
481    printf("\tnum_queues:    %u\n", table->num_queues);
482    printf("\tactive_queues: %u\n", table->active_queues);
483 
484    for (unsigned i = 0; i < table->num_queues; i++) {
485       struct a6xx_hfi_queue_header *queue = &table->queue[i];
486 
487       printf("\tqueue[%u]:\n", i);
488       printf("\t\tstatus:       0x%x\n", queue->status);
489       printf("\t\tiova:         0x%x\n", queue->iova);
490       printf("\t\ttype:         0x%x\n", queue->type);
491       printf("\t\tsize:         %u\n",   queue->size);
492       printf("\t\tmsg_size:     %u\n",   queue->msg_size);
493       printf("\t\tdropped:      %u\n",   queue->dropped);
494       printf("\t\trx_watermark: 0x%x\n", queue->rx_watermark);
495       printf("\t\ttx_watermark: 0x%x\n", queue->tx_watermark);
496       printf("\t\trx_request:   0x%x\n", queue->rx_request);
497       printf("\t\ttx_request:   0x%x\n", queue->tx_request);
498       printf("\t\tread_index:   %u\n",   queue->read_index);
499       printf("\t\twrite_index:  %u\n",   queue->write_index);
500 
501       int32_t read_index = find_decode_start(hfi, i);
502       if (read_index >= 0)
503          decode_hfi(hfi, i, read_index);
504    }
505 }
506