aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/xmit.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c112
1 files changed, 37 insertions, 75 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index eab0fcb7ded6..1c9b1bac8b0d 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -125,24 +125,6 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
125 list_add_tail(&ac->list, &txq->axq_acq); 125 list_add_tail(&ac->list, &txq->axq_acq);
126} 126}
127 127
128static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
129{
130 struct ath_txq *txq = tid->ac->txq;
131
132 WARN_ON(!tid->paused);
133
134 ath_txq_lock(sc, txq);
135 tid->paused = false;
136
137 if (skb_queue_empty(&tid->buf_q))
138 goto unlock;
139
140 ath_tx_queue_tid(txq, tid);
141 ath_txq_schedule(sc, txq);
142unlock:
143 ath_txq_unlock_complete(sc, txq);
144}
145
146static struct ath_frame_info *get_frame_info(struct sk_buff *skb) 128static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
147{ 129{
148 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 130 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -201,11 +183,6 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
201 } 183 }
202 } 184 }
203 185
204 if (tid->baw_head == tid->baw_tail) {
205 tid->state &= ~AGGR_ADDBA_COMPLETE;
206 tid->state &= ~AGGR_CLEANUP;
207 }
208
209 if (sendbar) { 186 if (sendbar) {
210 ath_txq_unlock(sc, txq); 187 ath_txq_unlock(sc, txq);
211 ath_send_bar(tid, tid->seq_start); 188 ath_send_bar(tid, tid->seq_start);
@@ -277,9 +254,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
277 254
278 list_add_tail(&bf->list, &bf_head); 255 list_add_tail(&bf->list, &bf_head);
279 256
280 if (fi->retries) 257 ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
281 ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
282
283 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); 258 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
284 } 259 }
285 260
@@ -491,19 +466,19 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
491 tx_info = IEEE80211_SKB_CB(skb); 466 tx_info = IEEE80211_SKB_CB(skb);
492 fi = get_frame_info(skb); 467 fi = get_frame_info(skb);
493 468
494 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { 469 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
470 /*
471 * Outside of the current BlockAck window,
472 * maybe part of a previous session
473 */
474 txfail = 1;
475 } else if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) {
495 /* transmit completion, subframe is 476 /* transmit completion, subframe is
496 * acked by block ack */ 477 * acked by block ack */
497 acked_cnt++; 478 acked_cnt++;
498 } else if (!isaggr && txok) { 479 } else if (!isaggr && txok) {
499 /* transmit completion */ 480 /* transmit completion */
500 acked_cnt++; 481 acked_cnt++;
501 } else if (tid->state & AGGR_CLEANUP) {
502 /*
503 * cleanup in progress, just fail
504 * the un-acked sub-frames
505 */
506 txfail = 1;
507 } else if (flush) { 482 } else if (flush) {
508 txpending = 1; 483 txpending = 1;
509 } else if (fi->retries < ATH_MAX_SW_RETRIES) { 484 } else if (fi->retries < ATH_MAX_SW_RETRIES) {
@@ -527,7 +502,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
527 if (bf_next != NULL || !bf_last->bf_stale) 502 if (bf_next != NULL || !bf_last->bf_stale)
528 list_move_tail(&bf->list, &bf_head); 503 list_move_tail(&bf->list, &bf_head);
529 504
530 if (!txpending || (tid->state & AGGR_CLEANUP)) { 505 if (!txpending) {
531 /* 506 /*
532 * complete the acked-ones/xretried ones; update 507 * complete the acked-ones/xretried ones; update
533 * block-ack window 508 * block-ack window
@@ -601,9 +576,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
601 ath_txq_lock(sc, txq); 576 ath_txq_lock(sc, txq);
602 } 577 }
603 578
604 if (tid->state & AGGR_CLEANUP)
605 ath_tx_flush_tid(sc, tid);
606
607 rcu_read_unlock(); 579 rcu_read_unlock();
608 580
609 if (needreset) 581 if (needreset)
@@ -620,6 +592,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
620 struct ath_tx_status *ts, struct ath_buf *bf, 592 struct ath_tx_status *ts, struct ath_buf *bf,
621 struct list_head *bf_head) 593 struct list_head *bf_head)
622{ 594{
595 struct ieee80211_tx_info *info;
623 bool txok, flush; 596 bool txok, flush;
624 597
625 txok = !(ts->ts_status & ATH9K_TXERR_MASK); 598 txok = !(ts->ts_status & ATH9K_TXERR_MASK);
@@ -631,8 +604,12 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
631 txq->axq_ampdu_depth--; 604 txq->axq_ampdu_depth--;
632 605
633 if (!bf_isampdu(bf)) { 606 if (!bf_isampdu(bf)) {
634 if (!flush) 607 if (!flush) {
608 info = IEEE80211_SKB_CB(bf->bf_mpdu);
609 memcpy(info->control.rates, bf->rates,
610 sizeof(info->control.rates));
635 ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); 611 ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
612 }
636 ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); 613 ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
637 } else 614 } else
638 ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); 615 ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
@@ -676,7 +653,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
676 653
677 skb = bf->bf_mpdu; 654 skb = bf->bf_mpdu;
678 tx_info = IEEE80211_SKB_CB(skb); 655 tx_info = IEEE80211_SKB_CB(skb);
679 rates = tx_info->control.rates; 656 rates = bf->rates;
680 657
681 /* 658 /*
682 * Find the lowest frame length among the rate series that will have a 659 * Find the lowest frame length among the rate series that will have a
@@ -1231,9 +1208,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
1231 an = (struct ath_node *)sta->drv_priv; 1208 an = (struct ath_node *)sta->drv_priv;
1232 txtid = ATH_AN_2_TID(an, tid); 1209 txtid = ATH_AN_2_TID(an, tid);
1233 1210
1234 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
1235 return -EAGAIN;
1236
1237 /* update ampdu factor/density, they may have changed. This may happen 1211 /* update ampdu factor/density, they may have changed. This may happen
1238 * in HT IBSS when a beacon with HT-info is received after the station 1212 * in HT IBSS when a beacon with HT-info is received after the station
1239 * has already been added. 1213 * has already been added.
@@ -1245,7 +1219,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
1245 an->mpdudensity = density; 1219 an->mpdudensity = density;
1246 } 1220 }
1247 1221
1248 txtid->state |= AGGR_ADDBA_PROGRESS; 1222 txtid->active = true;
1249 txtid->paused = true; 1223 txtid->paused = true;
1250 *ssn = txtid->seq_start = txtid->seq_next; 1224 *ssn = txtid->seq_start = txtid->seq_next;
1251 txtid->bar_index = -1; 1225 txtid->bar_index = -1;
@@ -1262,28 +1236,9 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
1262 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); 1236 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
1263 struct ath_txq *txq = txtid->ac->txq; 1237 struct ath_txq *txq = txtid->ac->txq;
1264 1238
1265 if (txtid->state & AGGR_CLEANUP)
1266 return;
1267
1268 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
1269 txtid->state &= ~AGGR_ADDBA_PROGRESS;
1270 return;
1271 }
1272
1273 ath_txq_lock(sc, txq); 1239 ath_txq_lock(sc, txq);
1240 txtid->active = false;
1274 txtid->paused = true; 1241 txtid->paused = true;
1275
1276 /*
1277 * If frames are still being transmitted for this TID, they will be
1278 * cleaned up during tx completion. To prevent race conditions, this
1279 * TID can only be reused after all in-progress subframes have been
1280 * completed.
1281 */
1282 if (txtid->baw_head != txtid->baw_tail)
1283 txtid->state |= AGGR_CLEANUP;
1284 else
1285 txtid->state &= ~AGGR_ADDBA_COMPLETE;
1286
1287 ath_tx_flush_tid(sc, txtid); 1242 ath_tx_flush_tid(sc, txtid);
1288 ath_txq_unlock_complete(sc, txq); 1243 ath_txq_unlock_complete(sc, txq);
1289} 1244}
@@ -1349,18 +1304,28 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
1349 } 1304 }
1350} 1305}
1351 1306
1352void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) 1307void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
1308 u16 tidno)
1353{ 1309{
1354 struct ath_atx_tid *txtid; 1310 struct ath_atx_tid *tid;
1355 struct ath_node *an; 1311 struct ath_node *an;
1312 struct ath_txq *txq;
1356 1313
1357 an = (struct ath_node *)sta->drv_priv; 1314 an = (struct ath_node *)sta->drv_priv;
1315 tid = ATH_AN_2_TID(an, tidno);
1316 txq = tid->ac->txq;
1358 1317
1359 txtid = ATH_AN_2_TID(an, tid); 1318 ath_txq_lock(sc, txq);
1360 txtid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; 1319
1361 txtid->state |= AGGR_ADDBA_COMPLETE; 1320 tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
1362 txtid->state &= ~AGGR_ADDBA_PROGRESS; 1321 tid->paused = false;
1363 ath_tx_resume_tid(sc, txtid); 1322
1323 if (!skb_queue_empty(&tid->buf_q)) {
1324 ath_tx_queue_tid(txq, tid);
1325 ath_txq_schedule(sc, txq);
1326 }
1327
1328 ath_txq_unlock_complete(sc, txq);
1364} 1329}
1365 1330
1366/********************/ 1331/********************/
@@ -2409,12 +2374,10 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2409 tid->baw_head = tid->baw_tail = 0; 2374 tid->baw_head = tid->baw_tail = 0;
2410 tid->sched = false; 2375 tid->sched = false;
2411 tid->paused = false; 2376 tid->paused = false;
2412 tid->state &= ~AGGR_CLEANUP; 2377 tid->active = false;
2413 __skb_queue_head_init(&tid->buf_q); 2378 __skb_queue_head_init(&tid->buf_q);
2414 acno = TID_TO_WME_AC(tidno); 2379 acno = TID_TO_WME_AC(tidno);
2415 tid->ac = &an->ac[acno]; 2380 tid->ac = &an->ac[acno];
2416 tid->state &= ~AGGR_ADDBA_COMPLETE;
2417 tid->state &= ~AGGR_ADDBA_PROGRESS;
2418 } 2381 }
2419 2382
2420 for (acno = 0, ac = &an->ac[acno]; 2383 for (acno = 0, ac = &an->ac[acno];
@@ -2451,8 +2414,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
2451 } 2414 }
2452 2415
2453 ath_tid_drain(sc, txq, tid); 2416 ath_tid_drain(sc, txq, tid);
2454 tid->state &= ~AGGR_ADDBA_COMPLETE; 2417 tid->active = false;
2455 tid->state &= ~AGGR_CLEANUP;
2456 2418
2457 ath_txq_unlock(sc, txq); 2419 ath_txq_unlock(sc, txq);
2458 } 2420 }