aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/agg-tx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-03-23 12:28:41 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-03-27 20:13:22 -0400
commitcd8ffc800ce18e558335c4946b2217864fc16045 (patch)
treee9bb8c3d6011e89374f9df353ff1f15d45a63590 /net/mac80211/agg-tx.c
parenta220858d30604902f650074bfac5a7598bc97ea4 (diff)
mac80211: fix aggregation to not require queue stop
Instead of stopping the entire AC queue when enabling aggregation (which was only done for hardware with aggregation queues) buffer the packets for each station, and release them to the pending skb queue once aggregation is turned on successfully. We get a little more code, but it becomes conceptually simpler and we can remove the entire virtual queue mechanism from mac80211 in a follow-up patch. This changes how mac80211 behaves towards drivers that support aggregation but have no hardware queues -- those drivers will now not be handed packets while the aggregation session is being established, but only after it has been fully established. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
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();