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.c136
1 files changed, 84 insertions, 52 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index fd718e2b29f7..64b839bfbf17 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -132,16 +132,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
132 state = &sta->ampdu_mlme.tid_state_tx[tid]; 132 state = &sta->ampdu_mlme.tid_state_tx[tid];
133 133
134 if (local->hw.ampdu_queues) { 134 if (local->hw.ampdu_queues) {
135 if (initiator) {
136 /*
137 * Stop the AC queue to avoid issues where we send
138 * unaggregated frames already before the delba.
139 */
140 ieee80211_stop_queue_by_reason(&local->hw,
141 local->hw.queues + sta->tid_to_tx_q[tid],
142 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
143 }
144
145 /* 135 /*
146 * Pretend the driver woke the queue, just in case 136 * Pretend the driver woke the queue, just in case
147 * it disabled it before the session was stopped. 137 * it disabled it before the session was stopped.
@@ -158,6 +148,10 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
158 /* HW shall not deny going back to legacy */ 148 /* HW shall not deny going back to legacy */
159 if (WARN_ON(ret)) { 149 if (WARN_ON(ret)) {
160 *state = HT_AGG_STATE_OPERATIONAL; 150 *state = HT_AGG_STATE_OPERATIONAL;
151 /*
152 * We may have pending packets get stuck in this case...
153 * Not bothering with a workaround for now.
154 */
161 } 155 }
162 156
163 return ret; 157 return ret;
@@ -226,13 +220,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
226 ra, tid); 220 ra, tid);
227#endif /* CONFIG_MAC80211_HT_DEBUG */ 221#endif /* CONFIG_MAC80211_HT_DEBUG */
228 222
229 if (hw->ampdu_queues && ieee80211_ac_from_tid(tid) == 0) {
230#ifdef CONFIG_MAC80211_HT_DEBUG
231 printk(KERN_DEBUG "rejecting on voice AC\n");
232#endif
233 return -EINVAL;
234 }
235
236 rcu_read_lock(); 223 rcu_read_lock();
237 224
238 sta = sta_info_get(local, ra); 225 sta = sta_info_get(local, ra);
@@ -267,6 +254,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
267 } 254 }
268 255
269 spin_lock_bh(&sta->lock); 256 spin_lock_bh(&sta->lock);
257 spin_lock(&local->ampdu_lock);
270 258
271 sdata = sta->sdata; 259 sdata = sta->sdata;
272 260
@@ -308,21 +296,19 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
308 ret = -ENOSPC; 296 ret = -ENOSPC;
309 goto err_unlock_sta; 297 goto err_unlock_sta;
310 } 298 }
311
312 /*
313 * If we successfully allocate the session, we can't have
314 * anything going on on the queue this TID maps into, so
315 * stop it for now. This is a "virtual" stop using the same
316 * mechanism that drivers will use.
317 *
318 * XXX: queue up frames for this session in the sta_info
319 * struct instead to avoid hitting all other STAs.
320 */
321 ieee80211_stop_queue_by_reason(
322 &local->hw, hw->queues + qn,
323 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
324 } 299 }
325 300
301 /*
302 * While we're asking the driver about the aggregation,
303 * stop the AC queue so that we don't have to worry
304 * about frames that came in while we were doing that,
305 * which would require us to put them to the AC pending
306 * afterwards which just makes the code more complex.
307 */
308 ieee80211_stop_queue_by_reason(
309 &local->hw, ieee80211_ac_from_tid(tid),
310 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
311
326 /* prepare A-MPDU MLME for Tx aggregation */ 312 /* prepare A-MPDU MLME for Tx aggregation */
327 sta->ampdu_mlme.tid_tx[tid] = 313 sta->ampdu_mlme.tid_tx[tid] =
328 kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); 314 kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
@@ -336,6 +322,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
336 goto err_return_queue; 322 goto err_return_queue;
337 } 323 }
338 324
325 skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending);
326
339 /* Tx timer */ 327 /* Tx timer */
340 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = 328 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
341 sta_addba_resp_timer_expired; 329 sta_addba_resp_timer_expired;
@@ -362,6 +350,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
362 } 350 }
363 sta->tid_to_tx_q[tid] = qn; 351 sta->tid_to_tx_q[tid] = qn;
364 352
353 /* Driver vetoed or OKed, but we can take packets again now */
354 ieee80211_wake_queue_by_reason(
355 &local->hw, ieee80211_ac_from_tid(tid),
356 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
357
358 spin_unlock(&local->ampdu_lock);
365 spin_unlock_bh(&sta->lock); 359 spin_unlock_bh(&sta->lock);
366 360
367 /* send an addBA request */ 361 /* send an addBA request */
@@ -388,15 +382,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
388 sta->ampdu_mlme.tid_tx[tid] = NULL; 382 sta->ampdu_mlme.tid_tx[tid] = NULL;
389 err_return_queue: 383 err_return_queue:
390 if (qn >= 0) { 384 if (qn >= 0) {
391 /* We failed, so start queue again right away. */
392 ieee80211_wake_queue_by_reason(hw, hw->queues + qn,
393 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
394 /* give queue back to pool */ 385 /* give queue back to pool */
395 spin_lock(&local->queue_stop_reason_lock); 386 spin_lock(&local->queue_stop_reason_lock);
396 local->ampdu_ac_queue[qn] = -1; 387 local->ampdu_ac_queue[qn] = -1;
397 spin_unlock(&local->queue_stop_reason_lock); 388 spin_unlock(&local->queue_stop_reason_lock);
398 } 389 }
390 ieee80211_wake_queue_by_reason(
391 &local->hw, ieee80211_ac_from_tid(tid),
392 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
399 err_unlock_sta: 393 err_unlock_sta:
394 spin_unlock(&local->ampdu_lock);
400 spin_unlock_bh(&sta->lock); 395 spin_unlock_bh(&sta->lock);
401 unlock: 396 unlock:
402 rcu_read_unlock(); 397 rcu_read_unlock();
@@ -404,6 +399,45 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
404} 399}
405EXPORT_SYMBOL(ieee80211_start_tx_ba_session); 400EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
406 401
402/*
403 * splice packets from the STA's pending to the local pending,
404 * requires a call to ieee80211_agg_splice_finish and holding
405 * local->ampdu_lock across both calls.
406 */
407static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
408 struct sta_info *sta, u16 tid)
409{
410 unsigned long flags;
411 u16 queue = ieee80211_ac_from_tid(tid);
412
413 ieee80211_stop_queue_by_reason(
414 &local->hw, queue,
415 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
416
417 if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
418 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
419 /* mark queue as pending, it is stopped already */
420 __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
421 &local->queue_stop_reasons[queue]);
422 /* copy over remaining packets */
423 skb_queue_splice_tail_init(
424 &sta->ampdu_mlme.tid_tx[tid]->pending,
425 &local->pending[queue]);
426 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
427 }
428}
429
430static void ieee80211_agg_splice_finish(struct ieee80211_local *local,
431 struct sta_info *sta, u16 tid)
432{
433 u16 queue = ieee80211_ac_from_tid(tid);
434
435 ieee80211_wake_queue_by_reason(
436 &local->hw, queue,
437 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
438}
439
440/* caller must hold sta->lock */
407static void ieee80211_agg_tx_operational(struct ieee80211_local *local, 441static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
408 struct sta_info *sta, u16 tid) 442 struct sta_info *sta, u16 tid)
409{ 443{
@@ -411,15 +445,16 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
411 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); 445 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
412#endif 446#endif
413 447
414 if (local->hw.ampdu_queues) { 448 spin_lock(&local->ampdu_lock);
415 /* 449 ieee80211_agg_splice_packets(local, sta, tid);
416 * Wake up the A-MPDU queue, we stopped it earlier, 450 /*
417 * this will in turn wake the entire AC. 451 * NB: we rely on sta->lock being taken in the TX
418 */ 452 * processing here when adding to the pending queue,
419 ieee80211_wake_queue_by_reason(&local->hw, 453 * otherwise we could only change the state of the
420 local->hw.queues + sta->tid_to_tx_q[tid], 454 * session to OPERATIONAL _here_.
421 IEEE80211_QUEUE_STOP_REASON_AGGREGATION); 455 */
422 } 456 ieee80211_agg_splice_finish(local, sta, tid);
457 spin_unlock(&local->ampdu_lock);
423 458
424 local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL, 459 local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL,
425 &sta->sta, tid, NULL); 460 &sta->sta, tid, NULL);
@@ -602,22 +637,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
602 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); 637 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
603 638
604 spin_lock_bh(&sta->lock); 639 spin_lock_bh(&sta->lock);
640 spin_lock(&local->ampdu_lock);
605 641
606 if (*state & HT_AGG_STATE_INITIATOR_MSK && 642 ieee80211_agg_splice_packets(local, sta, tid);
607 hw->ampdu_queues) {
608 /*
609 * Wake up this queue, we stopped it earlier,
610 * this will in turn wake the entire AC.
611 */
612 ieee80211_wake_queue_by_reason(hw,
613 hw->queues + sta->tid_to_tx_q[tid],
614 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
615 }
616 643
617 *state = HT_AGG_STATE_IDLE; 644 *state = HT_AGG_STATE_IDLE;
645 /* from now on packets are no longer put onto sta->pending */
618 sta->ampdu_mlme.addba_req_num[tid] = 0; 646 sta->ampdu_mlme.addba_req_num[tid] = 0;
619 kfree(sta->ampdu_mlme.tid_tx[tid]); 647 kfree(sta->ampdu_mlme.tid_tx[tid]);
620 sta->ampdu_mlme.tid_tx[tid] = NULL; 648 sta->ampdu_mlme.tid_tx[tid] = NULL;
649
650 ieee80211_agg_splice_finish(local, sta, tid);
651
652 spin_unlock(&local->ampdu_lock);
621 spin_unlock_bh(&sta->lock); 653 spin_unlock_bh(&sta->lock);
622 654
623 rcu_read_unlock(); 655 rcu_read_unlock();