diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-09-22 12:01:58 -0400 |
---|---|---|
committer | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2010-10-07 18:49:34 -0400 |
commit | 5de33068a2f841536ca8632534e3e193d5b2607f (patch) | |
tree | 7e94cf905b7eacfbab73a6774d9930f6546954f8 /drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |
parent | 8289e07b8a4b588e167bc84f93419458fd6efa3e (diff) |
iwlwifi: move chain settings to agn
The core module doesn't need to carry around
the code for chain settings that is used for
HT drivers (agn) only.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-lib.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3fa2c5c3706a..0b45bced9c0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -2065,3 +2065,143 @@ void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv) | |||
2065 | { | 2065 | { |
2066 | cancel_work_sync(&priv->bt_traffic_change_work); | 2066 | cancel_work_sync(&priv->bt_traffic_change_work); |
2067 | } | 2067 | } |
2068 | |||
2069 | static bool is_single_rx_stream(struct iwl_priv *priv) | ||
2070 | { | ||
2071 | return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC || | ||
2072 | priv->current_ht_config.single_chain_sufficient; | ||
2073 | } | ||
2074 | |||
2075 | #define IWL_NUM_RX_CHAINS_MULTIPLE 3 | ||
2076 | #define IWL_NUM_RX_CHAINS_SINGLE 2 | ||
2077 | #define IWL_NUM_IDLE_CHAINS_DUAL 2 | ||
2078 | #define IWL_NUM_IDLE_CHAINS_SINGLE 1 | ||
2079 | |||
2080 | /* | ||
2081 | * Determine how many receiver/antenna chains to use. | ||
2082 | * | ||
2083 | * More provides better reception via diversity. Fewer saves power | ||
2084 | * at the expense of throughput, but only when not in powersave to | ||
2085 | * start with. | ||
2086 | * | ||
2087 | * MIMO (dual stream) requires at least 2, but works better with 3. | ||
2088 | * This does not determine *which* chains to use, just how many. | ||
2089 | */ | ||
2090 | static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) | ||
2091 | { | ||
2092 | if (priv->cfg->bt_params && | ||
2093 | priv->cfg->bt_params->advanced_bt_coexist && | ||
2094 | (priv->bt_full_concurrent || | ||
2095 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { | ||
2096 | /* | ||
2097 | * only use chain 'A' in bt high traffic load or | ||
2098 | * full concurrency mode | ||
2099 | */ | ||
2100 | return IWL_NUM_RX_CHAINS_SINGLE; | ||
2101 | } | ||
2102 | /* # of Rx chains to use when expecting MIMO. */ | ||
2103 | if (is_single_rx_stream(priv)) | ||
2104 | return IWL_NUM_RX_CHAINS_SINGLE; | ||
2105 | else | ||
2106 | return IWL_NUM_RX_CHAINS_MULTIPLE; | ||
2107 | } | ||
2108 | |||
2109 | /* | ||
2110 | * When we are in power saving mode, unless device support spatial | ||
2111 | * multiplexing power save, use the active count for rx chain count. | ||
2112 | */ | ||
2113 | static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) | ||
2114 | { | ||
2115 | /* # Rx chains when idling, depending on SMPS mode */ | ||
2116 | switch (priv->current_ht_config.smps) { | ||
2117 | case IEEE80211_SMPS_STATIC: | ||
2118 | case IEEE80211_SMPS_DYNAMIC: | ||
2119 | return IWL_NUM_IDLE_CHAINS_SINGLE; | ||
2120 | case IEEE80211_SMPS_OFF: | ||
2121 | return active_cnt; | ||
2122 | default: | ||
2123 | WARN(1, "invalid SMPS mode %d", | ||
2124 | priv->current_ht_config.smps); | ||
2125 | return active_cnt; | ||
2126 | } | ||
2127 | } | ||
2128 | |||
2129 | /* up to 4 chains */ | ||
2130 | static u8 iwl_count_chain_bitmap(u32 chain_bitmap) | ||
2131 | { | ||
2132 | u8 res; | ||
2133 | res = (chain_bitmap & BIT(0)) >> 0; | ||
2134 | res += (chain_bitmap & BIT(1)) >> 1; | ||
2135 | res += (chain_bitmap & BIT(2)) >> 2; | ||
2136 | res += (chain_bitmap & BIT(3)) >> 3; | ||
2137 | return res; | ||
2138 | } | ||
2139 | |||
2140 | /** | ||
2141 | * iwlagn_set_rxon_chain - Set up Rx chain usage in "staging" RXON image | ||
2142 | * | ||
2143 | * Selects how many and which Rx receivers/antennas/chains to use. | ||
2144 | * This should not be used for scan command ... it puts data in wrong place. | ||
2145 | */ | ||
2146 | void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | ||
2147 | { | ||
2148 | bool is_single = is_single_rx_stream(priv); | ||
2149 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); | ||
2150 | u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt; | ||
2151 | u32 active_chains; | ||
2152 | u16 rx_chain; | ||
2153 | |||
2154 | /* Tell uCode which antennas are actually connected. | ||
2155 | * Before first association, we assume all antennas are connected. | ||
2156 | * Just after first association, iwl_chain_noise_calibration() | ||
2157 | * checks which antennas actually *are* connected. */ | ||
2158 | if (priv->chain_noise_data.active_chains) | ||
2159 | active_chains = priv->chain_noise_data.active_chains; | ||
2160 | else | ||
2161 | active_chains = priv->hw_params.valid_rx_ant; | ||
2162 | |||
2163 | if (priv->cfg->bt_params && | ||
2164 | priv->cfg->bt_params->advanced_bt_coexist && | ||
2165 | (priv->bt_full_concurrent || | ||
2166 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { | ||
2167 | /* | ||
2168 | * only use chain 'A' in bt high traffic load or | ||
2169 | * full concurrency mode | ||
2170 | */ | ||
2171 | active_chains = first_antenna(active_chains); | ||
2172 | } | ||
2173 | |||
2174 | rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS; | ||
2175 | |||
2176 | /* How many receivers should we use? */ | ||
2177 | active_rx_cnt = iwl_get_active_rx_chain_count(priv); | ||
2178 | idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); | ||
2179 | |||
2180 | |||
2181 | /* correct rx chain count according hw settings | ||
2182 | * and chain noise calibration | ||
2183 | */ | ||
2184 | valid_rx_cnt = iwl_count_chain_bitmap(active_chains); | ||
2185 | if (valid_rx_cnt < active_rx_cnt) | ||
2186 | active_rx_cnt = valid_rx_cnt; | ||
2187 | |||
2188 | if (valid_rx_cnt < idle_rx_cnt) | ||
2189 | idle_rx_cnt = valid_rx_cnt; | ||
2190 | |||
2191 | rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; | ||
2192 | rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; | ||
2193 | |||
2194 | ctx->staging.rx_chain = cpu_to_le16(rx_chain); | ||
2195 | |||
2196 | if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam) | ||
2197 | ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; | ||
2198 | else | ||
2199 | ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; | ||
2200 | |||
2201 | IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n", | ||
2202 | ctx->staging.rx_chain, | ||
2203 | active_rx_cnt, idle_rx_cnt); | ||
2204 | |||
2205 | WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 || | ||
2206 | active_rx_cnt < idle_rx_cnt); | ||
2207 | } | ||