aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-10-02 16:43:58 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-07 16:39:44 -0400
commit7812b16730ccebce71a3b2228ac08dd4f8b39469 (patch)
tree83f45bd70261ea6405ca0b8792b92ad998e7547f
parentffe9793252de2e9a3cc7e29a6c7debd1d549df07 (diff)
iwlwifi: reliable entering of critical temperature state
When uCode detects critical temperature it should send "card state notification" interrupt to driver and then shut itself down to prevent overheating. There is a race condition where uCode shuts down before it can deliver the interrupt to driver. Additional method provided here for driver to enter CT_KILL state based on temperature reading. How it works: Method 1: If driver receive "card state notification" interrupt from uCode; it enters "CT_KILL" state immediately Method 2: If the last temperature report by Card reach Critical temperature, driver will send "statistic notification" request to uCode to verify the temperature reading, if driver can not get reply from uCode within 300ms, driver will enter CT_KILL state automatically. Method 3: If the last temperature report by Card did not reach Critical temperature, but uCode already shut down due to critical temperature. All the host commands send to uCode will not get process by uCode; when command queue reach the limit, driver will check the last reported temperature reading, if it is within pre-defined margin, enter "CT_KILL" state immediately. In this case, when uCode ready to exit from "CT_KILL" state, driver need to restart the adapter in order to reset all the queues and resume normal operation. One additional issue being address here, when system is in CT_KILL state, both tx and rx already stopped, but driver still can send host command to uCode, it will flood the command queue since card was not responding; adding STATUS_CT_KILL flag to reject enqueue host commands to uCode if it is in CT_KILL state, when uCode is ready to come out of CT_KILL, driver will clear the STATUS_CT_KILL bit and allow enqueue the host commands to uCode to recover from CT_KILL state. 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>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c146
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c10
5 files changed, 135 insertions, 32 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 744f0cac685..3bd0e59bb5a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -580,6 +580,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
580#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ 580#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
581#define STATUS_INT_ENABLED 2 581#define STATUS_INT_ENABLED 2
582#define STATUS_RF_KILL_HW 3 582#define STATUS_RF_KILL_HW 3
583#define STATUS_CT_KILL 4
583#define STATUS_INIT 5 584#define STATUS_INIT 5
584#define STATUS_ALIVE 6 585#define STATUS_ALIVE 6
585#define STATUS_READY 7 586#define STATUS_READY 7
@@ -624,6 +625,11 @@ static inline int iwl_is_rfkill(struct iwl_priv *priv)
624 return iwl_is_rfkill_hw(priv); 625 return iwl_is_rfkill_hw(priv);
625} 626}
626 627
628static inline int iwl_is_ctkill(struct iwl_priv *priv)
629{
630 return test_bit(STATUS_CT_KILL, &priv->status);
631}
632
627static inline int iwl_is_ready_rf(struct iwl_priv *priv) 633static inline int iwl_is_ready_rf(struct iwl_priv *priv)
628{ 634{
629 635
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 037b75ca77f..fa6371d171c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -535,6 +535,8 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
535 test_bit(STATUS_INT_ENABLED, &priv->status)); 535 test_bit(STATUS_INT_ENABLED, &priv->status));
536 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", 536 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
537 test_bit(STATUS_RF_KILL_HW, &priv->status)); 537 test_bit(STATUS_RF_KILL_HW, &priv->status));
538 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
539 test_bit(STATUS_CT_KILL, &priv->status));
538 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", 540 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
539 test_bit(STATUS_INIT, &priv->status)); 541 test_bit(STATUS_INIT, &priv->status));
540 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", 542 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index e50d77bd7aa..9c6b1495206 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -165,26 +165,26 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
165 *============================================================================= 165 *=============================================================================
166 * Condition Nxt State Condition Nxt State Condition Nxt State 166 * Condition Nxt State Condition Nxt State Condition Nxt State
167 *----------------------------------------------------------------------------- 167 *-----------------------------------------------------------------------------
168 * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A 168 * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
169 * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 169 * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
170 * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 170 * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
171 * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 171 * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
172 *============================================================================= 172 *=============================================================================
173 */ 173 */
174static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = { 174static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
175 {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104}, 175 {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
176 {IWL_TI_1, 105, CT_KILL_THRESHOLD}, 176 {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
177 {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} 177 {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
178}; 178};
179static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = { 179static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
180 {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95}, 180 {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
181 {IWL_TI_2, 110, CT_KILL_THRESHOLD}, 181 {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
182 {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} 182 {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
183}; 183};
184static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = { 184static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
185 {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100}, 185 {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
186 {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, 186 {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
187 {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} 187 {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
188}; 188};
189static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { 189static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
190 {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD}, 190 {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
@@ -351,6 +351,23 @@ bool iwl_ht_enabled(struct iwl_priv *priv)
351} 351}
352EXPORT_SYMBOL(iwl_ht_enabled); 352EXPORT_SYMBOL(iwl_ht_enabled);
353 353
354bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
355{
356 s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
357 bool within_margin = false;
358
359 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
360 temp = KELVIN_TO_CELSIUS(priv->temperature);
361
362 if (!priv->thermal_throttle.advanced_tt)
363 within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
364 CT_KILL_THRESHOLD_LEGACY) ? true : false;
365 else
366 within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
367 CT_KILL_THRESHOLD) ? true : false;
368 return within_margin;
369}
370
354enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv) 371enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
355{ 372{
356 struct iwl_tt_mgmt *tt = &priv->thermal_throttle; 373 struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
@@ -375,6 +392,7 @@ enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
375} 392}
376 393
377#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ 394#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
395#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */
378 396
379/* 397/*
380 * toggle the bit to wake up uCode and check the temperature 398 * 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)
412 /* Reschedule the ct_kill timer to occur in 430 /* Reschedule the ct_kill timer to occur in
413 * CT_KILL_EXIT_DURATION seconds to ensure we get a 431 * CT_KILL_EXIT_DURATION seconds to ensure we get a
414 * thermal update */ 432 * thermal update */
433 IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n");
415 mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + 434 mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
416 CT_KILL_EXIT_DURATION * HZ); 435 CT_KILL_EXIT_DURATION * HZ);
417 } 436 }
@@ -435,6 +454,33 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
435 } 454 }
436} 455}
437 456
457static void iwl_tt_ready_for_ct_kill(unsigned long data)
458{
459 struct iwl_priv *priv = (struct iwl_priv *)data;
460 struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
461
462 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
463 return;
464
465 /* temperature timer expired, ready to go into CT_KILL state */
466 if (tt->state != IWL_TI_CT_KILL) {
467 IWL_DEBUG_POWER(priv, "entering CT_KILL state when temperature timer expired\n");
468 tt->state = IWL_TI_CT_KILL;
469 set_bit(STATUS_CT_KILL, &priv->status);
470 iwl_perform_ct_kill_task(priv, true);
471 }
472}
473
474static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
475{
476 IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
477 /* make request to retrieve statistics information */
478 iwl_send_statistics_request(priv, 0);
479 /* Reschedule the ct_kill wait timer */
480 mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
481 jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
482}
483
438#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY) 484#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY)
439#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100) 485#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100)
440#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90) 486#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90)
@@ -448,7 +494,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
448 * Throttle early enough to lower the power consumption before 494 * Throttle early enough to lower the power consumption before
449 * drastic steps are needed 495 * drastic steps are needed
450 */ 496 */
451static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) 497static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
452{ 498{
453 struct iwl_tt_mgmt *tt = &priv->thermal_throttle; 499 struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
454 enum iwl_tt_state old_state; 500 enum iwl_tt_state old_state;
@@ -477,6 +523,8 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
477#ifdef CONFIG_IWLWIFI_DEBUG 523#ifdef CONFIG_IWLWIFI_DEBUG
478 tt->tt_previous_temp = temp; 524 tt->tt_previous_temp = temp;
479#endif 525#endif
526 /* stop ct_kill_waiting_tm timer */
527 del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
480 if (tt->state != old_state) { 528 if (tt->state != old_state) {
481 switch (tt->state) { 529 switch (tt->state) {
482 case IWL_TI_0: 530 case IWL_TI_0:
@@ -497,17 +545,28 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
497 break; 545 break;
498 } 546 }
499 mutex_lock(&priv->mutex); 547 mutex_lock(&priv->mutex);
500 if (iwl_power_update_mode(priv, true)) { 548 if (old_state == IWL_TI_CT_KILL)
549 clear_bit(STATUS_CT_KILL, &priv->status);
550 if (tt->state != IWL_TI_CT_KILL &&
551 iwl_power_update_mode(priv, true)) {
501 /* TT state not updated 552 /* TT state not updated
502 * try again during next temperature read 553 * try again during next temperature read
503 */ 554 */
555 if (old_state == IWL_TI_CT_KILL)
556 set_bit(STATUS_CT_KILL, &priv->status);
504 tt->state = old_state; 557 tt->state = old_state;
505 IWL_ERR(priv, "Cannot update power mode, " 558 IWL_ERR(priv, "Cannot update power mode, "
506 "TT state not updated\n"); 559 "TT state not updated\n");
507 } else { 560 } else {
508 if (tt->state == IWL_TI_CT_KILL) 561 if (tt->state == IWL_TI_CT_KILL) {
509 iwl_perform_ct_kill_task(priv, true); 562 if (force) {
510 else if (old_state == IWL_TI_CT_KILL && 563 set_bit(STATUS_CT_KILL, &priv->status);
564 iwl_perform_ct_kill_task(priv, true);
565 } else {
566 iwl_prepare_ct_kill_task(priv);
567 tt->state = old_state;
568 }
569 } else if (old_state == IWL_TI_CT_KILL &&
511 tt->state != IWL_TI_CT_KILL) 570 tt->state != IWL_TI_CT_KILL)
512 iwl_perform_ct_kill_task(priv, false); 571 iwl_perform_ct_kill_task(priv, false);
513 IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", 572 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)
534 *============================================================================= 593 *=============================================================================
535 * Condition Nxt State Condition Nxt State Condition Nxt State 594 * Condition Nxt State Condition Nxt State Condition Nxt State
536 *----------------------------------------------------------------------------- 595 *-----------------------------------------------------------------------------
537 * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A 596 * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
538 * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 597 * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
539 * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 598 * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
540 * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 599 * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
541 *============================================================================= 600 *=============================================================================
542 */ 601 */
543static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) 602static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
544{ 603{
545 struct iwl_tt_mgmt *tt = &priv->thermal_throttle; 604 struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
546 int i; 605 int i;
@@ -585,6 +644,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
585 break; 644 break;
586 } 645 }
587 } 646 }
647 /* stop ct_kill_waiting_tm timer */
648 del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
588 if (changed) { 649 if (changed) {
589 struct iwl_rxon_cmd *rxon = &priv->staging_rxon; 650 struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
590 651
@@ -616,12 +677,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
616 iwl_set_rxon_ht(priv, &priv->current_ht_config); 677 iwl_set_rxon_ht(priv, &priv->current_ht_config);
617 } 678 }
618 mutex_lock(&priv->mutex); 679 mutex_lock(&priv->mutex);
619 if (iwl_power_update_mode(priv, true)) { 680 if (old_state == IWL_TI_CT_KILL)
681 clear_bit(STATUS_CT_KILL, &priv->status);
682 if (tt->state != IWL_TI_CT_KILL &&
683 iwl_power_update_mode(priv, true)) {
620 /* TT state not updated 684 /* TT state not updated
621 * try again during next temperature read 685 * try again during next temperature read
622 */ 686 */
623 IWL_ERR(priv, "Cannot update power mode, " 687 IWL_ERR(priv, "Cannot update power mode, "
624 "TT state not updated\n"); 688 "TT state not updated\n");
689 if (old_state == IWL_TI_CT_KILL)
690 set_bit(STATUS_CT_KILL, &priv->status);
625 tt->state = old_state; 691 tt->state = old_state;
626 } else { 692 } else {
627 IWL_DEBUG_POWER(priv, 693 IWL_DEBUG_POWER(priv,
@@ -629,9 +695,15 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
629 tt->state); 695 tt->state);
630 if (old_state != IWL_TI_CT_KILL && 696 if (old_state != IWL_TI_CT_KILL &&
631 tt->state == IWL_TI_CT_KILL) { 697 tt->state == IWL_TI_CT_KILL) {
632 IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n"); 698 if (force) {
633 iwl_perform_ct_kill_task(priv, true); 699 IWL_DEBUG_POWER(priv,
634 700 "Enter IWL_TI_CT_KILL\n");
701 set_bit(STATUS_CT_KILL, &priv->status);
702 iwl_perform_ct_kill_task(priv, true);
703 } else {
704 iwl_prepare_ct_kill_task(priv);
705 tt->state = old_state;
706 }
635 } else if (old_state == IWL_TI_CT_KILL && 707 } else if (old_state == IWL_TI_CT_KILL &&
636 tt->state != IWL_TI_CT_KILL) { 708 tt->state != IWL_TI_CT_KILL) {
637 IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n"); 709 IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
@@ -668,10 +740,11 @@ static void iwl_bg_ct_enter(struct work_struct *work)
668 "- ucode going to sleep!\n"); 740 "- ucode going to sleep!\n");
669 if (!priv->thermal_throttle.advanced_tt) 741 if (!priv->thermal_throttle.advanced_tt)
670 iwl_legacy_tt_handler(priv, 742 iwl_legacy_tt_handler(priv,
671 IWL_MINIMAL_POWER_THRESHOLD); 743 IWL_MINIMAL_POWER_THRESHOLD,
744 true);
672 else 745 else
673 iwl_advance_tt_handler(priv, 746 iwl_advance_tt_handler(priv,
674 CT_KILL_THRESHOLD + 1); 747 CT_KILL_THRESHOLD + 1, true);
675 } 748 }
676} 749}
677 750
@@ -698,11 +771,18 @@ static void iwl_bg_ct_exit(struct work_struct *work)
698 IWL_ERR(priv, 771 IWL_ERR(priv,
699 "Device temperature below critical" 772 "Device temperature below critical"
700 "- ucode awake!\n"); 773 "- ucode awake!\n");
774 /*
775 * exit from CT_KILL state
776 * reset the current temperature reading
777 */
778 priv->temperature = 0;
701 if (!priv->thermal_throttle.advanced_tt) 779 if (!priv->thermal_throttle.advanced_tt)
702 iwl_legacy_tt_handler(priv, 780 iwl_legacy_tt_handler(priv,
703 IWL_REDUCED_PERFORMANCE_THRESHOLD_2); 781 IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
782 true);
704 else 783 else
705 iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); 784 iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
785 true);
706 } 786 }
707} 787}
708 788
@@ -738,9 +818,9 @@ static void iwl_bg_tt_work(struct work_struct *work)
738 temp = KELVIN_TO_CELSIUS(priv->temperature); 818 temp = KELVIN_TO_CELSIUS(priv->temperature);
739 819
740 if (!priv->thermal_throttle.advanced_tt) 820 if (!priv->thermal_throttle.advanced_tt)
741 iwl_legacy_tt_handler(priv, temp); 821 iwl_legacy_tt_handler(priv, temp, false);
742 else 822 else
743 iwl_advance_tt_handler(priv, temp); 823 iwl_advance_tt_handler(priv, temp, false);
744} 824}
745 825
746void iwl_tt_handler(struct iwl_priv *priv) 826void iwl_tt_handler(struct iwl_priv *priv)
@@ -771,8 +851,12 @@ void iwl_tt_initialize(struct iwl_priv *priv)
771 tt->state = IWL_TI_0; 851 tt->state = IWL_TI_0;
772 init_timer(&priv->thermal_throttle.ct_kill_exit_tm); 852 init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
773 priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; 853 priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
774 priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; 854 priv->thermal_throttle.ct_kill_exit_tm.function =
775 855 iwl_tt_check_exit_ct_kill;
856 init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
857 priv->thermal_throttle.ct_kill_waiting_tm.data = (unsigned long)priv;
858 priv->thermal_throttle.ct_kill_waiting_tm.function =
859 iwl_tt_ready_for_ct_kill;
776 /* setup deferred ct kill work */ 860 /* setup deferred ct kill work */
777 INIT_WORK(&priv->tt_work, iwl_bg_tt_work); 861 INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
778 INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); 862 INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
@@ -829,6 +913,8 @@ void iwl_tt_exit(struct iwl_priv *priv)
829 913
830 /* stop ct_kill_exit_tm timer if activated */ 914 /* stop ct_kill_exit_tm timer if activated */
831 del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); 915 del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
916 /* stop ct_kill_waiting_tm timer if activated */
917 del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
832 cancel_work_sync(&priv->tt_work); 918 cancel_work_sync(&priv->tt_work);
833 cancel_work_sync(&priv->ct_enter); 919 cancel_work_sync(&priv->ct_enter);
834 cancel_work_sync(&priv->ct_exit); 920 cancel_work_sync(&priv->ct_exit);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index df6f6a49712..310c32e8f69 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -33,6 +33,7 @@
33#define IWL_ABSOLUTE_ZERO 0 33#define IWL_ABSOLUTE_ZERO 0
34#define IWL_ABSOLUTE_MAX 0xFFFFFFFF 34#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
35#define IWL_TT_INCREASE_MARGIN 5 35#define IWL_TT_INCREASE_MARGIN 5
36#define IWL_TT_CT_KILL_MARGIN 3
36 37
37enum iwl_antenna_ok { 38enum iwl_antenna_ok {
38 IWL_ANT_OK_NONE, 39 IWL_ANT_OK_NONE,
@@ -110,6 +111,7 @@ struct iwl_tt_mgmt {
110 struct iwl_tt_restriction *restriction; 111 struct iwl_tt_restriction *restriction;
111 struct iwl_tt_trans *transaction; 112 struct iwl_tt_trans *transaction;
112 struct timer_list ct_kill_exit_tm; 113 struct timer_list ct_kill_exit_tm;
114 struct timer_list ct_kill_waiting_tm;
113}; 115};
114 116
115enum iwl_power_level { 117enum iwl_power_level {
@@ -129,6 +131,7 @@ struct iwl_power_mgr {
129 131
130int iwl_power_update_mode(struct iwl_priv *priv, bool force); 132int iwl_power_update_mode(struct iwl_priv *priv, bool force);
131bool iwl_ht_enabled(struct iwl_priv *priv); 133bool iwl_ht_enabled(struct iwl_priv *priv);
134bool iwl_within_ct_kill_margin(struct iwl_priv *priv);
132enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); 135enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
133enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); 136enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
134void iwl_tt_enter_ct_kill(struct iwl_priv *priv); 137void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index ad69479376a..2ba9725beff 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -969,13 +969,19 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
969 BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && 969 BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
970 !(cmd->flags & CMD_SIZE_HUGE)); 970 !(cmd->flags & CMD_SIZE_HUGE));
971 971
972 if (iwl_is_rfkill(priv)) { 972 if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
973 IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n"); 973 IWL_DEBUG_INFO(priv, "Not sending command - RF/CT KILL\n");
974 return -EIO; 974 return -EIO;
975 } 975 }
976 976
977 if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { 977 if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
978 IWL_ERR(priv, "No space for Tx\n"); 978 IWL_ERR(priv, "No space for Tx\n");
979 if (iwl_within_ct_kill_margin(priv))
980 iwl_tt_enter_ct_kill(priv);
981 else {
982 IWL_ERR(priv, "Restarting adapter due to queue full\n");
983 queue_work(priv->workqueue, &priv->restart);
984 }
979 return -ENOSPC; 985 return -ENOSPC;
980 } 986 }
981 987