aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-01-29 07:58:20 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-03-02 01:20:28 -0500
commitb6eaa45aa18bf010fd54cdac0e3007dfdd7f3f8a (patch)
tree69869fec6604ece7ef73c1a6c1395231d7c8a3dd
parentd2709ad723ff2ae22013978ed6ec29cf1b9b8332 (diff)
iwlwifi: mvm: add the cause of the firmware dump in the dump
Now that the firmware dump can be triggered by events in the code and not only the user or an firmware ASSERT, we need a way to know why the firmware dump was triggered. Add a section in the dump file for that. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h13
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c35
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c40
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h28
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c2
6 files changed, 108 insertions, 12 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index fabddd8ecd89..b733c58a06b0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -82,6 +82,8 @@
82 * sections like this in a single file. 82 * sections like this in a single file.
83 * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers 83 * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers
84 * @IWL_FW_ERROR_DUMP_MEM: chunk of memory 84 * @IWL_FW_ERROR_DUMP_MEM: chunk of memory
85 * @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump.
86 * Structured as &struct iwl_fw_error_dump_trigger_desc.
85 */ 87 */
86enum iwl_fw_error_dump_type { 88enum iwl_fw_error_dump_type {
87 /* 0 is deprecated */ 89 /* 0 is deprecated */
@@ -94,6 +96,7 @@ enum iwl_fw_error_dump_type {
94 IWL_FW_ERROR_DUMP_TXF = 7, 96 IWL_FW_ERROR_DUMP_TXF = 7,
95 IWL_FW_ERROR_DUMP_FH_REGS = 8, 97 IWL_FW_ERROR_DUMP_FH_REGS = 8,
96 IWL_FW_ERROR_DUMP_MEM = 9, 98 IWL_FW_ERROR_DUMP_MEM = 9,
99 IWL_FW_ERROR_DUMP_ERROR_INFO = 10,
97 100
98 IWL_FW_ERROR_DUMP_MAX, 101 IWL_FW_ERROR_DUMP_MAX,
99}; 102};
@@ -248,4 +251,14 @@ enum iwl_fw_dbg_trigger {
248 FW_DBG_TRIGGER_MAX, 251 FW_DBG_TRIGGER_MAX,
249}; 252};
250 253
254/**
255 * struct iwl_fw_error_dump_trigger_desc - describes the trigger condition
256 * @type: %enum iwl_fw_dbg_trigger
257 * @data: raw data about what happened
258 */
259struct iwl_fw_error_dump_trigger_desc {
260 __le32 type;
261 u8 data[];
262};
263
251#endif /* __fw_error_dump_h__ */ 264#endif /* __fw_error_dump_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index f890d5e4673f..8cbe77dc1dbb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -985,7 +985,7 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
985 if (ret) 985 if (ret)
986 return ret; 986 return ret;
987 987
988 iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, 0); 988 iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, NULL, 0, 0);
989 989
990 iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); 990 iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
991 991
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 8d684d5da964..64e9039254b9 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -479,13 +479,20 @@ exit:
479 iwl_free_resp(&cmd); 479 iwl_free_resp(&cmd);
480} 480}
481 481
482int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, 482int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
483 unsigned int delay) 483 struct iwl_mvm_dump_desc *desc,
484 unsigned int delay)
484{ 485{
485 if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status)) 486 if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status))
486 return -EBUSY; 487 return -EBUSY;
487 488
488 IWL_WARN(mvm, "Collecting data: trigger %d fired.\n", trig); 489 if (WARN_ON(mvm->fw_dump_desc))
490 iwl_mvm_free_fw_dump_desc(mvm);
491
492 IWL_WARN(mvm, "Collecting data: trigger %d fired.\n",
493 le32_to_cpu(desc->trig_desc.type));
494
495 mvm->fw_dump_desc = desc;
489 496
490 /* stop recording */ 497 /* stop recording */
491 if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { 498 if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
@@ -501,8 +508,25 @@ int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
501 return 0; 508 return 0;
502} 509}
503 510
511int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
512 const char *str, size_t len, unsigned int delay)
513{
514 struct iwl_mvm_dump_desc *desc;
515
516 desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC);
517 if (!desc)
518 return -ENOMEM;
519
520 desc->len = len;
521 desc->trig_desc.type = cpu_to_le32(trig);
522 memcpy(desc->trig_desc.data, str, len);
523
524 return iwl_mvm_fw_dbg_collect_desc(mvm, desc, delay);
525}
526
504int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, 527int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
505 struct iwl_fw_dbg_trigger_tlv *trigger) 528 struct iwl_fw_dbg_trigger_tlv *trigger,
529 const char *str, size_t len)
506{ 530{
507 unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); 531 unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay));
508 u16 occurrences = le16_to_cpu(trigger->occurrences); 532 u16 occurrences = le16_to_cpu(trigger->occurrences);
@@ -511,7 +535,8 @@ int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
511 if (!occurrences) 535 if (!occurrences)
512 return 0; 536 return 0;
513 537
514 ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), delay); 538 ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), str,
539 len, delay);
515 if (ret) 540 if (ret)
516 return ret; 541 return ret;
517 542
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index a5261a4e7e11..3b6b9f6031ae 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -886,12 +886,23 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
886 iwl_trans_release_nic_access(mvm->trans, &flags); 886 iwl_trans_release_nic_access(mvm->trans, &flags);
887} 887}
888 888
889void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm)
890{
891 if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert ||
892 !mvm->fw_dump_desc)
893 return;
894
895 kfree(mvm->fw_dump_desc);
896 mvm->fw_dump_desc = NULL;
897}
898
889void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) 899void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
890{ 900{
891 struct iwl_fw_error_dump_file *dump_file; 901 struct iwl_fw_error_dump_file *dump_file;
892 struct iwl_fw_error_dump_data *dump_data; 902 struct iwl_fw_error_dump_data *dump_data;
893 struct iwl_fw_error_dump_info *dump_info; 903 struct iwl_fw_error_dump_info *dump_info;
894 struct iwl_fw_error_dump_mem *dump_mem; 904 struct iwl_fw_error_dump_mem *dump_mem;
905 struct iwl_fw_error_dump_trigger_desc *dump_trig;
895 struct iwl_mvm_dump_ptrs *fw_error_dump; 906 struct iwl_mvm_dump_ptrs *fw_error_dump;
896 u32 sram_len, sram_ofs; 907 u32 sram_len, sram_ofs;
897 u32 file_len, fifo_data_len = 0; 908 u32 file_len, fifo_data_len = 0;
@@ -961,6 +972,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
961 fifo_data_len + 972 fifo_data_len +
962 sizeof(*dump_info); 973 sizeof(*dump_info);
963 974
975 if (mvm->fw_dump_desc)
976 file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
977 mvm->fw_dump_desc->len;
978
964 /* Make room for the SMEM, if it exists */ 979 /* Make room for the SMEM, if it exists */
965 if (smem_len) 980 if (smem_len)
966 file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; 981 file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len;
@@ -972,6 +987,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
972 dump_file = vzalloc(file_len); 987 dump_file = vzalloc(file_len);
973 if (!dump_file) { 988 if (!dump_file) {
974 kfree(fw_error_dump); 989 kfree(fw_error_dump);
990 iwl_mvm_free_fw_dump_desc(mvm);
975 return; 991 return;
976 } 992 }
977 993
@@ -1000,6 +1016,19 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
1000 if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) 1016 if (test_bit(STATUS_FW_ERROR, &mvm->trans->status))
1001 iwl_mvm_dump_fifos(mvm, &dump_data); 1017 iwl_mvm_dump_fifos(mvm, &dump_data);
1002 1018
1019 if (mvm->fw_dump_desc) {
1020 dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
1021 dump_data->len = cpu_to_le32(sizeof(*dump_trig) +
1022 mvm->fw_dump_desc->len);
1023 dump_trig = (void *)dump_data->data;
1024 memcpy(dump_trig, &mvm->fw_dump_desc->trig_desc,
1025 sizeof(*dump_trig) + mvm->fw_dump_desc->len);
1026
1027 /* now we can free this copy */
1028 iwl_mvm_free_fw_dump_desc(mvm);
1029 dump_data = iwl_fw_error_next_data(dump_data);
1030 }
1031
1003 dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); 1032 dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
1004 dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); 1033 dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
1005 dump_mem = (void *)dump_data->data; 1034 dump_mem = (void *)dump_data->data;
@@ -1042,14 +1071,22 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
1042 clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status); 1071 clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status);
1043} 1072}
1044 1073
1074struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert = {
1075 .trig_desc = {
1076 .type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT),
1077 },
1078};
1079
1045static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) 1080static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
1046{ 1081{
1047 /* clear the D3 reconfig, we only need it to avoid dumping a 1082 /* clear the D3 reconfig, we only need it to avoid dumping a
1048 * firmware coredump on reconfiguration, we shouldn't do that 1083 * firmware coredump on reconfiguration, we shouldn't do that
1049 * on D3->D0 transition 1084 * on D3->D0 transition
1050 */ 1085 */
1051 if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) 1086 if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) {
1087 mvm->fw_dump_desc = &iwl_mvm_dump_desc_assert;
1052 iwl_mvm_fw_error_dump(mvm); 1088 iwl_mvm_fw_error_dump(mvm);
1089 }
1053 1090
1054 /* cleanup all stale references (scan, roc), but keep the 1091 /* cleanup all stale references (scan, roc), but keep the
1055 * ucode_down ref until reconfig is complete 1092 * ucode_down ref until reconfig is complete
@@ -1261,6 +1298,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
1261 flush_work(&mvm->d0i3_exit_work); 1298 flush_work(&mvm->d0i3_exit_work);
1262 flush_work(&mvm->async_handlers_wk); 1299 flush_work(&mvm->async_handlers_wk);
1263 cancel_delayed_work_sync(&mvm->fw_dump_wk); 1300 cancel_delayed_work_sync(&mvm->fw_dump_wk);
1301 iwl_mvm_free_fw_dump_desc(mvm);
1264 1302
1265 mutex_lock(&mvm->mutex); 1303 mutex_lock(&mvm->mutex);
1266 __iwl_mvm_mac_stop(mvm); 1304 __iwl_mvm_mac_stop(mvm);
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 4068139efb54..f4ecd1bde1cf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -146,6 +146,19 @@ struct iwl_mvm_dump_ptrs {
146 u32 op_mode_len; 146 u32 op_mode_len;
147}; 147};
148 148
149/**
150 * struct iwl_mvm_dump_desc - describes the dump
151 * @len: length of trig_desc->data
152 * @trig_desc: the description of the dump
153 */
154struct iwl_mvm_dump_desc {
155 size_t len;
156 /* must be last */
157 struct iwl_fw_error_dump_trigger_desc trig_desc;
158};
159
160extern struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert;
161
149struct iwl_mvm_phy_ctxt { 162struct iwl_mvm_phy_ctxt {
150 u16 id; 163 u16 id;
151 u16 color; 164 u16 color;
@@ -706,6 +719,7 @@ struct iwl_mvm {
706 s8 restart_fw; 719 s8 restart_fw;
707 u8 fw_dbg_conf; 720 u8 fw_dbg_conf;
708 struct delayed_work fw_dump_wk; 721 struct delayed_work fw_dump_wk;
722 struct iwl_mvm_dump_desc *fw_dump_desc;
709 723
710#ifdef CONFIG_IWLWIFI_LEDS 724#ifdef CONFIG_IWLWIFI_LEDS
711 struct led_classdev led; 725 struct led_classdev led;
@@ -1415,9 +1429,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
1415 1429
1416int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id); 1430int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id);
1417int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, 1431int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
1418 unsigned int delay); 1432 const char *str, size_t len, unsigned int delay);
1433int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
1434 struct iwl_mvm_dump_desc *desc,
1435 unsigned int delay);
1436void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm);
1419int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, 1437int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
1420 struct iwl_fw_dbg_trigger_tlv *trigger); 1438 struct iwl_fw_dbg_trigger_tlv *trigger,
1439 const char *str, size_t len);
1421 1440
1422static inline bool 1441static inline bool
1423iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig, 1442iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig,
@@ -1451,7 +1470,8 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm,
1451static inline void 1470static inline void
1452iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm, 1471iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm,
1453 struct ieee80211_vif *vif, 1472 struct ieee80211_vif *vif,
1454 enum iwl_fw_dbg_trigger trig) 1473 enum iwl_fw_dbg_trigger trig,
1474 const char *str, size_t len)
1455{ 1475{
1456 struct iwl_fw_dbg_trigger_tlv *trigger; 1476 struct iwl_fw_dbg_trigger_tlv *trigger;
1457 1477
@@ -1462,7 +1482,7 @@ iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm,
1462 if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger)) 1482 if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger))
1463 return; 1483 return;
1464 1484
1465 iwl_mvm_fw_dbg_collect_trig(mvm, trigger); 1485 iwl_mvm_fw_dbg_collect_trig(mvm, trigger, str, len);
1466} 1486}
1467 1487
1468#endif /* __IWL_MVM_H__ */ 1488#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 96a4a154a42c..f1c5751934d5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -879,7 +879,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
879 * can't recover this since we're already half suspended. 879 * can't recover this since we're already half suspended.
880 */ 880 */
881 if (!mvm->restart_fw && fw_error) { 881 if (!mvm->restart_fw && fw_error) {
882 iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_FW_ASSERT, 0); 882 iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, 0);
883 } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, 883 } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART,
884 &mvm->status)) { 884 &mvm->status)) {
885 struct iwl_mvm_reprobe *reprobe; 885 struct iwl_mvm_reprobe *reprobe;