diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-04-29 03:53:29 -0400 |
---|---|---|
committer | Reinette Chatre <reinette.chatre@intel.com> | 2010-05-10 18:09:02 -0400 |
commit | 2c810ccdbac434ae38f4ec5331d3f047dc90f98a (patch) | |
tree | e1bd92e76baf88d5ac3f4af37e709f8c746fd623 /drivers/net/wireless/iwlwifi/iwl-sta.c | |
parent | a6a0345c837346d1b74f4907d4747e6c1053a99f (diff) |
iwlwifi: rework broadcast station management
Currently, the broadcast station is managed along
with the interface type, rather than always being
present. That leads to a bug with injection -- it
is currently not possible to inject frames when
the only virtual interface is a monitor, because
in that the required broadcast station is missing.
Additionally, allocating and deallocating the
broadcast station's LQ all the time is wasteful,
and the code to support this is fairly complex.
So this changes completely the way we manage the
broadcast station. Rather than manage it along
with any interface, we now allocate it when we
bring the device up, and remove it again when we
bring the device down. When we bring the device
up, we don't immediately program the broadcast
station into it, instead we just mark it active
and rely on the next restore cycle to upload it
to the device. This works because an unassociated
RXON is always required at least once to set up
device parameters, which implies a reprogramming
of stations into the device.
As we now manage all stations properly, there no
longer is a need for forcing a clearing of them
via iwl_clear_ucode_stations(), which can become
a lot simpler.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 137 |
1 files changed, 67 insertions, 70 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 5bf82b9b523b..7e51647cf02d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -656,63 +656,27 @@ out: | |||
656 | EXPORT_SYMBOL_GPL(iwl_remove_station); | 656 | EXPORT_SYMBOL_GPL(iwl_remove_station); |
657 | 657 | ||
658 | /** | 658 | /** |
659 | * iwl_clear_ucode_stations() - clear entire station table driver and/or ucode | 659 | * iwl_clear_ucode_stations - clear ucode station table bits |
660 | * @priv: | 660 | * |
661 | * @force: If set then the uCode station table needs to be cleared here. If | 661 | * This function clears all the bits in the driver indicating |
662 | * not set then the uCode station table has already been cleared, | 662 | * which stations are active in the ucode. Call when something |
663 | * for example after sending it a RXON command without ASSOC bit | 663 | * other than explicit station management would cause this in |
664 | * set, and we just need to change driver state here. | 664 | * the ucode, e.g. unassociated RXON. |
665 | */ | 665 | */ |
666 | void iwl_clear_ucode_stations(struct iwl_priv *priv, bool force) | 666 | void iwl_clear_ucode_stations(struct iwl_priv *priv) |
667 | { | 667 | { |
668 | int i; | 668 | int i; |
669 | unsigned long flags_spin; | 669 | unsigned long flags_spin; |
670 | bool cleared = false; | 670 | bool cleared = false; |
671 | 671 | ||
672 | IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver%s\n", | 672 | IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n"); |
673 | force ? " and ucode" : ""); | ||
674 | |||
675 | if (force) { | ||
676 | if (!iwl_is_ready(priv)) { | ||
677 | /* | ||
678 | * If device is not ready at this point the station | ||
679 | * table is likely already empty (uCode not ready | ||
680 | * to receive station requests) or will soon be | ||
681 | * due to interface going down. | ||
682 | */ | ||
683 | IWL_DEBUG_INFO(priv, "Unable to remove stations from device - device not ready\n"); | ||
684 | } else { | ||
685 | iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL); | ||
686 | } | ||
687 | } | ||
688 | 673 | ||
689 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | 674 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
690 | if (force) { | 675 | for (i = 0; i < priv->hw_params.max_stations; i++) { |
691 | IWL_DEBUG_INFO(priv, "Clearing all station information in driver\n"); | 676 | if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { |
692 | /* | 677 | IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i); |
693 | * The station entry contains a link to the LQ command. For | 678 | priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; |
694 | * all stations managed by mac80211 this memory will be | 679 | cleared = true; |
695 | * managed by it also. For local stations (broadcast and | ||
696 | * bssid station when in adhoc mode) we need to maintain | ||
697 | * this lq command separately. This memory is created when | ||
698 | * these stations are added. | ||
699 | */ | ||
700 | for (i = 0; i < priv->hw_params.max_stations; i++) { | ||
701 | if (priv->stations[i].used & IWL_STA_LOCAL) { | ||
702 | kfree(priv->stations[i].lq); | ||
703 | priv->stations[i].lq = NULL; | ||
704 | } | ||
705 | } | ||
706 | priv->num_stations = 0; | ||
707 | memset(priv->stations, 0, sizeof(priv->stations)); | ||
708 | cleared = true; | ||
709 | } else { | ||
710 | for (i = 0; i < priv->hw_params.max_stations; i++) { | ||
711 | if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { | ||
712 | IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i); | ||
713 | priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; | ||
714 | cleared = true; | ||
715 | } | ||
716 | } | 680 | } |
717 | } | 681 | } |
718 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 682 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); |
@@ -1251,34 +1215,67 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, | |||
1251 | EXPORT_SYMBOL(iwl_send_lq_cmd); | 1215 | EXPORT_SYMBOL(iwl_send_lq_cmd); |
1252 | 1216 | ||
1253 | /** | 1217 | /** |
1254 | * iwl_add_bcast_station - add broadcast station into station table. | 1218 | * iwl_alloc_bcast_station - add broadcast station into driver's station table. |
1219 | * | ||
1220 | * This adds the broadcast station into the driver's station table | ||
1221 | * and marks it driver active, so that it will be restored to the | ||
1222 | * device at the next best time. | ||
1255 | */ | 1223 | */ |
1256 | int iwl_add_bcast_station(struct iwl_priv *priv) | 1224 | int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq) |
1257 | { | 1225 | { |
1258 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); | 1226 | struct iwl_link_quality_cmd *link_cmd; |
1259 | return iwl_add_local_station(priv, iwl_bcast_addr, true); | 1227 | unsigned long flags; |
1228 | u8 sta_id; | ||
1229 | |||
1230 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1231 | sta_id = iwl_prep_station(priv, iwl_bcast_addr, false, NULL); | ||
1232 | if (sta_id == IWL_INVALID_STATION) { | ||
1233 | IWL_ERR(priv, "Unable to prepare broadcast station\n"); | ||
1234 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1235 | |||
1236 | return -EINVAL; | ||
1237 | } | ||
1238 | |||
1239 | priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; | ||
1240 | priv->stations[sta_id].used |= IWL_STA_BCAST; | ||
1241 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1242 | |||
1243 | if (init_lq) { | ||
1244 | link_cmd = iwl_sta_alloc_lq(priv, sta_id); | ||
1245 | if (!link_cmd) { | ||
1246 | IWL_ERR(priv, | ||
1247 | "Unable to initialize rate scaling for bcast station.\n"); | ||
1248 | return -ENOMEM; | ||
1249 | } | ||
1250 | |||
1251 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1252 | priv->stations[sta_id].lq = link_cmd; | ||
1253 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1254 | } | ||
1255 | |||
1256 | return 0; | ||
1260 | } | 1257 | } |
1261 | EXPORT_SYMBOL(iwl_add_bcast_station); | 1258 | EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station); |
1262 | 1259 | ||
1263 | /** | 1260 | void iwl_dealloc_bcast_station(struct iwl_priv *priv) |
1264 | * iwl3945_add_bcast_station - add broadcast station into station table. | ||
1265 | */ | ||
1266 | int iwl3945_add_bcast_station(struct iwl_priv *priv) | ||
1267 | { | 1261 | { |
1268 | int ret; | 1262 | unsigned long flags; |
1269 | 1263 | int i; | |
1270 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); | ||
1271 | ret = iwl_add_local_station(priv, iwl_bcast_addr, false); | ||
1272 | /* | ||
1273 | * It is assumed that when station is added more initialization | ||
1274 | * needs to be done, but for 3945 it is not the case and we can | ||
1275 | * just release station table access right here. | ||
1276 | */ | ||
1277 | priv->stations[priv->hw_params.bcast_sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
1278 | return ret; | ||
1279 | 1264 | ||
1265 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1266 | for (i = 0; i < priv->hw_params.max_stations; i++) { | ||
1267 | if (!(priv->stations[i].used & IWL_STA_BCAST)) | ||
1268 | continue; | ||
1269 | |||
1270 | priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; | ||
1271 | priv->num_stations--; | ||
1272 | BUG_ON(priv->num_stations < 0); | ||
1273 | kfree(priv->stations[i].lq); | ||
1274 | priv->stations[i].lq = NULL; | ||
1275 | } | ||
1276 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1280 | } | 1277 | } |
1281 | EXPORT_SYMBOL(iwl3945_add_bcast_station); | 1278 | EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station); |
1282 | 1279 | ||
1283 | /** | 1280 | /** |
1284 | * iwl_get_sta_id - Find station's index within station table | 1281 | * iwl_get_sta_id - Find station's index within station table |