Break out the legacy duration and protection code into routines,

call these after rate control selection is done.

The duration/protection code wasn't working - it expected the rix to
be valid.  Unfortunately after I moved the rate control selection into
late in the process, the rix value isn't valid and thus the protection/
duration code would get things wrong.

HT frames are now correctly protected with an RTS and for the AR5416,
this involves having the aggregate frames be limited to 8K.

TODO:

* Fix up the DMA sync to occur just before the frame is queued to the
  hardware.  I'm adjusting the duration here but not doing the DMA
  flush.

* Doubly/triply ensure that the aggregate frames are being limited to
  the correct size, or the AR5416 will get unhappy when TXing RTS-protected
  aggregates.
This commit is contained in:
Adrian Chadd 2012-04-07 05:48:26 +00:00
parent 781e7eaffd
commit e2e4a2c2a1
3 changed files with 156 additions and 83 deletions

View file

@ -344,6 +344,8 @@ ath_sysctl_txagg(SYSCTL_HANDLER_ARGS)
sc->sc_aggr_stats.aggr_aggr_pkt);
printf("aggr single packet low hwq: %d\n",
sc->sc_aggr_stats.aggr_low_hwq_single_pkt);
printf("aggr single packet RTS aggr limited: %d\n",
sc->sc_aggr_stats.aggr_rts_aggr_limited);
printf("aggr sched, no work: %d\n",
sc->sc_aggr_stats.aggr_sched_nopkt);
for (i = 0; i < 64; i++) {

View file

@ -720,6 +720,133 @@ ath_tx_tag_crypto(struct ath_softc *sc, struct ieee80211_node *ni,
return (1);
}
/*
* Calculate whether interoperability protection is required for
* this frame.
*
* This requires the rate control information be filled in,
* as the protection requirement depends upon the current
* operating mode / PHY.
*/
static void
ath_tx_calc_protection(struct ath_softc *sc, struct ath_buf *bf)
{
struct ieee80211_frame *wh;
uint8_t rix;
uint16_t flags;
int shortPreamble;
const HAL_RATE_TABLE *rt = sc->sc_currates;
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
flags = bf->bf_state.bfs_txflags;
rix = bf->bf_state.bfs_rc[0].rix;
shortPreamble = bf->bf_state.bfs_shpream;
wh = mtod(bf->bf_m, struct ieee80211_frame *);
/*
* If 802.11g protection is enabled, determine whether
* to use RTS/CTS or just CTS. Note that this is only
* done for OFDM unicast frames.
*/
if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
rt->info[rix].phy == IEEE80211_T_OFDM &&
(flags & HAL_TXDESC_NOACK) == 0) {
bf->bf_state.bfs_doprot = 1;
/* XXX fragments must use CCK rates w/ protection */
if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) {
flags |= HAL_TXDESC_RTSENA;
} else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
flags |= HAL_TXDESC_CTSENA;
}
/*
* For frags it would be desirable to use the
* highest CCK rate for RTS/CTS. But stations
* farther away may detect it at a lower CCK rate
* so use the configured protection rate instead
* (for now).
*/
sc->sc_stats.ast_tx_protect++;
}
/*
* If 11n protection is enabled and it's a HT frame,
* enable RTS.
*
* XXX ic_htprotmode or ic_curhtprotmode?
* XXX should it_htprotmode only matter if ic_curhtprotmode
* XXX indicates it's not a HT pure environment?
*/
if ((ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) &&
rt->info[rix].phy == IEEE80211_T_HT &&
(flags & HAL_TXDESC_NOACK) == 0) {
flags |= HAL_TXDESC_RTSENA;
sc->sc_stats.ast_tx_htprotect++;
}
bf->bf_state.bfs_txflags = flags;
}
/*
* Update the frame duration given the currently selected rate.
*
* This also updates the frame duration value, so it will require
* a DMA flush.
*/
static void
ath_tx_calc_duration(struct ath_softc *sc, struct ath_buf *bf)
{
struct ieee80211_frame *wh;
uint8_t rix;
uint16_t flags;
int shortPreamble;
struct ath_hal *ah = sc->sc_ah;
const HAL_RATE_TABLE *rt = sc->sc_currates;
int isfrag = bf->bf_m->m_flags & M_FRAG;
flags = bf->bf_state.bfs_txflags;
rix = bf->bf_state.bfs_rc[0].rix;
shortPreamble = bf->bf_state.bfs_shpream;
wh = mtod(bf->bf_m, struct ieee80211_frame *);
/*
* Calculate duration. This logically belongs in the 802.11
* layer but it lacks sufficient information to calculate it.
*/
if ((flags & HAL_TXDESC_NOACK) == 0 &&
(wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
u_int16_t dur;
if (shortPreamble)
dur = rt->info[rix].spAckDuration;
else
dur = rt->info[rix].lpAckDuration;
if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) {
dur += dur; /* additional SIFS+ACK */
KASSERT(bf->bf_m->m_nextpkt != NULL, ("no fragment"));
/*
* Include the size of next fragment so NAV is
* updated properly. The last fragment uses only
* the ACK duration
*/
dur += ath_hal_computetxtime(ah, rt,
bf->bf_m->m_nextpkt->m_pkthdr.len,
rix, shortPreamble);
}
if (isfrag) {
/*
* Force hardware to use computed duration for next
* fragment by disabling multi-rate retry which updates
* duration based on the multi-rate duration table.
*/
bf->bf_state.bfs_ismrr = 0;
bf->bf_state.bfs_try0 = ATH_TXMGTTRY;
/* XXX update bfs_rc[0].try? */
}
/* Update the duration field itself */
*(u_int16_t *)wh->i_dur = htole16(dur);
}
}
static uint8_t
ath_tx_get_rtscts_rate(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
int cix, int shortPreamble)
@ -1004,8 +1131,10 @@ ath_tx_xmit_normal(struct ath_softc *sc, struct ath_txq *txq,
/* Setup the descriptor before handoff */
ath_tx_do_ratelookup(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_calc_duration(sc, bf);
ath_tx_calc_protection(sc, bf);
ath_tx_set_rtscts(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_setds(sc, bf);
ath_tx_set_ratectrl(sc, bf->bf_node, bf);
ath_tx_chaindesclist(sc, bf);
@ -1203,84 +1332,6 @@ ath_tx_normal_setup(struct ath_softc *sc, struct ieee80211_node *ni,
}
#endif
/*
* If 802.11g protection is enabled, determine whether
* to use RTS/CTS or just CTS. Note that this is only
* done for OFDM unicast frames.
*/
if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
rt->info[rix].phy == IEEE80211_T_OFDM &&
(flags & HAL_TXDESC_NOACK) == 0) {
bf->bf_state.bfs_doprot = 1;
/* XXX fragments must use CCK rates w/ protection */
if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) {
flags |= HAL_TXDESC_RTSENA;
} else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
flags |= HAL_TXDESC_CTSENA;
}
/*
* For frags it would be desirable to use the
* highest CCK rate for RTS/CTS. But stations
* farther away may detect it at a lower CCK rate
* so use the configured protection rate instead
* (for now).
*/
sc->sc_stats.ast_tx_protect++;
}
#if 0
/*
* If 11n protection is enabled and it's a HT frame,
* enable RTS.
*
* XXX ic_htprotmode or ic_curhtprotmode?
* XXX should it_htprotmode only matter if ic_curhtprotmode
* XXX indicates it's not a HT pure environment?
*/
if ((ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) &&
rt->info[rix].phy == IEEE80211_T_HT &&
(flags & HAL_TXDESC_NOACK) == 0) {
cix = rt->info[sc->sc_protrix].controlRate;
flags |= HAL_TXDESC_RTSENA;
sc->sc_stats.ast_tx_htprotect++;
}
#endif
/*
* Calculate duration. This logically belongs in the 802.11
* layer but it lacks sufficient information to calculate it.
*/
if ((flags & HAL_TXDESC_NOACK) == 0 &&
(wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
u_int16_t dur;
if (shortPreamble)
dur = rt->info[rix].spAckDuration;
else
dur = rt->info[rix].lpAckDuration;
if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) {
dur += dur; /* additional SIFS+ACK */
KASSERT(m0->m_nextpkt != NULL, ("no fragment"));
/*
* Include the size of next fragment so NAV is
* updated properly. The last fragment uses only
* the ACK duration
*/
dur += ath_hal_computetxtime(ah, rt,
m0->m_nextpkt->m_pkthdr.len,
rix, shortPreamble);
}
if (isfrag) {
/*
* Force hardware to use computed duration for next
* fragment by disabling multi-rate retry which updates
* duration based on the multi-rate duration table.
*/
ismrr = 0;
try0 = ATH_TXMGTTRY; /* XXX? */
}
*(u_int16_t *)wh->i_dur = htole16(dur);
}
/*
* Determine if a tx interrupt should be generated for
* this descriptor. We take a tx interrupt to reap
@ -2441,8 +2492,10 @@ ath_tx_xmit_aggr(struct ath_softc *sc, struct ath_node *an, struct ath_buf *bf)
/* Direct dispatch to hardware */
ath_tx_do_ratelookup(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_calc_duration(sc, bf);
ath_tx_calc_protection(sc, bf);
ath_tx_set_rtscts(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_setds(sc, bf);
ath_tx_set_ratectrl(sc, bf->bf_node, bf);
ath_tx_chaindesclist(sc, bf);
@ -3892,8 +3945,10 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
ATH_TXQ_REMOVE(tid, bf, bf_list);
bf->bf_state.bfs_aggr = 0;
ath_tx_do_ratelookup(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_calc_duration(sc, bf);
ath_tx_calc_protection(sc, bf);
ath_tx_set_rtscts(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_setds(sc, bf);
ath_tx_chaindesclist(sc, bf);
ath_hal_clr11n_aggr(sc->sc_ah, bf->bf_desc);
@ -3918,6 +3973,11 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
ath_tx_do_ratelookup(sc, bf);
bf->bf_state.bfs_rc[3].rix = 0;
bf->bf_state.bfs_rc[3].tries = 0;
ath_tx_calc_duration(sc, bf);
ath_tx_calc_protection(sc, bf);
ath_tx_set_rtscts(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
status = ath_tx_form_aggr(sc, an, tid, &bf_q);
@ -3937,6 +3997,9 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
*/
bf = TAILQ_FIRST(&bf_q);
if (status == ATH_AGGR_8K_LIMITED)
sc->sc_aggr_stats.aggr_rts_aggr_limited++;
/*
* If it's the only frame send as non-aggregate
* assume that ath_tx_form_aggr() has checked
@ -3946,7 +4009,6 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
"%s: single-frame aggregate\n", __func__);
bf->bf_state.bfs_aggr = 0;
ath_tx_set_rtscts(sc, bf);
ath_tx_setds(sc, bf);
ath_tx_chaindesclist(sc, bf);
ath_hal_clr11n_aggr(sc->sc_ah, bf->bf_desc);
@ -3965,6 +4027,12 @@ ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
sc->sc_aggr_stats.aggr_pkts[bf->bf_state.bfs_nframes]++;
sc->sc_aggr_stats.aggr_aggr_pkt++;
/*
* Calculate the duration/protection as required.
*/
ath_tx_calc_duration(sc, bf);
ath_tx_calc_protection(sc, bf);
/*
* Update the rate and rtscts information based on the
* rate decision made by the rate control code;
@ -4066,8 +4134,10 @@ ath_tx_tid_hw_queue_norm(struct ath_softc *sc, struct ath_node *an,
/* Program descriptors + rate control */
ath_tx_do_ratelookup(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_calc_duration(sc, bf);
ath_tx_calc_protection(sc, bf);
ath_tx_set_rtscts(sc, bf);
ath_tx_rate_fill_rcflags(sc, bf);
ath_tx_setds(sc, bf);
ath_tx_chaindesclist(sc, bf);
ath_tx_set_ratectrl(sc, ni, bf);

View file

@ -43,6 +43,7 @@ struct ath_tx_aggr_stats {
u_int32_t aggr_baw_closed_single_pkt;
u_int32_t aggr_low_hwq_single_pkt;
u_int32_t aggr_sched_nopkt;
u_int32_t aggr_rts_aggr_limited;
};
struct ath_stats {