mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 03:10:30 -04:00
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: Ashley Thomas <Ashley.Thomas2@amd.com> Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com> Acked-by: Anson Jacob <Anson.Jacob@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
committed by
Alex Deucher
parent
eb945257fc
commit
2631ac1ac3
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user