Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 8 Jan 2005 00:16:59 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 68510 for review
Message-ID:  <200501080016.j080GxBT078057@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=68510

Change 68510 by sam@sam_ebb on 2005/01/08 00:16:43

	checkpoint SuperG WIP

Affected files ...

.. //depot/projects/wifi/sbin/ifconfig/ifieee80211.c#35 edit
.. //depot/projects/wifi/sys/dev/ath/if_ath.c#61 edit
.. //depot/projects/wifi/sys/dev/ath/if_athioctl.h#7 edit
.. //depot/projects/wifi/sys/dev/ath/if_athvar.h#25 edit
.. //depot/projects/wifi/sys/net80211/ieee80211.h#8 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_freebsd.h#12 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_input.c#36 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#33 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#21 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.c#34 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_node.h#18 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_output.c#31 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_proto.h#15 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_var.h#22 edit
.. //depot/projects/wifi/tools/tools/ath/80211debug.c#5 edit
.. //depot/projects/wifi/tools/tools/ath/athdebug.c#4 edit
.. //depot/projects/wifi/tools/tools/ath/athstats.c#7 edit

Differences ...

==== //depot/projects/wifi/sbin/ifconfig/ifieee80211.c#35 (text+ko) ====

@@ -24,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.12 2004/12/12 04:32:44 sam Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.15 2004/12/31 19:46:27 sam Exp $
  */
 
 /*-
@@ -410,6 +410,18 @@
 }
 
 static void
+set80211fastframes(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_FF, d, 0, NULL);
+}
+
+static void
+set80211turbo(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL);
+}
+
+static void
 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
 {
 	struct ieee80211req_chanlist chanlist;
@@ -1006,7 +1018,7 @@
 }
 
 #define	IEEE80211_C_BITS \
-"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
+"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\7FF\10TURBOP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
 "\31WPA2\32BURST\33WME"
 
@@ -1532,6 +1544,22 @@
 	} else
 		wme = 0;
 
+	ireq.i_type = IEEE80211_IOC_FF;
+	if (ioctl(s, SIOCG80211, &ireq) != -1) {
+		if (ireq.i_val)
+			LINE_CHECK("%cff", spacer);
+		else if (verbose)
+			LINE_CHECK("%c-ff", spacer);
+	}
+
+	ireq.i_type = IEEE80211_IOC_TURBOP;
+	if (ioctl(s, SIOCG80211, &ireq) != -1) {
+		if (ireq.i_val)
+			LINE_CHECK("%cturbo", spacer);
+		else if (verbose)
+			LINE_CHECK("%c-turbo", spacer);
+	}
+
 	if (opmode == IEEE80211_M_HOSTAP) {
 		ireq.i_type = IEEE80211_IOC_HIDESSID;
 		if (ioctl(s, SIOCG80211, &ireq) != -1) {
@@ -1788,6 +1816,10 @@
 #if 0
 	DEF_CMD_ARG("mac:kick",		set80211kickmac),
 #endif
+	DEF_CMD("ff",		1,	set80211fastframes),
+	DEF_CMD("-ff",		0,	set80211fastframes),
+	DEF_CMD("turbo",	1,	set80211turbo),
+	DEF_CMD("-turbo",	0,	set80211turbo),
 };
 static struct afswtch af_ieee80211 = {
 	.af_name	= "af_ieee80211",

==== //depot/projects/wifi/sys/dev/ath/if_ath.c#61 (text+ko) ====

@@ -222,6 +222,7 @@
 	ATH_DEBUG_STATE		= 0x00040000,	/* 802.11 state transitions */
 	ATH_DEBUG_NODE		= 0x00080000,	/* node management */
 	ATH_DEBUG_LED		= 0x00100000,	/* led management */
+	ATH_DEBUG_FF		= 0x00200000,	/* fast frames */
 	ATH_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
 	ATH_DEBUG_ANY		= 0xffffffff
 };
@@ -529,10 +530,16 @@
 	if (sc->sc_ac2q[WME_AC_BE] != sc->sc_ac2q[WME_AC_BK])
 		ic->ic_caps |= IEEE80211_C_WME;
 	/*
-	 * Check for frame bursting capability.
+	 * Check for misc other capabilities.
 	 */
 	if (ath_hal_hasbursting(ah))
 		ic->ic_caps |= IEEE80211_C_BURST;
