[ath] obey the peer A-MPDU density and max-size.

* Obey the peer A-MPDU density if it's larger than the currently configured
  one.

* Pay attention to the peer A-MPDU max-size and don't assume we can transmit
  a full A-MPDU (64k!) if the peer announces smaller values.

Relnotes:	ath(4): Fix A-MPDU transmit; obey A-MPDU density and max size.
This commit is contained in:
Adrian Chadd 2016-11-22 02:42:00 +00:00
parent 3d12d1f14f
commit c969f82d85

View File

@ -319,8 +319,8 @@ ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf)
* and we're not doing positioning, enable STBC.
*/
if (ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC &&
ni->ni_vap->iv_flags_ht & IEEE80211_FHT_STBC_TX &&
ni->ni_htcap & IEEE80211_HTCAP_RXSTBC_1STREAM &&
(ni->ni_vap->iv_flags_ht & IEEE80211_FHT_STBC_TX) &&
(ni->ni_htcap & IEEE80211_HTCAP_RXSTBC) &&
(sc->sc_cur_txchainmask > 1) &&
(HT_RC_2_STREAMS(rate) == 1) &&
(bf->bf_flags & ATH_BUF_TOA_PROBE) == 0) {
@ -404,24 +404,40 @@ static int
ath_compute_num_delims(struct ath_softc *sc, struct ath_buf *first_bf,
uint16_t pktlen)
{
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
const HAL_RATE_TABLE *rt = sc->sc_currates;
struct ieee80211_node *ni = first_bf->bf_node;
struct ieee80211vap *vap = ni->ni_vap;
int ndelim, mindelim = 0;
int mpdudensity; /* in 1/100'th of a microsecond */
int mpdudensity; /* in 1/100'th of a microsecond */
int peer_mpdudensity; /* net80211 value */
uint8_t rc, rix, flags;
int width, half_gi;
uint32_t nsymbits, nsymbols;
uint16_t minlen;
/*
* vap->iv_ampdu_density is a value, rather than the actual
* density.
* Get the advertised density from the node.
*/
if (vap->iv_ampdu_density > IEEE80211_HTCAP_MPDUDENSITY_16)
peer_mpdudensity = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
/*
* vap->iv_ampdu_density is a net80211 value, rather than the actual
* density. Larger values are longer A-MPDU density spacing values,
* and we want to obey larger configured / negotiated density values
* per station if we get it.
*/
if (vap->iv_ampdu_density > peer_mpdudensity)
peer_mpdudensity = vap->iv_ampdu_density;
/*
* Convert the A-MPDU density net80211 value to a 1/100 microsecond
* value for subsequent calculations.
*/
if (peer_mpdudensity > IEEE80211_HTCAP_MPDUDENSITY_16)
mpdudensity = 1600; /* maximum density */
else
mpdudensity = ieee80211_mpdudensity_map[vap->iv_ampdu_density];
mpdudensity = ieee80211_mpdudensity_map[peer_mpdudensity];
/* Select standard number of delimiters based on frame length */
ndelim = ATH_AGGR_GET_NDELIM(pktlen);
@ -509,22 +525,49 @@ ath_compute_num_delims(struct ath_softc *sc, struct ath_buf *first_bf,
__func__, pktlen, minlen, rix, rc, width, half_gi, ndelim);
return ndelim;
#undef MS
}
/*
* Fetch the aggregation limit.
*
* It's the lowest of the four rate series 4ms frame length.
*
* Also take into account the hardware specific limits (8KiB on AR5416)
* and per-peer limits in non-STA mode.
*/
static int
ath_get_aggr_limit(struct ath_softc *sc, struct ath_buf *bf)
ath_get_aggr_limit(struct ath_softc *sc, struct ieee80211_node *ni,
struct ath_buf *bf)
{
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
int amin = ATH_AGGR_MAXSIZE;
int i;
/* Extract out the maximum configured driver A-MPDU limit */
if (sc->sc_aggr_limit > 0 && sc->sc_aggr_limit < ATH_AGGR_MAXSIZE)
amin = sc->sc_aggr_limit;
/*
* Check the HTCAP field for the maximum size the node has
* negotiated. If it's smaller than what we have, cap it there.
*/
switch (MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU)) {
case IEEE80211_HTCAP_MAXRXAMPDU_16K:
amin = MIN(amin, 16384);
break;
case IEEE80211_HTCAP_MAXRXAMPDU_32K:
amin = MIN(amin, 32768);
break;
case IEEE80211_HTCAP_MAXRXAMPDU_64K:
amin = MIN(amin, 65536);
break;
case IEEE80211_HTCAP_MAXRXAMPDU_8K:
default:
amin = MIN(amin, 8192);
break;
}
for (i = 0; i < ATH_RC_NUM; i++) {
if (bf->bf_state.bfs_rc[i].tries == 0)
continue;
@ -535,6 +578,7 @@ ath_get_aggr_limit(struct ath_softc *sc, struct ath_buf *bf)
__func__, amin);
return amin;
#undef MS
}
/*
@ -787,7 +831,8 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_node *an,
* set the aggregation limit based on the
* rate control decision that has been made.
*/
aggr_limit = ath_get_aggr_limit(sc, bf_first);
aggr_limit = ath_get_aggr_limit(sc, &an->an_node,
bf_first);
}
/* Set this early just so things don't get confused */