*=============================================================================
  *                 Condition Nxt State  Condition Nxt State Condition Nxt State
  *-----------------------------------------------------------------------------
- *     IWL_TI_0     T >= 115   CT_KILL  115>T>=105   TI_1      N/A      N/A
- *     IWL_TI_1     T >= 115   CT_KILL  115>T>=110   TI_2     T<=95     TI_0
- *     IWL_TI_2     T >= 115   CT_KILL                        T<=100    TI_1
+ *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
+ *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
+ *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
  *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
  *=============================================================================
  */
 static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
        {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
-       {IWL_TI_1, 105, CT_KILL_THRESHOLD},
-       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+       {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
+       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
 };
 static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
        {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
-       {IWL_TI_2, 110, CT_KILL_THRESHOLD},
-       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+       {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
+       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
 };
 static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
        {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
-       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
-       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
+       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
 };
 static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
        {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
 }
 EXPORT_SYMBOL(iwl_ht_enabled);
 
+bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
+{
+       s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+       bool within_margin = false;
+
+       if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+               temp = KELVIN_TO_CELSIUS(priv->temperature);
+
+       if (!priv->thermal_throttle.advanced_tt)
+               within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
+                               CT_KILL_THRESHOLD_LEGACY) ? true : false;
+       else
+               within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
+                               CT_KILL_THRESHOLD) ? true : false;
+       return within_margin;
+}
+
 enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
 {
        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 }
 
 #define CT_KILL_EXIT_DURATION (5)      /* 5 seconds duration */
+#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */
 
 /*
  * toggle the bit to wake up uCode and check the temperature
                /* Reschedule the ct_kill timer to occur in
                 * CT_KILL_EXIT_DURATION seconds to ensure we get a
                 * thermal update */
+               IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n");
                mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
                          CT_KILL_EXIT_DURATION * HZ);
        }
        }
 }
 
+static void iwl_tt_ready_for_ct_kill(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* temperature timer expired, ready to go into CT_KILL state */
+       if (tt->state != IWL_TI_CT_KILL) {
+               IWL_DEBUG_POWER(priv, "entering CT_KILL state when temperature timer expired\n");
+               tt->state = IWL_TI_CT_KILL;
+               set_bit(STATUS_CT_KILL, &priv->status);
+               iwl_perform_ct_kill_task(priv, true);
+       }
+}
+
+static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
+{
+       IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
+       /* make request to retrieve statistics information */
+       iwl_send_statistics_request(priv, 0);
+       /* Reschedule the ct_kill wait timer */
+       mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
+                jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
+}
+
 #define IWL_MINIMAL_POWER_THRESHOLD            (CT_KILL_THRESHOLD_LEGACY)
 #define IWL_REDUCED_PERFORMANCE_THRESHOLD_2    (100)
 #define IWL_REDUCED_PERFORMANCE_THRESHOLD_1    (90)
  *     Throttle early enough to lower the power consumption before
  *     drastic steps are needed
  */
