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.c232
1 files changed, 113 insertions, 119 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 1df116d4d6e7..947aaaad35d2 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -131,24 +131,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
131 131
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) {
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 /*
146 * Pretend the driver woke the queue, just in case
147 * it disabled it before the session was stopped.
148 */
149 ieee80211_wake_queue(
150 &local->hw, local->hw.queues + sta->tid_to_tx_q[tid]);
151 }
152 *state = HT_AGG_STATE_REQ_STOP_BA_MSK | 134 *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
153 (initiator << HT_AGG_STATE_INITIATOR_SHIFT); 135 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
154 136
@@ -158,6 +140,10 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
158 /* HW shall not deny going back to legacy */ 140 /* HW shall not deny going back to legacy */
159 if (WARN_ON(ret)) { 141 if (WARN_ON(ret)) {
160 *state = HT_AGG_STATE_OPERATIONAL; 142 *state = HT_AGG_STATE_OPERATIONAL;
143 /*
144 * We may have pending packets get stuck in this case...
145 * Not bothering with a workaround for now.
146 */
161 } 147 }
162 148
163 return ret; 149 return ret;
@@ -212,7 +198,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
212 struct sta_info *sta; 198 struct sta_info *sta;
213 struct ieee80211_sub_if_data *sdata; 199 struct ieee80211_sub_if_data *sdata;
214 u8 *state; 200 u8 *state;
215 int i, qn = -1, ret = 0; 201 int ret = 0;
216 u16 start_seq_num; 202 u16 start_seq_num;
217 203
218 if (WARN_ON(!local->ops->ampdu_action)) 204 if (WARN_ON(!local->ops->ampdu_action))
@@ -226,13 +212,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
226 ra, tid); 212 ra, tid);
227#endif /* CONFIG_MAC80211_HT_DEBUG */ 213#endif /* CONFIG_MAC80211_HT_DEBUG */
228 214
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(); 215 rcu_read_lock();
237 216
238 sta = sta_info_get(local, ra); 217 sta = sta_info_get(local, ra);
@@ -257,7 +236,17 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
257 goto unlock; 236 goto unlock;
258 } 237 }
259 238
239 if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
240#ifdef CONFIG_MAC80211_HT_DEBUG
241 printk(KERN_DEBUG "Suspend in progress. "
242 "Denying BA session request\n");
243#endif
244 ret = -EINVAL;
245 goto unlock;
246 }
247
260 spin_lock_bh(&sta->lock); 248 spin_lock_bh(&sta->lock);
249 spin_lock(&local->ampdu_lock);
261 250
262 sdata = sta->sdata; 251 sdata = sta->sdata;
263 252
@@ -278,41 +267,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
278 goto err_unlock_sta; 267 goto err_unlock_sta;
279 } 268 }
280 269
281 if (hw->ampdu_queues) { 270 /*
282 spin_lock(&local->queue_stop_reason_lock); 271 * While we're asking the driver about the aggregation,
283 /* reserve a new queue for this session */ 272 * stop the AC queue so that we don't have to worry
284 for (i = 0; i < local->hw.ampdu_queues; i++) { 273 * about frames that came in while we were doing that,
285 if (local->ampdu_ac_queue[i] < 0) { 274 * which would require us to put them to the AC pending
286 qn = i; 275 * afterwards which just makes the code more complex.
287 local->ampdu_ac_queue[qn] = 276 */
288 ieee80211_ac_from_tid(tid); 277 ieee80211_stop_queue_by_reason(
289 break; 278 &local->hw, ieee80211_ac_from_tid(tid),
290 } 279 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
291 }
292 spin_unlock(&local->queue_stop_reason_lock);
293
294 if (qn < 0) {
295#ifdef CONFIG_MAC80211_HT_DEBUG
296 printk(KERN_DEBUG "BA request denied - "
297 "queue unavailable for tid %d\n", tid);
298#endif /* CONFIG_MAC80211_HT_DEBUG */
299 ret = -ENOSPC;
300 goto err_unlock_sta;
301 }
302
303 /*
304 * If we successfully allocate the session, we can't have
305 * anything going on on the queue this TID maps into, so
306 * stop it for now. This is a "virtual" stop using the same
307 * mechanism that drivers will use.
308 *
309 * XXX: queue up frames for this session in the sta_info
310 * struct instead to avoid hitting all other STAs.
311 */
312 ieee80211_stop_queue_by_reason(
313 &local->hw, hw->queues + qn,
314 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
315 }
316 280
317 /* prepare A-MPDU MLME for Tx aggregation */ 281 /* prepare A-MPDU MLME for Tx aggregation */
318 sta->ampdu_mlme.tid_tx[tid] = 282 sta->ampdu_mlme.tid_tx[tid] =
@@ -324,9 +288,11 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
324 tid); 288 tid);
325#endif 289#endif
326 ret = -ENOMEM; 290 ret = -ENOMEM;
327 goto err_return_queue; 291 goto err_wake_queue;
328 } 292 }
329 293
294 skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending);
295
330 /* Tx timer */ 296 /* Tx timer */
331 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = 297 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
332 sta_addba_resp_timer_expired; 298 sta_addba_resp_timer_expired;
@@ -351,8 +317,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
351 *state = HT_AGG_STATE_IDLE; 317 *state = HT_AGG_STATE_IDLE;
352 goto err_free; 318 goto err_free;
353 } 319 }
354 sta->tid_to_tx_q[tid] = qn;
355 320
321 /* Driver vetoed or OKed, but we can take packets again now */
322 ieee80211_wake_queue_by_reason(
323 &local->hw, ieee80211_ac_from_tid(tid),
324 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
325
326 spin_unlock(&local->ampdu_lock);
356 spin_unlock_bh(&sta->lock); 327 spin_unlock_bh(&sta->lock);
357 328
358 /* send an addBA request */ 329 /* send an addBA request */
@@ -377,17 +348,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
377 err_free: 348 err_free:
378 kfree(sta->ampdu_mlme.tid_tx[tid]); 349 kfree(sta->ampdu_mlme.tid_tx[tid]);
379 sta->ampdu_mlme.tid_tx[tid] = NULL; 350 sta->ampdu_mlme.tid_tx[tid] = NULL;
380 err_return_queue: 351 err_wake_queue:
381 if (qn >= 0) { 352 ieee80211_wake_queue_by_reason(
382 /* We failed, so start queue again right away. */ 353 &local->hw, ieee80211_ac_from_tid(tid),
383 ieee80211_wake_queue_by_reason(hw, hw->queues + qn, 354 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
384 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
385 /* give queue back to pool */
386 spin_lock(&local->queue_stop_reason_lock);
387 local->ampdu_ac_queue[qn] = -1;
388 spin_unlock(&local->queue_stop_reason_lock);
389 }
390 err_unlock_sta: 355 err_unlock_sta:
356 spin_unlock(&local->ampdu_lock);
391 spin_unlock_bh(&sta->lock); 357 spin_unlock_bh(&sta->lock);
392 unlock: 358 unlock:
393 rcu_read_unlock(); 359 rcu_read_unlock();
@@ -395,6 +361,67 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
395} 361}
396EXPORT_SYMBOL(ieee80211_start_tx_ba_session); 362EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
397 363
364/*
365 * splice packets from the STA's pending to the local pending,
366 * requires a call to ieee80211_agg_splice_finish and holding
367 * local->ampdu_lock across both calls.
368 */
369static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
370 struct sta_info *sta, u16 tid)
371{
372 unsigned long flags;
373 u16 queue = ieee80211_ac_from_tid(tid);
374
375 ieee80211_stop_queue_by_reason(
376 &local->hw, queue,
377 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
378
379 if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
380 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
381 /* mark queue as pending, it is stopped already */
382 __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
383 &local->queue_stop_reasons[queue]);
384 /* copy over remaining packets */
385 skb_queue_splice_tail_init(
386 &sta->ampdu_mlme.tid_tx[tid]->pending,
387 &local->pending[queue]);
388 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
389 }
390}
391
392static void ieee80211_agg_splice_finish(struct ieee80211_local *local,
393 struct sta_info *sta, u16 tid)
394{
395 u16 queue = ieee80211_ac_from_tid(tid);
396
397 ieee80211_wake_queue_by_reason(
398 &local->hw, queue,
399 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
400}
401
402/* caller must hold sta->lock */
403static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
404 struct sta_info *sta, u16 tid)
405{
406#ifdef CONFIG_MAC80211_HT_DEBUG
407 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
408#endif
409
410 spin_lock(&local->ampdu_lock);
411 ieee80211_agg_splice_packets(local, sta, tid);
412 /*
413 * NB: we rely on sta->lock being taken in the TX
414 * processing here when adding to the pending queue,
415 * otherwise we could only change the state of the
416 * session to OPERATIONAL _here_.
417 */
418 ieee80211_agg_splice_finish(local, sta, tid);
419 spin_unlock(&local->ampdu_lock);
420
421 local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL,
422 &sta->sta, tid, NULL);
423}
424
398void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) 425void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
399{ 426{
400 struct ieee80211_local *local = hw_to_local(hw); 427 struct ieee80211_local *local = hw_to_local(hw);
@@ -437,20 +464,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
437 464
438 *state |= HT_ADDBA_DRV_READY_MSK; 465 *state |= HT_ADDBA_DRV_READY_MSK;
439 466
440 if (*state == HT_AGG_STATE_OPERATIONAL) { 467 if (*state == HT_AGG_STATE_OPERATIONAL)
441#ifdef CONFIG_MAC80211_HT_DEBUG 468 ieee80211_agg_tx_operational(local, sta, tid);
442 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
443#endif
444 if (hw->ampdu_queues) {
445 /*
446 * Wake up this queue, we stopped it earlier,
447 * this will in turn wake the entire AC.
448 */
449 ieee80211_wake_queue_by_reason(hw,
450 hw->queues + sta->tid_to_tx_q[tid],
451 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
452 }
453 }
454 469
455 out: 470 out:
456 spin_unlock_bh(&sta->lock); 471 spin_unlock_bh(&sta->lock);
@@ -584,22 +599,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
584 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); 599 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
585 600
586 spin_lock_bh(&sta->lock); 601 spin_lock_bh(&sta->lock);
602 spin_lock(&local->ampdu_lock);
587 603
588 if (*state & HT_AGG_STATE_INITIATOR_MSK && 604 ieee80211_agg_splice_packets(local, sta, tid);
589 hw->ampdu_queues) {
590 /*
591 * Wake up this queue, we stopped it earlier,
592 * this will in turn wake the entire AC.
593 */
594 ieee80211_wake_queue_by_reason(hw,
595 hw->queues + sta->tid_to_tx_q[tid],
596 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
597 }
598 605
599 *state = HT_AGG_STATE_IDLE; 606 *state = HT_AGG_STATE_IDLE;
607 /* from now on packets are no longer put onto sta->pending */
600 sta->ampdu_mlme.addba_req_num[tid] = 0; 608 sta->ampdu_mlme.addba_req_num[tid] = 0;
601 kfree(sta->ampdu_mlme.tid_tx[tid]); 609 kfree(sta->ampdu_mlme.tid_tx[tid]);
602 sta->ampdu_mlme.tid_tx[tid] = NULL; 610 sta->ampdu_mlme.tid_tx[tid] = NULL;
611
612 ieee80211_agg_splice_finish(local, sta, tid);
613
614 spin_unlock(&local->ampdu_lock);
603 spin_unlock_bh(&sta->lock); 615 spin_unlock_bh(&sta->lock);
604 616
605 rcu_read_unlock(); 617 rcu_read_unlock();
@@ -637,9 +649,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
637 struct ieee80211_mgmt *mgmt, 649 struct ieee80211_mgmt *mgmt,
638 size_t len) 650 size_t len)
639{ 651{
640 struct ieee80211_hw *hw = &local->hw; 652 u16 capab, tid;
641 u16 capab;
642 u16 tid, start_seq_num;
643 u8 *state; 653 u8 *state;
644 654
645 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); 655 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
@@ -673,26 +683,10 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
673 683
674 *state |= HT_ADDBA_RECEIVED_MSK; 684 *state |= HT_ADDBA_RECEIVED_MSK;
675 685
676 if (hw->ampdu_queues && *state != curstate && 686 if (*state != curstate && *state == HT_AGG_STATE_OPERATIONAL)
677 *state == HT_AGG_STATE_OPERATIONAL) { 687 ieee80211_agg_tx_operational(local, sta, tid);
678 /*
679 * Wake up this queue, we stopped it earlier,
680 * this will in turn wake the entire AC.
681 */
682 ieee80211_wake_queue_by_reason(hw,
683 hw->queues + sta->tid_to_tx_q[tid],
684 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
685 }
686 sta->ampdu_mlme.addba_req_num[tid] = 0;
687 688
688 if (local->ops->ampdu_action) { 689 sta->ampdu_mlme.addba_req_num[tid] = 0;
689 (void)local->ops->ampdu_action(hw,
690 IEEE80211_AMPDU_TX_RESUME,
691 &sta->sta, tid, &start_seq_num);
692 }
693#ifdef CONFIG_MAC80211_HT_DEBUG
694 printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
695#endif /* CONFIG_MAC80211_HT_DEBUG */
696 } else { 690 } else {
697 sta->ampdu_mlme.addba_req_num[tid]++; 691 sta->ampdu_mlme.addba_req_num[tid]++;
698 ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); 692 ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);