aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-02-19 09:13:53 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-03-06 10:47:26 -0500
commite3d9e7ce4cd8ea7299cad568b21d50873a29f011 (patch)
tree9128505e4eac826eb00a5fbe6c61f3ad96843e09 /drivers/net/wireless
parent831e85f3fe078297ba452e12c0dba96008c59438 (diff)
iwlwifi: mvm: support IEEE80211_AMPDU_TX_STOP_FLUSH
mac80211 tells us when we need to dump the frames from the AGG queue instead of releasing them as single MPDUs. Being able to differentiate between the different cases (IEEE80211_AMPDU_TX_STOP_*) allows us to handle races better. When the station is removed, mac80211 asks to flush and removes the station right away. This allows to avoid a case where we still have frames in AGG queues, but the station has been remove already. Note that we can have frames on the shared queues, but this is not a problem: the station in the fw will be kept until all the frames on the shared queues have been drained. AGG queues are a special case since they are dynamically allocated. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c28
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h2
3 files changed, 33 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index d08ae2604d7b..924cabf88b26 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -284,9 +284,11 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
284 ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn); 284 ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn);
285 break; 285 break;
286 case IEEE80211_AMPDU_TX_STOP_CONT: 286 case IEEE80211_AMPDU_TX_STOP_CONT:
287 ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
288 break;
287 case IEEE80211_AMPDU_TX_STOP_FLUSH: 289 case IEEE80211_AMPDU_TX_STOP_FLUSH:
288 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 290 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
289 ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid); 291 ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid);
290 break; 292 break;
291 case IEEE80211_AMPDU_TX_OPERATIONAL: 293 case IEEE80211_AMPDU_TX_OPERATIONAL:
292 ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size); 294 ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size);
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index ca7aba404502..8b8629317e9c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -834,6 +834,34 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
834 return err; 834 return err;
835} 835}
836 836
837int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
838 struct ieee80211_sta *sta, u16 tid)
839{
840 struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
841 struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
842 u16 txq_id;
843
844 /*
845 * First set the agg state to OFF to avoid calling
846 * ieee80211_stop_tx_ba_cb in iwl_mvm_check_ratid_empty.
847 */
848 spin_lock_bh(&mvmsta->lock);
849 txq_id = tid_data->txq_id;
850 IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
851 mvmsta->sta_id, tid, txq_id, tid_data->state);
852 tid_data->state = IWL_AGG_OFF;
853 spin_unlock_bh(&mvmsta->lock);
854
855 if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
856 IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
857
858 iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
859 mvm->queue_to_mac80211[tid_data->txq_id] =
860 IWL_INVALID_MAC80211_QUEUE;
861
862 return 0;
863}
864
837static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) 865static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
838{ 866{
839 int i; 867 int i;
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
index 119de72c6d18..b0352df981e4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -348,6 +348,8 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
348 struct ieee80211_sta *sta, u16 tid, u8 buf_size); 348 struct ieee80211_sta *sta, u16 tid, u8 buf_size);
349int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 349int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
350 struct ieee80211_sta *sta, u16 tid); 350 struct ieee80211_sta *sta, u16 tid);
351int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
352 struct ieee80211_sta *sta, u16 tid);
351 353
352int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); 354int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
353int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, 355int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,