diff options
author | Wey-Yi Guy | 2010-02-03 20:47:19 +0100 |
---|---|---|
committer | Reinette Chatre | 2010-02-11 19:24:12 +0100 |
commit | a93e7973d0983d22fcbe5f691244736211639fe7 (patch) | |
tree | 161f64fa2297146b8263ea120638404f97fc288c /drivers/net/wireless/iwlwifi/iwl-core.c | |
parent | iwlwifi: clear all tx queues when firmware ready (diff) | |
download | kernel-qcow2-linux-a93e7973d0983d22fcbe5f691244736211639fe7.tar.gz kernel-qcow2-linux-a93e7973d0983d22fcbe5f691244736211639fe7.tar.xz kernel-qcow2-linux-a93e7973d0983d22fcbe5f691244736211639fe7.zip |
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>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-core.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d390eef2efe5..500ced452098 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/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); -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)) return; @@ -3356,7 +3356,47 @@ void iwl_force_rf_reset(struct iwl_priv *priv) iwl_internal_short_hw_scan(priv); 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 |