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:
@@ -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];
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user