diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 74 |
1 files changed, 48 insertions, 26 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index eab0fcb7ded6..14bb3354ea64 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -164,7 +164,20 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, | |||
164 | ARRAY_SIZE(bf->rates)); | 164 | ARRAY_SIZE(bf->rates)); |
165 | } | 165 | } |
166 | 166 | ||
167 | static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) | 167 | static void ath_tx_clear_tid(struct ath_softc *sc, struct ath_atx_tid *tid) |
168 | { | ||
169 | tid->state &= ~AGGR_ADDBA_COMPLETE; | ||
170 | tid->state &= ~AGGR_CLEANUP; | ||
171 | if (!tid->stop_cb) | ||
172 | return; | ||
173 | |||
174 | ieee80211_start_tx_ba_cb_irqsafe(tid->an->vif, tid->an->sta->addr, | ||
175 | tid->tidno); | ||
176 | tid->stop_cb = false; | ||
177 | } | ||
178 | |||
179 | static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid, | ||
180 | bool flush_packets) | ||
168 | { | 181 | { |
169 | struct ath_txq *txq = tid->ac->txq; | 182 | struct ath_txq *txq = tid->ac->txq; |
170 | struct sk_buff *skb; | 183 | struct sk_buff *skb; |
@@ -181,16 +194,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) | |||
181 | while ((skb = __skb_dequeue(&tid->buf_q))) { | 194 | while ((skb = __skb_dequeue(&tid->buf_q))) { |
182 | fi = get_frame_info(skb); | 195 | fi = get_frame_info(skb); |
183 | bf = fi->bf; | 196 | bf = fi->bf; |
197 | if (!bf && !flush_packets) | ||
198 | bf = ath_tx_setup_buffer(sc, txq, tid, skb); | ||
184 | 199 | ||
185 | if (!bf) { | 200 | if (!bf) { |
186 | bf = ath_tx_setup_buffer(sc, txq, tid, skb); | 201 | ieee80211_free_txskb(sc->hw, skb); |
187 | if (!bf) { | 202 | continue; |
188 | ieee80211_free_txskb(sc->hw, skb); | ||
189 | continue; | ||
190 | } | ||
191 | } | 203 | } |
192 | 204 | ||
193 | if (fi->retries) { | 205 | if (fi->retries || flush_packets) { |
194 | list_add_tail(&bf->list, &bf_head); | 206 | list_add_tail(&bf->list, &bf_head); |
195 | ath_tx_update_baw(sc, tid, bf->bf_state.seqno); | 207 | ath_tx_update_baw(sc, tid, bf->bf_state.seqno); |
196 | ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); | 208 | ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); |
@@ -201,12 +213,10 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) | |||
201 | } | 213 | } |
202 | } | 214 | } |
203 | 215 | ||
204 | if (tid->baw_head == tid->baw_tail) { | 216 | if (tid->baw_head == tid->baw_tail) |
205 | tid->state &= ~AGGR_ADDBA_COMPLETE; | 217 | ath_tx_clear_tid(sc, tid); |
206 | tid->state &= ~AGGR_CLEANUP; | ||
207 | } | ||
208 | 218 | ||
209 | if (sendbar) { | 219 | if (sendbar && !flush_packets) { |
210 | ath_txq_unlock(sc, txq); | 220 | ath_txq_unlock(sc, txq); |
211 | ath_send_bar(tid, tid->seq_start); | 221 | ath_send_bar(tid, tid->seq_start); |
212 | ath_txq_lock(sc, txq); | 222 | ath_txq_lock(sc, txq); |
@@ -277,9 +287,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, | |||
277 | 287 | ||
278 | list_add_tail(&bf->list, &bf_head); | 288 | list_add_tail(&bf->list, &bf_head); |
279 | 289 | ||
280 | if (fi->retries) | 290 | 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); | 291 | ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); |
284 | } | 292 | } |
285 | 293 | ||
@@ -602,7 +610,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
602 | } | 610 | } |
603 | 611 | ||
604 | if (tid->state & AGGR_CLEANUP) | 612 | if (tid->state & AGGR_CLEANUP) |
605 | ath_tx_flush_tid(sc, tid); | 613 | ath_tx_flush_tid(sc, tid, false); |
606 | 614 | ||
607 | rcu_read_unlock(); | 615 | rcu_read_unlock(); |
608 | 616 | ||
@@ -620,6 +628,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, | 628 | struct ath_tx_status *ts, struct ath_buf *bf, |
621 | struct list_head *bf_head) | 629 | struct list_head *bf_head) |
622 | { | 630 | { |
631 | struct ieee80211_tx_info *info; | ||
623 | bool txok, flush; | 632 | bool txok, flush; |
624 | 633 | ||
625 | txok = !(ts->ts_status & ATH9K_TXERR_MASK); | 634 | txok = !(ts->ts_status & ATH9K_TXERR_MASK); |
@@ -631,8 +640,12 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, | |||
631 | txq->axq_ampdu_depth--; | 640 | txq->axq_ampdu_depth--; |
632 | 641 | ||
633 | if (!bf_isampdu(bf)) { | 642 | if (!bf_isampdu(bf)) { |
634 | if (!flush) | 643 | if (!flush) { |
644 | info = IEEE80211_SKB_CB(bf->bf_mpdu); | ||
645 | memcpy(info->control.rates, bf->rates, | ||
646 | sizeof(info->control.rates)); | ||
635 | ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); | 647 | ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); |
648 | } | ||
636 | ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); | 649 | ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); |
637 | } else | 650 | } else |
638 | ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); | 651 | ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); |
@@ -676,7 +689,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, | |||
676 | 689 | ||
677 | skb = bf->bf_mpdu; | 690 | skb = bf->bf_mpdu; |
678 | tx_info = IEEE80211_SKB_CB(skb); | 691 | tx_info = IEEE80211_SKB_CB(skb); |
679 | rates = tx_info->control.rates; | 692 | rates = bf->rates; |
680 | 693 | ||
681 | /* | 694 | /* |
682 | * Find the lowest frame length among the rate series that will have a | 695 | * Find the lowest frame length among the rate series that will have a |
@@ -1256,18 +1269,23 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | |||
1256 | return 0; | 1269 | return 0; |
1257 | } | 1270 | } |
1258 | 1271 | ||
1259 | void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) | 1272 | bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, |
1273 | bool flush) | ||
1260 | { | 1274 | { |
1261 | struct ath_node *an = (struct ath_node *)sta->drv_priv; | 1275 | struct ath_node *an = (struct ath_node *)sta->drv_priv; |
1262 | struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); | 1276 | struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); |
1263 | struct ath_txq *txq = txtid->ac->txq; | 1277 | struct ath_txq *txq = txtid->ac->txq; |
1278 | bool ret = !flush; | ||
1279 | |||
1280 | if (flush) | ||
1281 | txtid->stop_cb = false; | ||
1264 | 1282 | ||
1265 | if (txtid->state & AGGR_CLEANUP) | 1283 | if (txtid->state & AGGR_CLEANUP) |
1266 | return; | 1284 | return false; |
1267 | 1285 | ||
1268 | if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { | 1286 | if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { |
1269 | txtid->state &= ~AGGR_ADDBA_PROGRESS; | 1287 | txtid->state &= ~AGGR_ADDBA_PROGRESS; |
1270 | return; | 1288 | return ret; |
1271 | } | 1289 | } |
1272 | 1290 | ||
1273 | ath_txq_lock(sc, txq); | 1291 | ath_txq_lock(sc, txq); |
@@ -1279,13 +1297,17 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) | |||
1279 | * TID can only be reused after all in-progress subframes have been | 1297 | * TID can only be reused after all in-progress subframes have been |
1280 | * completed. | 1298 | * completed. |
1281 | */ | 1299 | */ |
1282 | if (txtid->baw_head != txtid->baw_tail) | 1300 | if (txtid->baw_head != txtid->baw_tail) { |
1283 | txtid->state |= AGGR_CLEANUP; | 1301 | txtid->state |= AGGR_CLEANUP; |
1284 | else | 1302 | ret = false; |
1303 | txtid->stop_cb = !flush; | ||
1304 | } else { | ||
1285 | txtid->state &= ~AGGR_ADDBA_COMPLETE; | 1305 | txtid->state &= ~AGGR_ADDBA_COMPLETE; |
1306 | } | ||
1286 | 1307 | ||
1287 | ath_tx_flush_tid(sc, txtid); | 1308 | ath_tx_flush_tid(sc, txtid, flush); |
1288 | ath_txq_unlock_complete(sc, txq); | 1309 | ath_txq_unlock_complete(sc, txq); |
1310 | return ret; | ||
1289 | } | 1311 | } |
1290 | 1312 | ||
1291 | void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, | 1313 | void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, |
@@ -2415,6 +2437,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) | |||
2415 | tid->ac = &an->ac[acno]; | 2437 | tid->ac = &an->ac[acno]; |
2416 | tid->state &= ~AGGR_ADDBA_COMPLETE; | 2438 | tid->state &= ~AGGR_ADDBA_COMPLETE; |
2417 | tid->state &= ~AGGR_ADDBA_PROGRESS; | 2439 | tid->state &= ~AGGR_ADDBA_PROGRESS; |
2440 | tid->stop_cb = false; | ||
2418 | } | 2441 | } |
2419 | 2442 | ||
2420 | for (acno = 0, ac = &an->ac[acno]; | 2443 | for (acno = 0, ac = &an->ac[acno]; |
@@ -2451,8 +2474,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) | |||
2451 | } | 2474 | } |
2452 | 2475 | ||
2453 | ath_tid_drain(sc, txq, tid); | 2476 | ath_tid_drain(sc, txq, tid); |
2454 | tid->state &= ~AGGR_ADDBA_COMPLETE; | 2477 | ath_tx_clear_tid(sc, tid); |
2455 | tid->state &= ~AGGR_CLEANUP; | ||
2456 | 2478 | ||
2457 | ath_txq_unlock(sc, txq); | 2479 | ath_txq_unlock(sc, txq); |
2458 | } | 2480 | } |