iwlwifi: mvm: dump the radio registers when the firmware crashes
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 28 Dec 2015 13:22:28 +0000 (15:22 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 7 Jan 2016 17:01:28 +0000 (19:01 +0200)
Dumping the content of the radio registers greatly helps
to debug PHY issues, which can lead to TFD queue hang.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h
drivers/net/wireless/intel/iwlwifi/iwl-prph.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c

index f08a1319fc0431ec94fa84e126ae69a39edc46f2..a5aaf685370462d97bae6b9c0935c567ad758bfa 100644 (file)
@@ -88,6 +88,7 @@
  *     &struct iwl_fw_error_dump_rb
  * @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were
  *     paged to the DRAM.
+ * @IWL_FW_ERROR_DUMP_RADIO_REG: Dump the radio registers.
  */
 enum iwl_fw_error_dump_type {
        /* 0 is deprecated */
@@ -103,6 +104,7 @@ enum iwl_fw_error_dump_type {
        IWL_FW_ERROR_DUMP_ERROR_INFO = 10,
        IWL_FW_ERROR_DUMP_RB = 11,
        IWL_FW_ERROR_DUMP_PAGING = 12,
+       IWL_FW_ERROR_DUMP_RADIO_REG = 13,
 
        IWL_FW_ERROR_DUMP_MAX,
 };
index 9da7dc49549cd99c3812334f19bddc20153f185e..5bde23a472b4ebfec1a082309eb72c733d292074 100644 (file)
@@ -345,6 +345,12 @@ enum secure_load_status_reg {
 #define TXF_READ_MODIFY_DATA           (0xa00448)
 #define TXF_READ_MODIFY_ADDR           (0xa0044c)
 
+/* Radio registers access */
+#define RSP_RADIO_CMD                  (0xa02804)
+#define RSP_RADIO_RDDAT                        (0xa02814)
+#define RADIO_RSP_ADDR_POS             (6)
+#define RADIO_RSP_RD_CMD               (3)
+
 /* FW monitor */
 #define MON_BUFF_SAMPLE_CTL            (0xa03c00)
 #define MON_BUFF_BASE_ADDR             (0xa03c3c)
index f406c76b430247fa134a5f7114a499677d6b39d0..59450f177c430f818add3b930a98bb4a28831708 100644 (file)
@@ -113,6 +113,35 @@ static void iwl_mvm_free_coredump(const void *data)
        kfree(fw_error_dump);
 }
 
+#define RADIO_REG_MAX_READ 0x2ad
+static void iwl_mvm_read_radio_reg(struct iwl_mvm *mvm,
+                                  struct iwl_fw_error_dump_data **dump_data)
+{
+       u8 *pos = (void *)(*dump_data)->data;
+       unsigned long flags;
+       int i;
+
+       if (!iwl_trans_grab_nic_access(mvm->trans, &flags))
+               return;
+
+       (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RADIO_REG);
+       (*dump_data)->len = cpu_to_le32(RADIO_REG_MAX_READ);
+
+       for (i = 0; i < RADIO_REG_MAX_READ; i++) {
+               u32 rd_cmd = RADIO_RSP_RD_CMD;
+
+               rd_cmd |= i << RADIO_RSP_ADDR_POS;
+               iwl_write_prph_no_grab(mvm->trans, RSP_RADIO_CMD, rd_cmd);
+               *pos =  (u8)iwl_read_prph_no_grab(mvm->trans, RSP_RADIO_RDDAT);
+
+               pos++;
+       }
+
+       *dump_data = iwl_fw_error_next_data(*dump_data);
+
+       iwl_trans_release_nic_access(mvm->trans, &flags);
+}
+
 static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
                               struct iwl_fw_error_dump_data **dump_data)
 {
@@ -401,7 +430,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        struct iwl_fw_error_dump_trigger_desc *dump_trig;
        struct iwl_mvm_dump_ptrs *fw_error_dump;
        u32 sram_len, sram_ofs;
-       u32 file_len, fifo_data_len = 0, prph_len = 0;
+       u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0;
        u32 smem_len = mvm->cfg->smem_len;
        u32 sram2_len = mvm->cfg->dccm2_len;
        bool monitor_dump_only = false;
@@ -472,6 +501,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
                                sizeof(struct iwl_fw_error_dump_prph) +
                                num_bytes_in_chunk;
                }
+
+               if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
+                       radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
        }
 
        file_len = sizeof(*dump_file) +
@@ -479,6 +511,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
                   sram_len + sizeof(*dump_mem) +
                   fifo_data_len +
                   prph_len +
+                  radio_len +
                   sizeof(*dump_info);
 
        /* Make room for the SMEM, if it exists */
@@ -543,8 +576,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 
        dump_data = iwl_fw_error_next_data(dump_data);
        /* We only dump the FIFOs if the FW is in error state */
-       if (test_bit(STATUS_FW_ERROR, &mvm->trans->status))
+       if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) {
                iwl_mvm_dump_fifos(mvm, &dump_data);
+               if (radio_len)
+                       iwl_mvm_read_radio_reg(mvm, &dump_data);
+       }
 
        if (mvm->fw_dump_desc) {
                dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);