aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-03-08 03:37:53 -0500
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2012-04-23 17:20:13 -0400
commit9543c5f3d6f8a1eaf770ab097d3f1c13f96ca544 (patch)
treecede8573315f626de2380c48a43955f2cee6d56f
parent647ad135e3cbad19a7a963922750a4a5cd2e9e8f (diff)
iwlwifi: properly set basic rates
This fixes a long-standing bug: iwlwifi always assumes that the CCK ACK rates are 1 and 2 MBps and the OFDM ACK rates are 6, 12 and 24 MBps. Fix this problem by using the basic rates the AP (or in AP case hostapd) told us to use and add the necessary mandatory rates to the mix. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h26
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c119
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-mac80211.c1
4 files changed, 94 insertions, 53 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 203b1c13c491..351717a77ad9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -174,32 +174,6 @@ enum {
174 IWL_RATE_11M_IEEE = 22, 174 IWL_RATE_11M_IEEE = 22,
175}; 175};
176 176
177#define IWL_CCK_BASIC_RATES_MASK \
178 (IWL_RATE_1M_MASK | \
179 IWL_RATE_2M_MASK)
180
181#define IWL_CCK_RATES_MASK \
182 (IWL_CCK_BASIC_RATES_MASK | \
183 IWL_RATE_5M_MASK | \
184 IWL_RATE_11M_MASK)
185
186#define IWL_OFDM_BASIC_RATES_MASK \
187 (IWL_RATE_6M_MASK | \
188 IWL_RATE_12M_MASK | \
189 IWL_RATE_24M_MASK)
190
191#define IWL_OFDM_RATES_MASK \
192 (IWL_OFDM_BASIC_RATES_MASK | \
193 IWL_RATE_9M_MASK | \
194 IWL_RATE_18M_MASK | \
195 IWL_RATE_36M_MASK | \
196 IWL_RATE_48M_MASK | \
197 IWL_RATE_54M_MASK)
198
199#define IWL_BASIC_RATES_MASK \
200 (IWL_OFDM_BASIC_RATES_MASK | \
201 IWL_CCK_BASIC_RATES_MASK)
202
203#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) 177#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
204 178
205#define IWL_INVALID_VALUE -1 179#define IWL_INVALID_VALUE -1
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index d9501664dd1d..8f41543d8306 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -87,11 +87,6 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
87 87
88 iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif); 88 iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
89 89
90 ctx->staging.ofdm_basic_rates =
91 (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
92 ctx->staging.cck_basic_rates =
93 (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
94
95 /* clear both MIX and PURE40 mode flag */ 90 /* clear both MIX and PURE40 mode flag */
96 ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED | 91 ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
97 RXON_FLG_CHANNEL_MODE_PURE_40); 92 RXON_FLG_CHANNEL_MODE_PURE_40);
@@ -771,19 +766,6 @@ void iwl_set_flags_for_band(struct iwl_priv *priv,
771 } 766 }
772} 767}
773 768
774void iwl_set_rate(struct iwl_priv *priv)
775{
776 struct iwl_rxon_context *ctx;
777
778 for_each_context(priv, ctx) {
779 ctx->staging.cck_basic_rates =
780 (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
781
782 ctx->staging.ofdm_basic_rates =
783 (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
784 }
785}
786
787static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, 769static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv,
788 struct iwl_rxon_context *ctx, int hw_decrypt) 770 struct iwl_rxon_context *ctx, int hw_decrypt)
789{ 771{
@@ -959,6 +941,97 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
959} 941}
960#endif 942#endif
961 943
944static void iwl_calc_basic_rates(struct iwl_priv *priv,
945 struct iwl_rxon_context *ctx)
946{
947 int lowest_present_ofdm = 100;
948 int lowest_present_cck = 100;
949 u8 cck = 0;
950 u8 ofdm = 0;
951
952 if (ctx->vif) {
953 struct ieee80211_supported_band *sband;
954 unsigned long basic = ctx->vif->bss_conf.basic_rates;
955 int i;
956
957 sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
958
959 for_each_set_bit(i, &basic, BITS_PER_LONG) {
960 int hw = sband->bitrates[i].hw_value;
961 if (hw >= IWL_FIRST_OFDM_RATE) {
962 ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE);
963 if (lowest_present_ofdm > hw)
964 lowest_present_ofdm = hw;
965 } else {
966 BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
967
968 cck |= BIT(hw);
969 if (lowest_present_cck > hw)
970 lowest_present_cck = hw;
971 }
972 }
973 }
974
975 /*
976 * Now we've got the basic rates as bitmaps in the ofdm and cck
977 * variables. This isn't sufficient though, as there might not
978 * be all the right rates in the bitmap. E.g. if the only basic
979 * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
980 * and 6 Mbps because the 802.11-2007 standard says in 9.6:
981 *
982 * [...] a STA responding to a received frame shall transmit
983 * its Control Response frame [...] at the highest rate in the
984 * BSSBasicRateSet parameter that is less than or equal to the
985 * rate of the immediately previous frame in the frame exchange
986 * sequence ([...]) and that is of the same modulation class
987 * ([...]) as the received frame. If no rate contained in the
988 * BSSBasicRateSet parameter meets these conditions, then the
989 * control frame sent in response to a received frame shall be
990 * transmitted at the highest mandatory rate of the PHY that is
991 * less than or equal to the rate of the received frame, and
992 * that is of the same modulation class as the received frame.
993 *
994 * As a consequence, we need to add all mandatory rates that are
995 * lower than all of the basic rates to these bitmaps.
996 */
997
998 if (IWL_RATE_24M_INDEX < lowest_present_ofdm)
999 ofdm |= IWL_RATE_24M_MASK >> IWL_FIRST_OFDM_RATE;
1000 if (IWL_RATE_12M_INDEX < lowest_present_ofdm)
1001 ofdm |= IWL_RATE_12M_MASK >> IWL_FIRST_OFDM_RATE;
1002 /* 6M already there or needed so always add */
1003 ofdm |= IWL_RATE_6M_MASK >> IWL_FIRST_OFDM_RATE;
1004
1005 /*
1006 * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
1007 * Note, however:
1008 * - if no CCK rates are basic, it must be ERP since there must
1009 * be some basic rates at all, so they're OFDM => ERP PHY
1010 * (or we're in 5 GHz, and the cck bitmap will never be used)
1011 * - if 11M is a basic rate, it must be ERP as well, so add 5.5M
1012 * - if 5.5M is basic, 1M and 2M are mandatory
1013 * - if 2M is basic, 1M is mandatory
1014 * - if 1M is basic, that's the only valid ACK rate.
1015 * As a consequence, it's not as complicated as it sounds, just add
1016 * any lower rates to the ACK rate bitmap.
1017 */
1018 if (IWL_RATE_11M_INDEX < lowest_present_ofdm)
1019 ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE;
1020 if (IWL_RATE_5M_INDEX < lowest_present_ofdm)
1021 ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE;
1022 if (IWL_RATE_2M_INDEX < lowest_present_ofdm)
1023 ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE;
1024 /* 1M already there or needed so always add */
1025 cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE;
1026
1027 IWL_DEBUG_RATE(priv, "Set basic rates cck:0x%.2x ofdm:0x%.2x\n",
1028 cck, ofdm);
1029
1030 /* "basic_rates" is a misnomer here -- should be called ACK rates */
1031 ctx->staging.cck_basic_rates = cck;
1032 ctx->staging.ofdm_basic_rates = ofdm;
1033}
1034
962/** 1035/**
963 * iwlagn_commit_rxon - commit staging_rxon to hardware 1036 * iwlagn_commit_rxon - commit staging_rxon to hardware
964 * 1037 *
@@ -998,6 +1071,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
998 /* always get timestamp with Rx frame */ 1071 /* always get timestamp with Rx frame */
999 ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; 1072 ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
1000 1073
1074 /* recalculate basic rates */
1075 iwl_calc_basic_rates(priv, ctx);
1076
1001 /* 1077 /*
1002 * force CTS-to-self frames protection if RTS-CTS is not preferred 1078 * force CTS-to-self frames protection if RTS-CTS is not preferred
1003 * one aggregation protection method 1079 * one aggregation protection method
@@ -1186,13 +1262,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
1186 } 1262 }
1187 1263
1188 iwl_update_bcast_stations(priv); 1264 iwl_update_bcast_stations(priv);
1189
1190 /*
1191 * The list of supported rates and rate mask can be different
1192 * for each band; since the band may have changed, reset
1193 * the rate mask to what mac80211 lists.
1194 */
1195 iwl_set_rate(priv);
1196 } 1265 }
1197 1266
1198 if (changed & (IEEE80211_CONF_CHANGE_PS | 1267 if (changed & (IEEE80211_CONF_CHANGE_PS |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 3d6f3e2ded65..bd467c0c519f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -154,7 +154,6 @@ void iwl_set_flags_for_band(struct iwl_priv *priv,
154 struct iwl_rxon_context *ctx, 154 struct iwl_rxon_context *ctx,
155 enum ieee80211_band band, 155 enum ieee80211_band band,
156 struct ieee80211_vif *vif); 156 struct ieee80211_vif *vif);
157void iwl_set_rate(struct iwl_priv *priv);
158 157
159/* uCode */ 158/* uCode */
160int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); 159int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
index b309ede4f072..8adbbf2d343b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c
+++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
@@ -894,7 +894,6 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
894 iwl_set_rxon_ht(priv, ht_conf); 894 iwl_set_rxon_ht(priv, ht_conf);
895 iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif); 895 iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
896 896
897 iwl_set_rate(priv);
898 /* 897 /*
899 * at this point, staging_rxon has the 898 * at this point, staging_rxon has the
900 * configuration for channel switch 899 * configuration for channel switch