-static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
+static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
 {
        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
        enum iwl_tt_state old_state;
 #ifdef CONFIG_IWLWIFI_DEBUG
        tt->tt_previous_temp = temp;
 #endif
+       /* stop ct_kill_waiting_tm timer */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
        if (tt->state != old_state) {
                switch (tt->state) {
                case IWL_TI_0:
                        break;
                }
                mutex_lock(&priv->mutex);
-               if (iwl_power_update_mode(priv, true)) {
+               if (old_state == IWL_TI_CT_KILL)
+                       clear_bit(STATUS_CT_KILL, &priv->status);
+               if (tt->state != IWL_TI_CT_KILL &&
+                   iwl_power_update_mode(priv, true)) {
                        /* TT state not updated
                         * try again during next temperature read
                         */
+                       if (old_state == IWL_TI_CT_KILL)
+                               set_bit(STATUS_CT_KILL, &priv->status);
                        tt->state = old_state;
                        IWL_ERR(priv, "Cannot update power mode, "
                                        "TT state not updated\n");
                } else {
-                       if (tt->state == IWL_TI_CT_KILL)
-                               iwl_perform_ct_kill_task(priv, true);
-                       else if (old_state == IWL_TI_CT_KILL &&
+                       if (tt->state == IWL_TI_CT_KILL) {
+                               if (force) {
+                                       set_bit(STATUS_CT_KILL, &priv->status);
+                                       iwl_perform_ct_kill_task(priv, true);
+                               } else {
+                                       iwl_prepare_ct_kill_task(priv);
+                                       tt->state = old_state;
+                               }
+                       } else if (old_state == IWL_TI_CT_KILL &&
                                 tt->state != IWL_TI_CT_KILL)
                                iwl_perform_ct_kill_task(priv, false);
                        IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
  *=============================================================================
  *                 Condition Nxt State  Condition Nxt State Condition Nxt State
  *-----------------------------------------------------------------------------
- *     IWL_TI_0     T >= 115   CT_KILL  115>T>=105   TI_1      N/A      N/A
- *     IWL_TI_1     T >= 115   CT_KILL  115>T>=110   TI_2     T<=95     TI_0
- *     IWL_TI_2     T >= 115   CT_KILL                        T<=100    TI_1
+ *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
+ *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
+ *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
  *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
  *=============================================================================
  */
-static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
+static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
 {
        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
        int i;
                        break;
                }
        }
+       /* stop ct_kill_waiting_tm timer */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
        if (changed) {
                struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
 
                        iwl_set_rxon_ht(priv, &priv->current_ht_config);
                }
                mutex_lock(&priv->mutex);
-               if (iwl_power_update_mode(priv, true)) {
+               if (old_state == IWL_TI_CT_KILL)
+                       clear_bit(STATUS_CT_KILL, &priv->status);
+               if (tt->state != IWL_TI_CT_KILL &&
+                   iwl_power_update_mode(priv, true)) {
                        /* TT state not updated
                         * try again during next temperature read
                         */
                        IWL_ERR(priv, "Cannot update power mode, "
                                        "TT state not updated\n");
+                       if (old_state == IWL_TI_CT_KILL)
+                               set_bit(STATUS_CT_KILL, &priv->status);
                        tt->state = old_state;
                } else {
                        IWL_DEBUG_POWER(priv,
                                        tt->state);
                        if (old_state != IWL_TI_CT_KILL &&
                            tt->state == IWL_TI_CT_KILL) {
-                               IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n");
-                               iwl_perform_ct_kill_task(priv, true);
-
+                               if (force) {
+                                       IWL_DEBUG_POWER(priv,
+                                               "Enter IWL_TI_CT_KILL\n");
+                                       set_bit(STATUS_CT_KILL, &priv->status);
+                                       iwl_perform_ct_kill_task(priv, true);
+                               } else {
+                                       iwl_prepare_ct_kill_task(priv);
+                                       tt->state = old_state;
+                               }
                        } else if (old_state == IWL_TI_CT_KILL &&
                                  tt->state != IWL_TI_CT_KILL) {
                                IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
                              "- ucode going to sleep!\n");
                if (!priv->thermal_throttle.advanced_tt)
                        iwl_legacy_tt_handler(priv,
-                                             IWL_MINIMAL_POWER_THRESHOLD);
+                                             IWL_MINIMAL_POWER_THRESHOLD,
+                                             true);
                else
                        iwl_advance_tt_handler(priv,
-                                              CT_KILL_THRESHOLD + 1);
+                                              CT_KILL_THRESHOLD + 1, true);
        }
 }
 
                IWL_ERR(priv,
                        "Device temperature below critical"
                        "- ucode awake!\n");
+               /*
+                * exit from CT_KILL state
+                * reset the current temperature reading
+                */
+               priv->temperature = 0;
                if (!priv->thermal_throttle.advanced_tt)
                        iwl_legacy_tt_handler(priv,
-                                       IWL_REDUCED_PERFORMANCE_THRESHOLD_2);
+                                             IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
+                                             true);
                else
-                       iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD);
+                       iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
+                                              true);
        }
 }
 
                temp = KELVIN_TO_CELSIUS(priv->temperature);
 
        if (!priv->thermal_throttle.advanced_tt)
-               iwl_legacy_tt_handler(priv, temp);
+               iwl_legacy_tt_handler(priv, temp, false);
        else
-               iwl_advance_tt_handler(priv, temp);
+               iwl_advance_tt_handler(priv, temp, false);
 }
 
 void iwl_tt_handler(struct iwl_priv *priv)
        tt->state = IWL_TI_0;
        init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
        priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
-       priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
-
+       priv->thermal_throttle.ct_kill_exit_tm.function =
+               iwl_tt_check_exit_ct_kill;
+       init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
+       priv->thermal_throttle.ct_kill_waiting_tm.data = (unsigned long)priv;
+       priv->thermal_throttle.ct_kill_waiting_tm.function =
+               iwl_tt_ready_for_ct_kill;
        /* setup deferred ct kill work */
        INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
        INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
 
        /* stop ct_kill_exit_tm timer if activated */
        del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+       /* stop ct_kill_waiting_tm timer if activated */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
        cancel_work_sync(&priv->tt_work);
        cancel_work_sync(&priv->ct_enter);
        cancel_work_sync(&priv->ct_exit);