iwlwifi: fw: dump TCM error table if present
If the TCM is present in the hardware (as advertised in the firmware file TLV data), dump its error log table during firmware error dumps. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Link: https://lore.kernel.org/r/iwlwifi.20210621103449.2d2149f6654f.Id831f8fbca59900ba7efc623ffca0ca938b664d3@changeid Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
This commit is contained in:
parent
c863797b81
commit
48d0c8d5a0
|
@ -271,6 +271,65 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu
|
|||
IWL_ERR(fwrt, "0x%08X | flow_handler\n", table.flow_handler);
|
||||
}
|
||||
|
||||
/*
|
||||
* TCM error struct.
|
||||
* Note: This structure is read from the device with IO accesses,
|
||||
* and the reading already does the endian conversion. As it is
|
||||
* read with u32-sized accesses, any members with a different size
|
||||
* need to be ordered correctly though!
|
||||
*/
|
||||
struct iwl_tcm_error_event_table {
|
||||
u32 valid;
|
||||
u32 error_id;
|
||||
u32 blink2;
|
||||
u32 ilink1;
|
||||
u32 ilink2;
|
||||
u32 data1, data2, data3;
|
||||
u32 logpc;
|
||||
u32 frame_pointer;
|
||||
u32 stack_pointer;
|
||||
u32 msgid;
|
||||
u32 isr;
|
||||
u32 hw_status[5];
|
||||
u32 sw_status[1];
|
||||
u32 reserved[4];
|
||||
} __packed; /* TCM_LOG_ERROR_TABLE_API_S_VER_1 */
|
||||
|
||||
static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
struct iwl_trans *trans = fwrt->trans;
|
||||
struct iwl_tcm_error_event_table table = {};
|
||||
u32 base = fwrt->trans->dbg.tcm_error_event_table;
|
||||
int i;
|
||||
|
||||
if (!base ||
|
||||
!(fwrt->trans->dbg.error_event_table_tlv_status &
|
||||
IWL_ERROR_EVENT_TABLE_TCM))
|
||||
return;
|
||||
|
||||
iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
|
||||
|
||||
IWL_ERR(fwrt, "TCM status:\n");
|
||||
IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm interruptlink1\n", table.ilink1);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm data3\n", table.data3);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm log PC\n", table.logpc);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm frame pointer\n", table.frame_pointer);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm stack pointer\n", table.stack_pointer);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm msg ID\n", table.msgid);
|
||||
IWL_ERR(fwrt, "0x%08X | tcm ISR status\n", table.isr);
|
||||
for (i = 0; i < ARRAY_SIZE(table.hw_status); i++)
|
||||
IWL_ERR(fwrt, "0x%08X | tcm HW status[%d]\n",
|
||||
table.hw_status[i], i);
|
||||
for (i = 0; i < ARRAY_SIZE(table.sw_status); i++)
|
||||
IWL_ERR(fwrt, "0x%08X | tcm SW status[%d]\n",
|
||||
table.sw_status[i], i);
|
||||
}
|
||||
|
||||
static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
struct iwl_trans *trans = fwrt->trans;
|
||||
|
@ -352,6 +411,7 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt)
|
|||
if (fwrt->trans->dbg.lmac_error_event_table[1])
|
||||
iwl_fwrt_dump_lmac_error_log(fwrt, 1);
|
||||
iwl_fwrt_dump_umac_error_log(fwrt);
|
||||
iwl_fwrt_dump_tcm_error_log(fwrt);
|
||||
iwl_fwrt_dump_iml_error_log(fwrt);
|
||||
iwl_fwrt_dump_fseq_regs(fwrt);
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ enum iwl_ucode_tlv_type {
|
|||
|
||||
IWL_UCODE_TLV_PNVM_VERSION = 62,
|
||||
IWL_UCODE_TLV_PNVM_SKU = 64,
|
||||
IWL_UCODE_TLV_TCM_DEBUG_ADDRS = 65,
|
||||
|
||||
IWL_UCODE_TLV_FW_NUM_STATIONS = IWL_UCODE_TLV_CONST_BASE + 0,
|
||||
|
||||
|
@ -950,6 +951,10 @@ struct iwl_fw_cmd_version {
|
|||
u8 notif_ver;
|
||||
} __packed;
|
||||
|
||||
struct iwl_fw_tcm_error_addr {
|
||||
__le32 addr;
|
||||
}; /* FW_TLV_TCM_ERROR_INFO_ADDRS_S */
|
||||
|
||||
static inline size_t _iwl_tlv_array_len(const struct iwl_ucode_tlv *tlv,
|
||||
size_t fixed_size, size_t var_size)
|
||||
{
|
||||
|
|
|
@ -1117,6 +1117,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
IWL_ERROR_EVENT_TABLE_LMAC1;
|
||||
break;
|
||||
}
|
||||
case IWL_UCODE_TLV_TCM_DEBUG_ADDRS: {
|
||||
struct iwl_fw_tcm_error_addr *ptr = (void *)tlv_data;
|
||||
|
||||
if (tlv_len != sizeof(*ptr))
|
||||
goto invalid_tlv_len;
|
||||
drv->trans->dbg.tcm_error_event_table =
|
||||
le32_to_cpu(ptr->addr) & ~FW_ADDR_CACHE_CONTROL;
|
||||
drv->trans->dbg.error_event_table_tlv_status |=
|
||||
IWL_ERROR_EVENT_TABLE_TCM;
|
||||
break;
|
||||
}
|
||||
case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
|
||||
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
|
||||
case IWL_UCODE_TLV_TYPE_HCMD:
|
||||
|
|
|
@ -193,6 +193,7 @@ enum iwl_error_event_table_status {
|
|||
IWL_ERROR_EVENT_TABLE_LMAC1 = BIT(0),
|
||||
IWL_ERROR_EVENT_TABLE_LMAC2 = BIT(1),
|
||||
IWL_ERROR_EVENT_TABLE_UMAC = BIT(2),
|
||||
IWL_ERROR_EVENT_TABLE_TCM = BIT(3),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -708,6 +709,7 @@ struct iwl_self_init_dram {
|
|||
* @trigger_tlv: array of pointers to triggers TLVs for debug
|
||||
* @lmac_error_event_table: addrs of lmacs error tables
|
||||
* @umac_error_event_table: addr of umac error table
|
||||
* @tcm_error_event_table: address of TCM error table
|
||||
* @error_event_table_tlv_status: bitmap that indicates what error table
|
||||
* pointers was recevied via TLV. uses enum &iwl_error_event_table_status
|
||||
* @internal_ini_cfg: internal debug cfg state. Uses &enum iwl_ini_cfg_state
|
||||
|
@ -734,6 +736,7 @@ struct iwl_trans_debug {
|
|||
|
||||
u32 lmac_error_event_table[2];
|
||||
u32 umac_error_event_table;
|
||||
u32 tcm_error_event_table;
|
||||
unsigned int error_event_table_tlv_status;
|
||||
|
||||
enum iwl_ini_cfg_state internal_ini_cfg;
|
||||
|
|
Loading…
Reference in New Issue