From owner-p4-projects@FreeBSD.ORG Sat Jan 8 00:17:00 2005 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 5133116A4D0; Sat, 8 Jan 2005 00:17:00 +0000 (GMT) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 2ACDE16A4CE for ; Sat, 8 Jan 2005 00:17:00 +0000 (GMT) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id DD73343D2F for ; Sat, 8 Jan 2005 00:16:59 +0000 (GMT) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id j080GxLb078060 for ; Sat, 8 Jan 2005 00:16:59 GMT (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id j080GxBT078057 for perforce@freebsd.org; Sat, 8 Jan 2005 00:16:59 GMT (envelope-from sam@freebsd.org) Date: Sat, 8 Jan 2005 00:16:59 GMT Message-Id: <200501080016.j080GxBT078057@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to sam@freebsd.org using -f From: Sam Leffler To: Perforce Change Reviews Subject: PERFORCE change 68510 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 08 Jan 2005 00:17:01 -0000 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<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) <<<