mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
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:
parent
781e7eaffd
commit
e2e4a2c2a1
3 changed files with 156 additions and 83 deletions
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue