Skip to content

Commit

Permalink
iwlwifi: fw: dump TCM error table if present
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg authored and Luca Coelho committed Jun 22, 2021
1 parent c863797 commit 48d0c8d
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 0 deletions.
60 changes: 60 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/fw/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/fw/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down Expand Up @@ -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)
{
Expand Down
11 changes: 11 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/iwl-drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/iwl-trans.h
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};

/**
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down

0 comments on commit 48d0c8d

Please sign in to comment.