Эх сурвалжийг харах

iwlwifi: multiple force reset mode

Provide the function to perform different type of uCode reset/reload operation.
When uCode detect error and can not fix itself, this iwl_force_reset()
function allow driver to perform the necessary reset/reload functions and help
to bring uCode back to normal operation state.

Currently only 2 type of force reset are available:
 - reset radio
 - reload firmware

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Wey-Yi Guy 15 жил өмнө
parent
commit
a93e7973d0

+ 42 - 2
drivers/net/wireless/iwlwifi/iwl-core.c

@@ -3334,7 +3334,7 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
 }
 }
 EXPORT_SYMBOL(iwl_dump_fh);
 EXPORT_SYMBOL(iwl_dump_fh);
 
 
-void iwl_force_rf_reset(struct iwl_priv *priv)
+static void iwl_force_rf_reset(struct iwl_priv *priv)
 {
 {
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 		return;
@@ -3356,7 +3356,47 @@ void iwl_force_rf_reset(struct iwl_priv *priv)
 	iwl_internal_short_hw_scan(priv);
 	iwl_internal_short_hw_scan(priv);
 	return;
 	return;
 }
 }
-EXPORT_SYMBOL(iwl_force_rf_reset);
+
+#define IWL_DELAY_NEXT_FORCE_RESET (HZ*3)
+
+int iwl_force_reset(struct iwl_priv *priv, int mode)
+{
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return -EINVAL;
+
+	if (priv->last_force_reset_jiffies &&
+	    time_after(priv->last_force_reset_jiffies +
+		       IWL_DELAY_NEXT_FORCE_RESET, jiffies)) {
+		IWL_DEBUG_INFO(priv, "force reset rejected\n");
+		return -EAGAIN;
+	}
+
+	IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode);
+
+	switch (mode) {
+	case IWL_RF_RESET:
+		iwl_force_rf_reset(priv);
+		break;
+	case IWL_FW_RESET:
+		IWL_ERR(priv, "On demand firmware reload\n");
+		/* Set the FW error flag -- cleared on iwl_down */
+		set_bit(STATUS_FW_ERROR, &priv->status);
+		wake_up_interruptible(&priv->wait_command_queue);
+		/*
+		 * Keep the restart process from trying to send host
+		 * commands by clearing the INIT status bit
+		 */
+		clear_bit(STATUS_READY, &priv->status);
+		queue_work(priv->workqueue, &priv->restart);
+		break;
+	default:
+		IWL_DEBUG_INFO(priv, "invalid reset request.\n");
+		return -EINVAL;
+	}
+	priv->last_force_reset_jiffies = jiffies;
+
+	return 0;
+}
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 
 

+ 1 - 1
drivers/net/wireless/iwlwifi/iwl-core.h

@@ -501,7 +501,7 @@ int iwl_scan_cancel(struct iwl_priv *priv);
 int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
 int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
 int iwl_internal_short_hw_scan(struct iwl_priv *priv);
 int iwl_internal_short_hw_scan(struct iwl_priv *priv);
-void iwl_force_rf_reset(struct iwl_priv *priv);
+int iwl_force_reset(struct iwl_priv *priv, int mode);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
 		       const u8 *ie, int ie_len, int left);
 		       const u8 *ie, int ie_len, int left);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);

+ 8 - 1
drivers/net/wireless/iwlwifi/iwl-dev.h

@@ -1035,6 +1035,11 @@ struct iwl_event_log {
 #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF	(100)
 #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF	(100)
 #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX	(255)
 #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX	(255)
 
 
+enum iwl_reset {
+	IWL_RF_RESET = 0,
+	IWL_FW_RESET,
+};
+
 struct iwl_priv {
 struct iwl_priv {
 
 
 	/* ieee device used by generic ieee processing code */
 	/* ieee device used by generic ieee processing code */
@@ -1066,6 +1071,9 @@ struct iwl_priv {
 	/* storing the jiffies when the plcp error rate is received */
 	/* storing the jiffies when the plcp error rate is received */
 	unsigned long plcp_jiffies;
 	unsigned long plcp_jiffies;
 
 
+	/* force reset */
+	unsigned long last_force_reset_jiffies;
+
 	/* we allocate array of iwl4965_channel_info for NIC's valid channels.
 	/* we allocate array of iwl4965_channel_info for NIC's valid channels.
 	 *    Access via channel # using indirect index array */
 	 *    Access via channel # using indirect index array */
 	struct iwl_channel_info *channel_info;	/* channel info array */
 	struct iwl_channel_info *channel_info;	/* channel info array */
@@ -1087,7 +1095,6 @@ struct iwl_priv {
 	unsigned long scan_start;
 	unsigned long scan_start;
 	unsigned long scan_pass_start;
 	unsigned long scan_pass_start;
 	unsigned long scan_start_tsf;
 	unsigned long scan_start_tsf;
-	unsigned long last_internal_scan_jiffies;
 	void *scan;
 	void *scan;
 	int scan_bands;
 	int scan_bands;
 	struct cfg80211_scan_request *scan_request;
 	struct cfg80211_scan_request *scan_request;

+ 1 - 1
drivers/net/wireless/iwlwifi/iwl-rx.c

@@ -689,7 +689,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
 			 * Reset the RF radio due to the high plcp
 			 * Reset the RF radio due to the high plcp
 			 * error rate
 			 * error rate
 			 */
 			 */
-			iwl_force_rf_reset(priv);
+			iwl_force_reset(priv, IWL_RF_RESET);
 		}
 		}
 	}
 	}
 
 

+ 0 - 10
drivers/net/wireless/iwlwifi/iwl-scan.c

@@ -250,8 +250,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
 
 
 	if (!priv->is_internal_short_scan)
 	if (!priv->is_internal_short_scan)
 		priv->next_scan_jiffies = 0;
 		priv->next_scan_jiffies = 0;
-	else
-		priv->last_internal_scan_jiffies = jiffies;
 
 
 	IWL_DEBUG_INFO(priv, "Setting scan to off\n");
 	IWL_DEBUG_INFO(priv, "Setting scan to off\n");
 
 
@@ -551,8 +549,6 @@ EXPORT_SYMBOL(iwl_mac_hw_scan);
  * internal short scan, this function should only been called while associated.
  * internal short scan, this function should only been called while associated.
  * It will reset and tune the radio to prevent possible RF related problem
  * It will reset and tune the radio to prevent possible RF related problem
  */
  */
-#define IWL_DELAY_NEXT_INTERNAL_SCAN (HZ*1)
-
 int iwl_internal_short_hw_scan(struct iwl_priv *priv)
 int iwl_internal_short_hw_scan(struct iwl_priv *priv)
 {
 {
 	int ret = 0;
 	int ret = 0;
@@ -572,12 +568,6 @@ int iwl_internal_short_hw_scan(struct iwl_priv *priv)
 		ret = -EAGAIN;
 		ret = -EAGAIN;
 		goto out;
 		goto out;
 	}
 	}
-	if (priv->last_internal_scan_jiffies &&
-	    time_after(priv->last_internal_scan_jiffies +
-		       IWL_DELAY_NEXT_INTERNAL_SCAN, jiffies)) {
-		IWL_DEBUG_SCAN(priv, "internal scan rejected\n");
-		goto out;
-	}
 
 
 	priv->scan_bands = 0;
 	priv->scan_bands = 0;
 	if (priv->band == IEEE80211_BAND_5GHZ)
 	if (priv->band == IEEE80211_BAND_5GHZ)