aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/xmit.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-06-24 19:26:16 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-28 15:16:19 -0400
commit78c4653a2274479547e259e1f416d2b3d04c42a8 (patch)
tree84249c1c0d2cc299c6422347653651406c6a0d01 /drivers/net/wireless/ath/ath9k/xmit.c
parent6665b54e79d52c813914481783d82398ca2451f6 (diff)
ath9k: fix retry count for A-MPDU rate control status reports
The 'bf_retries' field of the ath_buf structure was used for both software retries (AMPDU subframes) and hardware retries (legacy frames). This led to a wrong retry count being reported for the A-MPDU rate control stats. This patch changes the code to no longer use bf_retries for reporting retry counts, but instead always using the real on-chip retry count from the ath_tx_status. Additionally, if the first subframe of an A-MPDU was not acked, the tx status report is submitted along with the first acked subframe, which may not contain the correct rates in the tx info. This is easily corrected by saving the tx rate info before looping over subframes, and then copying it back once the A-MPDU status report is submitted. In my tests this change improves throughput visibly. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Reported-by: Björn Smedman <bjorn.smedman@venatech.se> Cc: stable@kernel.org Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index c41185b28c0a..c3681a1dc941 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -328,6 +328,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
328 u32 ba[WME_BA_BMP_SIZE >> 5]; 328 u32 ba[WME_BA_BMP_SIZE >> 5];
329 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; 329 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
330 bool rc_update = true; 330 bool rc_update = true;
331 struct ieee80211_tx_rate rates[4];
331 332
332 skb = bf->bf_mpdu; 333 skb = bf->bf_mpdu;
333 hdr = (struct ieee80211_hdr *)skb->data; 334 hdr = (struct ieee80211_hdr *)skb->data;
@@ -335,6 +336,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
335 tx_info = IEEE80211_SKB_CB(skb); 336 tx_info = IEEE80211_SKB_CB(skb);
336 hw = bf->aphy->hw; 337 hw = bf->aphy->hw;
337 338
339 memcpy(rates, tx_info->control.rates, sizeof(rates));
340
338 rcu_read_lock(); 341 rcu_read_lock();
339 342
340 /* XXX: use ieee80211_find_sta! */ 343 /* XXX: use ieee80211_find_sta! */
@@ -375,6 +378,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
375 txfail = txpending = 0; 378 txfail = txpending = 0;
376 bf_next = bf->bf_next; 379 bf_next = bf->bf_next;
377 380
381 skb = bf->bf_mpdu;
382 tx_info = IEEE80211_SKB_CB(skb);
383
378 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { 384 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
379 /* transmit completion, subframe is 385 /* transmit completion, subframe is
380 * acked by block ack */ 386 * acked by block ack */
@@ -428,6 +434,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
428 spin_unlock_bh(&txq->axq_lock); 434 spin_unlock_bh(&txq->axq_lock);
429 435
430 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { 436 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
437 memcpy(tx_info->control.rates, rates, sizeof(rates));
431 ath_tx_rc_status(bf, ts, nbad, txok, true); 438 ath_tx_rc_status(bf, ts, nbad, txok, true);
432 rc_update = false; 439 rc_update = false;
433 } else { 440 } else {
@@ -2033,7 +2040,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
2033 tx_info->status.rates[i].idx = -1; 2040 tx_info->status.rates[i].idx = -1;
2034 } 2041 }
2035 2042
2036 tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1; 2043 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
2037} 2044}
2038 2045
2039static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) 2046static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
@@ -2144,7 +2151,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
2144 * This frame is sent out as a single frame. 2151 * This frame is sent out as a single frame.
2145 * Use hardware retry status for this frame. 2152 * Use hardware retry status for this frame.
2146 */ 2153 */
2147 bf->bf_retries = ts.ts_longretry;
2148 if (ts.ts_status & ATH9K_TXERR_XRETRY) 2154 if (ts.ts_status & ATH9K_TXERR_XRETRY)
2149 bf->bf_state.bf_type |= BUF_XRETRY; 2155 bf->bf_state.bf_type |= BUF_XRETRY;
2150 ath_tx_rc_status(bf, &ts, 0, txok, true); 2156 ath_tx_rc_status(bf, &ts, 0, txok, true);
@@ -2274,7 +2280,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
2274 } 2280 }
2275 2281
2276 if (!bf_isampdu(bf)) { 2282 if (!bf_isampdu(bf)) {
2277 bf->bf_retries = txs.ts_longretry;
2278 if (txs.ts_status & ATH9K_TXERR_XRETRY) 2283 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2279 bf->bf_state.bf_type |= BUF_XRETRY; 2284 bf->bf_state.bf_type |= BUF_XRETRY;
2280 ath_tx_rc_status(bf, &txs, 0, txok, true); 2285 ath_tx_rc_status(bf, &txs, 0, txok, true);