aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-09-22 12:01:58 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2010-10-07 18:49:34 -0400
commit5de33068a2f841536ca8632534e3e193d5b2607f (patch)
tree7e94cf905b7eacfbab73a6774d9930f6546954f8 /drivers/net/wireless/iwlwifi/iwl-agn-lib.c
parent8289e07b8a4b588e167bc84f93419458fd6efa3e (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.c140
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
2069static 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 */
2090static 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 */
2113static 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 */
2130static 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 */
2146void 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}