drm/amd/display: add DMUB registers to crash dump diagnostic data.
authorAshley Thomas <Ashley.Thomas2@amd.com>
Tue, 18 May 2021 01:34:45 +0000 (18:34 -0700)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 15 Jun 2021 21:25:40 +0000 (17:25 -0400)
[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>
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
drivers/gpu/drm/amd/display/dmub/dmub_srv.h
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn301.c
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn302.c
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn303.c
drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c

index 48ca23e1e5999da02bc100aeea46e52e875a0af0..36b6fbcc04417926157eaad6f849f4a18d154d55 100644 (file)
@@ -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);
+}
index f5489c7aa77000839571ac0b46688438aeeabb93..0d568019893758e40eeeab54e1024f4d2f85ae6a 100644 (file)
@@ -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_ */
index 7634e8d94543f4ff7773c9f2f25d0629678f4fca..2bf5e72077442ae042c3e29c50a2a9caf3b4a188 100644 (file)
@@ -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
index 8cdc1c75394e71c3402a68efa6742766761e923c..a6540e27044d289c67d93eb4389282c8828b27b5 100644 (file)
 
 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;
+}
index f772f8b348ea81387d5f5ba17a2fabb81fd404b2..c2e5831ac52cc017454587b4c23d423d40ef591c 100644 (file)
@@ -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_ */
index 1cf67b3e47714af6a7e0485486be89b13eaa2b9c..51bb9bceb1b101f164da6bd8141dc37753afaf1b 100644 (file)
 
 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),
index fb11c8d392081d4bf718c2fe3e475a9327ac44dc..81dae75e9ff81010756aab37f530810649b911ad 100644 (file)
 
 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),
index 197398257692456e517e17bf7027af4c5457279c..84c3ab3becc5391b131cc8f855880916b9e9c342 100644 (file)
 
 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),
index f5db4437a8821ab7509a8e6fbb738d0a4b033940..8c02575e168df7851b0365f9607b20f0a2382c17 100644 (file)
 
 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),
index 9331e1719901c9420d5887148e60827908515739..b42369984473acb258ecfde6bf281e2492c04397 100644 (file)
 
 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),
index 681500f42c91b511736b7a94c890d25100c05ddf..a195734b4ddf1967b03f6cb674acdf7428ea9b1d 100644 (file)
@@ -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;
+}