+	if (ath_hal_hasfastframes(ah))
+		ic->ic_caps |= IEEE80211_C_FF;
+#ifdef notyet
+	if (ath_hal_getwirelessmodes(ah) & (HAL_MODE_108G|HAL_MODE_TURBO))
+		ic->ic_caps |= IEEE80211_C_TURBOP;
+#endif
 
 	/*
 	 * Indicate we need the 802.11 header padded to a
@@ -1033,6 +1040,315 @@
 	return 0;
 }
 
+static int 
+ath_ff_always(struct ath_txq *txq, struct ath_buf *bf)
+{
+	return 0;
+}
+
+#if 0
+static int 
+ath_ff_ageflushtestdone(struct ath_txq *txq, struct ath_buf *bf)
+{
+	return (txq->axq_curage - bf->bf_age) < ATH_FF_STAGEMAX;
+}
+#endif
+
+/*
+ * Flush FF staging queue.
+ */
+static void
+ath_ff_stageq_flush(struct ath_softc *sc, struct ath_txq *txq,
+	int (*ath_ff_flushdonetest)(struct ath_txq *txq, struct ath_buf *bf))
+{
+	struct ath_buf *bf;
+	struct ieee80211_node *ni;
+	int pktlen, pri;
+	
+	for (;;) {
+		ATH_TXQ_LOCK(txq);
+		/*
+		 * Go from the back (oldest) to front so we can
+		 * stop early based on the age of the entry.
+		 */
+		bf = TAILQ_LAST(&txq->axq_stageq, axq_headtype);
+		if (bf == NULL || ath_ff_flushdonetest(txq, bf)) {
+			ATH_TXQ_UNLOCK(txq);
+			break;
+		}
+
+		ni = bf->bf_node;
+		pri = M_WME_GETAC(bf->bf_m);
+		KASSERT(ATH_NODE(ni)->an_ff_buf[pri],
+			("no bf on staging queue %p", bf));
+		ATH_NODE(ni)->an_ff_buf[pri] = NULL;
+		TAILQ_REMOVE(&txq->axq_stageq, bf, bf_stagelist);
+		
+		ATH_TXQ_UNLOCK(txq);
+
+		DPRINTF(sc, ATH_DEBUG_FF, "%s: flush frame, age %u\n",
+			__func__, bf->bf_age);
+
+		sc->sc_stats.ast_ff_flush++;
+		
+		/* encap and xmit */
+		bf->bf_m = ieee80211_encap(&sc->sc_ic, bf->bf_m, ni);
+		if (bf->bf_m == NULL) {
+			DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
+				"%s: discard, encapsulation failure\n",
+				__func__);
+			sc->sc_stats.ast_tx_encap++;
+			goto bad;
+		}
+		pktlen = bf->bf_m->m_pkthdr.len; /* NB: don't reference below */
+		if (ath_tx_start(sc, ni, bf, bf->bf_m) == 0) {
+#if 0 /*XXX*/
+			ifp->if_opackets++;
+#endif
+			continue;
+		}
+	bad:
+		if (ni != NULL)
+			ieee80211_free_node(ni);
+		if (bf->bf_m != NULL)
+			m_freem(bf->bf_m);
+		if (bf != NULL) {
+			ATH_TXBUF_LOCK(sc);
+			STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+			ATH_TXBUF_UNLOCK(sc);
+		}			
+	}
+}
+
+static __inline u_int32_t
+ath_ff_approx_txtime(struct ath_softc *sc, struct ath_node *an, struct mbuf *m)
+{
+	u_int32_t framelen;
+	struct ath_buf *bf;
+
+	/*
+	 * Approximate the frame length to be transmitted. A swag to add
+	 * the following maximal values to the skb payload:
+	 *   - 32: 802.11 encap + CRC
+	 *   - 24: encryption overhead (if wep bit)
+	 *   - 4 + 6: fast-frame header and padding
+	 *   - 16: 2 LLC FF tunnel headers
+	 *   - 14: 1 802.3 FF tunnel header (skb already accounts for 2nd)
+	 */
+	framelen = m->m_pkthdr.len + 32 + 4 + 6 + 16 + 14;
+	if (sc->sc_ic.ic_flags & IEEE80211_F_PRIVACY)
+		framelen += 24;
+	bf = an->an_ff_buf[M_WME_GETAC(m)];
+	if (bf != NULL)
+		framelen += bf->bf_m->m_pkthdr.len;
+	return ath_hal_computetxtime(sc->sc_ah, sc->sc_currates, framelen,
+			sc->sc_lastdatarix, AH_FALSE);
+}
+
+/*
+ * Determine if a data frame may be aggregated via ff tunnelling.
+ * Note the caller is responsible for checking if the destination
+ * supports fast frames.
+ *
+ *  NB: allowing EAPOL frames to be aggregated with other unicast traffic.
+ *      Do 802.1x EAPOL frames proceed in the clear? Then they couldn't
+ *      be aggregated with other types of frames when encryption is on?
+ *
+ *  NB: assumes lock on an_ff_buf effectively held by txq lock mechanism.
+ */
+static __inline int 
+ath_ff_can_aggregate(struct ath_softc *sc,
+	struct ath_node *an, struct mbuf *m, int *flushq)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ath_txq *txq;
+	u_int32_t txoplimit;
+	u_int pri;
+
+	*flushq = 0;
+
+	/*
+	 * If there is no frame to combine with and the txq has
+	 * fewer frames than the minimum required; then do not
+	 * attempt to aggregate this frame.
+	 */
+	pri = M_WME_GETAC(m);
+	txq = sc->sc_ac2q[pri];
+	if (an->an_ff_buf[pri] == NULL && txq->axq_depth < sc->sc_fftxqmin)
+		return 0;
+	/*
+	 * When not in station mode never aggregate a multicast
+	 * frame; this insures, for example, that a combined frame
+	 * does not require multiple encryption keys when using
+	 * 802.1x/WPA.
+	 */
+	if (ic->ic_opmode != IEEE80211_M_STA &&
+	    ETHER_IS_MULTICAST(mtod(m, struct ether_header *)->ether_dhost))
+		return 0;		
+	/*
+	 * Consult the max bursting interval to insure a combined
+	 * frame fits within the TxOp window.
+	 */
+	txoplimit = IEEE80211_TXOP_TO_US(
+		ic->ic_wme.wme_chanParams.cap_wmeParams[pri].wmep_txopLimit);
+	if (txoplimit != 0 && ath_ff_approx_txtime(sc, an, m) > txoplimit) {
+		DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
+			"%s: FF TxOp violation\n", __func__);
+		if (an->an_ff_buf[pri] != NULL)
+			*flushq = 1;
+		return 0;
+	}
+	return 1;		/* try to aggregate */
+}
+
+/*
+ * Check if the supplied frame can be partnered with an existing
+ * or pending frame.  Return a reference to any frame that should be
+ * sent on return; otherwise return NULL.
+ */
+static struct mbuf *
+ath_ff_check(struct ath_softc *sc, struct ath_txq *txq,
+	struct ath_buf *bf, struct mbuf *m, struct ieee80211_node *ni)
+{
+	struct ieee80211com *ic = ni->ni_ic;
+	struct ath_node *an = ATH_NODE(ni);
+	struct ath_buf *bfstaged;
+	int ff_flush, pri;
+
+	/*
+	 * Check if the supplied frame can be aggregated.
+	 *
+	 * NB: we use the txq lock to protect references to
+	 *     an->an_ff_txbuf in ath_ff_can_aggregate().
+	 */
+	ATH_TXQ_LOCK(txq);
+	pri = M_WME_GETAC(m);
+	if (ath_ff_can_aggregate(sc, an, m, &ff_flush)) {
+		struct ath_buf *bfstaged = an->an_ff_buf[pri];
+		if (bfstaged != NULL) {
+			/*
+			 * A frame is available for partnering; remove
+			 * it, chain it to this one, and encapsulate.
+			 */
+			an->an_ff_buf[pri] = NULL;
+			TAILQ_REMOVE(&txq->axq_stageq, bfstaged, bf_stagelist);
+			ATH_TXQ_UNLOCK(txq);
+
+			/* 
+			 * Chain mbufs and add FF magic.
+			 */
+			DPRINTF(sc, ATH_DEBUG_FF,
+				"[%s] aggregate fast-frame, age %u\n",
+				ether_sprintf(ni->ni_macaddr), txq->axq_curage);
+			m->m_nextpkt = NULL;
+			bfstaged->bf_m->m_nextpkt = m;
+			m = bfstaged->bf_m;
+			m->m_flags |= M_FF;
+			/*
+			 * Release the node reference held while
+			 * the packet sat on an_ff_buf[]
+			 */
+			ieee80211_free_node(ni);
+
+			/*
+			 * Return bfstaged to the free list.
+			 */
+			ATH_TXBUF_LOCK(sc);
+			STAILQ_INSERT_TAIL(&sc->sc_txbuf, bfstaged, bf_list);
+			ATH_TXBUF_UNLOCK(sc);
+
+			return m;		/* ready to go */
+		} else {
+			/*
+			 * No frame available, queue this frame to wait
+			 * for a partner.  Note that we hold the buffer
+			 * and a reference to the node; we need the
+			 * buffer in particular so we're certain we
+			 * can flush the frame at a later time.
+			 */
+			DPRINTF(sc, ATH_DEBUG_FF,
+				"[%s] stage fast-frame, age %u\n",
+				ether_sprintf(ni->ni_macaddr), txq->axq_curage);
+
+			bf->bf_m = m;
+			bf->bf_node = ni;	/* NB: held reference */
+			bf->bf_age = txq->axq_curage;
+			an->an_ff_buf[pri] = bf;
+			TAILQ_INSERT_HEAD(&txq->axq_stageq, bf, bf_stagelist);
+			ATH_TXQ_UNLOCK(txq);
+
+			return NULL;		/* consumed */
+		}
+	}
+	/*
+	 * Frame could not be aggregated, it needs to be returned
+	 * to the caller for immediate transmission.  In addition
+	 * we check if we should first flush a frame from the
+	 * staging queue before sending this one.
+	 *
+	 * NB: ath_ff_can_aggregate only marks ff_flush if a frame
+	 *     is present to flush.
+	 */
+	if (ff_flush) {
+		int pktlen;
+
+		bfstaged = an->an_ff_buf[pri];
+		an->an_ff_buf[pri] = NULL;
+		TAILQ_REMOVE(&txq->axq_stageq, bfstaged, bf_stagelist);
+		ATH_TXQ_UNLOCK(txq);
+
+		DPRINTF(sc, ATH_DEBUG_FF, "[%s] flush staged frame\n",
+			ether_sprintf(an->an_node.ni_macaddr));
+
+		/* encap and xmit */
+		bfstaged->bf_m = ieee80211_encap(ic, bfstaged->bf_m, ni);
+		if (bfstaged->bf_m == NULL) {
+			DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
+				"%s: discard, encap failure\n", __func__);
+			sc->sc_stats.ast_tx_encap++;
+			goto ff_flushbad;
+		}
+		pktlen = bfstaged->bf_m->m_pkthdr.len;
+		if (ath_tx_start(sc, ni, bfstaged, bfstaged->bf_m)) {
+			DPRINTF(sc, ATH_DEBUG_XMIT,
+				"%s: discard, xmit failure\n", __func__);
+	ff_flushbad:
+			/*
+			 * Unable to transmit frame that was on the staging
+			 * queue.  Reclaim the node reference and other
+			 * resources.
+			 */
+			if (ni != NULL)
+				ieee80211_free_node(ni);
+			if (bfstaged->bf_m != NULL)
+				m_freem(bfstaged->bf_m);
+			if (bfstaged != NULL) {
+				ATH_TXBUF_LOCK(sc);
+				STAILQ_INSERT_TAIL(&sc->sc_txbuf,
+					bfstaged, bf_list);
+				ATH_TXBUF_UNLOCK(sc);
+			}
+		} else {
+#if 0
+			ifp->if_opackets++;
+#endif
+		}
+	} else {
+		if (an->an_ff_buf[pri] != NULL) {
+			/* 
+			 * XXX: out-of-order condition only occurs for AP
+			 * mode and multicast.  There may be no valid way
+			 * to get this condition.
+			 */
+			DPRINTF(sc, ATH_DEBUG_FF, "[%s] out-of-order frame\n",
+				ether_sprintf(an->an_node.ni_macaddr));
+			/* XXX stat */
+		}
+		ATH_TXQ_UNLOCK(txq);
+	}
+	return m;
+}
+
 static void
 ath_start(struct ifnet *ifp)
 {
@@ -1044,6 +1360,8 @@
 	struct mbuf *m;
 	struct ieee80211_frame *wh;
 	struct ether_header *eh;
+	struct ath_txq *txq;
+	int pri;
 
 	if ((ifp->if_flags & IFF_RUNNING) == 0 || sc->sc_invalid)
 		return;
@@ -1122,6 +1440,28 @@
 					__func__);
 				goto bad;
 			}
