aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-03-05 14:24:47 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-03-06 15:16:15 -0500
commitab0bd5b32a9c7ea2e7cc69d56c82a96be340c269 (patch)
treeffc06b7cd0ea59e6d2ef10091de15ab43cbb6389 /drivers/net
parent61f0439277abb4f65d99b362b62cbabbde7032a0 (diff)
iwlwifi: fix station HT parameters
My patch "iwlwifi: simplify auth/assoc flow" caused a serious throughput degradation due to me forgetting that there are HT settings in the station table. To restore throughput, set these parameters correctly when the sta moves to assoc state. This patch should probably be merged with the auth/assoc redesign patch for upstream. In that case, this paragraph should be added to the commit log as the third paragraph (before talking about RXON): However, as we only get the station HT data when the station moves into assoc state, we also need to program this into the device (and copy it into our database) then. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-sta.c81
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-mac80211.c18
3 files changed, 75 insertions, 26 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
index 736f8dc404df..ca080265a829 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
@@ -169,34 +169,38 @@ int iwl_send_add_sta(struct iwl_priv *priv,
169 return cmd.handler_status; 169 return cmd.handler_status;
170} 170}
171 171
172static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, 172static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
173 struct ieee80211_sta *sta, 173 struct ieee80211_sta *sta,
174 struct iwl_rxon_context *ctx) 174 struct iwl_rxon_context *ctx,
175 __le32 *flags, __le32 *mask)
175{ 176{
176 struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; 177 struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
177 __le32 sta_flags;
178 u8 mimo_ps_mode; 178 u8 mimo_ps_mode;
179 179
180 *mask = STA_FLG_RTS_MIMO_PROT_MSK |
181 STA_FLG_MIMO_DIS_MSK |
182 STA_FLG_HT40_EN_MSK |
183 STA_FLG_MAX_AGG_SIZE_MSK |
184 STA_FLG_AGG_MPDU_DENSITY_MSK;
185 *flags = 0;
186
180 if (!sta || !sta_ht_inf->ht_supported) 187 if (!sta || !sta_ht_inf->ht_supported)
181 goto done; 188 return;
182 189
183 mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; 190 mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
184 IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save mode: %s\n", 191
192 IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
185 (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? 193 (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
186 "static" : 194 "static" :
187 (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? 195 (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
188 "dynamic" : "disabled"); 196 "dynamic" : "disabled");
189 197
190 sta_flags = priv->stations[index].sta.station_flags;
191
192 sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
193
194 switch (mimo_ps_mode) { 198 switch (mimo_ps_mode) {
195 case WLAN_HT_CAP_SM_PS_STATIC: 199 case WLAN_HT_CAP_SM_PS_STATIC:
196 sta_flags |= STA_FLG_MIMO_DIS_MSK; 200 *flags |= STA_FLG_MIMO_DIS_MSK;
197 break; 201 break;
198 case WLAN_HT_CAP_SM_PS_DYNAMIC: 202 case WLAN_HT_CAP_SM_PS_DYNAMIC:
199 sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; 203 *flags |= STA_FLG_RTS_MIMO_PROT_MSK;
200 break; 204 break;
201 case WLAN_HT_CAP_SM_PS_DISABLED: 205 case WLAN_HT_CAP_SM_PS_DISABLED:
202 break; 206 break;
@@ -205,20 +209,53 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
205 break; 209 break;
206 } 210 }
207 211
208 sta_flags |= cpu_to_le32( 212 *flags |= cpu_to_le32(
209 (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); 213 (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
210 214
211 sta_flags |= cpu_to_le32( 215 *flags |= cpu_to_le32(
212 (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); 216 (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
213 217
214 if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) 218 if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
215 sta_flags |= STA_FLG_HT40_EN_MSK; 219 *flags |= STA_FLG_HT40_EN_MSK;
216 else 220}
217 sta_flags &= ~STA_FLG_HT40_EN_MSK; 221
222int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
223 struct ieee80211_sta *sta)
224{
225 u8 sta_id = iwl_sta_id(sta);
226 __le32 flags, mask;
227 struct iwl_addsta_cmd cmd;
228
229 if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
230 return -EINVAL;
218 231
219 priv->stations[index].sta.station_flags = sta_flags; 232 iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
220 done: 233
221 return; 234 spin_lock_bh(&priv->sta_lock);
235 priv->stations[sta_id].sta.station_flags &= ~mask;
236 priv->stations[sta_id].sta.station_flags |= flags;
237 spin_unlock_bh(&priv->sta_lock);
238
239 memset(&cmd, 0, sizeof(cmd));
240 cmd.mode = STA_CONTROL_MODIFY_MSK;
241 cmd.station_flags_msk = mask;
242 cmd.station_flags = flags;
243 cmd.sta.sta_id = sta_id;
244
245 return iwl_send_add_sta(priv, &cmd, CMD_SYNC);
246}
247
248static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
249 struct ieee80211_sta *sta,
250 struct iwl_rxon_context *ctx)
251{
252 __le32 flags, mask;
253
254 iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
255
256 lockdep_assert_held(&priv->sta_lock);
257 priv->stations[index].sta.station_flags &= ~mask;
258 priv->stations[index].sta.station_flags |= flags;
222} 259}
223 260
224/** 261/**
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index a9c018a7b8ba..70100f9a2e5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -229,6 +229,8 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
229 struct iwl_link_quality_cmd *lq, u8 flags, bool init); 229 struct iwl_link_quality_cmd *lq, u8 flags, bool init);
230int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, 230int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
231 struct iwl_device_cmd *cmd); 231 struct iwl_device_cmd *cmd);
232int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
233 struct ieee80211_sta *sta);
232 234
233 235
234static inline int iwl_sta_id(struct ieee80211_sta *sta) 236static inline int iwl_sta_id(struct ieee80211_sta *sta)
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
index 8160f615f71a..7f937151a8af 100644
--- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c
+++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
@@ -740,8 +740,9 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
740 enum ieee80211_sta_state new_state) 740 enum ieee80211_sta_state new_state)
741{ 741{
742 struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); 742 struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
743 struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
743 enum { 744 enum {
744 NONE, ADD, REMOVE, RATE_INIT, ADD_RATE_INIT, 745 NONE, ADD, REMOVE, HT_RATE_INIT, ADD_RATE_INIT,
745 } op = NONE; 746 } op = NONE;
746 int ret; 747 int ret;
747 748
@@ -758,7 +759,7 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
758 op = REMOVE; 759 op = REMOVE;
759 else if (old_state == IEEE80211_STA_AUTH && 760 else if (old_state == IEEE80211_STA_AUTH &&
760 new_state == IEEE80211_STA_ASSOC) 761 new_state == IEEE80211_STA_ASSOC)
761 op = RATE_INIT; 762 op = HT_RATE_INIT;
762 } else { 763 } else {
763 if (old_state == IEEE80211_STA_AUTH && 764 if (old_state == IEEE80211_STA_AUTH &&
764 new_state == IEEE80211_STA_ASSOC) 765 new_state == IEEE80211_STA_ASSOC)
@@ -779,8 +780,6 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
779 ret = iwlagn_mac_sta_add(hw, vif, sta); 780 ret = iwlagn_mac_sta_add(hw, vif, sta);
780 if (ret) 781 if (ret)
781 break; 782 break;
782 /* fall through */
783 case RATE_INIT:
784 /* Initialize rate scaling */ 783 /* Initialize rate scaling */
785 IWL_DEBUG_INFO(priv, 784 IWL_DEBUG_INFO(priv,
786 "Initializing rate scaling for station %pM\n", 785 "Initializing rate scaling for station %pM\n",
@@ -788,6 +787,17 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
788 iwl_rs_rate_init(priv, sta, iwl_sta_id(sta)); 787 iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
789 ret = 0; 788 ret = 0;
790 break; 789 break;
790 case HT_RATE_INIT:
791 /* Initialize rate scaling */
792 ret = iwl_sta_update_ht(priv, vif_priv->ctx, sta);
793 if (ret)
794 break;
795 IWL_DEBUG_INFO(priv,
796 "Initializing rate scaling for station %pM\n",
797 sta->addr);
798 iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
799 ret = 0;
800 break;
791 default: 801 default:
792 ret = 0; 802 ret = 0;
793 break; 803 break;