summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h9
2 files changed, 31 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 4ad89389a0a..977ddfb8c24 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -948,6 +948,9 @@ EXPORT_SYMBOL(iwl_print_rx_config_cmd);
*/
void iwl_irq_handle_error(struct iwl_priv *priv)
{
+ unsigned int reload_msec;
+ unsigned long reload_jiffies;
+
/* Set the FW error flag -- cleared on iwl_down */
set_bit(STATUS_FW_ERROR, &priv->status);
@@ -991,6 +994,25 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
* commands by clearing the INIT status bit */
clear_bit(STATUS_READY, &priv->status);
+ /*
+ * If firmware keep reloading, then it indicate something
+ * serious wrong and firmware having problem to recover
+ * from it. Instead of keep trying which will fill the syslog
+ * and hang the system, let's just stop it
+ */
+ reload_jiffies = jiffies;
+ reload_msec = jiffies_to_msecs((long) reload_jiffies -
+ (long) priv->reload_jiffies);
+ priv->reload_jiffies = reload_jiffies;
+ if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
+ priv->reload_count++;
+ if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
+ IWL_ERR(priv, "BUG_ON, Stop restarting\n");
+ return;
+ }
+ } else
+ priv->reload_count = 0;
+
if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
"Restarting adapter due to uCode error.\n");
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index ecfbef40278..065615ee040 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1110,6 +1110,11 @@ struct iwl_event_log {
/* BT Antenna Coupling Threshold (dB) */
#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
+/* Firmware reload counter and Timestamp */
+#define IWL_MIN_RELOAD_DURATION 1000 /* 1000 ms */
+#define IWL_MAX_CONTINUE_RELOAD_CNT 4
+
+
enum iwl_reset {
IWL_RF_RESET = 0,
IWL_FW_RESET,
@@ -1262,6 +1267,10 @@ struct iwl_priv {
/* force reset */
struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET];
+ /* firmware reload counter and timestamp */
+ unsigned long reload_jiffies;
+ int reload_count;
+
/* we allocate array of iwl_channel_info for NIC's valid channels.
* Access via channel # using indirect index array */
struct iwl_channel_info *channel_info; /* channel info array */