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