aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorBjörn Smedman <bjorn.smedman@venatech.se>2010-10-10 16:44:39 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-11 15:04:24 -0400
commitebd022873aa61937603d2c4dfea19ce63ea1a3c8 (patch)
tree2801c6da6f7481cb2ebae440282780c9e5b611df /drivers/net/wireless
parent15d46f38df87f89242e470f5797120fa384c1fc3 (diff)
ath9k: A-MPDU rate control info fix
This patch fixes the following problems with the rate control feedback generated by ath9k for A-MPDU frames: 1. Rate control feedback is carried on the first frame of an aggregate that is either ACKed, or has execeeded the software retry count and is considered failed. However, ath9k would incorrectly assume the aggregate had the length 1 if one of these conditions did not apply to the first frame of the aggregate, but instead a later frame. This fix therefor copies the bf_nframes field of the buffer in the same manner as the rates field of the tx status. 2. Sometimes the ampdu_len and ampdu_ack_len fields of the tx status was left uninitialized eventhough the IEEE80211_TX_STAT_AMPDU flag was set. This is now avoid by setting flag and fields in the same place. 3. Even if a frame has been selected for aggregation by mac80211 and marked with the IEEE80211_TX_CTL_AMPDU flag it can sometimes happen that ath9k transmits the frame without aggregation. In these cases the ampdu_ack_len field could be incorrectly computed because the nbad parameter to ath_tx_rc_status was incorrect. Cc: <stable@kernel.org> Signed-off-by: Björn Smedman <bjorn.smedman@venatech.se> Acked-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index aa447770eb2b..9a11099dd86a 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -317,6 +317,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
317 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; 317 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
318 bool rc_update = true; 318 bool rc_update = true;
319 struct ieee80211_tx_rate rates[4]; 319 struct ieee80211_tx_rate rates[4];
320 int nframes;
320 321
321 skb = bf->bf_mpdu; 322 skb = bf->bf_mpdu;
322 hdr = (struct ieee80211_hdr *)skb->data; 323 hdr = (struct ieee80211_hdr *)skb->data;
@@ -325,6 +326,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
325 hw = bf->aphy->hw; 326 hw = bf->aphy->hw;
326 327
327 memcpy(rates, tx_info->control.rates, sizeof(rates)); 328 memcpy(rates, tx_info->control.rates, sizeof(rates));
329 nframes = bf->bf_nframes;
328 330
329 rcu_read_lock(); 331 rcu_read_lock();
330 332
@@ -341,7 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
341 !bf->bf_stale || bf_next != NULL) 343 !bf->bf_stale || bf_next != NULL)
342 list_move_tail(&bf->list, &bf_head); 344 list_move_tail(&bf->list, &bf_head);
343 345
344 ath_tx_rc_status(bf, ts, 0, 0, false); 346 ath_tx_rc_status(bf, ts, 1, 0, false);
345 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 347 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
346 0, 0); 348 0, 0);
347 349
@@ -446,6 +448,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
446 448
447 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { 449 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
448 memcpy(tx_info->control.rates, rates, sizeof(rates)); 450 memcpy(tx_info->control.rates, rates, sizeof(rates));
451 bf->bf_nframes = nframes;
449 ath_tx_rc_status(bf, ts, nbad, txok, true); 452 ath_tx_rc_status(bf, ts, nbad, txok, true);
450 rc_update = false; 453 rc_update = false;
451 } else { 454 } else {
@@ -1979,9 +1982,15 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
1979 1982
1980 if (ts->ts_status & ATH9K_TXERR_FILT) 1983 if (ts->ts_status & ATH9K_TXERR_FILT)
1981 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; 1984 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
1982 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) 1985 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
1983 tx_info->flags |= IEEE80211_TX_STAT_AMPDU; 1986 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
1984 1987
1988 BUG_ON(nbad > bf->bf_nframes);
1989
1990 tx_info->status.ampdu_len = bf->bf_nframes;
1991 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
1992 }
1993
1985 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && 1994 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
1986 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { 1995 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
1987 if (ieee80211_is_data(hdr->frame_control)) { 1996 if (ieee80211_is_data(hdr->frame_control)) {
@@ -1991,8 +2000,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
1991 if ((ts->ts_status & ATH9K_TXERR_XRETRY) || 2000 if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
1992 (ts->ts_status & ATH9K_TXERR_FIFO)) 2001 (ts->ts_status & ATH9K_TXERR_FIFO))
1993 tx_info->pad[0] |= ATH_TX_INFO_XRETRY; 2002 tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
1994 tx_info->status.ampdu_len = bf->bf_nframes;
1995 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
1996 } 2003 }
1997 } 2004 }
1998 2005
@@ -2102,7 +2109,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
2102 */ 2109 */
2103 if (ts.ts_status & ATH9K_TXERR_XRETRY) 2110 if (ts.ts_status & ATH9K_TXERR_XRETRY)
2104 bf->bf_state.bf_type |= BUF_XRETRY; 2111 bf->bf_state.bf_type |= BUF_XRETRY;
2105 ath_tx_rc_status(bf, &ts, 0, txok, true); 2112 ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
2106 } 2113 }
2107 2114
2108 if (bf_isampdu(bf)) 2115 if (bf_isampdu(bf))
@@ -2220,7 +2227,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
2220 if (!bf_isampdu(bf)) { 2227 if (!bf_isampdu(bf)) {
2221 if (txs.ts_status & ATH9K_TXERR_XRETRY) 2228 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2222 bf->bf_state.bf_type |= BUF_XRETRY; 2229 bf->bf_state.bf_type |= BUF_XRETRY;
2223 ath_tx_rc_status(bf, &txs, 0, txok, true); 2230 ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
2224 } 2231 }
2225 2232
2226 if (bf_isampdu(bf)) 2233 if (bf_isampdu(bf))