diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-11-10 21:25:48 -0500 |
---|---|---|
committer | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2010-11-16 10:46:35 -0500 |
commit | 2b5f7a679c2ae34407f6cc9387e77b563578bfdc (patch) | |
tree | bbd9eee3ec9925d132b4dbf044871b23997c8279 /drivers/net/wireless | |
parent | 893654de3ff41a4f5037397d06a3f853bbbb3484 (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/net/wireless')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 39 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 51 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.h | 1 |
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 | ||
402 | static int iwl_send_remove_station(struct iwl_priv *priv, | 402 | static 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); |
509 | out_err: | 512 | out_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 | } |
625 | EXPORT_SYMBOL(iwl_restore_stations); | 628 | EXPORT_SYMBOL(iwl_restore_stations); |
626 | 629 | ||
630 | void 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 | } | ||
666 | EXPORT_SYMBOL(iwl_reprogram_ap_sta); | ||
667 | |||
627 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) | 668 | int 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 | ||
64 | int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | 64 | int 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); |
66 | void 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 |