diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-core.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 78 |
1 files changed, 46 insertions, 32 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 9bd61809129f..80f2f84defa8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -28,7 +28,6 @@ | |||
28 | 28 | ||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/version.h> | ||
32 | #include <net/mac80211.h> | 31 | #include <net/mac80211.h> |
33 | 32 | ||
34 | struct iwl_priv; /* FIXME: remove */ | 33 | struct iwl_priv; /* FIXME: remove */ |
@@ -593,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv) | |||
593 | clear_bit(STATUS_GEO_CONFIGURED, &priv->status); | 592 | clear_bit(STATUS_GEO_CONFIGURED, &priv->status); |
594 | } | 593 | } |
595 | 594 | ||
596 | static u8 is_single_rx_stream(struct iwl_priv *priv) | 595 | static bool is_single_rx_stream(struct iwl_priv *priv) |
597 | { | 596 | { |
598 | return !priv->current_ht_config.is_ht || | 597 | return !priv->current_ht_config.is_ht || |
599 | ((priv->current_ht_config.supp_mcs_set[1] == 0) && | 598 | ((priv->current_ht_config.supp_mcs_set[1] == 0) && |
600 | (priv->current_ht_config.supp_mcs_set[2] == 0)) || | 599 | (priv->current_ht_config.supp_mcs_set[2] == 0)); |
601 | priv->ps_mode == IWL_MIMO_PS_STATIC; | ||
602 | } | 600 | } |
603 | 601 | ||
604 | static u8 iwl_is_channel_extension(struct iwl_priv *priv, | 602 | static u8 iwl_is_channel_extension(struct iwl_priv *priv, |
@@ -705,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht); | |||
705 | * MIMO (dual stream) requires at least 2, but works better with 3. | 703 | * MIMO (dual stream) requires at least 2, but works better with 3. |
706 | * This does not determine *which* chains to use, just how many. | 704 | * This does not determine *which* chains to use, just how many. |
707 | */ | 705 | */ |
708 | static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, | 706 | static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) |
709 | u8 *idle_state, u8 *rx_state) | ||
710 | { | 707 | { |
711 | u8 is_single = is_single_rx_stream(priv); | 708 | bool is_single = is_single_rx_stream(priv); |
712 | u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; | 709 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); |
713 | 710 | ||
714 | /* # of Rx chains to use when expecting MIMO. */ | 711 | /* # of Rx chains to use when expecting MIMO. */ |
715 | if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) | 712 | if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) |
716 | *rx_state = 2; | 713 | return 2; |
717 | else | 714 | else |
718 | *rx_state = 3; | 715 | return 3; |
716 | } | ||
719 | 717 | ||
718 | static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) | ||
719 | { | ||
720 | int idle_cnt; | ||
721 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); | ||
720 | /* # Rx chains when idling and maybe trying to save power */ | 722 | /* # Rx chains when idling and maybe trying to save power */ |
721 | switch (priv->ps_mode) { | 723 | switch (priv->ps_mode) { |
722 | case IWL_MIMO_PS_STATIC: | 724 | case IWL_MIMO_PS_STATIC: |
723 | case IWL_MIMO_PS_DYNAMIC: | 725 | case IWL_MIMO_PS_DYNAMIC: |
724 | *idle_state = (is_cam) ? 2 : 1; | 726 | idle_cnt = (is_cam) ? 2 : 1; |
725 | break; | 727 | break; |
726 | case IWL_MIMO_PS_NONE: | 728 | case IWL_MIMO_PS_NONE: |
727 | *idle_state = (is_cam) ? *rx_state : 1; | 729 | idle_cnt = (is_cam) ? active_cnt : 1; |
728 | break; | 730 | break; |
731 | case IWL_MIMO_PS_INVALID: | ||
729 | default: | 732 | default: |
730 | *idle_state = 1; | 733 | IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode); |
734 | WARN_ON(1); | ||
735 | idle_cnt = -1; | ||
731 | break; | 736 | break; |
732 | } | 737 | } |
733 | 738 | return idle_cnt; | |
734 | return 0; | ||
735 | } | 739 | } |
736 | 740 | ||
737 | /** | 741 | /** |
@@ -742,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, | |||
742 | */ | 746 | */ |
743 | void iwl_set_rxon_chain(struct iwl_priv *priv) | 747 | void iwl_set_rxon_chain(struct iwl_priv *priv) |
744 | { | 748 | { |
745 | u8 is_single = is_single_rx_stream(priv); | 749 | bool is_single = is_single_rx_stream(priv); |
746 | u8 idle_state, rx_state; | 750 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); |
747 | 751 | u8 idle_rx_cnt, active_rx_cnt; | |
748 | priv->staging_rxon.rx_chain = 0; | 752 | u16 rx_chain; |
749 | rx_state = idle_state = 3; | ||
750 | 753 | ||
751 | /* Tell uCode which antennas are actually connected. | 754 | /* Tell uCode which antennas are actually connected. |
752 | * Before first association, we assume all antennas are connected. | 755 | * Before first association, we assume all antennas are connected. |
753 | * Just after first association, iwl_chain_noise_calibration() | 756 | * Just after first association, iwl_chain_noise_calibration() |
754 | * checks which antennas actually *are* connected. */ | 757 | * checks which antennas actually *are* connected. */ |
755 | priv->staging_rxon.rx_chain |= | 758 | rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; |
756 | cpu_to_le16(priv->hw_params.valid_rx_ant << | ||
757 | RXON_RX_CHAIN_VALID_POS); | ||
758 | 759 | ||
759 | /* How many receivers should we use? */ | 760 | /* How many receivers should we use? */ |
760 | iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state); | 761 | active_rx_cnt = iwl_get_active_rx_chain_count(priv); |
761 | priv->staging_rxon.rx_chain |= | 762 | idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); |
762 | cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS); | 763 | |
763 | priv->staging_rxon.rx_chain |= | 764 | /* correct rx chain count accoridng hw settings */ |
764 | cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); | 765 | if (priv->hw_params.rx_chains_num < active_rx_cnt) |
765 | 766 | active_rx_cnt = priv->hw_params.rx_chains_num; | |
766 | if (!is_single && (rx_state >= 2) && | 767 | |
767 | !test_bit(STATUS_POWER_PMI, &priv->status)) | 768 | if (priv->hw_params.rx_chains_num < idle_rx_cnt) |
769 | idle_rx_cnt = priv->hw_params.rx_chains_num; | ||
770 | |||
771 | rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; | ||
772 | rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; | ||
773 | |||
774 | priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain); | ||
775 | |||
776 | if (!is_single && (active_rx_cnt >= 2) && is_cam) | ||
768 | priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; | 777 | priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; |
769 | else | 778 | else |
770 | priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; | 779 | priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; |
771 | 780 | ||
772 | IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); | 781 | IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n", |
782 | priv->staging_rxon.rx_chain, | ||
783 | active_rx_cnt, idle_rx_cnt); | ||
784 | |||
785 | WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 || | ||
786 | active_rx_cnt < idle_rx_cnt); | ||
773 | } | 787 | } |
774 | EXPORT_SYMBOL(iwl_set_rxon_chain); | 788 | EXPORT_SYMBOL(iwl_set_rxon_chain); |
775 | 789 | ||