+			pri = M_WME_GETAC(m);
+			txq = sc->sc_ac2q[pri];
+			if (ni->ni_flags & IEEE80211_NODE_FF) {
+				/*
+				 * Check queue length; if too deep drop this
+				 * frame (tail drop considered good).
+				 */
+				if (txq->axq_depth >= sc->sc_fftxqmax) {
+					DPRINTF(sc, ATH_DEBUG_FF,
+					    "[%s] tail drop on q %u depth %u\n",
+					    ether_sprintf(ni->ni_macaddr),
+					    txq->axq_qnum, txq->axq_depth);
+					sc->sc_stats.ast_tx_qfull++;
+					m_freem(m);
+					goto reclaim;
+				}
+				m = ath_ff_check(sc, txq, bf, m, ni);
+				if (m == NULL) {
+					/* NB: ni ref & bf held on stageq */
+					continue;
+				}
+			}
 			ifp->if_opackets++;
 			BPF_MTAP(ifp, m);
 			/*
@@ -1179,6 +1519,13 @@
 
 		sc->sc_tx_timer = 5;
 		ifp->if_timer = 1;
+#if 0
+		/*
+		 * Flush stale frames from the fast-frame staging queue.
+		 */
+		if (ic->ic_opmode != IEEE80211_M_STA)
+			ath_ff_stageq_flush(sc, txq, ath_ff_ageflushtestdone);
+#endif
 	}
 }
 
