|
@@ -165,26 +165,26 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
|
|
|
*=============================================================================
|
|
|
* 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},
|
|
@@ -351,6 +351,23 @@ bool iwl_ht_enabled(struct iwl_priv *priv)
|
|
|
}
|
|
|
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;
|
|
@@ -375,6 +392,7 @@ enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
|
|
|
}
|
|
|
|
|
|
#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
|
|
@@ -412,6 +430,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
|
|
|
/* 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);
|
|
|
}
|
|
@@ -435,6 +454,33 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+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)
|
|
@@ -448,7 +494,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
|
|
|
* 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;
|
|
@@ -477,6 +523,8 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
|
|
|
#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:
|
|
@@ -497,17 +545,28 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
|
|
|
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",
|
|
@@ -534,13 +593,13 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
|
|
|
*=============================================================================
|
|
|
* 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;
|
|
@@ -585,6 +644,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
|
|
|
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;
|
|
|
|
|
@@ -616,12 +677,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
|
|
|
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,
|
|
@@ -629,9 +695,15 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
|
|
|
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");
|
|
@@ -668,10 +740,11 @@ static void iwl_bg_ct_enter(struct work_struct *work)
|
|
|
"- 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);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -698,11 +771,18 @@ static void iwl_bg_ct_exit(struct work_struct *work)
|
|
|
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);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -738,9 +818,9 @@ static void iwl_bg_tt_work(struct work_struct *work)
|
|
|
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)
|
|
@@ -771,8 +851,12 @@ void iwl_tt_initialize(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);
|
|
@@ -829,6 +913,8 @@ void iwl_tt_exit(struct iwl_priv *priv)
|
|
|
|
|
|
/* 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);
|