Commit 2631ac1a authored by Ashley Thomas's avatar Ashley Thomas Committed by Alex Deucher

drm/amd/display: add DMUB registers to crash dump diagnostic data.

[WHY]
Ability to triage DMCUB is improved with availability of certain
dmub registers not currently captured in crash dump diagnostic data.

[HOW]
Add dmub registers to diagnostic data collection.

Thanks Nicholas Kazlauskas for awesome input on this!
Signed-off-by: default avatarAshley Thomas <Ashley.Thomas2@amd.com>
Reviewed-by: default avatarNicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: default avatarAnson Jacob <Anson.Jacob@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent eb945257
......@@ -86,6 +86,7 @@ void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv,
error:
DC_ERROR("Error queuing DMUB command: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
}
void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv)
......@@ -95,8 +96,10 @@ void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv)
enum dmub_status status;
status = dmub_srv_cmd_execute(dmub);
if (status != DMUB_STATUS_OK)
if (status != DMUB_STATUS_OK) {
DC_ERROR("Error starting DMUB execution: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
}
}
void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv)
......@@ -106,8 +109,10 @@ void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv)
enum dmub_status status;
status = dmub_srv_wait_for_idle(dmub, 100000);
if (status != DMUB_STATUS_OK)
if (status != DMUB_STATUS_OK) {
DC_ERROR("Error waiting for DMUB idle: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
}
}
void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv,
......@@ -214,3 +219,94 @@ void dc_dmub_trace_event_control(struct dc *dc, bool enable)
{
dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable);
}
bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv, struct dmub_diagnostic_data *diag_data)
{
if (!dc_dmub_srv || !dc_dmub_srv->dmub || !diag_data)
return false;
return dmub_srv_get_diagnostic_data(dc_dmub_srv->dmub, diag_data);
}
void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
{
struct dmub_diagnostic_data diag_data = {0};
if (!dc_dmub_srv || !dc_dmub_srv->dmub) {
DC_LOG_ERROR("%s: invalid parameters.", __func__);
return;
}
if (!dc_dmub_srv_get_diagnostic_data(dc_dmub_srv, &diag_data)) {
DC_LOG_ERROR("%s: dc_dmub_srv_get_diagnostic_data failed.", __func__);
return;
}
DC_LOG_DEBUG(
"DMCUB STATE\n"
" dmcub_version : %08x\n"
" scratch [0] : %08x\n"
" scratch [1] : %08x\n"
" scratch [2] : %08x\n"
" scratch [3] : %08x\n"
" scratch [4] : %08x\n"
" scratch [5] : %08x\n"
" scratch [6] : %08x\n"
" scratch [7] : %08x\n"
" scratch [8] : %08x\n"
" scratch [9] : %08x\n"
" scratch [10] : %08x\n"
" scratch [11] : %08x\n"
" scratch [12] : %08x\n"
" scratch [13] : %08x\n"
" scratch [14] : %08x\n"
" scratch [15] : %08x\n"
" pc : %08x\n"
" unk_fault_addr : %08x\n"
" inst_fault_addr : %08x\n"
" data_fault_addr : %08x\n"
" inbox1_rptr : %08x\n"
" inbox1_wptr : %08x\n"
" inbox1_size : %08x\n"
" inbox0_rptr : %08x\n"
" inbox0_wptr : %08x\n"
" inbox0_size : %08x\n"
" is_enabled : %d\n"
" is_soft_reset : %d\n"
" is_secure_reset : %d\n"
" is_traceport_en : %d\n"
" is_cw0_en : %d\n"
" is_cw6_en : %d\n",
diag_data.dmcub_version,
diag_data.scratch[0],
diag_data.scratch[1],
diag_data.scratch[2],
diag_data.scratch[3],
diag_data.scratch[4],
diag_data.scratch[5],
diag_data.scratch[6],
diag_data.scratch[7],
diag_data.scratch[8],
diag_data.scratch[9],
diag_data.scratch[10],
diag_data.scratch[11],
diag_data.scratch[12],
diag_data.scratch[13],
diag_data.scratch[14],
diag_data.scratch[15],
diag_data.pc,
diag_data.undefined_address_fault_addr,
diag_data.inst_fetch_fault_addr,
diag_data.data_write_fault_addr,
diag_data.inbox1_rptr,
diag_data.inbox1_wptr,
diag_data.inbox1_size,
diag_data.inbox0_rptr,
diag_data.inbox0_wptr,
diag_data.inbox0_size,
diag_data.is_dmcub_enabled,
diag_data.is_dmcub_soft_reset,
diag_data.is_dmcub_secure_reset,
diag_data.is_traceport_en,
diag_data.is_cw0_enabled,
diag_data.is_cw6_enabled);
}
......@@ -71,4 +71,8 @@ void dc_dmub_trace_event_control(struct dc *dc, bool enable);
void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv, union dmub_inbox0_data_register data);
bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv, struct dmub_diagnostic_data *dmub_oca);
void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv);
#endif /* _DMUB_DC_SRV_H_ */
......@@ -243,6 +243,31 @@ struct dmub_srv_hw_params {
#endif
};
/**
* struct dmub_diagnostic_data - Diagnostic data retrieved from DMCUB for
* debugging purposes, including logging, crash analysis, etc.
*/
struct dmub_diagnostic_data {
uint32_t dmcub_version;
uint32_t scratch[16];
uint32_t pc;
uint32_t undefined_address_fault_addr;
uint32_t inst_fetch_fault_addr;
uint32_t data_write_fault_addr;
uint32_t inbox1_rptr;
uint32_t inbox1_wptr;
uint32_t inbox1_size;
uint32_t inbox0_rptr;
uint32_t inbox0_wptr;
uint32_t inbox0_size;
uint8_t is_dmcub_enabled : 1;
uint8_t is_dmcub_soft_reset : 1;
uint8_t is_dmcub_secure_reset : 1;
uint8_t is_traceport_en : 1;
uint8_t is_cw0_enabled : 1;
uint8_t is_cw6_enabled : 1;
};
/**
* struct dmub_srv_base_funcs - Driver specific base callbacks
*/
......@@ -335,6 +360,8 @@ struct dmub_srv_hw_funcs {
void (*send_inbox0_cmd)(struct dmub_srv *dmub, union dmub_inbox0_data_register data);
uint32_t (*get_current_time)(struct dmub_srv *dmub);
void (*get_diagnostic_data)(struct dmub_srv *dmub, struct dmub_diagnostic_data *dmub_oca);
};
/**
......@@ -685,6 +712,8 @@ enum dmub_status dmub_srv_cmd_with_reply_data(struct dmub_srv *dmub,
bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entry *entry);
bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data);
#if defined(__cplusplus)
}
#endif
......
......@@ -40,7 +40,10 @@
const struct dmub_srv_common_regs dmub_srv_dcn20_regs = {
#define DMUB_SR(reg) REG_OFFSET(reg),
{ DMUB_COMMON_REGS() },
{
DMUB_COMMON_REGS()
DMCUB_INTERNAL_REGS()
},
#undef DMUB_SR
#define DMUB_SF(reg, field) FD_MASK(reg, field),
......@@ -404,3 +407,63 @@ uint32_t dmub_dcn20_get_current_time(struct dmub_srv *dmub)
{
return REG_READ(DMCUB_TIMER_CURRENT);
}
void dmub_dcn20_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data)
{
uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset;
uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled;
if (!dmub || !diag_data)
return;
memset(diag_data, 0, sizeof(*diag_data));
diag_data->dmcub_version = dmub->fw_version;
diag_data->scratch[0] = REG_READ(DMCUB_SCRATCH0);
diag_data->scratch[1] = REG_READ(DMCUB_SCRATCH1);
diag_data->scratch[2] = REG_READ(DMCUB_SCRATCH2);
diag_data->scratch[3] = REG_READ(DMCUB_SCRATCH3);
diag_data->scratch[4] = REG_READ(DMCUB_SCRATCH4);
diag_data->scratch[5] = REG_READ(DMCUB_SCRATCH5);
diag_data->scratch[6] = REG_READ(DMCUB_SCRATCH6);
diag_data->scratch[7] = REG_READ(DMCUB_SCRATCH7);
diag_data->scratch[8] = REG_READ(DMCUB_SCRATCH8);
diag_data->scratch[9] = REG_READ(DMCUB_SCRATCH9);
diag_data->scratch[10] = REG_READ(DMCUB_SCRATCH10);
diag_data->scratch[11] = REG_READ(DMCUB_SCRATCH11);
diag_data->scratch[12] = REG_READ(DMCUB_SCRATCH12);
diag_data->scratch[13] = REG_READ(DMCUB_SCRATCH13);
diag_data->scratch[14] = REG_READ(DMCUB_SCRATCH14);
diag_data->scratch[15] = REG_READ(DMCUB_SCRATCH15);
diag_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR);
diag_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR);
diag_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR);
diag_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR);
diag_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR);
diag_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE);
diag_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR);
diag_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR);
diag_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE);
REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled);
diag_data->is_dmcub_enabled = is_dmub_enabled;
REG_GET(DMCUB_CNTL, DMCUB_SOFT_RESET, &is_soft_reset);
diag_data->is_dmcub_soft_reset = is_soft_reset;
REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset);
diag_data->is_dmcub_secure_reset = is_sec_reset;
REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled);
diag_data->is_traceport_en = is_traceport_enabled;
REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled);
diag_data->is_cw0_enabled = is_cw0_enabled;
REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled);
diag_data->is_cw6_enabled = is_cw6_enabled;
}
......@@ -36,6 +36,9 @@ struct dmub_srv;
DMUB_SR(DMCUB_CNTL) \
DMUB_SR(DMCUB_MEM_CNTL) \
DMUB_SR(DMCUB_SEC_CNTL) \
DMUB_SR(DMCUB_INBOX0_SIZE) \
DMUB_SR(DMCUB_INBOX0_RPTR) \
DMUB_SR(DMCUB_INBOX0_WPTR) \
DMUB_SR(DMCUB_INBOX1_BASE_ADDRESS) \
DMUB_SR(DMCUB_INBOX1_SIZE) \
DMUB_SR(DMCUB_INBOX1_RPTR) \
......@@ -108,7 +111,12 @@ struct dmub_srv;
DMUB_SR(DCN_VM_FB_LOCATION_BASE) \
DMUB_SR(DCN_VM_FB_OFFSET) \
DMUB_SR(DMCUB_INTERRUPT_ACK) \
DMUB_SR(DMCUB_TIMER_CURRENT)
DMUB_SR(DMCUB_TIMER_CURRENT) \
DMUB_SR(DMCUB_INST_FETCH_FAULT_ADDR) \
DMUB_SR(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR) \
DMUB_SR(DMCUB_DATA_WRITE_FAULT_ADDR)
#define DMCUB_INTERNAL_REGS()
#define DMUB_COMMON_FIELDS() \
DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \
......@@ -118,6 +126,7 @@ struct dmub_srv;
DMUB_SF(DMCUB_MEM_CNTL, DMCUB_MEM_WRITE_SPACE) \
DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET) \
DMUB_SF(DMCUB_SEC_CNTL, DMCUB_MEM_UNIT_ID) \
DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS) \
DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_TOP_ADDRESS) \
DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE) \
DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_TOP_ADDRESS) \
......@@ -147,6 +156,7 @@ struct dmub_srv;
struct dmub_srv_common_reg_offset {
#define DMUB_SR(reg) uint32_t reg;
DMUB_COMMON_REGS()
DMCUB_INTERNAL_REGS()
#undef DMUB_SR
};
......@@ -234,4 +244,6 @@ bool dmub_dcn20_use_cached_trace_buffer(struct dmub_srv *dmub);
uint32_t dmub_dcn20_get_current_time(struct dmub_srv *dmub);
void dmub_dcn20_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *dmub_oca);
#endif /* _DMUB_DCN20_H_ */
......@@ -39,7 +39,10 @@
const struct dmub_srv_common_regs dmub_srv_dcn21_regs = {
#define DMUB_SR(reg) REG_OFFSET(reg),
{ DMUB_COMMON_REGS() },
{
DMUB_COMMON_REGS()
DMCUB_INTERNAL_REGS()
},
#undef DMUB_SR
#define DMUB_SF(reg, field) FD_MASK(reg, field),
......
......@@ -40,7 +40,10 @@
const struct dmub_srv_common_regs dmub_srv_dcn30_regs = {
#define DMUB_SR(reg) REG_OFFSET(reg),
{ DMUB_COMMON_REGS() },
{
DMUB_COMMON_REGS()
DMCUB_INTERNAL_REGS()
},
#undef DMUB_SR
#define DMUB_SF(reg, field) FD_MASK(reg, field),
......
......@@ -39,7 +39,10 @@
const struct dmub_srv_common_regs dmub_srv_dcn301_regs = {
#define DMUB_SR(reg) REG_OFFSET(reg),
{ DMUB_COMMON_REGS() },
{
DMUB_COMMON_REGS()
DMCUB_INTERNAL_REGS()
},
#undef DMUB_SR
#define DMUB_SF(reg, field) FD_MASK(reg, field),
......
......@@ -39,7 +39,10 @@
const struct dmub_srv_common_regs dmub_srv_dcn302_regs = {
#define DMUB_SR(reg) REG_OFFSET(reg),
{ DMUB_COMMON_REGS() },
{
DMUB_COMMON_REGS()
DMCUB_INTERNAL_REGS()
},
#undef DMUB_SR
#define DMUB_SF(reg, field) FD_MASK(reg, field),
......
......@@ -21,7 +21,10 @@
const struct dmub_srv_common_regs dmub_srv_dcn303_regs = {
#define DMUB_SR(reg) REG_OFFSET(reg),
{ DMUB_COMMON_REGS() },
{
DMUB_COMMON_REGS()
DMCUB_INTERNAL_REGS()
},
#undef DMUB_SR
#define DMUB_SF(reg, field) FD_MASK(reg, field),
......
......@@ -176,6 +176,8 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
funcs->get_outbox0_wptr = dmub_dcn20_get_outbox0_wptr;
funcs->set_outbox0_rptr = dmub_dcn20_set_outbox0_rptr;
funcs->get_diagnostic_data = dmub_dcn20_get_diagnostic_data;
if (asic == DMUB_ASIC_DCN21) {
dmub->regs = &dmub_srv_dcn21_regs;
......@@ -794,3 +796,11 @@ bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entr
return dmub_rb_out_trace_buffer_front(&dmub->outbox0_rb, (void *)entry);
}
bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data)
{
if (!dmub || !dmub->hw_funcs.get_diagnostic_data || !diag_data)
return false;
dmub->hw_funcs.get_diagnostic_data(dmub, diag_data);
return true;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment