diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 32 |
1 files changed, 19 insertions, 13 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index e2497e7ba926..a51a7cfa5a14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -1036,7 +1036,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1036 | int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | 1036 | int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, |
1037 | struct ieee80211_sta *sta, u16 tid) | 1037 | struct ieee80211_sta *sta, u16 tid) |
1038 | { | 1038 | { |
1039 | int tx_fifo_id, txq_id, sta_id, ssn = -1; | 1039 | int tx_fifo_id, txq_id, sta_id, ssn; |
1040 | struct iwl_tid_data *tid_data; | 1040 | struct iwl_tid_data *tid_data; |
1041 | int write_ptr, read_ptr; | 1041 | int write_ptr, read_ptr; |
1042 | unsigned long flags; | 1042 | unsigned long flags; |
@@ -1054,21 +1054,26 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1054 | 1054 | ||
1055 | spin_lock_irqsave(&priv->sta_lock, flags); | 1055 | spin_lock_irqsave(&priv->sta_lock, flags); |
1056 | 1056 | ||
1057 | if (priv->stations[sta_id].tid[tid].agg.state == | ||
1058 | IWL_EMPTYING_HW_QUEUE_ADDBA) { | ||
1059 | IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); | ||
1060 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
1061 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; | ||
1062 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1063 | return 0; | ||
1064 | } | ||
1065 | |||
1066 | if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) | ||
1067 | IWL_WARN(priv, "Stopping AGG while state not ON or starting\n"); | ||
1068 | |||
1069 | tid_data = &priv->stations[sta_id].tid[tid]; | 1057 | tid_data = &priv->stations[sta_id].tid[tid]; |
1070 | ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; | 1058 | ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; |
1071 | txq_id = tid_data->agg.txq_id; | 1059 | txq_id = tid_data->agg.txq_id; |
1060 | |||
1061 | switch (priv->stations[sta_id].tid[tid].agg.state) { | ||
1062 | case IWL_EMPTYING_HW_QUEUE_ADDBA: | ||
1063 | /* | ||
1064 | * This can happen if the peer stops aggregation | ||
1065 | * again before we've had a chance to drain the | ||
1066 | * queue we selected previously, i.e. before the | ||
1067 | * session was really started completely. | ||
1068 | */ | ||
1069 | IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); | ||
1070 | goto turn_off; | ||
1071 | case IWL_AGG_ON: | ||
1072 | break; | ||
1073 | default: | ||
1074 | IWL_WARN(priv, "Stopping AGG while state not ON or starting\n"); | ||
1075 | } | ||
1076 | |||
1072 | write_ptr = priv->txq[txq_id].q.write_ptr; | 1077 | write_ptr = priv->txq[txq_id].q.write_ptr; |
1073 | read_ptr = priv->txq[txq_id].q.read_ptr; | 1078 | read_ptr = priv->txq[txq_id].q.read_ptr; |
1074 | 1079 | ||
@@ -1082,6 +1087,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1082 | } | 1087 | } |
1083 | 1088 | ||
1084 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); | 1089 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); |
1090 | turn_off: | ||
1085 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; | 1091 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; |
1086 | 1092 | ||
1087 | /* do not restore/save irqs */ | 1093 | /* do not restore/save irqs */ |