diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 154 |
1 files changed, 95 insertions, 59 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index efee4e39d282..0a376f720d78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -144,9 +144,6 @@ int iwl_commit_rxon(struct iwl_priv *priv) return 0; } - /* station table will be cleared */ - priv->assoc_station_added = 0; - /* If we are currently associated and the new config requires * an RXON_ASSOC and the new config wants the associated mask enabled, * we must clear the associated from the active configuration @@ -166,6 +163,8 @@ int iwl_commit_rxon(struct iwl_priv *priv) IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret); return ret; } + iwl_clear_ucode_stations(priv, false); + iwl_restore_stations(priv); } IWL_DEBUG_INFO(priv, "Sending RXON\n" @@ -179,9 +178,8 @@ int iwl_commit_rxon(struct iwl_priv *priv) iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto); /* Apply the new configuration - * RXON unassoc clears the station table in uCode, send it before - * we add the bcast station. If assoc bit is set, we will send RXON - * after having added the bcast and bssid station. + * RXON unassoc clears the station table in uCode so restoration of + * stations is needed after it (the RXON command) completes */ if (!new_assoc) { ret = iwl_send_cmd_pdu(priv, REPLY_RXON, @@ -190,35 +188,14 @@ int iwl_commit_rxon(struct iwl_priv *priv) IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); return ret; } + IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON. \n"); memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + iwl_clear_ucode_stations(priv, false); + iwl_restore_stations(priv); } - iwl_clear_stations_table(priv); - priv->start_calib = 0; - - /* Add the broadcast address so we can send broadcast frames */ - priv->cfg->ops->lib->add_bcast_station(priv); - - - /* If we have set the ASSOC_MSK and we are in BSS mode then - * add the IWL_AP_ID to the station rate table */ if (new_assoc) { - if (priv->iw_mode == NL80211_IFTYPE_STATION) { - ret = iwl_rxon_add_station(priv, - priv->active_rxon.bssid_addr, 1); - if (ret == IWL_INVALID_STATION) { - IWL_ERR(priv, - "Error adding AP address for TX.\n"); - return -EIO; - } - priv->assoc_station_added = 1; - if (priv->default_wep_key && - iwl_send_static_wepkey_cmd(priv, 0)) - IWL_ERR(priv, - "Could not send WEP static key.\n"); - } - /* * allow CTS-to-self if possible for new association. * this is relevant only for 5000 series and up, @@ -2087,7 +2064,6 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - iwl_clear_stations_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARN(priv, @@ -2098,6 +2074,13 @@ static void iwl_alive_start(struct iwl_priv *priv) /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); + if (priv->cfg->ops->lib->recover_from_tx_stall) { + /* Enable timer to monitor the driver queues */ + mod_timer(&priv->monitor_recover, + jiffies + + msecs_to_jiffies(priv->cfg->monitor_recover_period)); + } + if (iwl_is_rfkill(priv)) return; @@ -2143,6 +2126,8 @@ static void iwl_alive_start(struct iwl_priv *priv) wake_up_interruptible(&priv->wait_command_queue); iwl_power_update_mode(priv, true); + IWL_DEBUG_INFO(priv, "Updated power mode\n"); + return; @@ -2162,7 +2147,7 @@ static void __iwl_down(struct iwl_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl_clear_stations_table(priv); + iwl_clear_ucode_stations(priv, true); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -2359,8 +2344,6 @@ static int __iwl_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - iwl_clear_stations_table(priv); - /* load bootstrap state machine, * load bootstrap program into processor's memory, * prepare to load the "initialize" uCode */ @@ -2501,10 +2484,6 @@ void iwl_post_associate(struct iwl_priv *priv) return; } - IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", - priv->assoc_id, priv->active_rxon.bssid_addr); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -2556,6 +2535,9 @@ void iwl_post_associate(struct iwl_priv *priv) iwlcore_commit_rxon(priv); + IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", + priv->assoc_id, priv->active_rxon.bssid_addr); + switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: break; @@ -2565,7 +2547,7 @@ void iwl_post_associate(struct iwl_priv *priv) /* assume default assoc id */ priv->assoc_id = 1; - iwl_rxon_add_station(priv, priv->bssid, 0); + iwl_add_local_station(priv, priv->bssid, true); iwl_send_beacon_cmd(priv); break; @@ -2576,9 +2558,6 @@ void iwl_post_associate(struct iwl_priv *priv) break; } - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) - priv->assoc_station_added = 1; - spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 0); spin_unlock_irqrestore(&priv->lock, flags); @@ -2937,10 +2916,21 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, return ret; case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT(priv, "start Tx\n"); - return iwl_tx_agg_start(priv, sta->addr, tid, ssn); + ret = iwl_tx_agg_start(priv, sta->addr, tid, ssn); + if (ret == 0) { + priv->_agn.agg_tids_count++; + IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n", + priv->_agn.agg_tids_count); + } + return ret; case IEEE80211_AMPDU_TX_STOP: IWL_DEBUG_HT(priv, "stop Tx\n"); ret = iwl_tx_agg_stop(priv, sta->addr, tid); + if ((ret == 0) && (priv->_agn.agg_tids_count > 0)) { + priv->_agn.agg_tids_count--; + IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n", + priv->_agn.agg_tids_count); + } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return 0; else @@ -2977,18 +2967,7 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw, struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; int sta_id; - /* - * TODO: We really should use this callback to - * actually maintain the station table in - * the device. - */ - switch (cmd) { - case STA_NOTIFY_ADD: - atomic_set(&sta_priv->pending_frames, 0); - if (vif->type == NL80211_IFTYPE_AP) - sta_priv->client = true; - break; case STA_NOTIFY_SLEEP: WARN_ON(!sta_priv->client); sta_priv->asleep = true; @@ -3009,6 +2988,55 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw, } } +/** + * iwl_restore_wepkeys - Restore WEP keys to device + */ +static void iwl_restore_wepkeys(struct iwl_priv *priv) +{ + mutex_lock(&priv->mutex); + if (priv->iw_mode == NL80211_IFTYPE_STATION && + priv->default_wep_key && + iwl_send_static_wepkey_cmd(priv, 0)) + IWL_ERR(priv, "Could not send WEP static key\n"); + mutex_unlock(&priv->mutex); +} + +static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; + bool is_ap = priv->iw_mode == NL80211_IFTYPE_STATION; + int ret; + u8 sta_id; + + IWL_DEBUG_INFO(priv, "received request to add station %pM\n", + sta->addr); + + atomic_set(&sta_priv->pending_frames, 0); + if (vif->type == NL80211_IFTYPE_AP) + sta_priv->client = true; + + ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap, + &sta_id); + if (ret) { + IWL_ERR(priv, "Unable to add station %pM (%d)\n", + sta->addr, ret); + /* Should we return success if return code is EEXIST ? */ + return ret; + } + + iwl_restore_wepkeys(priv); + + /* Initialize rate scaling */ + IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM \n", + sta->addr); + iwl_rs_rate_init(priv, sta, sta_id); + + return ret; +} + /***************************************************************************** * * sysfs attributes @@ -3214,6 +3242,13 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->ucode_trace.data = (unsigned long)priv; priv->ucode_trace.function = iwl_bg_ucode_trace; + if (priv->cfg->ops->lib->recover_from_tx_stall) { + init_timer(&priv->monitor_recover); + priv->monitor_recover.data = (unsigned long)priv; + priv->monitor_recover.function = + priv->cfg->ops->lib->recover_from_tx_stall; + } + if (!priv->cfg->use_isr_legacy) tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) iwl_irq_tasklet, (unsigned long)priv); @@ -3233,6 +3268,8 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->beacon_update); del_timer_sync(&priv->statistics_periodic); del_timer_sync(&priv->ucode_trace); + if (priv->cfg->ops->lib->recover_from_tx_stall) + del_timer_sync(&priv->monitor_recover); } static void iwl_init_hw_rates(struct iwl_priv *priv, @@ -3270,9 +3307,6 @@ static int iwl_init_drv(struct iwl_priv *priv) mutex_init(&priv->mutex); mutex_init(&priv->sync_cmd_mutex); - /* Clear the driver's (not device's) station table */ - iwl_clear_stations_table(priv); - priv->ieee_channels = NULL; priv->ieee_rates = NULL; priv->band = IEEE80211_BAND_2GHZ; @@ -3280,6 +3314,7 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = NL80211_IFTYPE_STATION; priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; + priv->_agn.agg_tids_count = 0; /* initialize force reset */ priv->force_reset[IWL_RF_RESET].reset_duration = @@ -3365,6 +3400,8 @@ static struct ieee80211_ops iwl_hw_ops = { .ampdu_action = iwl_mac_ampdu_action, .hw_scan = iwl_mac_hw_scan, .sta_notify = iwl_mac_sta_notify, + .sta_add = iwlagn_mac_sta_add, + .sta_remove = iwl_mac_sta_remove, }; static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -3468,7 +3505,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); iwl_hw_detect(priv); - IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n", + IWL_INFO(priv, "Detected %s, REV=0x%X\n", priv->cfg->name, priv->hw_rev); /* We disable the RETRY_TIMEOUT register (0x41) to keep @@ -3649,7 +3686,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_rx_queue_free(priv, &priv->rxq); iwl_hw_txq_ctx_free(priv); - iwl_clear_stations_table(priv); iwl_eeprom_free(priv); |