ath9k: fix aggregate size limit based on queue TXOP limit

If the aggregate size exceeds the TXOP limit, it leads to lots of unnecessary
hardware and software retries.

The previous 4ms frame limit table was completely undocumented, the commit
that updated it only vaguely referenced and equation from the standard,
but I've been unable to replicate its results.

Fix this by using a formula based on the code in ath_pkt_duration, which is
more likely to be correct for this case.

Reported-by: Dave Täht <dave.taht@gmail.com>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Felix Fietkau 2012-07-15 19:53:36 +02:00 committed by John W. Linville
parent 7702e788e7
commit aa5955c36f
3 changed files with 46 additions and 30 deletions

View File

@ -298,6 +298,7 @@ struct ath_tx {
struct ath_descdma txdma;
struct ath_txq *txq_map[WME_NUM_AC];
u32 txq_max_pending[WME_NUM_AC];
u16 max_aggr_framelen[WME_NUM_AC][4][32];
};
struct ath_rx_edma {
@ -342,6 +343,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs);
void ath_tx_cleanup(struct ath_softc *sc);
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *q);
void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_tx_control *txctl);
void ath_tx_tasklet(struct ath_softc *sc);

View File

@ -1395,6 +1395,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw,
queue, txq->axq_qnum, params->aifs, params->cw_min,
params->cw_max, params->txop);
ath_update_max_aggr_framelen(sc, queue, qi.tqi_burstTime);
ret = ath_txq_update(sc, txq->axq_qnum, &qi);
if (ret)
ath_err(common, "TXQ Update failed\n");

View File

@ -29,6 +29,8 @@
#define HT_LTF(_ns) (4 * (_ns))
#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
#define TIME_SYMBOLS(t) ((t) >> 2)
#define TIME_SYMBOLS_HALFGI(t) (((t) * 5 - 4) / 18)
#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
@ -74,33 +76,6 @@ enum {
MCS_HT40_SGI,
};
static int ath_max_4ms_framelen[4][32] = {
[MCS_HT20] = {
3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
},
[MCS_HT20_SGI] = {
3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
},
[MCS_HT40] = {
6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
},
[MCS_HT40_SGI] = {
7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
}
};
/*********************/
/* Aggregation logic */
/*********************/
@ -650,6 +625,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
struct ieee80211_tx_rate *rates;
u32 max_4ms_framelen, frmlen;
u16 aggr_limit, bt_aggr_limit, legacy = 0;
int q = tid->ac->txq->mac80211_qnum;
int i;
skb = bf->bf_mpdu;
@ -658,8 +634,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
/*
* Find the lowest frame length among the rate series that will have a
* 4ms transmit duration.
* TODO - TXOP limit needs to be considered.
* 4ms (or TXOP limited) transmit duration.
*/
max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
@ -682,7 +657,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
modeidx++;
frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
frmlen = sc->tx.max_aggr_framelen[q][modeidx][rates[i].idx];
max_4ms_framelen = min(max_4ms_framelen, frmlen);
}
@ -929,6 +904,44 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
return duration;
}
static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi)
{
int streams = HT_RC_2_STREAMS(mcs);
int symbols, bits;
int bytes = 0;
symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec);
bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams;
bits -= OFDM_PLCP_BITS;
bytes = bits / 8;
bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
if (bytes > 65532)
bytes = 65532;
return bytes;
}
void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop)
{
u16 *cur_ht20, *cur_ht20_sgi, *cur_ht40, *cur_ht40_sgi;
int mcs;
/* 4ms is the default (and maximum) duration */
if (!txop || txop > 4096)
txop = 4096;
cur_ht20 = sc->tx.max_aggr_framelen[queue][MCS_HT20];
cur_ht20_sgi = sc->tx.max_aggr_framelen[queue][MCS_HT20_SGI];
cur_ht40 = sc->tx.max_aggr_framelen[queue][MCS_HT40];
cur_ht40_sgi = sc->tx.max_aggr_framelen[queue][MCS_HT40_SGI];
for (mcs = 0; mcs < 32; mcs++) {
cur_ht20[mcs] = ath_max_framelen(txop, mcs, false, false);
cur_ht20_sgi[mcs] = ath_max_framelen(txop, mcs, false, true);
cur_ht40[mcs] = ath_max_framelen(txop, mcs, true, false);
cur_ht40_sgi[mcs] = ath_max_framelen(txop, mcs, true, true);
}
}
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_info *info, int len)
{