aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-07-24 14:13:03 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-27 15:24:21 -0400
commit46f9381aa3fb62f6a141bfd41dcbeda1ec5fa26e (patch)
tree1023c715eac2b99b4443afbfefddb52719923593 /drivers/net
parent39b73fb15e4704fd4d1e33688135810637f5f3fb (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/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c48
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c285
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h51
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);
180static void rs_fill_link_cmd(const struct iwl_priv *priv, 180static 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
2689static void rs_fill_link_cmd(const struct iwl_priv *priv, 2719static 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 */
112static 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};
117static 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};
122static 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};
127static 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 */
134static 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 */
103static int iwl_set_power(struct iwl_priv *priv, void *cmd) 142static 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}
274EXPORT_SYMBOL(iwl_power_set_user_mode); 313EXPORT_SYMBOL(iwl_power_set_user_mode);
275 314
315bool 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}
325EXPORT_SYMBOL(iwl_ht_enabled);
326
327u8 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}
337EXPORT_SYMBOL(iwl_tx_ant_restriction);
338
339u8 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}
349EXPORT_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 */
526static 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 */
437void iwl_tt_enter_ct_kill(struct iwl_priv *priv) 647void 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}
450EXPORT_SYMBOL(iwl_tt_enter_ct_kill); 665EXPORT_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}
475EXPORT_SYMBOL(iwl_tt_exit_ct_kill); 693EXPORT_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}
489EXPORT_SYMBOL(iwl_tt_handler); 710EXPORT_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 */
493void iwl_tt_initialize(struct iwl_priv *priv) 717void 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}
509EXPORT_SYMBOL(iwl_tt_initialize); 776EXPORT_SYMBOL(iwl_tt_initialize);
510 777
511/* cleanup thermal throttling management related memory and timer */ 778/* cleanup thermal throttling management related memory and timer */
512void iwl_tt_exit(struct iwl_priv *priv) 779void 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}
517EXPORT_SYMBOL(iwl_tt_exit); 794EXPORT_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
34struct iwl_priv; 34struct 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 */
39enum iwl_tt_state { 49enum 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 */
66struct 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 */
80struct 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 */
59struct iwl_tt_mgmt { 103struct 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
68enum { 114enum {
@@ -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
101int iwl_power_update_mode(struct iwl_priv *priv, bool force); 149int iwl_power_update_mode(struct iwl_priv *priv, bool force);
102int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); 150int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
151bool iwl_ht_enabled(struct iwl_priv *priv);
152u8 iwl_tx_ant_restriction(struct iwl_priv *priv);
153u8 iwl_rx_ant_restriction(struct iwl_priv *priv);
103void iwl_tt_enter_ct_kill(struct iwl_priv *priv); 154void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
104void iwl_tt_exit_ct_kill(struct iwl_priv *priv); 155void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
105void iwl_tt_handler(struct iwl_priv *priv); 156void iwl_tt_handler(struct iwl_priv *priv);