@@ -2806,6 +3153,8 @@
 		txq->axq_link = NULL;
 		STAILQ_INIT(&txq->axq_q);
 		ATH_TXQ_LOCK_INIT(sc, txq);
+		TAILQ_INIT(&txq->axq_stageq);
+		txq->axq_curage = 0;
 		sc->sc_txqsetup |= 1<<qnum;
 	}
 	return &sc->sc_txq[qnum];
@@ -3105,6 +3454,7 @@
 		ath_rate_findrate(sc, an, shortPreamble, pktlen,
 			&rix, &try0, &txrate);
 		sc->sc_txrate = txrate;			/* for LED blinking */
+		sc->sc_lastdatarix = rix;		/* for fast frames */
 		/*
 		 * Default all non-QoS traffic to the best-effort queue.
 		 */
@@ -3112,7 +3462,7 @@
 			u_int pri = M_WME_GETAC(m0);
 			txq = sc->sc_ac2q[pri];
 			if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[pri].wmep_noackPolicy) {
-				 flags |= HAL_TXDESC_NOACK;
+				flags |= HAL_TXDESC_NOACK;
 				sc->sc_stats.ast_tx_noack++;
 			}
 		} else
@@ -3142,7 +3492,8 @@
 	if (ismcast) {
 		flags |= HAL_TXDESC_NOACK;	/* no ack on broad/multicast */
 		sc->sc_stats.ast_tx_noack++;
-	} else if (pktlen > ic->ic_rtsthreshold) {
+	} else if (pktlen > ic->ic_rtsthreshold &&
+	    (ni->ni_flags & IEEE80211_NODE_FF) == 0) {
 		flags |= HAL_TXDESC_RTSENA;	/* RTS based on frame length */
 		cix = rt->info[rix].controlRate;
 		sc->sc_stats.ast_tx_rts++;
@@ -3422,6 +3773,8 @@
 					ds->ds_txstat.ts_rssi;
 				ATH_RSSI_LPF(an->an_halstats.ns_avgtxrssi,
 					ds->ds_txstat.ts_rssi);
+				if (bf->bf_m->m_flags & M_FF)
+					sc->sc_stats.ast_ff_txok++;
 				pri = M_WME_GETAC(bf->bf_m);
 				if (pri >= WME_AC_VO)
 					ic->ic_wme.wme_hipri_traffic++;
@@ -3433,6 +3786,8 @@
 					sc->sc_stats.ast_tx_fifoerr++;
 				if (ds->ds_txstat.ts_status & HAL_TXERR_FILT)
 					sc->sc_stats.ast_tx_filtered++;
+				if (bf->bf_m->m_flags & M_FF)
+					sc->sc_stats.ast_ff_txerr++;
 			}
 			sr = ds->ds_txstat.ts_shortretry;
 			lr = ds->ds_txstat.ts_longretry;
