diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 112 |
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 | ||
128 | static 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); | ||
142 | unlock: | ||
143 | ath_txq_unlock_complete(sc, txq); | ||
144 | } | ||
145 | |||
146 | static struct ath_frame_info *get_frame_info(struct sk_buff *skb) | 128 | static 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 | ||
1352 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) | 1307 | void 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 | } |