diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 108 |
1 files changed, 85 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index b1aad306efa..312099099ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -34,9 +34,6 @@ #include "iwl-core.h" #include "iwl-sta.h" -#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ -#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ - u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) { int i; @@ -495,37 +492,102 @@ out: } /** - * iwl_clear_stations_table - Clear the driver's station table - * - * NOTE: This does not clear or otherwise alter the device's station table. + * iwl_clear_ucode_stations() - clear entire station table driver and/or ucode + * @priv: + * @force: If set then the uCode station table needs to be cleared here. If + * not set then the uCode station table has already been cleared, + * for example after sending it a RXON command without ASSOC bit + * set, and we just need to change driver state here. */ -void iwl_clear_stations_table(struct iwl_priv *priv) +void iwl_clear_ucode_stations(struct iwl_priv *priv, bool force) { - unsigned long flags; int i; + unsigned long flags_spin; + bool cleared = false; + + IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver%s\n", + force ? " and ucode" : ""); + + if (force) { + if (!iwl_is_ready(priv)) { + /* + * If device is not ready at this point the station + * table is likely already empty (uCode not ready + * to receive station requests) or will soon be + * due to interface going down. + */ + IWL_DEBUG_INFO(priv, "Unable to remove stations from device - device not ready\n"); + } else { + iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL); + } + } - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->sta_lock, flags_spin); + if (force) { + IWL_DEBUG_INFO(priv, "Clearing all station information in driver\n"); + priv->num_stations = 0; + memset(priv->stations, 0, sizeof(priv->stations)); + } else { + for (i = 0; i < priv->hw_params.max_stations; i++) { + if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { + IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d \n", i); + priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; + cleared = true; + } + } + } + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + + if (!cleared) + IWL_DEBUG_INFO(priv, "No active stations found to be cleared\n"); +} +EXPORT_SYMBOL(iwl_clear_ucode_stations); - if (iwl_is_alive(priv) && - !test_bit(STATUS_EXIT_PENDING, &priv->status) && - iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) - IWL_ERR(priv, "Couldn't clear the station table\n"); +/** + * iwl_restore_stations() - Restore driver known stations to device + * + * All stations considered active by driver, but not present in ucode, is + * restored. + */ +void iwl_restore_stations(struct iwl_priv *priv) +{ + unsigned long flags_spin; + int i; + bool found = false; - priv->num_stations = 0; - memset(priv->stations, 0, sizeof(priv->stations)); + if (!iwl_is_ready(priv)) { + IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n"); + return; + } - /* clean ucode key table bit map */ - priv->ucode_key_table = 0; + IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n"); + spin_lock_irqsave(&priv->sta_lock, flags_spin); + for (i = 0; i < priv->hw_params.max_stations; i++) { + if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) && + !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) { + IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n", + priv->stations[i].sta.sta.addr); + priv->stations[i].sta.mode = 0; + priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS; + found = true; + } + } - /* keep track of static keys */ - for (i = 0; i < WEP_KEYS_MAX ; i++) { - if (priv->wep_keys[i].key_size) - set_bit(i, &priv->ucode_key_table); + for (i = 0; i < priv->hw_params.max_stations; i++) { + if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) { + iwl_send_add_sta(priv, &priv->stations[i].sta, + CMD_ASYNC); + priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; + } } - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + if (!found) + IWL_DEBUG_INFO(priv, "Restoring all known stations .... no stations to be restored.\n"); + else + IWL_DEBUG_INFO(priv, "Restoring all known stations .... in progress.\n"); } -EXPORT_SYMBOL(iwl_clear_stations_table); +EXPORT_SYMBOL(iwl_restore_stations); int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { |