|
@@ -317,6 +317,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|
|
int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
|
|
|
bool rc_update = true;
|
|
|
struct ieee80211_tx_rate rates[4];
|
|
|
+ int nframes;
|
|
|
|
|
|
skb = bf->bf_mpdu;
|
|
|
hdr = (struct ieee80211_hdr *)skb->data;
|
|
@@ -325,6 +326,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|
|
hw = bf->aphy->hw;
|
|
|
|
|
|
memcpy(rates, tx_info->control.rates, sizeof(rates));
|
|
|
+ nframes = bf->bf_nframes;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
@@ -341,7 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|
|
!bf->bf_stale || bf_next != NULL)
|
|
|
list_move_tail(&bf->list, &bf_head);
|
|
|
|
|
|
- ath_tx_rc_status(bf, ts, 0, 0, false);
|
|
|
+ ath_tx_rc_status(bf, ts, 1, 0, false);
|
|
|
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
|
|
|
0, 0);
|
|
|
|
|
@@ -446,6 +448,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|
|
|
|
|
if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
|
|
|
memcpy(tx_info->control.rates, rates, sizeof(rates));
|
|
|
+ bf->bf_nframes = nframes;
|
|
|
ath_tx_rc_status(bf, ts, nbad, txok, true);
|
|
|
rc_update = false;
|
|
|
} else {
|
|
@@ -1979,9 +1982,15 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
|
|
|
|
|
|
if (ts->ts_status & ATH9K_TXERR_FILT)
|
|
|
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
|
|
- if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
|
|
|
+ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
|
|
|
tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
|
|
|
|
|
|
+ BUG_ON(nbad > bf->bf_nframes);
|
|
|
+
|
|
|
+ tx_info->status.ampdu_len = bf->bf_nframes;
|
|
|
+ tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
|
|
|
+ }
|
|
|
+
|
|
|
if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
|
|
|
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
|
|
|
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,
|
|
|
if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
|
|
|
(ts->ts_status & ATH9K_TXERR_FIFO))
|
|
|
tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
|
|
|
- tx_info->status.ampdu_len = bf->bf_nframes;
|
|
|
- tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2102,7 +2109,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|
|
*/
|
|
|
if (ts.ts_status & ATH9K_TXERR_XRETRY)
|
|
|
bf->bf_state.bf_type |= BUF_XRETRY;
|
|
|
- ath_tx_rc_status(bf, &ts, 0, txok, true);
|
|
|
+ ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
|
|
|
}
|
|
|
|
|
|
if (bf_isampdu(bf))
|
|
@@ -2220,7 +2227,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
|
|
|
if (!bf_isampdu(bf)) {
|
|
|
if (txs.ts_status & ATH9K_TXERR_XRETRY)
|
|
|
bf->bf_state.bf_type |= BUF_XRETRY;
|
|
|
- ath_tx_rc_status(bf, &txs, 0, txok, true);
|
|
|
+ ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
|
|
|
}
|
|
|
|
|
|
if (bf_isampdu(bf))
|