From 7b445f3501c8f9004a40994710deec0ad7c230ae Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 20 Mar 2014 11:08:19 +0200 Subject: [PATCH] iwlwifi: mvm: dump Rx FIFO when the firmware asserts The Rx FIFO includes valuable data - dump it when the FW asserts. Also - free the SRAM and Rx FIFO when we create the file, and don't collect new SRAM / Rx FIFO if the previous file hasn't been collected through debugfs yet. Also - add a comment to saying that the ASSERT output should not be modified since we have automatic scripts that monitor this output. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 8 ++++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 3 -- .../net/wireless/iwlwifi/mvm/fw-error-dump.h | 6 ++- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 20 +++++++- drivers/net/wireless/iwlwifi/mvm/utils.c | 46 ++++++++++++++++++- 6 files changed, 78 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 5f657c501406..779311080a9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -348,4 +348,12 @@ enum secure_load_status_reg { #define LMPM_SECURE_TIME_OUT (100) +/* Rx FIFO */ +#define RXF_SIZE_ADDR (0xa00c88) +#define RXF_SIZE_BYTE_CND_POS (7) +#define RXF_SIZE_BYTE_CNT_MSK (0x3ff << RXF_SIZE_BYTE_CND_POS) + +#define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10) +#define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c) + #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 1b52deea6081..d7275726e723 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -136,9 +136,6 @@ static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file) file->private_data = mvm->fw_error_dump; mvm->fw_error_dump = NULL; - kfree(mvm->fw_error_sram); - mvm->fw_error_sram = NULL; - mvm->fw_error_sram_len = 0; ret = 0; out: diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h b/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h index 58c8941c0d95..f381908be7e5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h @@ -71,10 +71,12 @@ * enum iwl_fw_error_dump_type - types of data in the dump file * @IWL_FW_ERROR_DUMP_SRAM: * @IWL_FW_ERROR_DUMP_REG: + * @IWL_FW_ERROR_DUMP_RXF: */ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_SRAM = 0, IWL_FW_ERROR_DUMP_REG = 1, + IWL_FW_ERROR_DUMP_RXF = 2, IWL_FW_ERROR_DUMP_MAX, }; @@ -89,7 +91,7 @@ struct iwl_fw_error_dump_data { __le32 type; __le32 len; __u8 data[]; -} __packed __aligned(4); +} __packed; /** * struct iwl_fw_error_dump_file - the layout of the header of the file @@ -101,6 +103,6 @@ struct iwl_fw_error_dump_file { __le32 barker; __le32 file_len; u8 data[0]; -} __packed __aligned(4); +} __packed; #endif /* __fw_error_dump_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 54207007382a..9f2ecf22bb43 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -580,6 +580,8 @@ struct iwl_mvm { void *fw_error_dump; void *fw_error_sram; u32 fw_error_sram_len; + u32 *fw_error_rxf; + u32 fw_error_rxf_len; struct led_classdev led; @@ -705,6 +707,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm); +void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm); #endif u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e436c04083c2..7cb401b45e49 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -538,6 +538,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) kfree(mvm->scan_cmd); vfree(mvm->fw_error_dump); kfree(mvm->fw_error_sram); + kfree(mvm->fw_error_rxf); kfree(mvm->mcast_filter_cmd); mvm->mcast_filter_cmd = NULL; @@ -821,8 +822,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) return; file_len = mvm->fw_error_sram_len + + mvm->fw_error_rxf_len + sizeof(*dump_file) + - sizeof(*dump_data); + sizeof(*dump_data) * 2; dump_file = vmalloc(file_len); if (!dump_file) @@ -833,7 +835,12 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); dump_file->file_len = cpu_to_le32(file_len); dump_data = (void *)dump_file->data; - dump_data->type = IWL_FW_ERROR_DUMP_SRAM; + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); + dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); + memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len); + + dump_data = (void *)((u8 *)dump_data->data + mvm->fw_error_rxf_len); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); /* @@ -842,6 +849,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) * mvm->fw_error_sram right now. */ memcpy(dump_data->data, mvm->fw_error_sram, mvm->fw_error_sram_len); + + kfree(mvm->fw_error_rxf); + mvm->fw_error_rxf = NULL; + mvm->fw_error_rxf_len = 0; + + kfree(mvm->fw_error_sram); + mvm->fw_error_sram = NULL; + mvm->fw_error_sram_len = 0; } #endif @@ -853,6 +868,7 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_mvm_fw_error_sram_dump(mvm); + iwl_mvm_fw_error_rxf_dump(mvm); #endif iwl_mvm_nic_restart(mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index d619851745a1..c5f4532cafa9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -64,6 +64,7 @@ #include "iwl-debug.h" #include "iwl-io.h" +#include "iwl-prph.h" #include "mvm.h" #include "fw-api-rs.h" @@ -469,6 +470,8 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) mvm->status, table.valid); } + /* Do not change this output - scripts rely on it */ + IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version); trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, @@ -522,7 +525,7 @@ void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm) u32 ofs, sram_len; void *sram; - if (!mvm->ucode_loaded || mvm->fw_error_sram) + if (!mvm->ucode_loaded || mvm->fw_error_sram || mvm->fw_error_dump) return; img = &mvm->fw->img[mvm->cur_ucode]; @@ -538,6 +541,47 @@ void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm) mvm->fw_error_sram_len = sram_len; } +void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm) +{ + int i, reg_val; + unsigned long flags; + + if (!mvm->ucode_loaded || mvm->fw_error_rxf || mvm->fw_error_dump) + return; + + /* reading buffer size */ + reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); + mvm->fw_error_rxf_len = + (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; + + /* the register holds the value divided by 128 */ + mvm->fw_error_rxf_len = mvm->fw_error_rxf_len << 7; + + if (!mvm->fw_error_rxf_len) + return; + + mvm->fw_error_rxf = kzalloc(mvm->fw_error_rxf_len, GFP_ATOMIC); + if (!mvm->fw_error_rxf) { + mvm->fw_error_rxf_len = 0; + return; + } + + if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { + kfree(mvm->fw_error_rxf); + mvm->fw_error_rxf = NULL; + mvm->fw_error_rxf_len = 0; + return; + } + + for (i = 0; i < (mvm->fw_error_rxf_len / sizeof(u32)); i++) { + iwl_trans_write_prph(mvm->trans, RXF_LD_FENCE_OFFSET_ADDR, + i * sizeof(u32)); + mvm->fw_error_rxf[i] = + iwl_trans_read_prph(mvm->trans, RXF_FIFO_RD_FENCE_ADDR); + } + iwl_trans_release_nic_access(mvm->trans, &flags); +} + /** * iwl_mvm_send_lq_cmd() - Send link quality command * @init: This command is sent as part of station initialization right -- 2.45.2