summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-core.c
diff options
context:
space:
mode:
authorWey-Yi Guy2010-02-03 20:47:19 +0100
committerReinette Chatre2010-02-11 19:24:12 +0100
commita93e7973d0983d22fcbe5f691244736211639fe7 (patch)
tree161f64fa2297146b8263ea120638404f97fc288c /drivers/net/wireless/iwlwifi/iwl-core.c
parentiwlwifi: clear all tx queues when firmware ready (diff)
downloadkernel-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.c44
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