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: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
b3a902850a
commit
0934af2340
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue