PERFORCE change 68510 for review
Sam Leffler
sam at FreeBSD.org
Fri Jan 7 16:17:01 PST 2005
http://perforce.freebsd.org/chv.cgi?CH=68510
Change 68510 by sam at 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) <<<
More information about the p4-projects
mailing list