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 27static 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 45struct 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 60struct 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 76struct a6xx_hfi_msg_response { 77 uint32_t header; 78 uint32_t ret_header; 79 uint32_t error; 80 uint32_t payload[16]; 81}; 82 83static void 84decode_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 96struct a6xx_hfi_msg_error { 97 uint32_t header; 98 uint32_t code; 99 uint32_t payload[2]; 100}; 101 102static void 103decode_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 110struct 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 118static void 119decode_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 129struct a6xx_hfi_msg_fw_version { 130 uint32_t header; 131 uint32_t supported_version; 132}; 133 134static void 135decode_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 142struct perf_level { 143 uint32_t vote; 144 uint32_t freq; 145}; 146 147struct perf_gx_level { 148 uint32_t vote; 149 uint32_t acd; 150 uint32_t freq; 151}; 152 153struct 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 162struct 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 171static void 172decode_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 237struct 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 250static void 251decode_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 280struct a6xx_hfi_msg_test { 281 uint32_t header; 282}; 283 284static void 285decode_H2F_MSG_TEST(struct a6xx_hfi_msg_test *msg) 286{ 287} 288 289#define HFI_H2F_MSG_START 10 290 291struct a6xx_hfi_msg_start { 292 uint32_t header; 293}; 294 295static void 296decode_H2F_MSG_START(struct a6xx_hfi_msg_start *msg) 297{ 298} 299 300#define HFI_H2F_MSG_CORE_FW_START 14 301 302struct a6xx_hfi_msg_core_fw_start { 303 uint32_t header; 304 uint32_t handle; 305}; 306 307static void 308decode_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 315struct 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 322static void 323decode_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 332struct a6xx_hfi_prep_slumber_cmd { 333 uint32_t header; 334 uint32_t bw; 335 uint32_t freq; 336}; 337 338static void 339decode_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 345static 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 363static bool 364is_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 376static const char * 377hfi_msg_name(unsigned msgid) 378{ 379 if (msgid < ARRAY_SIZE(hfi_msgs)) 380 return hfi_msgs[msgid].name; 381 return NULL; 382} 383 384static bool 385is_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 427static void 428decode_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 */ 469static int32_t 470find_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 490void 491dump_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