@@ -3462,6 +3817,11 @@
 		STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
 		ATH_TXBUF_UNLOCK(sc);
 	}
+	/*
+	 * Flush fast-frame staging queue when traffic slows.
+	 */
+	if (txq->axq_depth <= 1)
+		ath_ff_stageq_flush(sc, txq, ath_ff_always);
 }
 
 static __inline int
@@ -4615,6 +4975,16 @@
 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
 			"tpc", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
 			ath_sysctl_tpc, "I", "enable/disable per-packet TPC");
+	if (ath_hal_hasfastframes(sc->sc_ah)) {
+		sc->sc_fftxqmin = ATH_FF_TXQMIN;
+		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+			"fftxqmin", CTLFLAG_RW, &sc->sc_fftxqmin, 0,
+			"min frames before fast-frame staging");
+		sc->sc_fftxqmax = ATH_FF_TXQMAX;
+		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+			"fftxqmax", CTLFLAG_RW, &sc->sc_fftxqmax, 0,
+			"max queued frames before tail drop");
+	}
 }
 
 static void

==== //depot/projects/wifi/sys/dev/ath/if_athioctl.h#7 (text+ko) ====

@@ -103,6 +103,11 @@
 	u_int32_t	ast_ant_txswitch;/* tx antenna switches */
 	u_int32_t	ast_ant_rx[8];	/* rx frames with antenna */
 	u_int32_t	ast_ant_tx[8];	/* tx frames with antenna */
+	u_int32_t	ast_ff_txok;	/* fast frames tx'd successfully */
+	u_int32_t	ast_ff_txerr;	/* fast frames tx'd w/ error */
+	u_int32_t	ast_ff_rx;	/* fast frames rx'd */
+	u_int32_t	ast_ff_flush;	/* fast frames flushed from staging q */
+	u_int32_t	ast_tx_qfull;	/* tx dropped 'cuz of queue limit */
 };
 
 #define	SIOCGATHSTATS	_IOWR('i', 137, struct ifreq)

==== //depot/projects/wifi/sys/dev/ath/if_athvar.h#25 (text+ko) ====

@@ -52,11 +52,17 @@
 #define	ATH_TIMEOUT		1000
 
 #define	ATH_RXBUF	40		/* number of RX buffers */
-#define	ATH_TXBUF	60		/* number of TX buffers */
+#define	ATH_TXBUF	100		/* number of TX buffers */
 #define	ATH_TXDESC	8		/* number of descriptors per buffer */
 #define	ATH_TXMAXTRY	11		/* max number of transmit attempts */
 #define	ATH_TXINTR_PERIOD 5		/* max number of batched tx descriptors */
 
+#define	ATH_FF_TXQMIN	2		/* min txq depth for staging */
+#define	ATH_FF_TXQMAX	50		/* maximum # of queued frames allowed */
+#define	ATH_FF_STAGEMAX	5		/* max waiting period for staged frame*/
+
+struct ath_buf;
+
 /* driver-specific node state */
 struct ath_node {
 	struct ieee80211_node an_node;	/* base class */
@@ -64,6 +70,7 @@
 	u_int8_t	an_tx_mgtratesp;/* short preamble h/w rate for " " */
 	u_int32_t	an_avgrssi;	/* average rssi over all rx frames */
 	HAL_NODE_STATS	an_halstats;	/* rssi statistics used by hal */
+	struct ath_buf	*an_ff_buf[WME_NUM_AC]; /* ff staging area */
 	/* variable-length rate control state follows */
 };
 #define	ATH_NODE(ni)	((struct ath_node *)(ni))
@@ -82,6 +89,8 @@
 
 struct ath_buf {
 	STAILQ_ENTRY(ath_buf)	bf_list;
+	TAILQ_ENTRY(ath_buf)	bf_stagelist;	/* stage queue list */
+	u_int32_t		bf_age;		/* age when placed on stageq */
 	int			bf_nseg;
 	struct ath_desc		*bf_desc;	/* virtual addr of desc */
 	bus_addr_t		bf_daddr;	/* physical addr of desc */
@@ -124,6 +133,26 @@
 	u_int32_t		*axq_link;	/* link ptr in last TX desc */
 	STAILQ_HEAD(, ath_buf)	axq_q;		/* transmit queue */
 	struct mtx		axq_lock;	/* lock on q and link */
+	/*
+	 * State for patching up CTS when bursting.
+	 */
+	struct	ath_buf		*axq_linkbuf;	/* va of last buffer */
+	struct	ath_desc	*axq_lastdsWithCTS;
+						/* first desc of last descriptor
+						 * that contains CTS 
+						 */
+	struct	ath_desc	*axq_gatingds;	/* final desc of the gating desc
+						 * that determines whether
+						 * lastdsWithCTS has been DMA'ed
+						 * or not
+						 */
+	/*
+	 * Fast-frame state.  The staging queue holds awaiting
+	 * a fast-frame pairing.  Buffers on this queue are
+	 * assigned an ``age'' and flushed when they wait too long.
+	 */
+	TAILQ_HEAD(axq_headtype, ath_buf) axq_stageq;
+	u_int32_t		axq_curage;	/* queue age */
 };
 
 #define	ATH_TXQ_LOCK_INIT(_sc, _tq) \
@@ -137,6 +166,8 @@
 #define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \
 	STAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \
 	(_tq)->axq_depth++; \
+	(_tq)->axq_curage++; \
+	(_tq)->axq_linkbuf = (_elm); \
 } while (0)
 #define ATH_TXQ_REMOVE_HEAD(_tq, _field) do { \
 	STAILQ_REMOVE_HEAD(&(_tq)->axq_q, _field); \
@@ -190,6 +221,9 @@
 		u_int16_t	ledoff;		/* softled off time */
 	} sc_hwmap[32];				/* h/w rate ix mappings */
 	u_int8_t		sc_protrix;	/* protection rate index */
+	u_int8_t		sc_lastdatarix;	/* last data frame rate index */
+	u_int			sc_fftxqmin;	/* min frames before staging */
+	u_int			sc_fftxqmax;	/* max frames before drop */
 	u_int			sc_txantenna;	/* tx antenna (fixed or auto) */
 	HAL_INT			sc_imask;	/* interrupt mask copy */
 	u_int			sc_keymax;	/* size of key cache */
@@ -462,6 +496,8 @@
 	ath_hal_setcapability(_ah, HAL_CAP_TPC, 1, _v, NULL)
 #define	ath_hal_hasbursting(_ah) \
 	(ath_hal_getcapability(_ah, HAL_CAP_BURST, 0, NULL) == HAL_OK)
+#define	ath_hal_hasfastframes(_ah) \
+	(ath_hal_getcapability(_ah, HAL_CAP_FASTFRAME, 0, NULL) == HAL_OK)
 
 #define	ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \
 	((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))

==== //depot/projects/wifi/sys/net80211/ieee80211.h#8 (text+ko) ====

@@ -431,6 +431,25 @@
 	} band[4] __packed;			/* up to 4 sub bands */
 } __packed;
 
+/*
+ * Atheros advanced capability information element.
+ */
+struct ieee80211_ath_ie {
+	u_int8_t	ath_id;			/* IEEE80211_ELEMID_VENDOR */
+	u_int8_t	ath_len;		/* length in bytes */
+	u_int8_t	ath_oui[3];		/* 0x00, 0x03, 0x7f */
+	u_int8_t	ath_oui_type;		/* OUI type */
+	u_int8_t	ath_oui_subtype;	/* OUI subtype */
+	u_int8_t	ath_version;		/* spec revision */
+	u_int8_t	ath_capability;		/* capability info */
+#define	ATHEROS_CAP_TURBO_PRIME		0x01	/* dynamic turbo--aka Turbo' */
+#define	ATHEROS_CAP_COMPRESSION		0x02	/* data compression */
+#define	ATHEROS_CAP_FAST_FRAME		0x04	/* fast (jumbo) frames */
+/* bits 3-6 reserved */
+#define	ATHEROS_CAP_BOOST		0x80	/* use turbo/!turbo mode */
+	u_int8_t	ath_defkeyix[2];
+} __packed;
+
 #define IEEE80211_CHALLENGE_LEN		128
 
 #define	IEEE80211_RATE_BASIC		0x80
@@ -441,16 +460,10 @@
 #define	IEEE80211_ERP_USE_PROTECTION	0x02
 #define	IEEE80211_ERP_LONG_PREAMBLE	0x04
 
-/* Atheros private advanced capabilities info */
-#define	ATHEROS_CAP_TURBO_PRIME		0x01
-#define	ATHEROS_CAP_COMPRESSION		0x02
-#define	ATHEROS_CAP_FAST_FRAME		0x04
-/* bits 3-6 reserved */
-#define	ATHEROS_CAP_BOOST		0x80
-
 #define	ATH_OUI			0x7f0300		/* Atheros OUI */
 #define	ATH_OUI_TYPE		0x01
-#define	ATH_OUI_VERSION		0x01
+#define	ATH_OUI_SUBTYPE		0x01
+#define	ATH_OUI_VERSION		0x00
 
 #define	WPA_OUI			0xf25000
 #define	WPA_OUI_TYPE		0x01
@@ -634,4 +647,33 @@
 #define	IEEE80211_RTS_MIN		1
 #define	IEEE80211_RTS_MAX		IEEE80211_MAX_LEN
 
+/*
+ * Atheros fast-frame encapsulation format.
+ * FF max payload:
+ * 802.2 + FFHDR + HPAD + 802.3 + 802.2 + 1500 + SPAD + 802.3 + 802.2 + 1500:
+ *   8   +   4   +  4   +   14  +   8   + 1500 +  6   +   14  +   8   + 1500
+ * = 3066
+ */
+/* fast frame header is 32-bits */
+#define	ATH_FF_PROTO	0x0000003f	/* protocol */
+#define	ATH_FF_PROTO_S	0
+#define	ATH_FF_FTYPE	0x000000c0	/* frame type */
+#define	ATH_FF_FTYPE_S	6
+#define	ATH_FF_HLEN32	0x00000300	/* optional hdr length */
+#define	ATH_FF_HLEN32_S	8
+#define	ATH_FF_SEQNUM	0x001ffc00	/* sequence number */
+#define	ATH_FF_SEQNUM_S	10
+#define	ATH_FF_OFFSET	0xffe00000	/* offset to 2nd payload */
+#define	ATH_FF_OFFSET_S	21
+
+#define	ATH_FF_MAX_HDR_PAD	4
+#define	ATH_FF_MAX_SEP_PAD	6
+#define	ATH_FF_MAX_HDR		30
+
+#define	ATH_FF_PROTO_L2TUNNEL	0	/* L2 tunnel protocol */
+#define	ATH_FF_ETH_TYPE		0x88bd	/* Ether type for encapsulated frames */
+#define	ATH_FF_SNAP_ORGCODE_0	0x00
+#define	ATH_FF_SNAP_ORGCODE_1	0x03
+#define	ATH_FF_SNAP_ORGCODE_2	0x7f
+
 #endif /* _NET80211_IEEE80211_H_ */

==== //depot/projects/wifi/sys/net80211/ieee80211_freebsd.h#12 (text+ko) ====

@@ -148,6 +148,7 @@
 extern	struct mbuf *ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen);
 #define	M_LINK0		M_PROTO1		/* WEP requested */
 #define	M_PWR_SAV	M_PROTO4		/* bypass PS handling */
+#define	M_FF		M_PROTO5		/* fast-frame */
 /*
  * Encode WME access control bits in the PROTO flags.
  * This is safe since it's passed directly in to the

==== //depot/projects/wifi/sys/net80211/ieee80211_input.c#36 (text+ko) ====

@@ -1611,6 +1611,40 @@
 #undef MS
 }
 
+static int
+ieee80211_parse_athparams(struct ieee80211_node *ni, u_int8_t *frm,
+	const struct ieee80211_frame *wh)
+{
+	struct ieee80211com *ic = ni->ni_ic;
+	const struct ieee80211_ath_ie *ath;
+	u_int len = frm[1];
+	int caps;
+
+	if (len < sizeof(struct ieee80211_ath_ie)-2) {
+		IEEE80211_DISCARD_IE(ic,
+		    IEEE80211_MSG_ELEMID | IEEE80211_MSG_SUPERG,
+		    wh, "Atheros", "too short, len %u", len);
+		return -1;
+	}
+	ath = (const struct ieee80211_ath_ie *)frm;
+	caps = 0;
+	if ((ath->ath_capability & ATHEROS_CAP_TURBO_PRIME) &&
+	    (ic->ic_flags & IEEE80211_F_TURBOP))
+		caps |= IEEE80211_NODE_TURBOP;
+	if ((ath->ath_capability & ATHEROS_CAP_FAST_FRAME) &&
+	    (ic->ic_flags & IEEE80211_F_FF))
+		caps |= IEEE80211_NODE_FF;
+	if ((ni->ni_flags ^ caps) & IEEE80211_NODE_ATH) {
+		IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG,
+		    "[%s] ath ie: caps 0x%x defkeyix 0x%x, use 0x%x\n",
+		    ether_sprintf(ni->ni_macaddr),
+		    ath->ath_capability, LE_READ_2(ath->ath_defkeyix), caps);
+		ni->ni_flags = (ni->ni_flags &~ IEEE80211_NODE_ATH) | caps;
+		return 1;
+	} else
+		return 0;			/* NB: no change */
+}
+
 static void
 ieee80211_saveie(u_int8_t **iep, const u_int8_t *ie)
 {
@@ -1669,7 +1703,7 @@
 #define	ISREASSOC(_st)	((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
 	struct ieee80211_frame *wh;
 	u_int8_t *frm, *efrm;
-	u_int8_t *ssid, *rates, *xrates, *wpa, *wme;
+	u_int8_t *ssid, *rates, *xrates, *wpa, *wme, *ath;
 	int reassoc, resp, allocbs;
 
 	wh = mtod(m0, struct ieee80211_frame *);
@@ -1710,12 +1744,13 @@
 		 *	[tlv] extended supported rates
 		 *	[tlv] WME
 		 *	[tlv] WPA or RSN
+		 *	[tlv] Atheros capabilities
 		 */
 		IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
 		tstamp  = frm;				frm += 8;
 		bintval = le16toh(*(u_int16_t *)frm);	frm += 2;
 		capinfo = le16toh(*(u_int16_t *)frm);	frm += 2;
-		ssid = rates = xrates = country = wpa = wme = NULL;
+		ssid = rates = xrates = country = wpa = wme = ath = NULL;
 		bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
 		chan = bchan;
 		fhdwell = 0;
@@ -1775,7 +1810,8 @@
 					wpa = frm;
 				else if (iswmeparam(frm) || iswmeinfo(frm))
 					wme = frm;
-				/* XXX Atheros OUI support */
+				else if (isatherosoui(frm))
+					ath = frm;
 				break;
 			default:
 				IEEE80211_DISCARD_IE(ic, IEEE80211_MSG_ELEMID,
@@ -1867,6 +1903,8 @@
 			if (wme != NULL &&
 			    ieee80211_parse_wmeparams(ic, wme, wh) > 0)
 				ieee80211_wme_updateparams(ic);
+			if (ath != NULL)
+				ieee80211_parse_athparams(ni, ath, wh);
 			/* NB: don't need the rest of this */
 			if ((ic->ic_flags & IEEE80211_F_SCAN) == 0)
 				return;
@@ -1942,6 +1980,10 @@
 			ieee80211_saveie(&ni->ni_wme_ie, wme);
 		if (wpa != NULL)
 			ieee80211_saveie(&ni->ni_wpa_ie, wpa);
+		if (ath != NULL) {
+			ieee80211_saveie(&ni->ni_ath_ie, ath);
+			(void) ieee80211_parse_athparams(ni, ath, wh);
+		}
 		/* NB: must be after ni_chan is setup */
 		ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT);
 		break;
@@ -1966,8 +2008,9 @@
 		 *	[tlv] ssid
 		 *	[tlv] supported rates
 		 *	[tlv] extended supported rates
+		 *	[tlv] Atheros capabilities
 		 */
-		ssid = rates = xrates = NULL;
+		ssid = rates = xrates = ath = NULL;
 		while (frm < efrm) {
 			switch (*frm) {
 			case IEEE80211_ELEMID_SSID:
@@ -1979,6 +2022,10 @@
 			case IEEE80211_ELEMID_XRATES:
 				xrates = frm;
 				break;
+			case IEEE80211_ELEMID_VENDOR:
+				if (isatherosoui(frm))
+					ath = frm;
+				break;
 			}
 			frm += frm[1] + 2;
 		}
@@ -2007,6 +2054,10 @@
 		    "[%s] recv probe req\n", ether_sprintf(wh->i_addr2));
 		ni->ni_rssi = rssi;
 		ni->ni_rstamp = rstamp;
+		if (ath != NULL) {
+			ieee80211_saveie(&ni->ni_ath_ie, ath);
+			(void) ieee80211_parse_athparams(ni, ath, wh);
+		}
 		rate = ieee80211_setup_rates(ic, ni, rates, xrates,
 			  IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE
 			| IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
@@ -2113,6 +2164,7 @@
 		 *	[tlv] supported rates
 		 *	[tlv] extended supported rates
 		 *	[tlv] WPA or RSN
+		 *	[tlv] Atheros capabilities
 		 */
 		IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
 		if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) {
@@ -2127,7 +2179,7 @@
 		bintval = le16toh(*(u_int16_t *)frm);	frm += 2;
 		if (reassoc)
 			frm += 6;	/* ignore current AP info */
-		ssid = rates = xrates = wpa = wme = NULL;
+		ssid = rates = xrates = wpa = wme = ath = NULL;
 		while (frm < efrm) {
 			switch (*frm) {
 			case IEEE80211_ELEMID_SSID:
@@ -2149,7 +2201,8 @@
 						wpa = frm;
 				} else if (iswmeinfo(frm))
 					wme = frm;
-				/* XXX Atheros OUI support */
+				else if (isatherosoui(frm))
+					ath = frm;
 				break;
 			}
 			frm += frm[1] + 2;
@@ -2276,6 +2329,23 @@
 			ni->ni_wme_ie = NULL;
 			ni->ni_flags &= ~IEEE80211_NODE_QOS;
 		}
+		if (ath != NULL) {
+			/* 
+			 * Record ATH parameters for station, mark
+			 * node with appropriate capabilities, and
+			 * record the information element for
+			 * applications that require it.
+			 */
+			ieee80211_saveie(&ni->ni_ath_ie, ath);
+			(void) ieee80211_parse_athparams(ni, ath, wh);
+		} else if (ni->ni_ath_ie != NULL) {
+			/*
+			 * Flush any state from a previous association.
+			 */
+			FREE(ni->ni_ath_ie, M_DEVBUF);
+			ni->ni_ath_ie = NULL;
+			ni->ni_flags &= ~IEEE80211_NODE_ATH;
+		}
 		ieee80211_node_join(ic, ni, resp);
 		break;
 	}
@@ -2319,7 +2389,7 @@
 		associd = le16toh(*(u_int16_t *)frm);
 		frm += 2;
 
-		rates = xrates = wpa = wme = NULL;
+		rates = xrates = wme = NULL;
 		while (frm < efrm) {
 			switch (*frm) {
 			case IEEE80211_ELEMID_RATES:
@@ -2387,13 +2457,15 @@
 		else
 			ic->ic_flags &= ~IEEE80211_F_USEPROT;
 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
-		    "[%s] %sassoc success: %s preamble, %s slot time%s%s\n",
+		    "[%s] %sassoc success: %s preamble, %s slot time%s%s%s%s\n",
 		    ether_sprintf(wh->i_addr2),
 		    ISREASSOC(subtype) ? "re" : "",
 		    ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
 		    ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
 		    ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "",
-		    ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : ""
+		    ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
+		    ni->ni_flags & IEEE80211_NODE_FF ? ", fast-frames" : "",
+		    ni->ni_flags & IEEE80211_NODE_TURBOP ? ", turbo'" : ""
 		);
 		ieee80211_new_state(ic, IEEE80211_S_RUN, subtype);
 		break;

==== //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#33 (text+ko) ====

@@ -1015,6 +1015,8 @@
 		sr->isr_ie_len += 2+ni->ni_wpa_ie[1];
 	if (ni->ni_wme_ie != NULL)
 		sr->isr_ie_len += 2+ni->ni_wme_ie[1];
+	if (ni->ni_ath_ie != NULL)
+		sr->isr_ie_len += 2+ni->ni_ath_ie[1];
 	sr->isr_len = sizeof(*sr) + sr->isr_ssid_len + sr->isr_ie_len;

>>> TRUNCATED FOR MAIL (1000 lines) <<<



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