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