aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/agg-tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/agg-tx.c')
-rw-r--r--net/mac80211/agg-tx.c77
1 files changed, 47 insertions, 30 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 5a7ef51e302..7f2042d3790 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -220,6 +220,41 @@ static inline int ieee80211_ac_from_tid(int tid)
220 return ieee802_1d_to_ac[tid & 7]; 220 return ieee802_1d_to_ac[tid & 7];
221} 221}
222 222
223/*
224 * When multiple aggregation sessions on multiple stations
225 * are being created/destroyed simultaneously, we need to
226 * refcount the global queue stop caused by that in order
227 * to not get into a situation where one of the aggregation
228 * setup or teardown re-enables queues before the other is
229 * ready to handle that.
230 *
231 * These two functions take care of this issue by keeping
232 * a global "agg_queue_stop" refcount.
233 */
234static void __acquires(agg_queue)
235ieee80211_stop_queue_agg(struct ieee80211_local *local, int tid)
236{
237 int queue = ieee80211_ac_from_tid(tid);
238
239 if (atomic_inc_return(&local->agg_queue_stop[queue]) == 1)
240 ieee80211_stop_queue_by_reason(
241 &local->hw, queue,
242 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
243 __acquire(agg_queue);
244}
245
246static void __releases(agg_queue)
247ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
248{
249 int queue = ieee80211_ac_from_tid(tid);
250
251 if (atomic_dec_return(&local->agg_queue_stop[queue]) == 0)
252 ieee80211_wake_queue_by_reason(
253 &local->hw, queue,
254 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
255 __release(agg_queue);
256}
257
223int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) 258int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
224{ 259{
225 struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 260 struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
@@ -263,7 +298,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
263 } 298 }
264 299
265 spin_lock_bh(&sta->lock); 300 spin_lock_bh(&sta->lock);
266 spin_lock(&local->ampdu_lock);
267 301
268 /* we have tried too many times, receiver does not want A-MPDU */ 302 /* we have tried too many times, receiver does not want A-MPDU */
269 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { 303 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
@@ -289,9 +323,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
289 * which would require us to put them to the AC pending 323 * which would require us to put them to the AC pending
290 * afterwards which just makes the code more complex. 324 * afterwards which just makes the code more complex.
291 */ 325 */
292 ieee80211_stop_queue_by_reason( 326 ieee80211_stop_queue_agg(local, tid);
293 &local->hw, ieee80211_ac_from_tid(tid),
294 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
295 327
296 /* prepare A-MPDU MLME for Tx aggregation */ 328 /* prepare A-MPDU MLME for Tx aggregation */
297 tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); 329 tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
@@ -327,11 +359,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
327 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); 359 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
328 360
329 /* Driver vetoed or OKed, but we can take packets again now */ 361 /* Driver vetoed or OKed, but we can take packets again now */
330 ieee80211_wake_queue_by_reason( 362 ieee80211_wake_queue_agg(local, tid);
331 &local->hw, ieee80211_ac_from_tid(tid),
332 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
333
334 spin_unlock(&local->ampdu_lock);
335 363
336 /* activate the timer for the recipient's addBA response */ 364 /* activate the timer for the recipient's addBA response */
337 tid_tx->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL; 365 tid_tx->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL;
@@ -358,11 +386,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
358 err_free: 386 err_free:
359 kfree(tid_tx); 387 kfree(tid_tx);
360 err_wake_queue: 388 err_wake_queue:
361 ieee80211_wake_queue_by_reason( 389 ieee80211_wake_queue_agg(local, tid);
362 &local->hw, ieee80211_ac_from_tid(tid),
363 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
364 err_unlock_sta: 390 err_unlock_sta:
365 spin_unlock(&local->ampdu_lock);
366 spin_unlock_bh(&sta->lock); 391 spin_unlock_bh(&sta->lock);
367 return ret; 392 return ret;
368} 393}
@@ -370,19 +395,16 @@ EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
370 395
371/* 396/*
372 * splice packets from the STA's pending to the local pending, 397 * splice packets from the STA's pending to the local pending,
373 * requires a call to ieee80211_agg_splice_finish and holding 398 * requires a call to ieee80211_agg_splice_finish later
374 * local->ampdu_lock across both calls.
375 */ 399 */
376static void ieee80211_agg_splice_packets(struct ieee80211_local *local, 400static void __acquires(agg_queue)
377 struct tid_ampdu_tx *tid_tx, 401ieee80211_agg_splice_packets(struct ieee80211_local *local,
378 u16 tid) 402 struct tid_ampdu_tx *tid_tx, u16 tid)
379{ 403{
404 int queue = ieee80211_ac_from_tid(tid);
380 unsigned long flags; 405 unsigned long flags;
381 u16 queue = ieee80211_ac_from_tid(tid);
382 406
383 ieee80211_stop_queue_by_reason( 407 ieee80211_stop_queue_agg(local, tid);
384 &local->hw, queue,
385 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
386 408
387 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" 409 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
388 " from the pending queue\n", tid)) 410 " from the pending queue\n", tid))
@@ -397,11 +419,10 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
397 } 419 }
398} 420}
399 421
400static void ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) 422static void __releases(agg_queue)
423ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
401{ 424{
402 ieee80211_wake_queue_by_reason( 425 ieee80211_wake_queue_agg(local, tid);
403 &local->hw, ieee80211_ac_from_tid(tid),
404 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
405} 426}
406 427
407/* caller must hold sta->lock */ 428/* caller must hold sta->lock */
@@ -414,7 +435,6 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
414 printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); 435 printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
415#endif 436#endif
416 437
417 spin_lock(&local->ampdu_lock);
418 ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); 438 ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid);
419 /* 439 /*
420 * Now mark as operational. This will be visible 440 * Now mark as operational. This will be visible
@@ -423,7 +443,6 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
423 */ 443 */
424 set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); 444 set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state);
425 ieee80211_agg_splice_finish(local, tid); 445 ieee80211_agg_splice_finish(local, tid);
426 spin_unlock(&local->ampdu_lock);
427 446
428 drv_ampdu_action(local, sta->sdata, 447 drv_ampdu_action(local, sta->sdata,
429 IEEE80211_AMPDU_TX_OPERATIONAL, 448 IEEE80211_AMPDU_TX_OPERATIONAL,
@@ -604,7 +623,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
604 * more. 623 * more.
605 */ 624 */
606 625
607 spin_lock(&local->ampdu_lock);
608 ieee80211_agg_splice_packets(local, tid_tx, tid); 626 ieee80211_agg_splice_packets(local, tid_tx, tid);
609 627
610 /* future packets must not find the tid_tx struct any more */ 628 /* future packets must not find the tid_tx struct any more */
@@ -613,7 +631,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
613 ieee80211_agg_splice_finish(local, tid); 631 ieee80211_agg_splice_finish(local, tid);
614 632
615 call_rcu(&tid_tx->rcu_head, kfree_tid_tx); 633 call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
616 spin_unlock(&local->ampdu_lock);
617 634
618 spin_unlock_bh(&sta->lock); 635 spin_unlock_bh(&sta->lock);
619 rcu_read_unlock(); 636 rcu_read_unlock();