aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2013-12-01 06:50:40 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-12-17 12:39:50 -0500
commit2a988e98085a76c1a238442e67e53874944cb353 (patch)
tree57d23374a6823e476d89ffd08535c91e69898f8c
parent8c678ed4665d9c6452279b770eb43feed32ca3e8 (diff)
iwlwifi: trans: prevent reprobe on repeated FW errors before restart
In case a sync command timeouts or Tx is stuck while a FW error interrupt arrives, we might call iwl_op_mode_nic_error twice before a restart has been initiated. This will cause a reprobe. Unify calls to this function at the transport level and only call it on the first FW error in a given by checking the transport FW error flag. While at it, remove the privately defined iwl_nic_error from PCIE code and use the common callback instead. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h11
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h6
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c12
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c6
4 files changed, 20 insertions, 15 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index c71519d54402..fa495bafa4e2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -70,6 +70,7 @@
70#include "iwl-debug.h" 70#include "iwl-debug.h"
71#include "iwl-config.h" 71#include "iwl-config.h"
72#include "iwl-fw.h" 72#include "iwl-fw.h"
73#include "iwl-op-mode.h"
73 74
74/** 75/**
75 * DOC: Transport layer - what is it ? 76 * DOC: Transport layer - what is it ?
@@ -805,6 +806,16 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
805 __release(nic_access); 806 __release(nic_access);
806} 807}
807 808
809static inline void iwl_trans_fw_error(struct iwl_trans *trans)
810{
811 if (WARN_ON_ONCE(!trans->op_mode))
812 return;
813
814 /* prevent double restarts due to the same erroneous FW */
815 if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status))
816 iwl_op_mode_nic_error(trans->op_mode);
817}
818
808/***************************************************** 819/*****************************************************
809* driver (transport) register/unregister functions 820* driver (transport) register/unregister functions
810******************************************************/ 821******************************************************/
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 8a2de33df48b..674c75b0d002 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -456,10 +456,4 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
456 CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); 456 CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
457} 457}
458 458
459static inline void iwl_nic_error(struct iwl_trans *trans)
460{
461 set_bit(STATUS_FW_ERROR, &trans->status);
462 iwl_op_mode_nic_error(trans->op_mode);
463}
464
465#endif /* __iwl_trans_int_pcie_h__ */ 459#endif /* __iwl_trans_int_pcie_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index bbbb3ca400d7..7aeec5ccefa5 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -797,14 +797,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
797 iwl_pcie_dump_csr(trans); 797 iwl_pcie_dump_csr(trans);
798 iwl_dump_fh(trans, NULL); 798 iwl_dump_fh(trans, NULL);
799 799
800 /* set the ERROR bit before we wake up the caller */
801 set_bit(STATUS_FW_ERROR, &trans->status);
802 clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
803 wake_up(&trans_pcie->wait_command_queue);
804
805 local_bh_disable(); 800 local_bh_disable();
806 iwl_nic_error(trans); 801 /* The STATUS_FW_ERROR bit is set in this function. This must happen
802 * before we wake up the command caller, to ensure a proper cleanup. */
803 iwl_trans_fw_error(trans);
807 local_bh_enable(); 804 local_bh_enable();
805
806 clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
807 wake_up(&trans_pcie->wait_command_queue);
808} 808}
809 809
810irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) 810irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 5b63948220c9..8df24787c141 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
207 IWL_ERR(trans, "scratch %d = 0x%08x\n", i, 207 IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
208 le32_to_cpu(txq->scratchbufs[i].scratch)); 208 le32_to_cpu(txq->scratchbufs[i].scratch));
209 209
210 iwl_nic_error(trans); 210 iwl_trans_fw_error(trans);
211} 211}
212 212
213/* 213/*
@@ -1021,7 +1021,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
1021 if (nfreed++ > 0) { 1021 if (nfreed++ > 0) {
1022 IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", 1022 IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
1023 idx, q->write_ptr, q->read_ptr); 1023 idx, q->write_ptr, q->read_ptr);
1024 iwl_nic_error(trans); 1024 iwl_trans_fw_error(trans);
1025 } 1025 }
1026 } 1026 }
1027 1027
@@ -1555,7 +1555,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
1555 get_cmd_string(trans_pcie, cmd->id)); 1555 get_cmd_string(trans_pcie, cmd->id));
1556 ret = -ETIMEDOUT; 1556 ret = -ETIMEDOUT;
1557 1557
1558 iwl_nic_error(trans); 1558 iwl_trans_fw_error(trans);
1559 1559
1560 goto cancel; 1560 goto cancel;
1561 } 1561 }