diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2009-07-24 14:13:03 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-27 15:24:21 -0400 |
commit | 46f9381aa3fb62f6a141bfd41dcbeda1ec5fa26e (patch) | |
tree | 1023c715eac2b99b4443afbfefddb52719923593 /drivers | |
parent | 39b73fb15e4704fd4d1e33688135810637f5f3fb (diff) |
iwlwifi: Thermal Throttling Management - part 2
Part 2 of Thermal Throttling Management -
Thermal Throttling feature is used to put NIC into low power state when
driver detect the Radio temperature reach pre-defined threshold
Two Thermal Throttling Management Methods; this patch introduce the
Advance Thermal Throttling:
TI-0: system power index, no tx/rx restriction, HT enabled
TI-1: power index 5, 1 spatial stream Tx, multiple spatial stream Rx, HT
enabled
TI-2: power index 5: 1 spatial stream Tx, 1 spatial stream Rx, HT
disabled
TI-CT-KILL: power index 5, no Tx, no Rx, HT disabled
For advance Thermal Throttling, CT_KILL_ENTER threshold and CT_KILL_EXIT
threshold are different; uCode will not stay awake until reach
CT_KILL_EXIT threshold.
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 48 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.c | 285 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.h | 51 |
3 files changed, 371 insertions, 13 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 40207dac6db5..52a4810274e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -177,7 +177,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, | |||
177 | struct sk_buff *skb, | 177 | struct sk_buff *skb, |
178 | struct ieee80211_sta *sta, | 178 | struct ieee80211_sta *sta, |
179 | struct iwl_lq_sta *lq_sta); | 179 | struct iwl_lq_sta *lq_sta); |
180 | static void rs_fill_link_cmd(const struct iwl_priv *priv, | 180 | static void rs_fill_link_cmd(struct iwl_priv *priv, |
181 | struct iwl_lq_sta *lq_sta, u32 rate_n_flags); | 181 | struct iwl_lq_sta *lq_sta, u32 rate_n_flags); |
182 | 182 | ||
183 | 183 | ||
@@ -1398,6 +1398,12 @@ static int rs_move_legacy_other(struct iwl_priv *priv, | |||
1398 | int ret = 0; | 1398 | int ret = 0; |
1399 | u8 update_search_tbl_counter = 0; | 1399 | u8 update_search_tbl_counter = 0; |
1400 | 1400 | ||
1401 | if (!iwl_ht_enabled(priv)) | ||
1402 | /* stay in Legacy */ | ||
1403 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; | ||
1404 | else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && | ||
1405 | tbl->action > IWL_LEGACY_SWITCH_SISO) | ||
1406 | tbl->action = IWL_LEGACY_SWITCH_SISO; | ||
1401 | for (; ;) { | 1407 | for (; ;) { |
1402 | lq_sta->action_counter++; | 1408 | lq_sta->action_counter++; |
1403 | switch (tbl->action) { | 1409 | switch (tbl->action) { |
@@ -1529,6 +1535,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, | |||
1529 | u8 update_search_tbl_counter = 0; | 1535 | u8 update_search_tbl_counter = 0; |
1530 | int ret; | 1536 | int ret; |
1531 | 1537 | ||
1538 | if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && | ||
1539 | tbl->action > IWL_SISO_SWITCH_ANTENNA2) { | ||
1540 | /* stay in SISO */ | ||
1541 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | ||
1542 | } | ||
1532 | for (;;) { | 1543 | for (;;) { |
1533 | lq_sta->action_counter++; | 1544 | lq_sta->action_counter++; |
1534 | switch (tbl->action) { | 1545 | switch (tbl->action) { |
@@ -1663,6 +1674,12 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, | |||
1663 | u8 update_search_tbl_counter = 0; | 1674 | u8 update_search_tbl_counter = 0; |
1664 | int ret; | 1675 | int ret; |
1665 | 1676 | ||
1677 | if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && | ||
1678 | (tbl->action < IWL_MIMO2_SWITCH_SISO_A || | ||
1679 | tbl->action > IWL_MIMO2_SWITCH_SISO_C)) { | ||
1680 | /* switch in SISO */ | ||
1681 | tbl->action = IWL_MIMO2_SWITCH_SISO_A; | ||
1682 | } | ||
1666 | for (;;) { | 1683 | for (;;) { |
1667 | lq_sta->action_counter++; | 1684 | lq_sta->action_counter++; |
1668 | switch (tbl->action) { | 1685 | switch (tbl->action) { |
@@ -1799,6 +1816,12 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, | |||
1799 | int ret; | 1816 | int ret; |
1800 | u8 update_search_tbl_counter = 0; | 1817 | u8 update_search_tbl_counter = 0; |
1801 | 1818 | ||
1819 | if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && | ||
1820 | (tbl->action < IWL_MIMO3_SWITCH_SISO_A || | ||
1821 | tbl->action > IWL_MIMO3_SWITCH_SISO_C)) { | ||
1822 | /* switch in SISO */ | ||
1823 | tbl->action = IWL_MIMO3_SWITCH_SISO_A; | ||
1824 | } | ||
1802 | for (;;) { | 1825 | for (;;) { |
1803 | lq_sta->action_counter++; | 1826 | lq_sta->action_counter++; |
1804 | switch (tbl->action) { | 1827 | switch (tbl->action) { |
@@ -2178,8 +2201,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, | |||
2178 | tbl->expected_tpt[index] + 64) / 128)); | 2201 | tbl->expected_tpt[index] + 64) / 128)); |
2179 | 2202 | ||
2180 | /* If we are searching for better modulation mode, check success. */ | 2203 | /* If we are searching for better modulation mode, check success. */ |
2181 | if (lq_sta->search_better_tbl) { | 2204 | if (lq_sta->search_better_tbl && |
2182 | 2205 | (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) { | |
2183 | /* If good success, continue using the "search" mode; | 2206 | /* If good success, continue using the "search" mode; |
2184 | * no need to send new link quality command, since we're | 2207 | * no need to send new link quality command, since we're |
2185 | * continuing to use the setup that we've been trying. */ | 2208 | * continuing to use the setup that we've been trying. */ |
@@ -2307,7 +2330,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, | |||
2307 | ((sr > IWL_RATE_HIGH_TH) || | 2330 | ((sr > IWL_RATE_HIGH_TH) || |
2308 | (current_tpt > (100 * tbl->expected_tpt[low])))) | 2331 | (current_tpt > (100 * tbl->expected_tpt[low])))) |
2309 | scale_action = 0; | 2332 | scale_action = 0; |
2310 | 2333 | if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type)) | |
2334 | scale_action = -1; | ||
2335 | if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI && | ||
2336 | (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) | ||
2337 | scale_action = -1; | ||
2311 | switch (scale_action) { | 2338 | switch (scale_action) { |
2312 | case -1: | 2339 | case -1: |
2313 | /* Decrease starting rate, update uCode's rate table */ | 2340 | /* Decrease starting rate, update uCode's rate table */ |
@@ -2341,9 +2368,11 @@ lq_update: | |||
2341 | rate = rs_update_rate_tbl(priv, lq_sta, | 2368 | rate = rs_update_rate_tbl(priv, lq_sta, |
2342 | tbl, index, is_green); | 2369 | tbl, index, is_green); |
2343 | 2370 | ||
2344 | /* Should we stay with this modulation mode, or search for a new one? */ | 2371 | if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) { |
2345 | rs_stay_in_table(lq_sta); | 2372 | /* Should we stay with this modulation mode, |
2346 | 2373 | * or search for a new one? */ | |
2374 | rs_stay_in_table(lq_sta); | ||
2375 | } | ||
2347 | /* | 2376 | /* |
2348 | * Search for new modulation mode if we're: | 2377 | * Search for new modulation mode if we're: |
2349 | * 1) Not changing rates right now | 2378 | * 1) Not changing rates right now |
@@ -2400,7 +2429,8 @@ lq_update: | |||
2400 | * have been tried and compared, stay in this best modulation | 2429 | * have been tried and compared, stay in this best modulation |
2401 | * mode for a while before next round of mode comparisons. */ | 2430 | * mode for a while before next round of mode comparisons. */ |
2402 | if (lq_sta->enable_counter && | 2431 | if (lq_sta->enable_counter && |
2403 | (lq_sta->action_counter >= tbl1->max_search)) { | 2432 | (lq_sta->action_counter >= tbl1->max_search) && |
2433 | iwl_ht_enabled(priv)) { | ||
2404 | if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && | 2434 | if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && |
2405 | (lq_sta->tx_agg_tid_en & (1 << tid)) && | 2435 | (lq_sta->tx_agg_tid_en & (1 << tid)) && |
2406 | (tid != MAX_TID_COUNT)) { | 2436 | (tid != MAX_TID_COUNT)) { |
@@ -2686,7 +2716,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, | |||
2686 | rs_initialize_lq(priv, conf, sta, lq_sta); | 2716 | rs_initialize_lq(priv, conf, sta, lq_sta); |
2687 | } | 2717 | } |
2688 | 2718 | ||
2689 | static void rs_fill_link_cmd(const struct iwl_priv *priv, | 2719 | static void rs_fill_link_cmd(struct iwl_priv *priv, |
2690 | struct iwl_lq_sta *lq_sta, u32 new_rate) | 2720 | struct iwl_lq_sta *lq_sta, u32 new_rate) |
2691 | { | 2721 | { |
2692 | struct iwl_scale_tbl_info tbl_type; | 2722 | struct iwl_scale_tbl_info tbl_type; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index d7fdb5825450..00937b3ee8ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
@@ -98,6 +98,45 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { | |||
98 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} | 98 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} |
99 | }; | 99 | }; |
100 | 100 | ||
101 | /* default Thermal Throttling transaction table | ||
102 | * Current state | Throttling Down | Throttling Up | ||
103 | *============================================================================= | ||
104 | * Condition Nxt State Condition Nxt State Condition Nxt State | ||
105 | *----------------------------------------------------------------------------- | ||
106 | * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A | ||
107 | * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 | ||
108 | * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 | ||
109 | * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 | ||
110 | *============================================================================= | ||
111 | */ | ||
112 | static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = { | ||
113 | {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104}, | ||
114 | {IWL_TI_1, 105, CT_KILL_THRESHOLD}, | ||
115 | {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} | ||
116 | }; | ||
117 | static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = { | ||
118 | {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95}, | ||
119 | {IWL_TI_2, 110, CT_KILL_THRESHOLD}, | ||
120 | {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} | ||
121 | }; | ||
122 | static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = { | ||
123 | {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100}, | ||
124 | {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, | ||
125 | {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} | ||
126 | }; | ||
127 | static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { | ||
128 | {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD}, | ||
129 | {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, | ||
130 | {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX} | ||
131 | }; | ||
132 | |||
133 | /* Advance Thermal Throttling default restriction table */ | ||
134 | static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { | ||
135 | {IWL_TX_MULTI, true, IWL_RX_MULTI}, | ||
136 | {IWL_TX_SINGLE, true, IWL_RX_MULTI}, | ||
137 | {IWL_TX_SINGLE, false, IWL_RX_SINGLE}, | ||
138 | {IWL_TX_NONE, false, IWL_RX_NONE} | ||
139 | }; | ||
101 | 140 | ||
102 | /* set card power command */ | 141 | /* set card power command */ |
103 | static int iwl_set_power(struct iwl_priv *priv, void *cmd) | 142 | static int iwl_set_power(struct iwl_priv *priv, void *cmd) |
@@ -273,6 +312,42 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) | |||
273 | } | 312 | } |
274 | EXPORT_SYMBOL(iwl_power_set_user_mode); | 313 | EXPORT_SYMBOL(iwl_power_set_user_mode); |
275 | 314 | ||
315 | bool iwl_ht_enabled(struct iwl_priv *priv) | ||
316 | { | ||
317 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
318 | struct iwl_tt_restriction *restriction; | ||
319 | |||
320 | if (!priv->power_data.adv_tt) | ||
321 | return true; | ||
322 | restriction = tt->restriction + tt->state; | ||
323 | return restriction->is_ht; | ||
324 | } | ||
325 | EXPORT_SYMBOL(iwl_ht_enabled); | ||
326 | |||
327 | u8 iwl_tx_ant_restriction(struct iwl_priv *priv) | ||
328 | { | ||
329 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
330 | struct iwl_tt_restriction *restriction; | ||
331 | |||
332 | if (!priv->power_data.adv_tt) | ||
333 | return IWL_TX_MULTI; | ||
334 | restriction = tt->restriction + tt->state; | ||
335 | return restriction->tx_stream; | ||
336 | } | ||
337 | EXPORT_SYMBOL(iwl_tx_ant_restriction); | ||
338 | |||
339 | u8 iwl_rx_ant_restriction(struct iwl_priv *priv) | ||
340 | { | ||
341 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
342 | struct iwl_tt_restriction *restriction; | ||
343 | |||
344 | if (!priv->power_data.adv_tt) | ||
345 | return IWL_RX_MULTI; | ||
346 | restriction = tt->restriction + tt->state; | ||
347 | return restriction->rx_stream; | ||
348 | } | ||
349 | EXPORT_SYMBOL(iwl_rx_ant_restriction); | ||
350 | |||
276 | #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ | 351 | #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ |
277 | 352 | ||
278 | /* | 353 | /* |
@@ -427,12 +502,147 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) | |||
427 | } | 502 | } |
428 | } | 503 | } |
429 | 504 | ||
505 | /* | ||
506 | * Advance thermal throttling | ||
507 | * 1) Avoid NIC destruction due to high temperatures | ||
508 | * Chip will identify dangerously high temperatures that can | ||
509 | * harm the device and will power down | ||
510 | * 2) Avoid the NIC power down due to high temperature | ||
511 | * Throttle early enough to lower the power consumption before | ||
512 | * drastic steps are needed | ||
513 | * Actions include relaxing the power down sleep thresholds and | ||
514 | * decreasing the number of TX streams | ||
515 | * 3) Avoid throughput performance impact as much as possible | ||
516 | * | ||
517 | *============================================================================= | ||
518 | * Condition Nxt State Condition Nxt State Condition Nxt State | ||
519 | *----------------------------------------------------------------------------- | ||
520 | * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A | ||
521 | * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 | ||
522 | * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 | ||
523 | * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 | ||
524 | *============================================================================= | ||
525 | */ | ||
526 | static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) | ||
527 | { | ||
528 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
529 | int i; | ||
530 | bool changed = false; | ||
531 | enum iwl_tt_state old_state; | ||
532 | struct iwl_tt_trans *transaction; | ||
533 | |||
534 | old_state = tt->state; | ||
535 | for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) { | ||
536 | /* based on the current TT state, | ||
537 | * find the curresponding transaction table | ||
538 | * each table has (IWL_TI_STATE_MAX - 1) entries | ||
539 | * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1)) | ||
540 | * will advance to the correct table. | ||
541 | * then based on the current temperature | ||
542 | * find the next state need to transaction to | ||
543 | * go through all the possible (IWL_TI_STATE_MAX - 1) entries | ||
544 | * in the current table to see if transaction is needed | ||
545 | */ | ||
546 | transaction = tt->transaction + | ||
547 | ((old_state * (IWL_TI_STATE_MAX - 1)) + i); | ||
548 | if (temp >= transaction->tt_low && | ||
549 | temp <= transaction->tt_high) { | ||
550 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
551 | if ((tt->tt_previous_temp) && | ||
552 | (temp > tt->tt_previous_temp) && | ||
553 | ((temp - tt->tt_previous_temp) > | ||
554 | IWL_TT_INCREASE_MARGIN)) { | ||
555 | IWL_DEBUG_POWER(priv, | ||
556 | "Temperature increase %d " | ||
557 | "degree Celsius\n", | ||
558 | (temp - tt->tt_previous_temp)); | ||
559 | } | ||
560 | tt->tt_previous_temp = temp; | ||
561 | #endif | ||
562 | if (old_state != | ||
563 | transaction->next_state) { | ||
564 | changed = true; | ||
565 | tt->state = | ||
566 | transaction->next_state; | ||
567 | } | ||
568 | break; | ||
569 | } | ||
570 | } | ||
571 | if (changed) { | ||
572 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | ||
573 | struct iwl_power_mgr *setting = &priv->power_data; | ||
574 | |||
575 | if (tt->state >= IWL_TI_1) { | ||
576 | /* if switching from IWL_TI_0 to other TT state | ||
577 | * save previous power setting in tt->sys_power_mode */ | ||
578 | if (old_state == IWL_TI_0) | ||
579 | tt->sys_power_mode = setting->power_mode; | ||
580 | /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ | ||
581 | tt->tt_power_mode = IWL_POWER_INDEX_5; | ||
582 | if (!iwl_ht_enabled(priv)) | ||
583 | /* disable HT */ | ||
584 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | | ||
585 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | | ||
586 | RXON_FLG_FAT_PROT_MSK | | ||
587 | RXON_FLG_HT_PROT_MSK); | ||
588 | else { | ||
589 | /* check HT capability and set | ||
590 | * according to the system HT capability | ||
591 | * in case get disabled before */ | ||
592 | iwl_set_rxon_ht(priv, &priv->current_ht_config); | ||
593 | } | ||
594 | |||
595 | } else { | ||
596 | /* restore system power setting */ | ||
597 | /* the previous power mode was saved in | ||
598 | * tt->sys_power_mode when system move into | ||
599 | * Thermal Throttling state | ||
600 | * set power_data.user_power_setting to the previous | ||
601 | * system power mode to make sure power will get | ||
602 | * updated correctly | ||
603 | */ | ||
604 | priv->power_data.user_power_setting = | ||
605 | tt->sys_power_mode; | ||
606 | tt->tt_power_mode = tt->sys_power_mode; | ||
607 | /* check HT capability and set | ||
608 | * according to the system HT capability | ||
609 | * in case get disabled before */ | ||
610 | iwl_set_rxon_ht(priv, &priv->current_ht_config); | ||
611 | } | ||
612 | if (iwl_power_update_mode(priv, true)) { | ||
613 | /* TT state not updated | ||
614 | * try again during next temperature read | ||
615 | */ | ||
616 | IWL_ERR(priv, "Cannot update power mode, " | ||
617 | "TT state not updated\n"); | ||
618 | tt->state = old_state; | ||
619 | } else { | ||
620 | IWL_DEBUG_POWER(priv, | ||
621 | "Thermal Throttling to new state: %u\n", | ||
622 | tt->state); | ||
623 | if (old_state != IWL_TI_CT_KILL && | ||
624 | tt->state == IWL_TI_CT_KILL) { | ||
625 | IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n"); | ||
626 | iwl_perform_ct_kill_task(priv, true); | ||
627 | |||
628 | } else if (old_state == IWL_TI_CT_KILL && | ||
629 | tt->state != IWL_TI_CT_KILL) { | ||
630 | IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n"); | ||
631 | iwl_perform_ct_kill_task(priv, false); | ||
632 | } | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | |||
430 | /* Card State Notification indicated reach critical temperature | 637 | /* Card State Notification indicated reach critical temperature |
431 | * if PSP not enable, no Thermal Throttling function will be performed | 638 | * if PSP not enable, no Thermal Throttling function will be performed |
432 | * just set the GP1 bit to acknowledge the event | 639 | * just set the GP1 bit to acknowledge the event |
433 | * otherwise, go into IWL_TI_CT_KILL state | 640 | * otherwise, go into IWL_TI_CT_KILL state |
434 | * since Card State Notification will not provide any temperature reading | 641 | * since Card State Notification will not provide any temperature reading |
642 | * for Legacy mode | ||
435 | * so just pass the CT_KILL temperature to iwl_legacy_tt_handler() | 643 | * so just pass the CT_KILL temperature to iwl_legacy_tt_handler() |
644 | * for advance mode | ||
645 | * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state | ||
436 | */ | 646 | */ |
437 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv) | 647 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv) |
438 | { | 648 | { |
@@ -444,7 +654,12 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) | |||
444 | if (tt->state != IWL_TI_CT_KILL) { | 654 | if (tt->state != IWL_TI_CT_KILL) { |
445 | IWL_ERR(priv, "Device reached critical temperature " | 655 | IWL_ERR(priv, "Device reached critical temperature " |
446 | "- ucode going to sleep!\n"); | 656 | "- ucode going to sleep!\n"); |
447 | iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD); | 657 | if (!priv->power_data.adv_tt) |
658 | iwl_legacy_tt_handler(priv, | ||
659 | IWL_MINIMAL_POWER_THRESHOLD); | ||
660 | else | ||
661 | iwl_advance_tt_handler(priv, | ||
662 | CT_KILL_THRESHOLD + 1); | ||
448 | } | 663 | } |
449 | } | 664 | } |
450 | EXPORT_SYMBOL(iwl_tt_enter_ct_kill); | 665 | EXPORT_SYMBOL(iwl_tt_enter_ct_kill); |
@@ -468,8 +683,11 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv) | |||
468 | IWL_ERR(priv, | 683 | IWL_ERR(priv, |
469 | "Device temperature below critical" | 684 | "Device temperature below critical" |
470 | "- ucode awake!\n"); | 685 | "- ucode awake!\n"); |
471 | iwl_legacy_tt_handler(priv, | 686 | if (!priv->power_data.adv_tt) |
472 | IWL_REDUCED_PERFORMANCE_THRESHOLD_2); | 687 | iwl_legacy_tt_handler(priv, |
688 | IWL_REDUCED_PERFORMANCE_THRESHOLD_2); | ||
689 | else | ||
690 | iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); | ||
473 | } | 691 | } |
474 | } | 692 | } |
475 | EXPORT_SYMBOL(iwl_tt_exit_ct_kill); | 693 | EXPORT_SYMBOL(iwl_tt_exit_ct_kill); |
@@ -484,16 +702,24 @@ void iwl_tt_handler(struct iwl_priv *priv) | |||
484 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) | 702 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) |
485 | temp = KELVIN_TO_CELSIUS(priv->temperature); | 703 | temp = KELVIN_TO_CELSIUS(priv->temperature); |
486 | 704 | ||
487 | iwl_legacy_tt_handler(priv, temp); | 705 | if (!priv->power_data.adv_tt) |
706 | iwl_legacy_tt_handler(priv, temp); | ||
707 | else | ||
708 | iwl_advance_tt_handler(priv, temp); | ||
488 | } | 709 | } |
489 | EXPORT_SYMBOL(iwl_tt_handler); | 710 | EXPORT_SYMBOL(iwl_tt_handler); |
490 | 711 | ||
491 | /* Thermal throttling initialization | 712 | /* Thermal throttling initialization |
713 | * For advance thermal throttling: | ||
714 | * Initialize Thermal Index and temperature threshold table | ||
715 | * Initialize thermal throttling restriction table | ||
492 | */ | 716 | */ |
493 | void iwl_tt_initialize(struct iwl_priv *priv) | 717 | void iwl_tt_initialize(struct iwl_priv *priv) |
494 | { | 718 | { |
495 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | 719 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; |
496 | struct iwl_power_mgr *setting = &priv->power_data; | 720 | struct iwl_power_mgr *setting = &priv->power_data; |
721 | int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); | ||
722 | struct iwl_tt_trans *transaction; | ||
497 | 723 | ||
498 | IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n"); | 724 | IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n"); |
499 | 725 | ||
@@ -505,14 +731,65 @@ void iwl_tt_initialize(struct iwl_priv *priv) | |||
505 | init_timer(&priv->power_data.ct_kill_exit_tm); | 731 | init_timer(&priv->power_data.ct_kill_exit_tm); |
506 | priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; | 732 | priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; |
507 | priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; | 733 | priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; |
734 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { | ||
735 | case CSR_HW_REV_TYPE_6x00: | ||
736 | case CSR_HW_REV_TYPE_6x50: | ||
737 | IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n"); | ||
738 | tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) * | ||
739 | IWL_TI_STATE_MAX, GFP_KERNEL); | ||
740 | tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) * | ||
741 | IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1), | ||
742 | GFP_KERNEL); | ||
743 | if (!tt->restriction || !tt->transaction) { | ||
744 | IWL_ERR(priv, "Fallback to Legacy Throttling\n"); | ||
745 | priv->power_data.adv_tt = false; | ||
746 | kfree(tt->restriction); | ||
747 | tt->restriction = NULL; | ||
748 | kfree(tt->transaction); | ||
749 | tt->transaction = NULL; | ||
750 | } else { | ||
751 | transaction = tt->transaction + | ||
752 | (IWL_TI_0 * (IWL_TI_STATE_MAX - 1)); | ||
753 | memcpy(transaction, &tt_range_0[0], size); | ||
754 | transaction = tt->transaction + | ||
755 | (IWL_TI_1 * (IWL_TI_STATE_MAX - 1)); | ||
756 | memcpy(transaction, &tt_range_1[0], size); | ||
757 | transaction = tt->transaction + | ||
758 | (IWL_TI_2 * (IWL_TI_STATE_MAX - 1)); | ||
759 | memcpy(transaction, &tt_range_2[0], size); | ||
760 | transaction = tt->transaction + | ||
761 | (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1)); | ||
762 | memcpy(transaction, &tt_range_3[0], size); | ||
763 | size = sizeof(struct iwl_tt_restriction) * | ||
764 | IWL_TI_STATE_MAX; | ||
765 | memcpy(tt->restriction, | ||
766 | &restriction_range[0], size); | ||
767 | priv->power_data.adv_tt = true; | ||
768 | } | ||
769 | break; | ||
770 | default: | ||
771 | IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); | ||
772 | priv->power_data.adv_tt = false; | ||
773 | break; | ||
774 | } | ||
508 | } | 775 | } |
509 | EXPORT_SYMBOL(iwl_tt_initialize); | 776 | EXPORT_SYMBOL(iwl_tt_initialize); |
510 | 777 | ||
511 | /* cleanup thermal throttling management related memory and timer */ | 778 | /* cleanup thermal throttling management related memory and timer */ |
512 | void iwl_tt_exit(struct iwl_priv *priv) | 779 | void iwl_tt_exit(struct iwl_priv *priv) |
513 | { | 780 | { |
781 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
782 | |||
514 | /* stop ct_kill_exit_tm timer if activated */ | 783 | /* stop ct_kill_exit_tm timer if activated */ |
515 | del_timer_sync(&priv->power_data.ct_kill_exit_tm); | 784 | del_timer_sync(&priv->power_data.ct_kill_exit_tm); |
785 | |||
786 | if (priv->power_data.adv_tt) { | ||
787 | /* free advance thermal throttling memory */ | ||
788 | kfree(tt->restriction); | ||
789 | tt->restriction = NULL; | ||
790 | kfree(tt->transaction); | ||
791 | tt->transaction = NULL; | ||
792 | } | ||
516 | } | 793 | } |
517 | EXPORT_SYMBOL(iwl_tt_exit); | 794 | EXPORT_SYMBOL(iwl_tt_exit); |
518 | 795 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 7bb10d41ae5f..3d49b7a45b74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h | |||
@@ -33,8 +33,18 @@ | |||
33 | 33 | ||
34 | struct iwl_priv; | 34 | struct iwl_priv; |
35 | 35 | ||
36 | #define IWL_ABSOLUTE_ZERO 0 | ||
37 | #define IWL_ABSOLUTE_MAX 0xFFFFFFFF | ||
36 | #define IWL_TT_INCREASE_MARGIN 5 | 38 | #define IWL_TT_INCREASE_MARGIN 5 |
37 | 39 | ||
40 | /* Tx/Rx restrictions */ | ||
41 | #define IWL_TX_MULTI 0x02 | ||
42 | #define IWL_TX_SINGLE 0x01 | ||
43 | #define IWL_TX_NONE 0x00 | ||
44 | #define IWL_RX_MULTI 0x02 | ||
45 | #define IWL_RX_SINGLE 0x01 | ||
46 | #define IWL_RX_NONE 0x00 | ||
47 | |||
38 | /* Thermal Throttling State Machine states */ | 48 | /* Thermal Throttling State Machine states */ |
39 | enum iwl_tt_state { | 49 | enum iwl_tt_state { |
40 | IWL_TI_0, /* normal temperature, system power state */ | 50 | IWL_TI_0, /* normal temperature, system power state */ |
@@ -45,6 +55,35 @@ enum iwl_tt_state { | |||
45 | }; | 55 | }; |
46 | 56 | ||
47 | /** | 57 | /** |
58 | * struct iwl_tt_restriction - Thermal Throttling restriction table used | ||
59 | * by advance thermal throttling management | ||
60 | * based on the current thermal throttling state, determine | ||
61 | * number of tx/rx streams; and the status of HT operation | ||
62 | * @tx_stream: number of tx stream allowed | ||
63 | * @is_ht: ht enable/disable | ||
64 | * @rx_stream: number of rx stream allowed | ||
65 | */ | ||
66 | struct iwl_tt_restriction { | ||
67 | u8 tx_stream; | ||
68 | bool is_ht; | ||
69 | u8 rx_stream; | ||
70 | }; | ||
71 | |||
72 | /** | ||
73 | * struct iwl_tt_trans - Thermal Throttling transaction table; used by | ||
74 | * advance thermal throttling algorithm to determine next | ||
75 | * thermal state to go based on the current temperature | ||
76 | * @next_state: next thermal throttling mode | ||
77 | * @tt_low: low temperature threshold to change state | ||
78 | * @tt_high: high temperature threshold to change state | ||
79 | */ | ||
80 | struct iwl_tt_trans { | ||
81 | enum iwl_tt_state next_state; | ||
82 | u32 tt_low; | ||
83 | u32 tt_high; | ||
84 | }; | ||
85 | |||
86 | /** | ||
48 | * struct iwl_tt_mgnt - Thermal Throttling Management structure | 87 | * struct iwl_tt_mgnt - Thermal Throttling Management structure |
49 | * @state: current Thermal Throttling state | 88 | * @state: current Thermal Throttling state |
50 | * @tt_power_mode: Thermal Throttling power mode index | 89 | * @tt_power_mode: Thermal Throttling power mode index |
@@ -55,6 +94,11 @@ enum iwl_tt_state { | |||
55 | * @sys_power_mode: previous system power mode | 94 | * @sys_power_mode: previous system power mode |
56 | * before transition into TT state | 95 | * before transition into TT state |
57 | * @tt_previous_temperature: last measured temperature | 96 | * @tt_previous_temperature: last measured temperature |
97 | * @iwl_tt_restriction: ptr to restriction tbl, used by advance | ||
98 | * thermal throttling to determine how many tx/rx streams | ||
99 | * should be used in tt state; and can HT be enabled or not | ||
100 | * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling | ||
101 | * state transaction | ||
58 | */ | 102 | */ |
59 | struct iwl_tt_mgmt { | 103 | struct iwl_tt_mgmt { |
60 | enum iwl_tt_state state; | 104 | enum iwl_tt_state state; |
@@ -63,6 +107,8 @@ struct iwl_tt_mgmt { | |||
63 | #ifdef CONFIG_IWLWIFI_DEBUG | 107 | #ifdef CONFIG_IWLWIFI_DEBUG |
64 | s32 tt_previous_temp; | 108 | s32 tt_previous_temp; |
65 | #endif | 109 | #endif |
110 | struct iwl_tt_restriction *restriction; | ||
111 | struct iwl_tt_trans *transaction; | ||
66 | }; | 112 | }; |
67 | 113 | ||
68 | enum { | 114 | enum { |
@@ -92,6 +138,8 @@ struct iwl_power_mgr { | |||
92 | u8 user_power_setting; /* set by user through sysfs */ | 138 | u8 user_power_setting; /* set by user through sysfs */ |
93 | u8 power_disabled; /* set by mac80211's CONF_PS */ | 139 | u8 power_disabled; /* set by mac80211's CONF_PS */ |
94 | struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ | 140 | struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ |
141 | bool adv_tt; /* false: legacy mode */ | ||
142 | /* true: advance mode */ | ||
95 | bool ct_kill_toggle; /* use to toggle the CSR bit when | 143 | bool ct_kill_toggle; /* use to toggle the CSR bit when |
96 | * checking uCode temperature | 144 | * checking uCode temperature |
97 | */ | 145 | */ |
@@ -100,6 +148,9 @@ struct iwl_power_mgr { | |||
100 | 148 | ||
101 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); | 149 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); |
102 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); | 150 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); |
151 | bool iwl_ht_enabled(struct iwl_priv *priv); | ||
152 | u8 iwl_tx_ant_restriction(struct iwl_priv *priv); | ||
153 | u8 iwl_rx_ant_restriction(struct iwl_priv *priv); | ||
103 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv); | 154 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv); |
104 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv); | 155 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv); |
105 | void iwl_tt_handler(struct iwl_priv *priv); | 156 | void iwl_tt_handler(struct iwl_priv *priv); |