freedreno/crashdec: Initial a7xx support

There are more things to do, e.g. BV mempool dumping and estimating the
BV location. However this is a good start.

The expanded register size is because the reglist includes registers
from other cores and these are read the same as any other GPU register.
Note that this is also the actual range of type4 packets, even though
registers higher than 0xffff are all protected. Right now these are
skipped on page faults but still read with the crashdumper for hangs.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27266>
This commit is contained in:
Connor Abbott
2024-01-24 05:00:22 -05:00
committed by Marge Bot
parent 81f42d82ed
commit 13fdde0c7d
4 changed files with 97 additions and 35 deletions

View File

@@ -62,7 +62,7 @@ static inline unsigned
regcnt(void)
{
if (options->info->chip >= 5)
return 0xffff;
return 0x3ffff;
else
return 0x7fff;
}
@@ -293,7 +293,7 @@ parse_dword_addr(uint32_t dword, uint32_t *gpuaddr, uint32_t *flags,
*flags = dword & mask;
}
static uint32_t type0_reg_vals[0xffff + 1];
static uint32_t type0_reg_vals[0x3ffff + 1];
static uint8_t type0_reg_rewritten[sizeof(type0_reg_vals) /
8]; /* written since last draw */
static uint8_t type0_reg_written[sizeof(type0_reg_vals) / 8];

View File

