Commit 0934af23 authored by Vasanthakumar Thiagarajan's avatar Vasanthakumar Thiagarajan Committed by John W. Linville

ath9k: Fix rate control update for aggregated frames

We will miss rate control update if first A-MPDU of an
aggregation is not Block Acked as we always tell if the
rate control needs to updated through update_rc of first
A-MPDU. This patch does rate control update for the first
A-MPDU which notifies it's tx status (which is not
necessarily the first A-MPDU of an aggregation) to mac80211.
Signed-off-by: default avatarVasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b3a90285
...@@ -64,6 +64,10 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, ...@@ -64,6 +64,10 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
struct list_head *head); struct list_head *head);
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf); static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
int txok);
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
int nbad, int txok);
/*********************/ /*********************/
/* Aggregation logic */ /* Aggregation logic */
...@@ -274,9 +278,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -274,9 +278,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
struct ath_desc *ds = bf_last->bf_desc; struct ath_desc *ds = bf_last->bf_desc;
struct list_head bf_head, bf_pending; struct list_head bf_head, bf_pending;
u16 seq_st = 0; u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
u32 ba[WME_BA_BMP_SIZE >> 5]; u32 ba[WME_BA_BMP_SIZE >> 5];
int isaggr, txfail, txpending, sendbar = 0, needreset = 0; int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
bool rc_update = true;
skb = (struct sk_buff *)bf->bf_mpdu; skb = (struct sk_buff *)bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
...@@ -316,6 +321,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -316,6 +321,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_pending); INIT_LIST_HEAD(&bf_pending);
INIT_LIST_HEAD(&bf_head); INIT_LIST_HEAD(&bf_head);
nbad = ath_tx_num_badfrms(sc, bf, txok);
while (bf) { while (bf) {
txfail = txpending = 0; txfail = txpending = 0;
bf_next = bf->bf_next; bf_next = bf->bf_next;
...@@ -323,8 +329,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -323,8 +329,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
/* transmit completion, subframe is /* transmit completion, subframe is
* acked by block ack */ * acked by block ack */
acked_cnt++;
} else if (!isaggr && txok) { } else if (!isaggr && txok) {
/* transmit completion */ /* transmit completion */
acked_cnt++;
} else { } else {
if (!(tid->state & AGGR_CLEANUP) && if (!(tid->state & AGGR_CLEANUP) &&
ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
...@@ -335,6 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -335,6 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_state.bf_type |= BUF_XRETRY; bf->bf_state.bf_type |= BUF_XRETRY;
txfail = 1; txfail = 1;
sendbar = 1; sendbar = 1;
txfail_cnt++;
} }
} else { } else {
/* /*
...@@ -361,6 +370,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -361,6 +370,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_update_baw(sc, tid, bf->bf_seqno); ath_tx_update_baw(sc, tid, bf->bf_seqno);
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
if (rc_update)
if (acked_cnt == 1 || txfail_cnt == 1) {
ath_tx_rc_status(bf, ds, nbad, txok);
rc_update = false;
}
ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar);
} else { } else {
/* retry the un-acked ones */ /* retry the un-acked ones */
...@@ -1901,7 +1915,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ...@@ -1901,7 +1915,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
struct ath_buf *bf, *lastbf, *bf_held = NULL; struct ath_buf *bf, *lastbf, *bf_held = NULL;
struct list_head bf_head; struct list_head bf_head;
struct ath_desc *ds; struct ath_desc *ds;
int txok, nbad = 0; int txok;
int status; int status;
DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
...@@ -1995,13 +2009,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ...@@ -1995,13 +2009,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
bf->bf_retries = ds->ds_txstat.ts_longretry; bf->bf_retries = ds->ds_txstat.ts_longretry;
if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY)
bf->bf_state.bf_type |= BUF_XRETRY; bf->bf_state.bf_type |= BUF_XRETRY;
nbad = 0; ath_tx_rc_status(bf, ds, 0, txok);
} else {
nbad = ath_tx_num_badfrms(sc, bf, txok);
} }
ath_tx_rc_status(bf, ds, nbad, txok);
if (bf_isampdu(bf)) if (bf_isampdu(bf))
ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok);
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment