Commit a93e7973 authored by Wey-Yi Guy's avatar Wey-Yi Guy Committed by Reinette Chatre

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: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
parent dff010ac
...@@ -3334,7 +3334,7 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) ...@@ -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) ...@@ -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
......
...@@ -501,7 +501,7 @@ int iwl_scan_cancel(struct iwl_priv *priv); ...@@ -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);
......
...@@ -1035,6 +1035,11 @@ struct iwl_event_log { ...@@ -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 { ...@@ -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 { ...@@ -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;
......
...@@ -689,7 +689,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, ...@@ -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);
} }
} }
......
...@@ -250,8 +250,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, ...@@ -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); ...@@ -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) ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment