Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Apr 2012 05:48:27 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r233989 - head/sys/dev/ath
Message-ID:  <201204070548.q375mR8L045591@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201204070548.q375mR8L045591>