aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-08-07 18:41:45 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:13:48 -0400
commita28027cd7f169edc399fe4b76d3a33b0203049a1 (patch)
tree70a5b1df8b93527cc8f0fd3051d7bf1673427d76
parentc03ea16285bf142172f9816b8a1f5c43bb4b4405 (diff)
iwlwifi: fix thermal throttling locking problem
Move all the thermal throttling functions to background task to make sure do not change power and rx chain in interrupt handler. 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-dev.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c57
2 files changed, 56 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 61f952330a8..35d07a81325 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1197,6 +1197,9 @@ struct iwl_priv {
1197 struct work_struct report_work; 1197 struct work_struct report_work;
1198 struct work_struct request_scan; 1198 struct work_struct request_scan;
1199 struct work_struct beacon_update; 1199 struct work_struct beacon_update;
1200 struct work_struct tt_work;
1201 struct work_struct ct_enter;
1202 struct work_struct ct_exit;
1200 1203
1201 struct tasklet_struct irq_tasklet; 1204 struct tasklet_struct irq_tasklet;
1202 1205
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 594b5c2540b..9c05af77f9e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -481,6 +481,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
481 tt->tt_power_mode = IWL_POWER_INDEX_5; 481 tt->tt_power_mode = IWL_POWER_INDEX_5;
482 break; 482 break;
483 } 483 }
484 mutex_lock(&priv->mutex);
484 if (iwl_power_update_mode(priv, true)) { 485 if (iwl_power_update_mode(priv, true)) {
485 /* TT state not updated 486 /* TT state not updated
486 * try again during next temperature read 487 * try again during next temperature read
@@ -499,6 +500,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
499 IWL_DEBUG_POWER(priv, "Power Index change to %u\n", 500 IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
500 tt->tt_power_mode); 501 tt->tt_power_mode);
501 } 502 }
503 mutex_unlock(&priv->mutex);
502 } 504 }
503} 505}
504 506
@@ -609,6 +611,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
609 * in case get disabled before */ 611 * in case get disabled before */
610 iwl_set_rxon_ht(priv, &priv->current_ht_config); 612 iwl_set_rxon_ht(priv, &priv->current_ht_config);
611 } 613 }
614 mutex_lock(&priv->mutex);
612 if (iwl_power_update_mode(priv, true)) { 615 if (iwl_power_update_mode(priv, true)) {
613 /* TT state not updated 616 /* TT state not updated
614 * try again during next temperature read 617 * try again during next temperature read
@@ -631,6 +634,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
631 iwl_perform_ct_kill_task(priv, false); 634 iwl_perform_ct_kill_task(priv, false);
632 } 635 }
633 } 636 }
637 mutex_unlock(&priv->mutex);
634 } 638 }
635} 639}
636 640
@@ -644,13 +648,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
644 * for advance mode 648 * for advance mode
645 * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state 649 * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
646 */ 650 */
647void iwl_tt_enter_ct_kill(struct iwl_priv *priv) 651static void iwl_bg_ct_enter(struct work_struct *work)
648{ 652{
653 struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
649 struct iwl_tt_mgmt *tt = &priv->power_data.tt; 654 struct iwl_tt_mgmt *tt = &priv->power_data.tt;
650 655
651 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 656 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
652 return; 657 return;
653 658
659 if (!iwl_is_ready(priv))
660 return;
661
654 if (tt->state != IWL_TI_CT_KILL) { 662 if (tt->state != IWL_TI_CT_KILL) {
655 IWL_ERR(priv, "Device reached critical temperature " 663 IWL_ERR(priv, "Device reached critical temperature "
656 "- ucode going to sleep!\n"); 664 "- ucode going to sleep!\n");
@@ -662,20 +670,23 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
662 CT_KILL_THRESHOLD + 1); 670 CT_KILL_THRESHOLD + 1);
663 } 671 }
664} 672}
665EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
666 673
667/* Card State Notification indicated out of critical temperature 674/* Card State Notification indicated out of critical temperature
668 * since Card State Notification will not provide any temperature reading 675 * since Card State Notification will not provide any temperature reading
669 * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature 676 * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
670 * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state 677 * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
671 */ 678 */
672void iwl_tt_exit_ct_kill(struct iwl_priv *priv) 679static void iwl_bg_ct_exit(struct work_struct *work)
673{ 680{
681 struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
674 struct iwl_tt_mgmt *tt = &priv->power_data.tt; 682 struct iwl_tt_mgmt *tt = &priv->power_data.tt;
675 683
676 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 684 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
677 return; 685 return;
678 686
687 if (!iwl_is_ready(priv))
688 return;
689
679 /* stop ct_kill_exit_tm timer */ 690 /* stop ct_kill_exit_tm timer */
680 del_timer_sync(&priv->power_data.ct_kill_exit_tm); 691 del_timer_sync(&priv->power_data.ct_kill_exit_tm);
681 692
@@ -690,10 +701,30 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
690 iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); 701 iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD);
691 } 702 }
692} 703}
704
705void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
706{
707 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
708 return;
709
710 IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n");
711 queue_work(priv->workqueue, &priv->ct_enter);
712}
713EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
714
715void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
716{
717 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
718 return;
719
720 IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n");
721 queue_work(priv->workqueue, &priv->ct_exit);
722}
693EXPORT_SYMBOL(iwl_tt_exit_ct_kill); 723EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
694 724
695void iwl_tt_handler(struct iwl_priv *priv) 725static void iwl_bg_tt_work(struct work_struct *work)
696{ 726{
727 struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
697 s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ 728 s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
698 729
699 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 730 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -707,6 +738,15 @@ void iwl_tt_handler(struct iwl_priv *priv)
707 else 738 else
708 iwl_advance_tt_handler(priv, temp); 739 iwl_advance_tt_handler(priv, temp);
709} 740}
741
742void iwl_tt_handler(struct iwl_priv *priv)
743{
744 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
745 return;
746
747 IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n");
748 queue_work(priv->workqueue, &priv->tt_work);
749}
710EXPORT_SYMBOL(iwl_tt_handler); 750EXPORT_SYMBOL(iwl_tt_handler);
711 751
712/* Thermal throttling initialization 752/* Thermal throttling initialization
@@ -731,6 +771,12 @@ void iwl_tt_initialize(struct iwl_priv *priv)
731 init_timer(&priv->power_data.ct_kill_exit_tm); 771 init_timer(&priv->power_data.ct_kill_exit_tm);
732 priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; 772 priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv;
733 priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; 773 priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
774
775 /* setup deferred ct kill work */
776 INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
777 INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
778 INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
779
734 switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { 780 switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
735 case CSR_HW_REV_TYPE_6x00: 781 case CSR_HW_REV_TYPE_6x00:
736 case CSR_HW_REV_TYPE_6x50: 782 case CSR_HW_REV_TYPE_6x50:
@@ -782,6 +828,9 @@ void iwl_tt_exit(struct iwl_priv *priv)
782 828
783 /* stop ct_kill_exit_tm timer if activated */ 829 /* stop ct_kill_exit_tm timer if activated */
784 del_timer_sync(&priv->power_data.ct_kill_exit_tm); 830 del_timer_sync(&priv->power_data.ct_kill_exit_tm);
831 cancel_work_sync(&priv->tt_work);
832 cancel_work_sync(&priv->ct_enter);
833 cancel_work_sync(&priv->ct_exit);
785 834
786 if (priv->power_data.adv_tt) { 835 if (priv->power_data.adv_tt) {
787 /* free advance thermal throttling memory */ 836 /* free advance thermal throttling memory */