1/* 2 * Copyright 2015 Advanced Micro Devices, 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 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24#include "ac_debug.h" 25 26#ifdef HAVE_VALGRIND 27#include <memcheck.h> 28#include <valgrind.h> 29#define VG(x) x 30#else 31#define VG(x) ((void)0) 32#endif 33 34#include "sid.h" 35#include "sid_tables.h" 36#include "util/compiler.h" 37#include "util/memstream.h" 38#include "util/u_math.h" 39#include "util/u_memory.h" 40#include "util/u_string.h" 41 42#include <assert.h> 43#include <inttypes.h> 44 45DEBUG_GET_ONCE_BOOL_OPTION(color, "AMD_COLOR", true); 46 47/* Parsed IBs are difficult to read without colors. Use "less -R file" to 48 * read them, or use "aha -b -f file" to convert them to html. 49 */ 50#define COLOR_RESET "\033[0m" 51#define COLOR_RED "\033[31m" 52#define COLOR_GREEN "\033[1;32m" 53#define COLOR_YELLOW "\033[1;33m" 54#define COLOR_CYAN "\033[1;36m" 55 56#define O_COLOR_RESET (debug_get_option_color() ? COLOR_RESET : "") 57#define O_COLOR_RED (debug_get_option_color() ? COLOR_RED : "") 58#define O_COLOR_GREEN (debug_get_option_color() ? COLOR_GREEN : "") 59#define O_COLOR_YELLOW (debug_get_option_color() ? COLOR_YELLOW : "") 60#define O_COLOR_CYAN (debug_get_option_color() ? COLOR_CYAN : "") 61 62#define INDENT_PKT 8 63 64struct ac_ib_parser { 65 FILE *f; 66 uint32_t *ib; 67 unsigned num_dw; 68 const int *trace_ids; 69 unsigned trace_id_count; 70 enum amd_gfx_level gfx_level; 71 ac_debug_addr_callback addr_callback; 72 void *addr_callback_data; 73 74 unsigned cur_dw; 75}; 76 77static void ac_do_parse_ib(FILE *f, struct ac_ib_parser *ib); 78 79static void print_spaces(FILE *f, unsigned num) 80{ 81 fprintf(f, "%*s", num, ""); 82} 83 84static void print_value(FILE *file, uint32_t value, int bits) 85{ 86 /* Guess if it's int or float */ 87 if (value <= (1 << 15)) { 88 if (value <= 9) 89 fprintf(file, "%u\n", value); 90 else 91 fprintf(file, "%u (0x%0*x)\n", value, bits / 4, value); 92 } else { 93 float f = uif(value); 94 95 if (fabs(f) < 100000 && f * 10 == floor(f * 10)) 96 fprintf(file, "%.1ff (0x%0*x)\n", f, bits / 4, value); 97 else 98 /* Don't print more leading zeros than there are bits. */ 99 fprintf(file, "0x%0*x\n", bits / 4, value); 100 } 101} 102 103static void print_named_value(FILE *file, const char *name, uint32_t value, int bits) 104{ 105 print_spaces(file, INDENT_PKT); 106 fprintf(file, "%s%s%s <- ", 107 O_COLOR_YELLOW, name, 108 O_COLOR_RESET); 109 print_value(file, value, bits); 110} 111 112static const struct si_reg *find_register(enum amd_gfx_level gfx_level, unsigned offset) 113{ 114 const struct si_reg *table; 115 unsigned table_size; 116 117 switch (gfx_level) { 118 case GFX11: 119 table = gfx11_reg_table; 120 table_size = ARRAY_SIZE(gfx11_reg_table); 121 break; 122 case GFX10_3: 123 case GFX10: 124 table = gfx10_reg_table; 125 table_size = ARRAY_SIZE(gfx10_reg_table); 126 break; 127 case GFX9: 128 table = gfx9_reg_table; 129 table_size = ARRAY_SIZE(gfx9_reg_table); 130 break; 131 case GFX8: 132 table = gfx8_reg_table; 133 table_size = ARRAY_SIZE(gfx8_reg_table); 134 break; 135 case GFX7: 136 table = gfx7_reg_table; 137 table_size = ARRAY_SIZE(gfx7_reg_table); 138 break; 139 case GFX6: 140 table = gfx6_reg_table; 141 table_size = ARRAY_SIZE(gfx6_reg_table); 142 break; 143 default: 144 return NULL; 145 } 146 147 for (unsigned i = 0; i < table_size; i++) { 148 const struct si_reg *reg = &table[i]; 149 150 if (reg->offset == offset) 151 return reg; 152 } 153 154 return NULL; 155} 156 157const char *ac_get_register_name(enum amd_gfx_level gfx_level, unsigned offset) 158{ 159 const struct si_reg *reg = find_register(gfx_level, offset); 160 161 return reg ? sid_strings + reg->name_offset : "(no name)"; 162} 163 164void ac_dump_reg(FILE *file, enum amd_gfx_level gfx_level, unsigned offset, uint32_t value, 165 uint32_t field_mask) 166{ 167 const struct si_reg *reg = find_register(gfx_level, offset); 168 169 if (reg) { 170 const char *reg_name = sid_strings + reg->name_offset; 171 bool first_field = true; 172 173 print_spaces(file, INDENT_PKT); 174 fprintf(file, "%s%s%s <- ", 175 O_COLOR_YELLOW, reg_name, 176 O_COLOR_RESET); 177 178 if (!reg->num_fields) { 179 print_value(file, value, 32); 180 return; 181 } 182 183 for (unsigned f = 0; f < reg->num_fields; f++) { 184 const struct si_field *field = sid_fields_table + reg->fields_offset + f; 185 const int *values_offsets = sid_strings_offsets + field->values_offset; 186 uint32_t val = (value & field->mask) >> (ffs(field->mask) - 1); 187 188 if (!(field->mask & field_mask)) 189 continue; 190 191 /* Indent the field. */ 192 if (!first_field) 193 print_spaces(file, INDENT_PKT + strlen(reg_name) + 4); 194 195 /* Print the field. */ 196 fprintf(file, "%s = ", sid_strings + field->name_offset); 197 198 if (val < field->num_values && values_offsets[val] >= 0) 199 fprintf(file, "%s\n", sid_strings + values_offsets[val]); 200 else 201 print_value(file, val, util_bitcount(field->mask)); 202 203 first_field = false; 204 } 205 return; 206 } 207 208 print_spaces(file, INDENT_PKT); 209 fprintf(file, "%s0x%05x%s <- 0x%08x\n", 210 O_COLOR_YELLOW, offset, 211 O_COLOR_RESET, value); 212} 213 214static uint32_t ac_ib_get(struct ac_ib_parser *ib) 215{ 216 uint32_t v = 0; 217 218 if (ib->cur_dw < ib->num_dw) { 219 v = ib->ib[ib->cur_dw]; 220#ifdef HAVE_VALGRIND 221 /* Help figure out where garbage data is written to IBs. 222 * 223 * Arguably we should do this already when the IBs are written, 224 * see RADEON_VALGRIND. The problem is that client-requests to 225 * Valgrind have an overhead even when Valgrind isn't running, 226 * and radeon_emit is performance sensitive... 227 */ 228 if (VALGRIND_CHECK_VALUE_IS_DEFINED(v)) 229 fprintf(ib->f, "%sValgrind: The next DWORD is garbage%s\n", 230 debug_get_option_color() ? COLOR_RED : "", O_COLOR_RESET); 231#endif 232 fprintf(ib->f, "\n\035#%08x ", v); 233 } else { 234 fprintf(ib->f, "\n\035#???????? "); 235 } 236 237 ib->cur_dw++; 238 return v; 239} 240 241static void ac_parse_set_reg_packet(FILE *f, unsigned count, unsigned reg_offset, 242 struct ac_ib_parser *ib) 243{ 244 unsigned reg_dw = ac_ib_get(ib); 245 unsigned reg = ((reg_dw & 0xFFFF) << 2) + reg_offset; 246 unsigned index = reg_dw >> 28; 247 int i; 248 249 if (index != 0) { 250 print_spaces(f, INDENT_PKT); 251 fprintf(f, "INDEX = %u\n", index); 252 } 253 254 for (i = 0; i < count; i++) 255 ac_dump_reg(f, ib->gfx_level, reg + i * 4, ac_ib_get(ib), ~0); 256} 257 258static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib, 259 int *current_trace_id) 260{ 261 unsigned first_dw = ib->cur_dw; 262 int count = PKT_COUNT_G(header); 263 unsigned op = PKT3_IT_OPCODE_G(header); 264 const char *predicate = PKT3_PREDICATE(header) ? "(predicate)" : ""; 265 int i; 266 267 /* Print the name first. */ 268 for (i = 0; i < ARRAY_SIZE(packet3_table); i++) 269 if (packet3_table[i].op == op) 270 break; 271 272 if (i < ARRAY_SIZE(packet3_table)) { 273 const char *name = sid_strings + packet3_table[i].name_offset; 274 275 if (op == PKT3_SET_CONTEXT_REG || op == PKT3_SET_CONFIG_REG || op == PKT3_SET_UCONFIG_REG || 276 op == PKT3_SET_UCONFIG_REG_INDEX || op == PKT3_SET_SH_REG || op == PKT3_SET_SH_REG_INDEX) 277 fprintf(f, "%s%s%s%s:\n", O_COLOR_CYAN, name, predicate, O_COLOR_RESET); 278 else 279 fprintf(f, "%s%s%s%s:\n", O_COLOR_GREEN, name, predicate, O_COLOR_RESET); 280 } else 281 fprintf(f, "%sPKT3_UNKNOWN 0x%x%s%s:\n", O_COLOR_RED, op, predicate, O_COLOR_RESET); 282 283 /* Print the contents. */ 284 switch (op) { 285 case PKT3_SET_CONTEXT_REG: 286 ac_parse_set_reg_packet(f, count, SI_CONTEXT_REG_OFFSET, ib); 287 break; 288 case PKT3_SET_CONFIG_REG: 289 ac_parse_set_reg_packet(f, count, SI_CONFIG_REG_OFFSET, ib); 290 break; 291 case PKT3_SET_UCONFIG_REG: 292 case PKT3_SET_UCONFIG_REG_INDEX: 293 ac_parse_set_reg_packet(f, count, CIK_UCONFIG_REG_OFFSET, ib); 294 break; 295 case PKT3_SET_SH_REG: 296 case PKT3_SET_SH_REG_INDEX: 297 ac_parse_set_reg_packet(f, count, SI_SH_REG_OFFSET, ib); 298 break; 299 case PKT3_ACQUIRE_MEM: 300 if (ib->gfx_level >= GFX11 && G_585_PWS_ENA(ib->ib[ib->cur_dw + 5])) { 301 ac_dump_reg(f, ib->gfx_level, R_580_ACQUIRE_MEM_PWS_2, ac_ib_get(ib), ~0); 302 print_named_value(f, "GCR_SIZE", ac_ib_get(ib), 32); 303 print_named_value(f, "GCR_SIZE_HI", ac_ib_get(ib), 25); 304 print_named_value(f, "GCR_BASE_LO", ac_ib_get(ib), 32); 305 print_named_value(f, "GCR_BASE_HI", ac_ib_get(ib), 32); 306 ac_dump_reg(f, ib->gfx_level, R_585_ACQUIRE_MEM_PWS_7, ac_ib_get(ib), ~0); 307 ac_dump_reg(f, ib->gfx_level, R_586_GCR_CNTL, ac_ib_get(ib), ~0); 308 break; 309 } 310 ac_dump_reg(f, ib->gfx_level, R_0301F0_CP_COHER_CNTL, ac_ib_get(ib), ~0); 311 ac_dump_reg(f, ib->gfx_level, R_0301F4_CP_COHER_SIZE, ac_ib_get(ib), ~0); 312 ac_dump_reg(f, ib->gfx_level, R_030230_CP_COHER_SIZE_HI, ac_ib_get(ib), ~0); 313 ac_dump_reg(f, ib->gfx_level, R_0301F8_CP_COHER_BASE, ac_ib_get(ib), ~0); 314 ac_dump_reg(f, ib->gfx_level, R_0301E4_CP_COHER_BASE_HI, ac_ib_get(ib), ~0); 315 print_named_value(f, "POLL_INTERVAL", ac_ib_get(ib), 16); 316 if (ib->gfx_level >= GFX10) 317 ac_dump_reg(f, ib->gfx_level, R_586_GCR_CNTL, ac_ib_get(ib), ~0); 318 break; 319 case PKT3_SURFACE_SYNC: 320 if (ib->gfx_level >= GFX7) { 321 ac_dump_reg(f, ib->gfx_level, R_0301F0_CP_COHER_CNTL, ac_ib_get(ib), ~0); 322 ac_dump_reg(f, ib->gfx_level, R_0301F4_CP_COHER_SIZE, ac_ib_get(ib), ~0); 323 ac_dump_reg(f, ib->gfx_level, R_0301F8_CP_COHER_BASE, ac_ib_get(ib), ~0); 324 } else { 325 ac_dump_reg(f, ib->gfx_level, R_0085F0_CP_COHER_CNTL, ac_ib_get(ib), ~0); 326 ac_dump_reg(f, ib->gfx_level, R_0085F4_CP_COHER_SIZE, ac_ib_get(ib), ~0); 327 ac_dump_reg(f, ib->gfx_level, R_0085F8_CP_COHER_BASE, ac_ib_get(ib), ~0); 328 } 329 print_named_value(f, "POLL_INTERVAL", ac_ib_get(ib), 16); 330 break; 331 case PKT3_EVENT_WRITE: { 332 uint32_t event_dw = ac_ib_get(ib); 333 ac_dump_reg(f, ib->gfx_level, R_028A90_VGT_EVENT_INITIATOR, event_dw, 334 S_028A90_EVENT_TYPE(~0)); 335 print_named_value(f, "EVENT_INDEX", (event_dw >> 8) & 0xf, 4); 336 print_named_value(f, "INV_L2", (event_dw >> 20) & 0x1, 1); 337 if (count > 0) { 338 print_named_value(f, "ADDRESS_LO", ac_ib_get(ib), 32); 339 print_named_value(f, "ADDRESS_HI", ac_ib_get(ib), 16); 340 } 341 break; 342 } 343 case PKT3_EVENT_WRITE_EOP: { 344 uint32_t event_dw = ac_ib_get(ib); 345 ac_dump_reg(f, ib->gfx_level, R_028A90_VGT_EVENT_INITIATOR, event_dw, 346 S_028A90_EVENT_TYPE(~0)); 347 print_named_value(f, "EVENT_INDEX", (event_dw >> 8) & 0xf, 4); 348 print_named_value(f, "TCL1_VOL_ACTION_ENA", (event_dw >> 12) & 0x1, 1); 349 print_named_value(f, "TC_VOL_ACTION_ENA", (event_dw >> 13) & 0x1, 1); 350 print_named_value(f, "TC_WB_ACTION_ENA", (event_dw >> 15) & 0x1, 1); 351 print_named_value(f, "TCL1_ACTION_ENA", (event_dw >> 16) & 0x1, 1); 352 print_named_value(f, "TC_ACTION_ENA", (event_dw >> 17) & 0x1, 1); 353 print_named_value(f, "ADDRESS_LO", ac_ib_get(ib), 32); 354 uint32_t addr_hi_dw = ac_ib_get(ib); 355 print_named_value(f, "ADDRESS_HI", addr_hi_dw, 16); 356 print_named_value(f, "DST_SEL", (addr_hi_dw >> 16) & 0x3, 2); 357 print_named_value(f, "INT_SEL", (addr_hi_dw >> 24) & 0x7, 3); 358 print_named_value(f, "DATA_SEL", addr_hi_dw >> 29, 3); 359 print_named_value(f, "DATA_LO", ac_ib_get(ib), 32); 360 print_named_value(f, "DATA_HI", ac_ib_get(ib), 32); 361 break; 362 } 363 case PKT3_RELEASE_MEM: { 364 uint32_t event_dw = ac_ib_get(ib); 365 if (ib->gfx_level >= GFX10) { 366 ac_dump_reg(f, ib->gfx_level, R_490_RELEASE_MEM_OP, event_dw, ~0u); 367 } else { 368 ac_dump_reg(f, ib->gfx_level, R_028A90_VGT_EVENT_INITIATOR, event_dw, 369 S_028A90_EVENT_TYPE(~0)); 370 print_named_value(f, "EVENT_INDEX", (event_dw >> 8) & 0xf, 4); 371 print_named_value(f, "TCL1_VOL_ACTION_ENA", (event_dw >> 12) & 0x1, 1); 372 print_named_value(f, "TC_VOL_ACTION_ENA", (event_dw >> 13) & 0x1, 1); 373 print_named_value(f, "TC_WB_ACTION_ENA", (event_dw >> 15) & 0x1, 1); 374 print_named_value(f, "TCL1_ACTION_ENA", (event_dw >> 16) & 0x1, 1); 375 print_named_value(f, "TC_ACTION_ENA", (event_dw >> 17) & 0x1, 1); 376 print_named_value(f, "TC_NC_ACTION_ENA", (event_dw >> 19) & 0x1, 1); 377 print_named_value(f, "TC_WC_ACTION_ENA", (event_dw >> 20) & 0x1, 1); 378 print_named_value(f, "TC_MD_ACTION_ENA", (event_dw >> 21) & 0x1, 1); 379 } 380 uint32_t sel_dw = ac_ib_get(ib); 381 print_named_value(f, "DST_SEL", (sel_dw >> 16) & 0x3, 2); 382 print_named_value(f, "INT_SEL", (sel_dw >> 24) & 0x7, 3); 383 print_named_value(f, "DATA_SEL", sel_dw >> 29, 3); 384 print_named_value(f, "ADDRESS_LO", ac_ib_get(ib), 32); 385 print_named_value(f, "ADDRESS_HI", ac_ib_get(ib), 32); 386 print_named_value(f, "DATA_LO", ac_ib_get(ib), 32); 387 print_named_value(f, "DATA_HI", ac_ib_get(ib), 32); 388 print_named_value(f, "CTXID", ac_ib_get(ib), 32); 389 break; 390 } 391 case PKT3_WAIT_REG_MEM: 392 print_named_value(f, "OP", ac_ib_get(ib), 32); 393 print_named_value(f, "ADDRESS_LO", ac_ib_get(ib), 32); 394 print_named_value(f, "ADDRESS_HI", ac_ib_get(ib), 32); 395 print_named_value(f, "REF", ac_ib_get(ib), 32); 396 print_named_value(f, "MASK", ac_ib_get(ib), 32); 397 print_named_value(f, "POLL_INTERVAL", ac_ib_get(ib), 16); 398 break; 399 case PKT3_DRAW_INDEX_AUTO: 400 ac_dump_reg(f, ib->gfx_level, R_030930_VGT_NUM_INDICES, ac_ib_get(ib), ~0); 401 ac_dump_reg(f, ib->gfx_level, R_0287F0_VGT_DRAW_INITIATOR, ac_ib_get(ib), ~0); 402 break; 403 case PKT3_DRAW_INDEX_2: 404 ac_dump_reg(f, ib->gfx_level, R_028A78_VGT_DMA_MAX_SIZE, ac_ib_get(ib), ~0); 405 ac_dump_reg(f, ib->gfx_level, R_0287E8_VGT_DMA_BASE, ac_ib_get(ib), ~0); 406 ac_dump_reg(f, ib->gfx_level, R_0287E4_VGT_DMA_BASE_HI, ac_ib_get(ib), ~0); 407 ac_dump_reg(f, ib->gfx_level, R_030930_VGT_NUM_INDICES, ac_ib_get(ib), ~0); 408 ac_dump_reg(f, ib->gfx_level, R_0287F0_VGT_DRAW_INITIATOR, ac_ib_get(ib), ~0); 409 break; 410 case PKT3_INDEX_TYPE: 411 ac_dump_reg(f, ib->gfx_level, R_028A7C_VGT_DMA_INDEX_TYPE, ac_ib_get(ib), ~0); 412 break; 413 case PKT3_NUM_INSTANCES: 414 ac_dump_reg(f, ib->gfx_level, R_030934_VGT_NUM_INSTANCES, ac_ib_get(ib), ~0); 415 break; 416 case PKT3_WRITE_DATA: 417 ac_dump_reg(f, ib->gfx_level, R_370_CONTROL, ac_ib_get(ib), ~0); 418 ac_dump_reg(f, ib->gfx_level, R_371_DST_ADDR_LO, ac_ib_get(ib), ~0); 419 ac_dump_reg(f, ib->gfx_level, R_372_DST_ADDR_HI, ac_ib_get(ib), ~0); 420 /* The payload is written automatically */ 421 break; 422 case PKT3_CP_DMA: 423 ac_dump_reg(f, ib->gfx_level, R_410_CP_DMA_WORD0, ac_ib_get(ib), ~0); 424 ac_dump_reg(f, ib->gfx_level, R_411_CP_DMA_WORD1, ac_ib_get(ib), ~0); 425 ac_dump_reg(f, ib->gfx_level, R_412_CP_DMA_WORD2, ac_ib_get(ib), ~0); 426 ac_dump_reg(f, ib->gfx_level, R_413_CP_DMA_WORD3, ac_ib_get(ib), ~0); 427 ac_dump_reg(f, ib->gfx_level, R_415_COMMAND, ac_ib_get(ib), ~0); 428 break; 429 case PKT3_DMA_DATA: 430 ac_dump_reg(f, ib->gfx_level, R_500_DMA_DATA_WORD0, ac_ib_get(ib), ~0); 431 ac_dump_reg(f, ib->gfx_level, R_501_SRC_ADDR_LO, ac_ib_get(ib), ~0); 432 ac_dump_reg(f, ib->gfx_level, R_502_SRC_ADDR_HI, ac_ib_get(ib), ~0); 433 ac_dump_reg(f, ib->gfx_level, R_503_DST_ADDR_LO, ac_ib_get(ib), ~0); 434 ac_dump_reg(f, ib->gfx_level, R_504_DST_ADDR_HI, ac_ib_get(ib), ~0); 435 ac_dump_reg(f, ib->gfx_level, R_415_COMMAND, ac_ib_get(ib), ~0); 436 break; 437 case PKT3_INDIRECT_BUFFER_SI: 438 case PKT3_INDIRECT_BUFFER_CONST: 439 case PKT3_INDIRECT_BUFFER_CIK: { 440 uint32_t base_lo_dw = ac_ib_get(ib); 441 ac_dump_reg(f, ib->gfx_level, R_3F0_IB_BASE_LO, base_lo_dw, ~0); 442 uint32_t base_hi_dw = ac_ib_get(ib); 443 ac_dump_reg(f, ib->gfx_level, R_3F1_IB_BASE_HI, base_hi_dw, ~0); 444 uint32_t control_dw = ac_ib_get(ib); 445 ac_dump_reg(f, ib->gfx_level, R_3F2_IB_CONTROL, control_dw, ~0); 446 447 if (!ib->addr_callback) 448 break; 449 450 uint64_t addr = ((uint64_t)base_hi_dw << 32) | base_lo_dw; 451 void *data = ib->addr_callback(ib->addr_callback_data, addr); 452 if (!data) 453 break; 454 455 if (G_3F2_CHAIN(control_dw)) { 456 ib->ib = data; 457 ib->num_dw = G_3F2_IB_SIZE(control_dw); 458 ib->cur_dw = 0; 459 return; 460 } 461 462 struct ac_ib_parser ib_recurse; 463 memcpy(&ib_recurse, ib, sizeof(ib_recurse)); 464 ib_recurse.ib = data; 465 ib_recurse.num_dw = G_3F2_IB_SIZE(control_dw); 466 ib_recurse.cur_dw = 0; 467 if (ib_recurse.trace_id_count) { 468 if (*current_trace_id == *ib->trace_ids) { 469 ++ib_recurse.trace_ids; 470 --ib_recurse.trace_id_count; 471 } else { 472 ib_recurse.trace_id_count = 0; 473 } 474 } 475 476 fprintf(f, "\n\035>------------------ nested begin ------------------\n"); 477 ac_do_parse_ib(f, &ib_recurse); 478 fprintf(f, "\n\035<------------------- nested end -------------------\n"); 479 break; 480 } 481 case PKT3_CLEAR_STATE: 482 case PKT3_INCREMENT_DE_COUNTER: 483 case PKT3_PFP_SYNC_ME: 484 break; 485 case PKT3_NOP: 486 if (header == PKT3_NOP_PAD) { 487 count = -1; /* One dword NOP. */ 488 } else if (count == 0 && ib->cur_dw < ib->num_dw && AC_IS_TRACE_POINT(ib->ib[ib->cur_dw])) { 489 unsigned packet_id = AC_GET_TRACE_POINT_ID(ib->ib[ib->cur_dw]); 490 491 print_spaces(f, INDENT_PKT); 492 fprintf(f, "%sTrace point ID: %u%s\n", O_COLOR_RED, packet_id, O_COLOR_RESET); 493 494 if (!ib->trace_id_count) 495 break; /* tracing was disabled */ 496 497 *current_trace_id = packet_id; 498 499 print_spaces(f, INDENT_PKT); 500 if (packet_id < *ib->trace_ids) { 501 fprintf(f, "%sThis trace point was reached by the CP.%s\n", 502 O_COLOR_RED, O_COLOR_RESET); 503 } else if (packet_id == *ib->trace_ids) { 504 fprintf(f, "%s!!!!! This is the last trace point that " 505 "was reached by the CP !!!!!%s\n", 506 O_COLOR_RED, O_COLOR_RESET); 507 } else if (packet_id + 1 == *ib->trace_ids) { 508 fprintf(f, "%s!!!!! This is the first trace point that " 509 "was NOT been reached by the CP !!!!!%s\n", 510 O_COLOR_RED, O_COLOR_RESET); 511 } else { 512 fprintf(f, "%s!!!!! This trace point was NOT reached " 513 "by the CP !!!!!%s\n", 514 O_COLOR_RED, O_COLOR_RESET); 515 } 516 break; 517 } 518 break; 519 } 520 521 /* print additional dwords */ 522 while (ib->cur_dw <= first_dw + count) 523 ac_ib_get(ib); 524 525 if (ib->cur_dw > first_dw + count + 1) 526 fprintf(f, "%s !!!!! count in header too low !!!!!%s\n", 527 O_COLOR_RED, O_COLOR_RESET); 528} 529 530/** 531 * Parse and print an IB into a file. 532 */ 533static void ac_do_parse_ib(FILE *f, struct ac_ib_parser *ib) 534{ 535 int current_trace_id = -1; 536 537 while (ib->cur_dw < ib->num_dw) { 538 uint32_t header = ac_ib_get(ib); 539 unsigned type = PKT_TYPE_G(header); 540 541 switch (type) { 542 case 3: 543 ac_parse_packet3(f, header, ib, ¤t_trace_id); 544 break; 545 case 2: 546 /* type-2 nop */ 547 if (header == 0x80000000) { 548 fprintf(f, "%sNOP (type 2)%s\n", 549 O_COLOR_GREEN, O_COLOR_RESET); 550 break; 551 } 552 FALLTHROUGH; 553 default: 554 fprintf(f, "Unknown packet type %i\n", type); 555 break; 556 } 557 } 558} 559 560static void format_ib_output(FILE *f, char *out) 561{ 562 unsigned depth = 0; 563 564 for (;;) { 565 char op = 0; 566 567 if (out[0] == '\n' && out[1] == '\035') 568 out++; 569 if (out[0] == '\035') { 570 op = out[1]; 571 out += 2; 572 } 573 574 if (op == '<') 575 depth--; 576 577 unsigned indent = 4 * depth; 578 if (op != '#') 579 indent += 9; 580 581 if (indent) 582 print_spaces(f, indent); 583 584 char *end = strchrnul(out, '\n'); 585 fwrite(out, end - out, 1, f); 586 fputc('\n', f); /* always end with a new line */ 587 if (!*end) 588 break; 589 590 out = end + 1; 591 592 if (op == '>') 593 depth++; 594 } 595} 596 597/** 598 * Parse and print an IB into a file. 599 * 600 * \param f file 601 * \param ib_ptr IB 602 * \param num_dw size of the IB 603 * \param gfx_level gfx level 604 * \param trace_ids the last trace IDs that are known to have been reached 605 * and executed by the CP, typically read from a buffer 606 * \param trace_id_count The number of entries in the trace_ids array. 607 * \param addr_callback Get a mapped pointer of the IB at a given address. Can 608 * be NULL. 609 * \param addr_callback_data user data for addr_callback 610 */ 611void ac_parse_ib_chunk(FILE *f, uint32_t *ib_ptr, int num_dw, const int *trace_ids, 612 unsigned trace_id_count, enum amd_gfx_level gfx_level, 613 ac_debug_addr_callback addr_callback, void *addr_callback_data) 614{ 615 struct ac_ib_parser ib = {0}; 616 ib.ib = ib_ptr; 617 ib.num_dw = num_dw; 618 ib.trace_ids = trace_ids; 619 ib.trace_id_count = trace_id_count; 620 ib.gfx_level = gfx_level; 621 ib.addr_callback = addr_callback; 622 ib.addr_callback_data = addr_callback_data; 623 624 char *out; 625 size_t outsize; 626 struct u_memstream mem; 627 u_memstream_open(&mem, &out, &outsize); 628 FILE *const memf = u_memstream_get(&mem); 629 ib.f = memf; 630 ac_do_parse_ib(memf, &ib); 631 u_memstream_close(&mem); 632 633 if (out) { 634 format_ib_output(f, out); 635 free(out); 636 } 637 638 if (ib.cur_dw > ib.num_dw) { 639 printf("\nPacket ends after the end of IB.\n"); 640 exit(1); 641 } 642} 643 644/** 645 * Parse and print an IB into a file. 646 * 647 * \param f file 648 * \param ib IB 649 * \param num_dw size of the IB 650 * \param gfx_level gfx level 651 * \param trace_ids the last trace IDs that are known to have been reached 652 * and executed by the CP, typically read from a buffer 653 * \param trace_id_count The number of entries in the trace_ids array. 654 * \param addr_callback Get a mapped pointer of the IB at a given address. Can 655 * be NULL. 656 * \param addr_callback_data user data for addr_callback 657 */ 658void ac_parse_ib(FILE *f, uint32_t *ib, int num_dw, const int *trace_ids, unsigned trace_id_count, 659 const char *name, enum amd_gfx_level gfx_level, ac_debug_addr_callback addr_callback, 660 void *addr_callback_data) 661{ 662 fprintf(f, "------------------ %s begin ------------------\n", name); 663 664 ac_parse_ib_chunk(f, ib, num_dw, trace_ids, trace_id_count, gfx_level, addr_callback, 665 addr_callback_data); 666 667 fprintf(f, "------------------- %s end -------------------\n\n", name); 668} 669 670/** 671 * Parse dmesg and return TRUE if a VM fault has been detected. 672 * 673 * \param gfx_level gfx level 674 * \param old_dmesg_timestamp previous dmesg timestamp parsed at init time 675 * \param out_addr detected VM fault addr 676 */ 677bool ac_vm_fault_occured(enum amd_gfx_level gfx_level, uint64_t *old_dmesg_timestamp, 678 uint64_t *out_addr) 679{ 680#ifdef _WIN32 681 return false; 682#else 683 char line[2000]; 684 unsigned sec, usec; 685 int progress = 0; 686 uint64_t dmesg_timestamp = 0; 687 bool fault = false; 688 689 FILE *p = popen("dmesg", "r"); 690 if (!p) 691 return false; 692 693 while (fgets(line, sizeof(line), p)) { 694 char *msg, len; 695 696 if (!line[0] || line[0] == '\n') 697 continue; 698 699 /* Get the timestamp. */ 700 if (sscanf(line, "[%u.%u]", &sec, &usec) != 2) { 701 static bool hit = false; 702 if (!hit) { 703 fprintf(stderr, "%s: failed to parse line '%s'\n", __func__, line); 704 hit = true; 705 } 706 continue; 707 } 708 dmesg_timestamp = sec * 1000000ull + usec; 709 710 /* If just updating the timestamp. */ 711 if (!out_addr) 712 continue; 713 714 /* Process messages only if the timestamp is newer. */ 715 if (dmesg_timestamp <= *old_dmesg_timestamp) 716 continue; 717 718 /* Only process the first VM fault. */ 719 if (fault) 720 continue; 721 722 /* Remove trailing \n */ 723 len = strlen(line); 724 if (len && line[len - 1] == '\n') 725 line[len - 1] = 0; 726 727 /* Get the message part. */ 728 msg = strchr(line, ']'); 729 if (!msg) 730 continue; 731 msg++; 732 733 const char *header_line, *addr_line_prefix, *addr_line_format; 734 735 if (gfx_level >= GFX9) { 736 /* Match this: 737 * ..: [gfxhub] VMC page fault (src_id:0 ring:158 vm_id:2 pas_id:0) 738 * ..: at page 0x0000000219f8f000 from 27 739 * ..: VM_L2_PROTECTION_FAULT_STATUS:0x0020113C 740 */ 741 header_line = "VMC page fault"; 742 addr_line_prefix = " at page"; 743 addr_line_format = "%" PRIx64; 744 } else { 745 header_line = "GPU fault detected:"; 746 addr_line_prefix = "VM_CONTEXT1_PROTECTION_FAULT_ADDR"; 747 addr_line_format = "%" PRIX64; 748 } 749 750 switch (progress) { 751 case 0: 752 if (strstr(msg, header_line)) 753 progress = 1; 754 break; 755 case 1: 756 msg = strstr(msg, addr_line_prefix); 757 if (msg) { 758 msg = strstr(msg, "0x"); 759 if (msg) { 760 msg += 2; 761 if (sscanf(msg, addr_line_format, out_addr) == 1) 762 fault = true; 763 } 764 } 765 progress = 0; 766 break; 767 default: 768 progress = 0; 769 } 770 } 771 pclose(p); 772 773 if (dmesg_timestamp > *old_dmesg_timestamp) 774 *old_dmesg_timestamp = dmesg_timestamp; 775 776 return fault; 777#endif 778} 779 780static int compare_wave(const void *p1, const void *p2) 781{ 782 struct ac_wave_info *w1 = (struct ac_wave_info *)p1; 783 struct ac_wave_info *w2 = (struct ac_wave_info *)p2; 784 785 /* Sort waves according to PC and then SE, SH, CU, etc. */ 786 if (w1->pc < w2->pc) 787 return -1; 788 if (w1->pc > w2->pc) 789 return 1; 790 if (w1->se < w2->se) 791 return -1; 792 if (w1->se > w2->se) 793 return 1; 794 if (w1->sh < w2->sh) 795 return -1; 796 if (w1->sh > w2->sh) 797 return 1; 798 if (w1->cu < w2->cu) 799 return -1; 800 if (w1->cu > w2->cu) 801 return 1; 802 if (w1->simd < w2->simd) 803 return -1; 804 if (w1->simd > w2->simd) 805 return 1; 806 if (w1->wave < w2->wave) 807 return -1; 808 if (w1->wave > w2->wave) 809 return 1; 810 811 return 0; 812} 813 814/* Return wave information. "waves" should be a large enough array. */ 815unsigned ac_get_wave_info(enum amd_gfx_level gfx_level, 816 struct ac_wave_info waves[AC_MAX_WAVES_PER_CHIP]) 817{ 818#ifdef _WIN32 819 return 0; 820#else 821 char line[2000], cmd[128]; 822 unsigned num_waves = 0; 823 824 sprintf(cmd, "umr -O halt_waves -wa %s", gfx_level >= GFX10 ? "gfx_0.0.0" : "gfx"); 825 826 FILE *p = popen(cmd, "r"); 827 if (!p) 828 return 0; 829 830 if (!fgets(line, sizeof(line), p) || strncmp(line, "SE", 2) != 0) { 831 pclose(p); 832 return 0; 833 } 834 835 while (fgets(line, sizeof(line), p)) { 836 struct ac_wave_info *w; 837 uint32_t pc_hi, pc_lo, exec_hi, exec_lo; 838 839 assert(num_waves < AC_MAX_WAVES_PER_CHIP); 840 w = &waves[num_waves]; 841 842 if (sscanf(line, "%u %u %u %u %u %x %x %x %x %x %x %x", &w->se, &w->sh, &w->cu, &w->simd, 843 &w->wave, &w->status, &pc_hi, &pc_lo, &w->inst_dw0, &w->inst_dw1, &exec_hi, 844 &exec_lo) == 12) { 845 w->pc = ((uint64_t)pc_hi << 32) | pc_lo; 846 w->exec = ((uint64_t)exec_hi << 32) | exec_lo; 847 w->matched = false; 848 num_waves++; 849 } 850 } 851 852 qsort(waves, num_waves, sizeof(struct ac_wave_info), compare_wave); 853 854 pclose(p); 855 return num_waves; 856#endif 857} 858