aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/mvm
diff options
context:
space:
mode:
authorMordechay Goodstein <mordechay.goodstein@intel.com>2018-12-13 16:04:51 -0500
committerLuca Coelho <luciano.coelho@intel.com>2019-02-14 04:29:45 -0500
commitf130bb75d8817c560b48c4d1a0e5279968a0859d (patch)
treed3f34bd761be323cd1c3382783e90aa8e198a7a8 /drivers/net/wireless/intel/iwlwifi/mvm
parentff911dcaa2e46627f5fc6a22802f72a8bfce4ab5 (diff)
iwlwifi: add FW recovery flow
Add new API and TLV for the ability to send commands in the beginning and end of reset flow. The full flow of recovery is: 1. While loading FW, get address (from the TLV) of target buffer to read in case of reset 2. If an error/assert happens read the address data from step 1. 3. Reset the HW and load the FW. 4. Send the data read in step 2. 5. Add station keys 6. Send notification to FW that reset flow is done. The main use of the recovery flow is for support in PN/SN recovery when offloaded Signed-off-by: Mordechay Goodstein <mordechay.goodstein@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c54
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c18
4 files changed, 76 insertions, 0 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index cf7f8c340ffe..28ef204c9cf7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -976,6 +976,57 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
976} 976}
977#endif /* CONFIG_ACPI */ 977#endif /* CONFIG_ACPI */
978 978
979void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
980{
981 u32 error_log_size = mvm->fw->ucode_capa.error_log_size;
982 int ret;
983 u32 resp;
984
985 struct iwl_fw_error_recovery_cmd recovery_cmd = {
986 .flags = cpu_to_le32(flags),
987 .buf_size = 0,
988 };
989 struct iwl_host_cmd host_cmd = {
990 .id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD),
991 .flags = CMD_WANT_SKB,
992 .data = {&recovery_cmd, },
993 .len = {sizeof(recovery_cmd), },
994 };
995
996 /* no error log was defined in TLV */
997 if (!error_log_size)
998 return;
999
1000 if (flags & ERROR_RECOVERY_UPDATE_DB) {
1001 /* no buf was allocated while HW reset */
1002 if (!mvm->error_recovery_buf)
1003 return;
1004
1005 host_cmd.data[1] = mvm->error_recovery_buf;
1006 host_cmd.len[1] = error_log_size;
1007 host_cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
1008 recovery_cmd.buf_size = cpu_to_le32(error_log_size);
1009 }
1010
1011 ret = iwl_mvm_send_cmd(mvm, &host_cmd);
1012 kfree(mvm->error_recovery_buf);
1013 mvm->error_recovery_buf = NULL;
1014
1015 if (ret) {
1016 IWL_ERR(mvm, "Failed to send recovery cmd %d\n", ret);
1017 return;
1018 }
1019
1020 /* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */
1021 if (flags & ERROR_RECOVERY_UPDATE_DB) {
1022 resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data);
1023 if (resp)
1024 IWL_ERR(mvm,
1025 "Failed to send recovery cmd blob was invalid %d\n",
1026 resp);
1027 }
1028}
1029
979static int iwl_mvm_sar_init(struct iwl_mvm *mvm) 1030static int iwl_mvm_sar_init(struct iwl_mvm *mvm)
980{ 1031{
981 int ret; 1032 int ret;
@@ -1212,6 +1263,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
1212 if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) 1263 if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
1213 iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); 1264 iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
1214 1265
1266 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
1267 iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB);
1268
1215 ret = iwl_mvm_sar_init(mvm); 1269 ret = iwl_mvm_sar_init(mvm);
1216 if (ret == 0) { 1270 if (ret == 0) {
1217 ret = iwl_mvm_sar_geo_init(mvm); 1271 ret = iwl_mvm_sar_geo_init(mvm);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 9377fca39edf..c02559766712 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -1326,6 +1326,8 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
1326 /* allow transport/FW low power modes */ 1326 /* allow transport/FW low power modes */
1327 iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); 1327 iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
1328 1328
1329 iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_END_OF_RECOVERY);
1330
1329 /* 1331 /*
1330 * If we have TDLS peers, remove them. We don't know the last seqno/PN 1332 * If we have TDLS peers, remove them. We don't know the last seqno/PN
1331 * of packets the FW sent out, so we must reconnect. 1333 * of packets the FW sent out, so we must reconnect.
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 0255157378db..c70fc90680af 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1014,6 +1014,7 @@ struct iwl_mvm {
1014 1014
1015 /* -1 for always, 0 for never, >0 for that many times */ 1015 /* -1 for always, 0 for never, >0 for that many times */
1016 s8 fw_restart; 1016 s8 fw_restart;
1017 u8 *error_recovery_buf;
1017 1018
1018#ifdef CONFIG_IWLWIFI_LEDS 1019#ifdef CONFIG_IWLWIFI_LEDS
1019 struct led_classdev led; 1020 struct led_classdev led;
@@ -1657,6 +1658,7 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
1657void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); 1658void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
1658void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, 1659void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm,
1659 struct iwl_rx_cmd_buffer *rxb); 1660 struct iwl_rx_cmd_buffer *rxb);
1661void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags);
1660void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); 1662void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
1661void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, 1663void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
1662 struct iwl_rx_cmd_buffer *rxb); 1664 struct iwl_rx_cmd_buffer *rxb);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 0c276124bf0f..f8a5a7074dc1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -422,6 +422,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
422static const struct iwl_hcmd_names iwl_mvm_system_names[] = { 422static const struct iwl_hcmd_names iwl_mvm_system_names[] = {
423 HCMD_NAME(SHARED_MEM_CFG_CMD), 423 HCMD_NAME(SHARED_MEM_CFG_CMD),
424 HCMD_NAME(INIT_EXTENDED_CFG_CMD), 424 HCMD_NAME(INIT_EXTENDED_CFG_CMD),
425 HCMD_NAME(FW_ERROR_RECOVERY_CMD),
425}; 426};
426 427
427/* Please keep this array *SORTED* by hex value. 428/* Please keep this array *SORTED* by hex value.
@@ -921,6 +922,9 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
921 kfree(mvm->mcast_filter_cmd); 922 kfree(mvm->mcast_filter_cmd);
922 mvm->mcast_filter_cmd = NULL; 923 mvm->mcast_filter_cmd = NULL;
923 924
925 kfree(mvm->error_recovery_buf);
926 mvm->error_recovery_buf = NULL;
927
924#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) 928#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
925 kfree(mvm->d3_resume_sram); 929 kfree(mvm->d3_resume_sram);
926#endif 930#endif
@@ -1301,6 +1305,20 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
1301 /* don't let the transport/FW power down */ 1305 /* don't let the transport/FW power down */
1302 iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); 1306 iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
1303 1307
1308 if (mvm->fw->ucode_capa.error_log_size) {
1309 u32 src_size = mvm->fw->ucode_capa.error_log_size;
1310 u32 src_addr = mvm->fw->ucode_capa.error_log_addr;
1311 u8 *recover_buf = kzalloc(src_size, GFP_ATOMIC);
1312
1313 if (recover_buf) {
1314 mvm->error_recovery_buf = recover_buf;
1315 iwl_trans_read_mem_bytes(mvm->trans,
1316 src_addr,
1317 recover_buf,
1318 src_size);
1319 }
1320 }
1321
1304 if (fw_error && mvm->fw_restart > 0) 1322 if (fw_error && mvm->fw_restart > 0)
1305 mvm->fw_restart--; 1323 mvm->fw_restart--;
1306 set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status); 1324 set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);