@@ -47,7 +47,13 @@ dump_mem_pool_reg_write(unsigned reg, uint32_t data, unsigned context,
}
rnn_reginfo_free(info);
} else {
printf("\t\twrite %s (%05x) context %d\n", regname(reg, 1), reg, context);
printf("\t\twrite %s (%05x)", regname(reg, 1), reg);
if (is_a6xx()) {
printf(" context %d", context);
}
printf("\n");
dump_register_val(&r, 2);
}
}
@@ -133,7 +139,7 @@ dump_cp_mem_pool(uint32_t *mempool)
const int num_blocks = small_mem_pool ? 0x30 : 0x80;
/* Number of queues */
const unsigned num_queues = 6;
const unsigned num_queues = is_a6xx() ? 6 : 7;
/* Unfortunately the per-queue state is a little more complicated than
* a simple pair of begin/end pointers. Instead of a single beginning
@@ -198,31 +204,31 @@ dump_cp_mem_pool(uint32_t *mempool)
uint32_t chunk : 3;
uint32_t first_block : 32 - 3;
} writer[6];
uint32_t padding1[2]; /* Mirrors of writer[4], writer[5] */
uint32_t padding1[2]; /* Mirror of writer[5] */
uint32_t unk1;
uint32_t padding2[7]; /* Mirrors of unk1 */
uint32_t writer_second_block[6];
uint32_t padding3[2];
uint32_t writer_second_block[7];
uint32_t padding3[1];
uint32_t unk2[6];
uint32_t padding4[2];
uint32_t unk2[7];
uint32_t padding4[1];
struct {
uint32_t chunk : 3;
uint32_t first_block : 32 - 3;
} reader[6];
uint32_t padding5[2]; /* Mirrors of reader[4], reader[5] */
} reader[7];
uint32_t padding5[1]; /* Mirror of reader[5] */
uint32_t unk3;
uint32_t padding6[7]; /* Mirrors of unk3 */
uint32_t reader_second_block[6];
uint32_t padding7[2];
uint32_t reader_second_block[7];
uint32_t padding7[1];
uint32_t block_count[6];
uint32_t padding[2];
uint32_t block_count[7];
uint32_t padding[1];
uint32_t unk4;
uint32_t padding9[7]; /* Mirrors of unk4 */
@@ -254,9 +260,12 @@ dump_cp_mem_pool(uint32_t *mempool)
}
for (int queue = 0; queue < num_queues; queue++) {
const char *cluster_names[6] = {"FE", "SP_VS", "PC_VS",
"GRAS", "SP_PS", "PS"};
printf("\tCLUSTER_%s:\n\n", cluster_names[queue]);
const char *cluster_names_a6xx[6] = {"FE", "SP_VS", "PC_VS",
"GRAS", "SP_PS", "PS"};
const char *cluster_names_a7xx[7] = {"FE", "SP_VS", "PC_VS",
"GRAS", "SP_PS", "VPC_PS", "PS"};
printf("\tCLUSTER_%s:\n\n",
is_a6xx() ? cluster_names_a6xx[queue] : cluster_names_a7xx[queue]);
if (verbose) {
printf("\t\twriter_first_block: 0x%x\n",

View File

@@ -174,8 +174,16 @@ startswith(const char *line, const char *start)
return strstr(line, start) == line;
}
static bool
startswith_nowhitespace(const char *line, const char *start)
{
while (*line == ' ' || *line == '\t')
line++;
return startswith(line, start);
}
static void
parseline(const char *line, const char *fmt, ...)
vparseline(const char *line, const char *fmt, va_list ap)
{
int fmtlen = strlen(fmt);
int n = 0;
@@ -194,12 +202,30 @@ parseline(const char *line, const char *fmt, ...)
}
}
va_list ap;
va_start(ap, fmt);
if (vsscanf(line, fmt, ap) != n) {
fprintf(stderr, "parse error scanning: '%s'\n", fmt);
exit(1);
}
}
static void
parseline(const char *line, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vparseline(line, fmt, ap);
va_end(ap);
}
static void
parseline_nowhitespace(const char *line, const char *fmt, ...)
{
while (*line == ' ' || *line == '\t')
line++;
va_list ap;
va_start(ap, fmt);
vparseline(line, fmt, ap);
va_end(ap);
}
@@ -348,10 +374,10 @@ dump_cmdstream(void)
printf("got rb_base=%" PRIx64 "\n", rb_base);
options.ibs[1].base = regval64("CP_IB1_BASE");
if (is_a6xx())
if (have_rem_info())
options.ibs[1].rem = regval("CP_IB1_REM_SIZE");
options.ibs[2].base = regval64("CP_IB2_BASE");
if (is_a6xx())
if (have_rem_info())
options.ibs[2].rem = regval("CP_IB2_REM_SIZE");
/* Adjust remaining size to account for cmdstream slurped into ROQ
@@ -363,7 +389,7 @@ dump_cmdstream(void)
* TODO it would be nice to be able to extract out register bitfields
* by name rather than hard-coding this.
*/
if (is_a6xx()) {
if (have_rem_info()) {
uint32_t ib1_rem = regval("CP_ROQ_AVAIL_IB1") >> 16;
uint32_t ib2_rem = regval("CP_ROQ_AVAIL_IB2") >> 16;
options.ibs[1].rem += ib1_rem ? ib1_rem - 1 : 0;
@@ -563,14 +589,15 @@ decode_clusters(void)
struct regacc r = regacc(NULL);
foreach_line_in_section (line) {
if (startswith(line, " - cluster-name:") ||
startswith(line, " - context:")) {
if (startswith_nowhitespace(line, "- cluster-name:") ||
startswith_nowhitespace(line, "- context:") ||
startswith_nowhitespace(line, "- pipe:")) {
printf("%s", line);
continue;
}
uint32_t offset, value;
parseline(line, " - { offset: %x, value: %x }", &offset, &value);
parseline_nowhitespace(line, "- { offset: %x, value: %x }", &offset, &value);
if (regacc_push(&r, offset / 4, value)) {
printf("\t%08"PRIx64, r.value);
@@ -590,7 +617,7 @@ dump_cp_sqe_stat(uint32_t *stat)
printf("\t PC: %04x\n", stat[0]);
stat++;
if (is_a6xx() && valid_header(stat[0])) {
if (!is_a5xx() && valid_header(stat[0])) {
if (pkt_is_type7(stat[0])) {
unsigned opc = cp_type7_opcode(stat[0]);
const char *name = pktname(opc);
@@ -690,10 +717,11 @@ decode_indexed_registers(void)
* so far) not useful, so skip them if not in verbose mode:
*/
bool dump = verbose || !strcmp(name, "CP_SQE_STAT") ||
!strcmp(name, "CP_BV_SQE_STAT") ||
!strcmp(name, "CP_DRAW_STATE") ||
!strcmp(name, "CP_ROQ") || 0;
if (!strcmp(name, "CP_SQE_STAT"))
if (!strcmp(name, "CP_SQE_STAT") || !strcmp(name, "CP_BV_SQE_STAT"))
dump_cp_sqe_stat(buf);
if (!strcmp(name, "CP_UCODE_DBG_DATA"))
@@ -728,19 +756,23 @@ decode_shader_blocks(void)
if (startswith(line, " - type:")) {
free(type);
parseline(line, " - type: %ms", &type);
} else if (startswith(line, " size:")) {
parseline(line, " size: %u", &sizedwords);
} else if (startswith(line, " data: !!ascii85 |")) {
} else if (startswith_nowhitespace(line, "size:")) {
parseline_nowhitespace(line, "size: %u", &sizedwords);
} else if (startswith_nowhitespace(line, "data: !!ascii85 |")) {
uint32_t *buf = popline_ascii85(sizedwords);
/* some of the sections are pretty large, and are (at least
* so far) not useful, so skip them if not in verbose mode:
*/
bool dump = verbose || !strcmp(type, "A6XX_SP_INST_DATA") ||
!strcmp(type, "A6XX_HLSQ_INST_RAM") || 0;
!strcmp(type, "A6XX_HLSQ_INST_RAM") ||
!strcmp(type, "A7XX_SP_INST_DATA") ||
!strcmp(type, "A7XX_HLSQ_INST_RAM") || 0;
if (!strcmp(type, "A6XX_SP_INST_DATA") ||
!strcmp(type, "A6XX_HLSQ_INST_RAM")) {
!strcmp(type, "A6XX_HLSQ_INST_RAM") ||
!strcmp(type, "A7XX_SP_INST_DATA") ||
!strcmp(type, "A7XX_HLSQ_INST_RAM")) {
/* TODO this section actually contains multiple shaders
* (or parts of shaders?), so perhaps we should search
* for ends of shaders and decode each?
@@ -826,7 +858,16 @@ decode(void)
cffdec_init(&options);
if (is_a6xx()) {
if (is_a7xx()) {
rnn_gmu = rnn_new(!options.color);
rnn_load_file(rnn_gmu, "adreno/a6xx_gmu.xml", "A6XX");
rnn_control = rnn_new(!options.color);
rnn_load_file(rnn_control, "adreno/adreno_control_regs.xml",
"A7XX_CONTROL_REG");
rnn_pipe = rnn_new(!options.color);
rnn_load_file(rnn_pipe, "adreno/adreno_pipe_regs.xml",
"A7XX_PIPE_REG");
} else if (is_a6xx()) {
rnn_gmu = rnn_new(!options.color);
rnn_load_file(rnn_gmu, "adreno/a6xx_gmu.xml", "A6XX");
rnn_control = rnn_new(!options.color);

View File

@@ -53,6 +53,18 @@ extern bool verbose;
extern struct cffdec_options options;
static inline bool
have_rem_info(void)
{
return options.info->chip == 6 || options.info->chip == 7;
}
static inline bool
is_a7xx(void)
{
return options.info->chip == 7;
}
static inline bool
is_a6xx(void)
{