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)
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)
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,
{
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);
+}
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_ */
#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
*/
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);
};
/**
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
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),
{
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;
+}
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) \
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) \
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) \
struct dmub_srv_common_reg_offset {
#define DMUB_SR(reg) uint32_t reg;
DMUB_COMMON_REGS()
+ DMCUB_INTERNAL_REGS()
#undef DMUB_SR
};
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_ */
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),
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),
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),
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),
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),
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;
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;
+}