aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-11-10 21:25:48 -0500
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2010-11-16 10:46:35 -0500
commit2b5f7a679c2ae34407f6cc9387e77b563578bfdc (patch)
treebbd9eee3ec9925d132b4dbf044871b23997c8279 /drivers
parent893654de3ff41a4f5037397d06a3f853bbbb3484 (diff)
iwlagn: reprogram AP STA after assoc
Instead of unconditionally sending unassoc RXON, before any assoc RXON, re-send only the AP STA entry which is required after the BSSID has been programmed into the device to set up internal filters in the microcode properly. This fixes some issues that we correlated with sending a lot of RXON commands to the device. 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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c51
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h1
3 files changed, 69 insertions, 22 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index fbaa8d293654..9db3924ea1d6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -97,6 +97,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
97 /* cast away the const for active_rxon in this function */ 97 /* cast away the const for active_rxon in this function */
98 struct iwl_rxon_cmd *active = (void *)&ctx->active; 98 struct iwl_rxon_cmd *active = (void *)&ctx->active;
99 bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); 99 bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
100 bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
100 int ret; 101 int ret;
101 102
102 lockdep_assert_held(&priv->mutex); 103 lockdep_assert_held(&priv->mutex);
@@ -176,25 +177,27 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
176 * AP station must be done after the BSSID is set to correctly 177 * AP station must be done after the BSSID is set to correctly
177 * set up filters in the device. 178 * set up filters in the device.
178 */ 179 */
179 if (ctx->ctxid == IWL_RXON_CTX_BSS) 180 if ((old_assoc && new_assoc) || !new_assoc) {
180 ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); 181 if (ctx->ctxid == IWL_RXON_CTX_BSS)
181 else 182 ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
182 ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); 183 else
183 if (ret) 184 ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
184 return ret; 185 if (ret)
186 return ret;
185 187
186 memcpy(active, &ctx->staging, sizeof(*active)); 188 memcpy(active, &ctx->staging, sizeof(*active));
187 189
188 /* 190 /*
189 * Un-assoc RXON clears the station table and WEP 191 * Un-assoc RXON clears the station table and WEP
190 * keys, so we have to restore those afterwards. 192 * keys, so we have to restore those afterwards.
191 */ 193 */
192 iwl_clear_ucode_stations(priv, ctx); 194 iwl_clear_ucode_stations(priv, ctx);
193 iwl_restore_stations(priv, ctx); 195 iwl_restore_stations(priv, ctx);
194 ret = iwl_restore_default_wep_keys(priv, ctx); 196 ret = iwl_restore_default_wep_keys(priv, ctx);
195 if (ret) { 197 if (ret) {
196 IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); 198 IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
197 return ret; 199 return ret;
200 }
198 } 201 }
199 202
200 /* RXON timing must be before associated RXON */ 203 /* RXON timing must be before associated RXON */
@@ -235,6 +238,8 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
235 } 238 }
236 memcpy(active, &ctx->staging, sizeof(*active)); 239 memcpy(active, &ctx->staging, sizeof(*active));
237 240
241 iwl_reprogram_ap_sta(priv, ctx);
242
238 /* IBSS beacon needs to be sent after setting assoc */ 243 /* IBSS beacon needs to be sent after setting assoc */
239 if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) 244 if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
240 if (iwlagn_update_beacon(priv, ctx->vif)) 245 if (iwlagn_update_beacon(priv, ctx->vif))
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 7c7f7dcb1b1e..0a67b2fa52a1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -400,7 +400,8 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
400} 400}
401 401
402static int iwl_send_remove_station(struct iwl_priv *priv, 402static int iwl_send_remove_station(struct iwl_priv *priv,
403 const u8 *addr, int sta_id) 403 const u8 *addr, int sta_id,
404 bool temporary)
404{ 405{
405 struct iwl_rx_packet *pkt; 406 struct iwl_rx_packet *pkt;
406 int ret; 407 int ret;
@@ -436,9 +437,11 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
436 if (!ret) { 437 if (!ret) {
437 switch (pkt->u.rem_sta.status) { 438 switch (pkt->u.rem_sta.status) {
438 case REM_STA_SUCCESS_MSK: 439 case REM_STA_SUCCESS_MSK:
439 spin_lock_irqsave(&priv->sta_lock, flags_spin); 440 if (!temporary) {
440 iwl_sta_ucode_deactivate(priv, sta_id); 441 spin_lock_irqsave(&priv->sta_lock, flags_spin);
441 spin_unlock_irqrestore(&priv->sta_lock, flags_spin); 442 iwl_sta_ucode_deactivate(priv, sta_id);
443 spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
444 }
442 IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); 445 IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
443 break; 446 break;
444 default: 447 default:
@@ -505,7 +508,7 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
505 508
506 spin_unlock_irqrestore(&priv->sta_lock, flags); 509 spin_unlock_irqrestore(&priv->sta_lock, flags);
507 510
508 return iwl_send_remove_station(priv, addr, sta_id); 511 return iwl_send_remove_station(priv, addr, sta_id, false);
509out_err: 512out_err:
510 spin_unlock_irqrestore(&priv->sta_lock, flags); 513 spin_unlock_irqrestore(&priv->sta_lock, flags);
511 return -EINVAL; 514 return -EINVAL;
@@ -624,6 +627,44 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
624} 627}
625EXPORT_SYMBOL(iwl_restore_stations); 628EXPORT_SYMBOL(iwl_restore_stations);
626 629
630void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
631{
632 unsigned long flags;
633 int sta_id = ctx->ap_sta_id;
634 int ret;
635 struct iwl_addsta_cmd sta_cmd;
636 struct iwl_link_quality_cmd lq;
637 bool active;
638
639 spin_lock_irqsave(&priv->sta_lock, flags);
640 if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
641 spin_unlock_irqrestore(&priv->sta_lock, flags);
642 return;
643 }
644
645 memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
646 sta_cmd.mode = 0;
647 memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
648
649 active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE;
650 spin_unlock_irqrestore(&priv->sta_lock, flags);
651
652 if (active) {
653 ret = iwl_send_remove_station(
654 priv, priv->stations[sta_id].sta.sta.addr,
655 sta_id, true);
656 if (ret)
657 IWL_ERR(priv, "failed to remove STA %pM (%d)\n",
658 priv->stations[sta_id].sta.sta.addr, ret);
659 }
660 ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
661 if (ret)
662 IWL_ERR(priv, "failed to re-add STA %pM (%d)\n",
663 priv->stations[sta_id].sta.sta.addr, ret);
664 iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
665}
666EXPORT_SYMBOL(iwl_reprogram_ap_sta);
667
627int iwl_get_free_ucode_key_index(struct iwl_priv *priv) 668int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
628{ 669{
629 int i; 670 int i;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 06475872eee4..206f1e1a0caf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -63,6 +63,7 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
63 63
64int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, 64int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
65 struct iwl_link_quality_cmd *lq, u8 flags, bool init); 65 struct iwl_link_quality_cmd *lq, u8 flags, bool init);
66void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
66 67
67/** 68/**
68 * iwl_clear_driver_stations - clear knowledge of all stations from driver 69 * iwl_clear_driver_stations - clear knowledge of all stations from driver