diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2009-08-07 18:41:45 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-14 09:13:48 -0400 |
commit | a28027cd7f169edc399fe4b76d3a33b0203049a1 (patch) | |
tree | 70a5b1df8b93527cc8f0fd3051d7bf1673427d76 /drivers/net/wireless/iwlwifi/iwl-power.c | |
parent | c03ea16285bf142172f9816b8a1f5c43bb4b4405 (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>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-power.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.c | 57 |
1 files changed, 53 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 594b5c2540b5..9c05af77f9e7 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 | */ |
647 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv) | 651 | static 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 | } |
665 | EXPORT_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 | */ |
672 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv) | 679 | static 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 | |||
705 | void 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 | } | ||
713 | EXPORT_SYMBOL(iwl_tt_enter_ct_kill); | ||
714 | |||
715 | void 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 | } | ||
693 | EXPORT_SYMBOL(iwl_tt_exit_ct_kill); | 723 | EXPORT_SYMBOL(iwl_tt_exit_ct_kill); |
694 | 724 | ||
695 | void iwl_tt_handler(struct iwl_priv *priv) | 725 | static 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 | |||
742 | void 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 | } | ||
710 | EXPORT_SYMBOL(iwl_tt_handler); | 750 | EXPORT_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 */ |