aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-18 07:51:25 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-01-03 07:01:42 -0500
commit18b559d5db47c86b10c14590aa2d26c0243c39e4 (patch)
tree15db56605202e2b43628b0f441ca6275bf9b2d50
parent30bf5f1f433c7612857ed13c50525945c483dfe0 (diff)
mac80211: split TX aggregation stop action
When TX aggregation is stopped, there are a few different cases: - connection with the peer was dropped - session stop was requested locally - session stop was requested by the peer - connection was dropped while a session is stopping The behaviour in these cases should be different, if the connection is dropped then the driver should drop all frames, otherwise the frames may continue to be transmitted, aggregated in the case of a locally requested session stop or unaggregated in the case of the peer requesting session stop. Split these different cases so that the driver can act accordingly; however, treat local and remote stop the same way and ask the driver to not send frames as aggregated packets any more. In the case of connection drop, the stop callback the driver is otherwise supposed to call is no longer required. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c4
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c4
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c4
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c4
-rw-r--r--drivers/net/wireless/mwl8k.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c4
-rw-r--r--drivers/net/wireless/rtlwifi/core.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c4
-rw-r--r--include/net/mac80211.h22
-rw-r--r--net/mac80211/agg-tx.c40
13 files changed, 85 insertions, 21 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 9c07a8fa5134..a8016d70088a 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1628,7 +1628,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1628 if (!ret) 1628 if (!ret)
1629 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1629 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1630 break; 1630 break;
1631 case IEEE80211_AMPDU_TX_STOP: 1631 case IEEE80211_AMPDU_TX_STOP_CONT:
1632 case IEEE80211_AMPDU_TX_STOP_FLUSH:
1633 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
1632 ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid); 1634 ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
1633 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1635 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1634 break; 1636 break;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index be30a9af1528..e1fa70596e61 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1610,7 +1610,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
1610 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1610 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1611 ath9k_ps_restore(sc); 1611 ath9k_ps_restore(sc);
1612 break; 1612 break;
1613 case IEEE80211_AMPDU_TX_STOP: 1613 case IEEE80211_AMPDU_TX_STOP_CONT:
1614 case IEEE80211_AMPDU_TX_STOP_FLUSH:
1615 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
1614 ath9k_ps_wakeup(sc); 1616 ath9k_ps_wakeup(sc);
1615 ath_tx_aggr_stop(sc, sta, tid); 1617 ath_tx_aggr_stop(sc, sta, tid);
1616 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1618 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 25a1e2f4f738..9d2051aeb782 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1394,7 +1394,9 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
1394 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1394 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1395 break; 1395 break;
1396 1396
1397 case IEEE80211_AMPDU_TX_STOP: 1397 case IEEE80211_AMPDU_TX_STOP_CONT:
1398 case IEEE80211_AMPDU_TX_STOP_FLUSH:
1399 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
1398 rcu_read_lock(); 1400 rcu_read_lock();
1399 tid_info = rcu_dereference(sta_info->agg[tid]); 1401 tid_info = rcu_dereference(sta_info->agg[tid]);
1400 if (tid_info) { 1402 if (tid_info) {
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 1fbd8ecbe2ea..f0fc8cd4d5df 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -668,7 +668,9 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
668 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); 668 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
669 break; 669 break;
670 670
671 case IEEE80211_AMPDU_TX_STOP: 671 case IEEE80211_AMPDU_TX_STOP_CONT:
672 case IEEE80211_AMPDU_TX_STOP_FLUSH:
673 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
672 spin_lock_bh(&wl->lock); 674 spin_lock_bh(&wl->lock);
673 brcms_c_ampdu_flush(wl->wlc, sta, tid); 675 brcms_c_ampdu_flush(wl->wlc, sta, tid);
674 spin_unlock_bh(&wl->lock); 676 spin_unlock_bh(&wl->lock);
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index c3fbf6717564..6a86ed45835d 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -5968,7 +5968,9 @@ il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
5968 D_HT("start Tx\n"); 5968 D_HT("start Tx\n");
5969 ret = il4965_tx_agg_start(il, vif, sta, tid, ssn); 5969 ret = il4965_tx_agg_start(il, vif, sta, tid, ssn);
5970 break; 5970 break;
5971 case IEEE80211_AMPDU_TX_STOP: 5971 case IEEE80211_AMPDU_TX_STOP_CONT:
5972 case IEEE80211_AMPDU_TX_STOP_FLUSH:
5973 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
5972 D_HT("stop Tx\n"); 5974 D_HT("stop Tx\n");
5973 ret = il4965_tx_agg_stop(il, vif, sta, tid); 5975 ret = il4965_tx_agg_stop(il, vif, sta, tid);
5974 if (test_bit(S_EXIT_PENDING, &il->status)) 5976 if (test_bit(S_EXIT_PENDING, &il->status))
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 3163e0f38c25..02fdcea76b21 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -679,7 +679,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
679 IWL_DEBUG_HT(priv, "start Tx\n"); 679 IWL_DEBUG_HT(priv, "start Tx\n");
680 ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); 680 ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
681 break; 681 break;
682 case IEEE80211_AMPDU_TX_STOP: 682 case IEEE80211_AMPDU_TX_STOP_CONT:
683 case IEEE80211_AMPDU_TX_STOP_FLUSH:
684 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
683 IWL_DEBUG_HT(priv, "stop Tx\n"); 685 IWL_DEBUG_HT(priv, "stop Tx\n");
684 ret = iwlagn_tx_agg_stop(priv, vif, sta, tid); 686 ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
685 if ((ret == 0) && (priv->agg_tids_count > 0)) { 687 if ((ret == 0) && (priv->agg_tids_count > 0)) {
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 145498f8411f..d248a4cc6656 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1312,7 +1312,9 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
1312 case IEEE80211_AMPDU_TX_START: 1312 case IEEE80211_AMPDU_TX_START:
1313 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1313 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1314 break; 1314 break;
1315 case IEEE80211_AMPDU_TX_STOP: 1315 case IEEE80211_AMPDU_TX_STOP_CONT:
1316 case IEEE80211_AMPDU_TX_STOP_FLUSH:
1317 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
1316 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1318 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1317 break; 1319 break;
1318 case IEEE80211_AMPDU_TX_OPERATIONAL: 1320 case IEEE80211_AMPDU_TX_OPERATIONAL:
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index f221b95b90b3..19b46fdf9f0f 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -5170,7 +5170,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
5170 } 5170 }
5171 ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); 5171 ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
5172 break; 5172 break;
5173 case IEEE80211_AMPDU_TX_STOP: 5173 case IEEE80211_AMPDU_TX_STOP_CONT:
5174 case IEEE80211_AMPDU_TX_STOP_FLUSH:
5175 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
5174 if (stream) { 5176 if (stream) {
5175 if (stream->state == AMPDU_STREAM_ACTIVE) { 5177 if (stream->state == AMPDU_STREAM_ACTIVE) {
5176 spin_unlock(&priv->stream_lock); 5178 spin_unlock(&priv->stream_lock);
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 197b4466a5d2..12f93e42e160 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -5484,7 +5484,9 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
5484 case IEEE80211_AMPDU_TX_START: 5484 case IEEE80211_AMPDU_TX_START:
5485 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); 5485 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
5486 break; 5486 break;
5487 case IEEE80211_AMPDU_TX_STOP: 5487 case IEEE80211_AMPDU_TX_STOP_CONT:
5488 case IEEE80211_AMPDU_TX_STOP_FLUSH:
5489 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
5488 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 5490 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
5489 break; 5491 break;
5490 case IEEE80211_AMPDU_TX_OPERATIONAL: 5492 case IEEE80211_AMPDU_TX_OPERATIONAL:
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index be33aa14c8af..d3ce9fbef00e 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -879,7 +879,9 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
879 "IEEE80211_AMPDU_TX_START: TID:%d\n", tid); 879 "IEEE80211_AMPDU_TX_START: TID:%d\n", tid);
880 return rtl_tx_agg_start(hw, sta, tid, ssn); 880 return rtl_tx_agg_start(hw, sta, tid, ssn);
881 break; 881 break;
882 case IEEE80211_AMPDU_TX_STOP: 882 case IEEE80211_AMPDU_TX_STOP_CONT:
883 case IEEE80211_AMPDU_TX_STOP_FLUSH:
884 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
883 RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, 885 RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
884 "IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid); 886 "IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid);
885 return rtl_tx_agg_stop(hw, sta, tid); 887 return rtl_tx_agg_stop(hw, sta, tid);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index ea9d8e011bc9..d7de06359ae1 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -4575,7 +4575,9 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4575 * Falling break here on purpose for all TX APDU commands. 4575 * Falling break here on purpose for all TX APDU commands.
4576 */ 4576 */
4577 case IEEE80211_AMPDU_TX_START: 4577 case IEEE80211_AMPDU_TX_START:
4578 case IEEE80211_AMPDU_TX_STOP: 4578 case IEEE80211_AMPDU_TX_STOP_CONT:
4579 case IEEE80211_AMPDU_TX_STOP_FLUSH:
4580 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
4579 case IEEE80211_AMPDU_TX_OPERATIONAL: 4581 case IEEE80211_AMPDU_TX_OPERATIONAL:
4580 ret = -EINVAL; 4582 ret = -EINVAL;
4581 break; 4583 break;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 0978b0faa880..a464f4fb36a0 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2033,17 +2033,29 @@ enum ieee80211_filter_flags {
2033 * calling ieee80211_start_tx_ba_cb_irqsafe, because the peer 2033 * calling ieee80211_start_tx_ba_cb_irqsafe, because the peer
2034 * might receive the addBA frame and send a delBA right away! 2034 * might receive the addBA frame and send a delBA right away!
2035 * 2035 *
2036 * @IEEE80211_AMPDU_RX_START: start Rx aggregation 2036 * @IEEE80211_AMPDU_RX_START: start RX aggregation
2037 * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation 2037 * @IEEE80211_AMPDU_RX_STOP: stop RX aggregation
2038 * @IEEE80211_AMPDU_TX_START: start Tx aggregation 2038 * @IEEE80211_AMPDU_TX_START: start TX aggregation
2039 * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation
2040 * @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational 2039 * @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational
2040 * @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting
2041 * queued packets, now unaggregated. After all packets are transmitted the
2042 * driver has to call ieee80211_stop_tx_ba_cb_irqsafe().
2043 * @IEEE80211_AMPDU_TX_STOP_FLUSH: stop TX aggregation and flush all packets,
2044 * called when the station is removed. There's no need or reason to call
2045 * ieee80211_stop_tx_ba_cb_irqsafe() in this case as mac80211 assumes the
2046 * session is gone and removes the station.
2047 * @IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: called when TX aggregation is stopped
2048 * but the driver hasn't called ieee80211_stop_tx_ba_cb_irqsafe() yet and
2049 * now the connection is dropped and the station will be removed. Drivers
2050 * should clean up and drop remaining packets when this is called.
2041 */ 2051 */
2042enum ieee80211_ampdu_mlme_action { 2052enum ieee80211_ampdu_mlme_action {
2043 IEEE80211_AMPDU_RX_START, 2053 IEEE80211_AMPDU_RX_START,
2044 IEEE80211_AMPDU_RX_STOP, 2054 IEEE80211_AMPDU_RX_STOP,
2045 IEEE80211_AMPDU_TX_START, 2055 IEEE80211_AMPDU_TX_START,
2046 IEEE80211_AMPDU_TX_STOP, 2056 IEEE80211_AMPDU_TX_STOP_CONT,
2057 IEEE80211_AMPDU_TX_STOP_FLUSH,
2058 IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
2047 IEEE80211_AMPDU_TX_OPERATIONAL, 2059 IEEE80211_AMPDU_TX_OPERATIONAL,
2048}; 2060};
2049 2061
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index dda8d7df4b54..2f0ccbc5f13e 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -257,10 +257,25 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
257{ 257{
258 struct ieee80211_local *local = sta->local; 258 struct ieee80211_local *local = sta->local;
259 struct tid_ampdu_tx *tid_tx; 259 struct tid_ampdu_tx *tid_tx;
260 enum ieee80211_ampdu_mlme_action action;
260 int ret; 261 int ret;
261 262
262 lockdep_assert_held(&sta->ampdu_mlme.mtx); 263 lockdep_assert_held(&sta->ampdu_mlme.mtx);
263 264
265 switch (reason) {
266 case AGG_STOP_DECLINED:
267 case AGG_STOP_LOCAL_REQUEST:
268 case AGG_STOP_PEER_REQUEST:
269 action = IEEE80211_AMPDU_TX_STOP_CONT;
270 break;
271 case AGG_STOP_DESTROY_STA:
272 action = IEEE80211_AMPDU_TX_STOP_FLUSH;
273 break;
274 default:
275 WARN_ON_ONCE(1);
276 return -EINVAL;
277 }
278
264 spin_lock_bh(&sta->lock); 279 spin_lock_bh(&sta->lock);
265 280
266 tid_tx = rcu_dereference_protected_tid_tx(sta, tid); 281 tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
@@ -269,10 +284,19 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
269 return -ENOENT; 284 return -ENOENT;
270 } 285 }
271 286
272 /* if we're already stopping ignore any new requests to stop */ 287 /*
288 * if we're already stopping ignore any new requests to stop
289 * unless we're destroying it in which case notify the driver
290 */
273 if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { 291 if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
274 spin_unlock_bh(&sta->lock); 292 spin_unlock_bh(&sta->lock);
275 return -EALREADY; 293 if (reason != AGG_STOP_DESTROY_STA)
294 return -EALREADY;
295 ret = drv_ampdu_action(local, sta->sdata,
296 IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
297 &sta->sta, tid, NULL, 0);
298 WARN_ON_ONCE(ret);
299 goto remove_tid_tx;
276 } 300 }
277 301
278 if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { 302 if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
@@ -319,8 +343,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
319 WLAN_BACK_INITIATOR; 343 WLAN_BACK_INITIATOR;
320 tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST; 344 tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
321 345
322 ret = drv_ampdu_action(local, sta->sdata, 346 ret = drv_ampdu_action(local, sta->sdata, action,
323 IEEE80211_AMPDU_TX_STOP,
324 &sta->sta, tid, NULL, 0); 347 &sta->sta, tid, NULL, 0);
325 348
326 /* HW shall not deny going back to legacy */ 349 /* HW shall not deny going back to legacy */
@@ -331,7 +354,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
331 */ 354 */
332 } 355 }
333 356
334 return ret; 357 if (reason == AGG_STOP_DESTROY_STA) {
358 remove_tid_tx:
359 spin_lock_bh(&sta->lock);
360 ieee80211_remove_tid_tx(sta, tid);
361 spin_unlock_bh(&sta->lock);
362 }
363
364 return 0;
335} 365}
336 366
337/* 367/*