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>
 }
 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;
        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
 
 
 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_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,
                       const u8 *ie, int ie_len, int left);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
 
 #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF    (100)
 #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255)
 
+enum iwl_reset {
+       IWL_RF_RESET = 0,
+       IWL_FW_RESET,
+};
+
 struct iwl_priv {
 
        /* ieee device used by generic ieee processing code */
        /* storing the jiffies when the plcp error rate is received */
        unsigned long plcp_jiffies;
 
+       /* force reset */
+       unsigned long last_force_reset_jiffies;
+
        /* we allocate array of iwl4965_channel_info for NIC's valid channels.
         *    Access via channel # using indirect index array */
        struct iwl_channel_info *channel_info;  /* channel info array */
        unsigned long scan_start;
        unsigned long scan_pass_start;
        unsigned long scan_start_tsf;
-       unsigned long last_internal_scan_jiffies;
        void *scan;
        int scan_bands;
        struct cfg80211_scan_request *scan_request;
 
                         * Reset the RF radio due to the high plcp
                         * error rate
                         */
-                       iwl_force_rf_reset(priv);
+                       iwl_force_reset(priv, IWL_RF_RESET);
                }
        }
 
 
 
        if (!priv->is_internal_short_scan)
                priv->next_scan_jiffies = 0;
-       else
-               priv->last_internal_scan_jiffies = jiffies;
 
        IWL_DEBUG_INFO(priv, "Setting scan to off\n");
 
  * internal short scan, this function should only been called while associated.
  * 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 ret = 0;
                ret = -EAGAIN;
                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;
        if (priv->band == IEEE80211_BAND_5GHZ)