aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-09-11 13:38:17 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-07 16:39:33 -0400
commit02bb1bea85e6570b4e64825026382556970b9296 (patch)
tree842b73d6ed4282b315bcbbe627db26080464cd72
parente307ddce394ee7bcec41fb74330ac89eafaea1d9 (diff)
iwlwifi: clarify and clean up chain settings
The chain settings we currently use in iwlwifi are rather confusing -- and we also go by the wrong settings entirely under certain circumstances. To clean it up, create a new variable in the current HT config -- single_chain_sufficient -- that tells us whether we need more than one chain. Calculate that based on the AP and operating mode (no IBSS HT implemented -- so no need for multiple chains, for station mode we use the AP's capabilities). Additionally, since APs always send disabled SM PS mode, keeping track of their sm_ps mode isn't very useful -- doubly not so for our _own_ RX config since that should depend on our, not the AP's, SM PS mode. Finally, document that our configuration of the number of RX chains used is currently wrong when in powersave (by adding a comment). All together this removes the two remaining items in struct iwl_ht_config that were done wrong there. For the future, the number of RX chains and some SM PS handshaking needs to be added to mac80211, which then needs to tell us, and the new variable current_ht_config.single_chain_sufficient should also be calculated by mac80211. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Daniel C Halperin <daniel.c.halperin@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-core.c105
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h3
2 files changed, 51 insertions, 57 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 9d01fde92cc6..2908bff49a3b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -607,8 +607,7 @@ EXPORT_SYMBOL(iwlcore_free_geos);
607static bool is_single_rx_stream(struct iwl_priv *priv) 607static bool is_single_rx_stream(struct iwl_priv *priv)
608{ 608{
609 return !priv->current_ht_config.is_ht || 609 return !priv->current_ht_config.is_ht ||
610 ((priv->current_ht_config.mcs.rx_mask[1] == 0) && 610 priv->current_ht_config.single_chain_sufficient;
611 (priv->current_ht_config.mcs.rx_mask[2] == 0));
612} 611}
613 612
614static u8 iwl_is_channel_extension(struct iwl_priv *priv, 613static u8 iwl_is_channel_extension(struct iwl_priv *priv,
@@ -936,12 +935,8 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
936 if (priv->cfg->ops->hcmd->set_rxon_chain) 935 if (priv->cfg->ops->hcmd->set_rxon_chain)
937 priv->cfg->ops->hcmd->set_rxon_chain(priv); 936 priv->cfg->ops->hcmd->set_rxon_chain(priv);
938 937
939 IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X " 938 IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
940 "rxon flags 0x%X operation mode :0x%X "
941 "extension channel offset 0x%x\n", 939 "extension channel offset 0x%x\n",
942 ht_conf->mcs.rx_mask[0],
943 ht_conf->mcs.rx_mask[1],
944 ht_conf->mcs.rx_mask[2],
945 le32_to_cpu(rxon->flags), ht_conf->ht_protection, 940 le32_to_cpu(rxon->flags), ht_conf->ht_protection,
946 ht_conf->extension_chan_offset); 941 ht_conf->extension_chan_offset);
947 return; 942 return;
@@ -960,12 +955,8 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
960 */ 955 */
961static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) 956static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
962{ 957{
963 bool is_single = is_single_rx_stream(priv);
964 bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
965
966 /* # of Rx chains to use when expecting MIMO. */ 958 /* # of Rx chains to use when expecting MIMO. */
967 if (is_single || (!is_cam && (priv->current_ht_config.sm_ps == 959 if (is_single_rx_stream(priv))
968 WLAN_HT_CAP_SM_PS_STATIC)))
969 return IWL_NUM_RX_CHAINS_SINGLE; 960 return IWL_NUM_RX_CHAINS_SINGLE;
970 else 961 else
971 return IWL_NUM_RX_CHAINS_MULTIPLE; 962 return IWL_NUM_RX_CHAINS_MULTIPLE;
@@ -973,27 +964,17 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
973 964
974static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) 965static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
975{ 966{
976 int idle_cnt;
977 bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); 967 bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
968
978 /* # Rx chains when idling and maybe trying to save power */ 969 /* # Rx chains when idling and maybe trying to save power */
979 switch (priv->current_ht_config.sm_ps) { 970
980 case WLAN_HT_CAP_SM_PS_STATIC: 971 /*
981 case WLAN_HT_CAP_SM_PS_DYNAMIC: 972 * XXX: this is incorrect!!
982 idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : 973 * we always indicate to the AP that
983 IWL_NUM_IDLE_CHAINS_SINGLE; 974 * our SM PS mode is "disabled"
984 break; 975 */
985 case WLAN_HT_CAP_SM_PS_DISABLED: 976
986 idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; 977 return is_cam ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
987 break;
988 case WLAN_HT_CAP_SM_PS_INVALID:
989 default:
990 IWL_ERR(priv, "invalid mimo ps mode %d\n",
991 priv->current_ht_config.sm_ps);
992 WARN_ON(1);
993 idle_cnt = -1;
994 break;
995 }
996 return idle_cnt;
997} 978}
998 979
999/* up to 4 chains */ 980/* up to 4 chains */
@@ -1493,8 +1474,6 @@ int iwl_init_drv(struct iwl_priv *priv)
1493 1474
1494 priv->iw_mode = NL80211_IFTYPE_STATION; 1475 priv->iw_mode = NL80211_IFTYPE_STATION;
1495 1476
1496 priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
1497
1498 /* Choose which receivers/antennas to use */ 1477 /* Choose which receivers/antennas to use */
1499 if (priv->cfg->ops->hcmd->set_rxon_chain) 1478 if (priv->cfg->ops->hcmd->set_rxon_chain)
1500 priv->cfg->ops->hcmd->set_rxon_chain(priv); 1479 priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -2226,10 +2205,9 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
2226EXPORT_SYMBOL(iwl_mac_conf_tx); 2205EXPORT_SYMBOL(iwl_mac_conf_tx);
2227 2206
2228static void iwl_ht_conf(struct iwl_priv *priv, 2207static void iwl_ht_conf(struct iwl_priv *priv,
2229 struct ieee80211_bss_conf *bss_conf) 2208 struct ieee80211_bss_conf *bss_conf)
2230{ 2209{
2231 struct iwl_ht_config *ht_conf = &priv->current_ht_config; 2210 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
2232 struct ieee80211_sta_ht_cap *ht_cap;
2233 struct ieee80211_sta *sta; 2211 struct ieee80211_sta *sta;
2234 2212
2235 IWL_DEBUG_MAC80211(priv, "enter: \n"); 2213 IWL_DEBUG_MAC80211(priv, "enter: \n");
@@ -2237,31 +2215,48 @@ static void iwl_ht_conf(struct iwl_priv *priv,
2237 if (!ht_conf->is_ht) 2215 if (!ht_conf->is_ht)
2238 return; 2216 return;
2239 2217
2240
2241 /*
2242 * It is totally wrong to base global information on something
2243 * that is valid only when associated, alas, this driver works
2244 * that way and I don't know how to fix it.
2245 */
2246
2247 rcu_read_lock();
2248 sta = ieee80211_find_sta(priv->hw, priv->bssid);
2249 if (!sta) {
2250 rcu_read_unlock();
2251 return;
2252 }
2253 ht_cap = &sta->ht_cap;
2254
2255 ht_conf->sm_ps = (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
2256
2257 memcpy(&ht_conf->mcs, &ht_cap->mcs, 16);
2258
2259 ht_conf->ht_protection = 2218 ht_conf->ht_protection =
2260 bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; 2219 bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
2261 ht_conf->non_GF_STA_present = 2220 ht_conf->non_GF_STA_present =
2262 !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 2221 !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
2263 2222
2264 rcu_read_unlock(); 2223 ht_conf->single_chain_sufficient = false;
2224
2225 switch (priv->iw_mode) {
2226 case NL80211_IFTYPE_STATION:
2227 rcu_read_lock();
2228 sta = ieee80211_find_sta(priv->hw, priv->bssid);
2229 if (sta) {
2230 struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
2231 int maxstreams;
2232
2233 maxstreams = (ht_cap->mcs.tx_params &
2234 IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
2235 >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
2236 maxstreams += 1;
2237
2238 if ((ht_cap->mcs.rx_mask[1] == 0) &&
2239 (ht_cap->mcs.rx_mask[2] == 0))
2240 ht_conf->single_chain_sufficient = true;
2241 if (maxstreams <= 1)
2242 ht_conf->single_chain_sufficient = true;
2243 } else {
2244 /*
2245 * If at all, this can only happen through a race
2246 * when the AP disconnects us while we're still
2247 * setting up the connection, in that case mac80211
2248 * will soon tell us about that.
2249 */
2250 ht_conf->single_chain_sufficient = true;
2251 }
2252 rcu_read_unlock();
2253 break;
2254 case NL80211_IFTYPE_ADHOC:
2255 ht_conf->single_chain_sufficient = true;
2256 break;
2257 default:
2258 break;
2259 }
2265 2260
2266 IWL_DEBUG_MAC80211(priv, "leave\n"); 2261 IWL_DEBUG_MAC80211(priv, "leave\n");
2267} 2262}
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index e161f8d1766e..0c80692f934b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -506,8 +506,7 @@ struct iwl_ht_config {
506 /* self configuration data */ 506 /* self configuration data */
507 bool is_ht; 507 bool is_ht;
508 bool is_40mhz; 508 bool is_40mhz;
509 u8 sm_ps; 509 bool single_chain_sufficient;
510 struct ieee80211_mcs_info mcs;
511 /* BSS related data */ 510 /* BSS related data */
512 u8 extension_chan_offset; 511 u8 extension_chan_offset;
513 u8 ht_protection; 512 u8 ht_protection;