svn commit: r233989 - head/sys/dev/ath
Adrian Chadd
adrian at FreeBSD.org
Sat Apr 7 05:48:27 UTC 2012
Author: adrian
Date: Sat Apr 7 05:48:26 2012
New Revision: 233989
URL: http://svn.freebsd.org/changeset/base/233989
Log:
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.
Modified:
head/sys/dev/ath/if_ath_sysctl.c
head/sys/dev/ath/if_ath_tx.c
head/sys/dev/ath/if_athioctl.h
Modified: head/sys/dev/ath/if_ath_sysctl.c
==============================================================================
--- head/sys/dev/ath/if_ath_sysctl.c Sat Apr 7 05:46:00 2012 (r233988)
+++ head/sys/dev/ath/if_ath_sysctl.c Sat Apr 7 05:48:26 2012 (r233989)
@@ -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++) {
Modified: head/sys/dev/ath/if_ath_tx.c
==============================================================================
--- head/sys/dev/ath/if_ath_tx.c Sat Apr 7 05:46:00 2012 (r233988)
+++ head/sys/dev/ath/if_ath_tx.c Sat Apr 7 05:48:26 2012 (r233989)
@@ -720,6 +720,133 @@ ath_tx_tag_crypto(struct ath_softc *sc,
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,
/* 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);
@@ -1204,84 +1333,6 @@ ath_tx_normal_setup(struct ath_softc *sc
#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
* descriptors when the h/w hits an EOL condition or
@@ -2441,8 +2492,10 @@ ath_tx_xmit_aggr(struct ath_softc *sc, s
/* 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_soft
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_soft
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_soft
*/
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_soft
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);
@@ -3966,6 +4028,12 @@ ath_tx_tid_hw_queue_aggr(struct ath_soft
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;
* the first frame in the aggregate needs it.
@@ -4066,8 +4134,10 @@ ath_tx_tid_hw_queue_norm(struct ath_soft
/* 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);
Modified: head/sys/dev/ath/if_athioctl.h
==============================================================================
--- head/sys/dev/ath/if_athioctl.h Sat Apr 7 05:46:00 2012 (r233988)
+++ head/sys/dev/ath/if_athioctl.h Sat Apr 7 05:48:26 2012 (r233989)
@@ -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 {
More information about the svn-src-head
mailing list