Date: Sat, 29 Jan 2011 11:35:23 +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: r218065 - in head/sys: conf dev/ath modules/ath Message-ID: <201101291135.p0TBZNqf030328@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Sat Jan 29 11:35:23 2011 New Revision: 218065 URL: http://svn.freebsd.org/changeset/base/218065 Log: Migrate the TX path code out of if_ath and into a separate source file. There's two reasons for this: * the raw and non-raw TX path shares a lot of duplicate code which should be refactored; * the 11n-ready chip TX path needs a little reworking. Added: head/sys/dev/ath/if_ath_misc.h (contents, props changed) head/sys/dev/ath/if_ath_tx.c (contents, props changed) head/sys/dev/ath/if_ath_tx.h (contents, props changed) Modified: head/sys/conf/files head/sys/dev/ath/if_ath.c head/sys/modules/ath/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Sat Jan 29 10:32:00 2011 (r218064) +++ head/sys/conf/files Sat Jan 29 11:35:23 2011 (r218065) @@ -568,6 +568,8 @@ dev/ath/if_ath.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_debug.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" +dev/ath/if_ath_tx.c optional ath \ + compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_pci.c optional ath pci \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/ah_osdep.c optional ath \ Modified: head/sys/dev/ath/if_ath.c ============================================================================== --- head/sys/dev/ath/if_ath.c Sat Jan 29 10:32:00 2011 (r218064) +++ head/sys/dev/ath/if_ath.c Sat Jan 29 11:35:23 2011 (r218065) @@ -90,6 +90,8 @@ __FBSDID("$FreeBSD$"); #include <dev/ath/ath_hal/ah_diagcodes.h> #include <dev/ath/if_ath_debug.h> +#include <dev/ath/if_ath_misc.h> +#include <dev/ath/if_ath_tx.h> #ifdef ATH_TX99_DIAG #include <dev/ath/ath_tx99/ath_tx99.h> @@ -111,15 +113,6 @@ __FBSDID("$FreeBSD$"); */ CTASSERT(ATH_BCBUF <= 8); -/* unaligned little endian access */ -#define LE_READ_2(p) \ - ((u_int16_t) \ - ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8))) -#define LE_READ_4(p) \ - ((u_int32_t) \ - ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \ - (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24))) - static struct ieee80211vap *ath_vap_create(struct ieee80211com *, const char name[IFNAMSIZ], int unit, int opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], @@ -184,9 +177,6 @@ static int ath_tx_setup(struct ath_softc static int ath_wme_update(struct ieee80211com *); static void ath_tx_cleanupq(struct ath_softc *, struct ath_txq *); static void ath_tx_cleanup(struct ath_softc *); -static void ath_freetx(struct mbuf *); -static int ath_tx_start(struct ath_softc *, struct ieee80211_node *, - struct ath_buf *, struct mbuf *); static void ath_tx_proc_q0(void *, int); static void ath_tx_proc_q0123(void *, int); static void ath_tx_proc(void *, int); @@ -215,8 +205,6 @@ static int ath_rate_setup(struct ath_sof static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode); static void ath_sysctlattach(struct ath_softc *); -static int ath_raw_xmit(struct ieee80211_node *, - struct mbuf *, const struct ieee80211_bpf_params *); static void ath_announce(struct ath_softc *); static void ath_sysctl_stats_attach(struct ath_softc *sc); @@ -1670,7 +1658,7 @@ ath_reset_vap(struct ieee80211vap *vap, return ath_reset(ifp); } -static struct ath_buf * +struct ath_buf * _ath_getbuf_locked(struct ath_softc *sc) { struct ath_buf *bf; @@ -1690,7 +1678,7 @@ _ath_getbuf_locked(struct ath_softc *sc) return bf; } -static struct ath_buf * +struct ath_buf * ath_getbuf(struct ath_softc *sc) { struct ath_buf *bf; @@ -1708,54 +1696,6 @@ ath_getbuf(struct ath_softc *sc) return bf; } -/* - * Cleanup driver resources when we run out of buffers - * while processing fragments; return the tx buffers - * allocated and drop node references. - */ -static void -ath_txfrag_cleanup(struct ath_softc *sc, - ath_bufhead *frags, struct ieee80211_node *ni) -{ - struct ath_buf *bf, *next; - - ATH_TXBUF_LOCK_ASSERT(sc); - - STAILQ_FOREACH_SAFE(bf, frags, bf_list, next) { - /* NB: bf assumed clean */ - STAILQ_REMOVE_HEAD(frags, bf_list); - STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); - ieee80211_node_decref(ni); - } -} - -/* - * Setup xmit of a fragmented frame. Allocate a buffer - * for each frag and bump the node reference count to - * reflect the held reference to be setup by ath_tx_start. - */ -static int -ath_txfrag_setup(struct ath_softc *sc, ath_bufhead *frags, - struct mbuf *m0, struct ieee80211_node *ni) -{ - struct mbuf *m; - struct ath_buf *bf; - - ATH_TXBUF_LOCK(sc); - for (m = m0->m_nextpkt; m != NULL; m = m->m_nextpkt) { - bf = _ath_getbuf_locked(sc); - if (bf == NULL) { /* out of buffers, cleanup */ - ath_txfrag_cleanup(sc, frags, ni); - break; - } - ieee80211_node_incref(ni); - STAILQ_INSERT_TAIL(frags, bf, bf_list); - } - ATH_TXBUF_UNLOCK(sc); - - return !STAILQ_EMPTY(frags); -} - static void ath_start(struct ifnet *ifp) { @@ -4227,7 +4167,7 @@ ath_tx_cleanup(struct ath_softc *sc) * Return h/w rate index for an IEEE rate (w/o basic rate bit) * using the current rates in sc_rixmap. */ -static __inline int +int ath_tx_findrix(const struct ath_softc *sc, uint8_t rate) { int rix = sc->sc_rixmap[rate]; @@ -4236,623 +4176,6 @@ ath_tx_findrix(const struct ath_softc *s } /* - * Reclaim mbuf resources. For fragmented frames we - * need to claim each frag chained with m_nextpkt. - */ -static void -ath_freetx(struct mbuf *m) -{ - struct mbuf *next; - - do { - next = m->m_nextpkt; - m->m_nextpkt = NULL; - m_freem(m); - } while ((m = next) != NULL); -} - -static int -ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0) -{ - struct mbuf *m; - int error; - - /* - * Load the DMA map so any coalescing is done. This - * also calculates the number of descriptors we need. - */ - error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0, - bf->bf_segs, &bf->bf_nseg, - BUS_DMA_NOWAIT); - if (error == EFBIG) { - /* XXX packet requires too many descriptors */ - bf->bf_nseg = ATH_TXDESC+1; - } else if (error != 0) { - sc->sc_stats.ast_tx_busdma++; - ath_freetx(m0); - return error; - } - /* - * Discard null packets and check for packets that - * require too many TX descriptors. We try to convert - * the latter to a cluster. - */ - if (bf->bf_nseg > ATH_TXDESC) { /* too many desc's, linearize */ - sc->sc_stats.ast_tx_linear++; - m = m_collapse(m0, M_DONTWAIT, ATH_TXDESC); - if (m == NULL) { - ath_freetx(m0); - sc->sc_stats.ast_tx_nombuf++; - return ENOMEM; - } - m0 = m; - error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0, - bf->bf_segs, &bf->bf_nseg, - BUS_DMA_NOWAIT); - if (error != 0) { - sc->sc_stats.ast_tx_busdma++; - ath_freetx(m0); - return error; - } - KASSERT(bf->bf_nseg <= ATH_TXDESC, - ("too many segments after defrag; nseg %u", bf->bf_nseg)); - } else if (bf->bf_nseg == 0) { /* null packet, discard */ - sc->sc_stats.ast_tx_nodata++; - ath_freetx(m0); - return EIO; - } - DPRINTF(sc, ATH_DEBUG_XMIT, "%s: m %p len %u\n", - __func__, m0, m0->m_pkthdr.len); - bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); - bf->bf_m = m0; - - return 0; -} - -static void -ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_desc *ds, *ds0; - int i; - - /* - * Fillin the remainder of the descriptor info. - */ - ds0 = ds = bf->bf_desc; - for (i = 0; i < bf->bf_nseg; i++, ds++) { - ds->ds_data = bf->bf_segs[i].ds_addr; - if (i == bf->bf_nseg - 1) - ds->ds_link = 0; - else - ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1); - ath_hal_filltxdesc(ah, ds - , bf->bf_segs[i].ds_len /* segment length */ - , i == 0 /* first segment */ - , i == bf->bf_nseg - 1 /* last segment */ - , ds0 /* first descriptor */ - ); - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: %d: %08x %08x %08x %08x %08x %08x\n", - __func__, i, ds->ds_link, ds->ds_data, - ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1]); - } - /* - * Insert the frame on the outbound list and pass it on - * to the hardware. Multicast frames buffered for power - * save stations and transmit from the CAB queue are stored - * on a s/w only queue and loaded on to the CAB queue in - * the SWBA handler since frames only go out on DTIM and - * to avoid possible races. - */ - ATH_TXQ_LOCK(txq); - KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0, - ("busy status 0x%x", bf->bf_flags)); - if (txq->axq_qnum != ATH_TXQ_SWQ) { -#ifdef IEEE80211_SUPPORT_TDMA - int qbusy; - - ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); - qbusy = ath_hal_txqenabled(ah, txq->axq_qnum); - if (txq->axq_link == NULL) { - /* - * Be careful writing the address to TXDP. If - * the tx q is enabled then this write will be - * ignored. Normally this is not an issue but - * when tdma is in use and the q is beacon gated - * this race can occur. If the q is busy then - * defer the work to later--either when another - * packet comes along or when we prepare a beacon - * frame at SWBA. - */ - if (!qbusy) { - ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - txq->axq_flags &= ~ATH_TXQ_PUTPENDING; - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: TXDP[%u] = %p (%p) depth %d\n", - __func__, txq->axq_qnum, - (caddr_t)bf->bf_daddr, bf->bf_desc, - txq->axq_depth); - } else { - txq->axq_flags |= ATH_TXQ_PUTPENDING; - DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT, - "%s: Q%u busy, defer enable\n", __func__, - txq->axq_qnum); - } - } else { - *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: link[%u](%p)=%p (%p) depth %d\n", __func__, - txq->axq_qnum, txq->axq_link, - (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth); - if ((txq->axq_flags & ATH_TXQ_PUTPENDING) && !qbusy) { - /* - * The q was busy when we previously tried - * to write the address of the first buffer - * in the chain. Since it's not busy now - * handle this chore. We are certain the - * buffer at the front is the right one since - * axq_link is NULL only when the buffer list - * is/was empty. - */ - ath_hal_puttxbuf(ah, txq->axq_qnum, - STAILQ_FIRST(&txq->axq_q)->bf_daddr); - txq->axq_flags &= ~ATH_TXQ_PUTPENDING; - DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT, - "%s: Q%u restarted\n", __func__, - txq->axq_qnum); - } - } -#else - ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); - if (txq->axq_link == NULL) { - ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: TXDP[%u] = %p (%p) depth %d\n", - __func__, txq->axq_qnum, - (caddr_t)bf->bf_daddr, bf->bf_desc, - txq->axq_depth); - } else { - *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: link[%u](%p)=%p (%p) depth %d\n", __func__, - txq->axq_qnum, txq->axq_link, - (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth); - } -#endif /* IEEE80211_SUPPORT_TDMA */ - txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link; - ath_hal_txstart(ah, txq->axq_qnum); - } else { - if (txq->axq_link != NULL) { - struct ath_buf *last = ATH_TXQ_LAST(txq); - struct ieee80211_frame *wh; - - /* mark previous frame */ - wh = mtod(last->bf_m, struct ieee80211_frame *); - wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; - bus_dmamap_sync(sc->sc_dmat, last->bf_dmamap, - BUS_DMASYNC_PREWRITE); - - /* link descriptor */ - *txq->axq_link = bf->bf_daddr; - } - ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); - txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link; - } - ATH_TXQ_UNLOCK(txq); -} - -static int -ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf, - struct mbuf *m0) -{ - struct ieee80211vap *vap = ni->ni_vap; - struct ath_vap *avp = ATH_VAP(vap); - struct ath_hal *ah = sc->sc_ah; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams; - int error, iswep, ismcast, isfrag, ismrr; - int keyix, hdrlen, pktlen, try0; - u_int8_t rix, txrate, ctsrate; - u_int8_t cix = 0xff; /* NB: silence compiler */ - struct ath_desc *ds; - struct ath_txq *txq; - struct ieee80211_frame *wh; - u_int subtype, flags, ctsduration; - HAL_PKT_TYPE atype; - const HAL_RATE_TABLE *rt; - HAL_BOOL shortPreamble; - struct ath_node *an; - u_int pri; - - wh = mtod(m0, struct ieee80211_frame *); - iswep = wh->i_fc[1] & IEEE80211_FC1_WEP; - ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); - isfrag = m0->m_flags & M_FRAG; - hdrlen = ieee80211_anyhdrsize(wh); - /* - * Packet length must not include any - * pad bytes; deduct them here. - */ - pktlen = m0->m_pkthdr.len - (hdrlen & 3); - - if (iswep) { - const struct ieee80211_cipher *cip; - struct ieee80211_key *k; - - /* - * Construct the 802.11 header+trailer for an encrypted - * frame. The only reason this can fail is because of an - * unknown or unsupported cipher/key type. - */ - k = ieee80211_crypto_encap(ni, m0); - if (k == NULL) { - /* - * This can happen when the key is yanked after the - * frame was queued. Just discard the frame; the - * 802.11 layer counts failures and provides - * debugging/diagnostics. - */ - ath_freetx(m0); - return EIO; - } - /* - * Adjust the packet + header lengths for the crypto - * additions and calculate the h/w key index. When - * a s/w mic is done the frame will have had any mic - * added to it prior to entry so m0->m_pkthdr.len will - * account for it. Otherwise we need to add it to the - * packet length. - */ - cip = k->wk_cipher; - hdrlen += cip->ic_header; - pktlen += cip->ic_header + cip->ic_trailer; - /* NB: frags always have any TKIP MIC done in s/w */ - if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && !isfrag) - pktlen += cip->ic_miclen; - keyix = k->wk_keyix; - - /* packet header may have moved, reset our local pointer */ - wh = mtod(m0, struct ieee80211_frame *); - } else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) { - /* - * Use station key cache slot, if assigned. - */ - keyix = ni->ni_ucastkey.wk_keyix; - if (keyix == IEEE80211_KEYIX_NONE) - keyix = HAL_TXKEYIX_INVALID; - } else - keyix = HAL_TXKEYIX_INVALID; - - pktlen += IEEE80211_CRC_LEN; - - /* - * Load the DMA map so any coalescing is done. This - * also calculates the number of descriptors we need. - */ - error = ath_tx_dmasetup(sc, bf, m0); - if (error != 0) - return error; - bf->bf_node = ni; /* NB: held reference */ - m0 = bf->bf_m; /* NB: may have changed */ - wh = mtod(m0, struct ieee80211_frame *); - - /* setup descriptors */ - ds = bf->bf_desc; - rt = sc->sc_currates; - KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); - - /* - * NB: the 802.11 layer marks whether or not we should - * use short preamble based on the current mode and - * negotiated parameters. - */ - if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && - (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) { - shortPreamble = AH_TRUE; - sc->sc_stats.ast_tx_shortpre++; - } else { - shortPreamble = AH_FALSE; - } - - an = ATH_NODE(ni); - flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ - ismrr = 0; /* default no multi-rate retry*/ - pri = M_WME_GETAC(m0); /* honor classification */ - /* XXX use txparams instead of fixed values */ - /* - * Calculate Atheros packet type from IEEE80211 packet header, - * setup for rate calculations, and select h/w transmit queue. - */ - switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { - case IEEE80211_FC0_TYPE_MGT: - subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; - if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) - atype = HAL_PKT_TYPE_BEACON; - else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) - atype = HAL_PKT_TYPE_PROBE_RESP; - else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM) - atype = HAL_PKT_TYPE_ATIM; - else - atype = HAL_PKT_TYPE_NORMAL; /* XXX */ - rix = an->an_mgmtrix; - txrate = rt->info[rix].rateCode; - if (shortPreamble) - txrate |= rt->info[rix].shortPreamble; - try0 = ATH_TXMGTTRY; - flags |= HAL_TXDESC_INTREQ; /* force interrupt */ - break; - case IEEE80211_FC0_TYPE_CTL: - atype = HAL_PKT_TYPE_PSPOLL; /* stop setting of duration */ - rix = an->an_mgmtrix; - txrate = rt->info[rix].rateCode; - if (shortPreamble) - txrate |= rt->info[rix].shortPreamble; - try0 = ATH_TXMGTTRY; - flags |= HAL_TXDESC_INTREQ; /* force interrupt */ - break; - case IEEE80211_FC0_TYPE_DATA: - atype = HAL_PKT_TYPE_NORMAL; /* default */ - /* - * Data frames: multicast frames go out at a fixed rate, - * EAPOL frames use the mgmt frame rate; otherwise consult - * the rate control module for the rate to use. - */ - if (ismcast) { - rix = an->an_mcastrix; - txrate = rt->info[rix].rateCode; - if (shortPreamble) - txrate |= rt->info[rix].shortPreamble; - try0 = 1; - } else if (m0->m_flags & M_EAPOL) { - /* XXX? maybe always use long preamble? */ - rix = an->an_mgmtrix; - txrate = rt->info[rix].rateCode; - if (shortPreamble) - txrate |= rt->info[rix].shortPreamble; - try0 = ATH_TXMAXTRY; /* XXX?too many? */ - } else { - ath_rate_findrate(sc, an, shortPreamble, pktlen, - &rix, &try0, &txrate); - sc->sc_txrix = rix; /* for LED blinking */ - sc->sc_lastdatarix = rix; /* for fast frames */ - if (try0 != ATH_TXMAXTRY) - ismrr = 1; - } - if (cap->cap_wmeParams[pri].wmep_noackPolicy) - flags |= HAL_TXDESC_NOACK; - break; - default: - if_printf(ifp, "bogus frame type 0x%x (%s)\n", - wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__); - /* XXX statistic */ - ath_freetx(m0); - return EIO; - } - txq = sc->sc_ac2q[pri]; - - /* - * When servicing one or more stations in power-save mode - * (or) if there is some mcast data waiting on the mcast - * queue (to prevent out of order delivery) multicast - * frames must be buffered until after the beacon. - */ - if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth)) - txq = &avp->av_mcastq; - - /* - * Calculate miscellaneous flags. - */ - if (ismcast) { - flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */ - } else if (pktlen > vap->iv_rtsthreshold && - (ni->ni_ath_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++; - } - if (flags & HAL_TXDESC_NOACK) /* NB: avoid double counting */ - sc->sc_stats.ast_tx_noack++; -#ifdef IEEE80211_SUPPORT_TDMA - if (sc->sc_tdma && (flags & HAL_TXDESC_NOACK) == 0) { - DPRINTF(sc, ATH_DEBUG_TDMA, - "%s: discard frame, ACK required w/ TDMA\n", __func__); - sc->sc_stats.ast_tdma_ack++; - ath_freetx(m0); - return EIO; - } -#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) { - /* 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; - if (isfrag) { - /* - * 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). - */ - cix = rt->info[sc->sc_protrix].controlRate; - } else - cix = rt->info[sc->sc_protrix].controlRate; - sc->sc_stats.ast_tx_protect++; - } - - /* - * 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); - } - - /* - * Calculate RTS/CTS rate and duration if needed. - */ - ctsduration = 0; - if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) { - /* - * CTS transmit rate is derived from the transmit rate - * by looking in the h/w rate table. We must also factor - * in whether or not a short preamble is to be used. - */ - /* NB: cix is set above where RTS/CTS is enabled */ - KASSERT(cix != 0xff, ("cix not setup")); - ctsrate = rt->info[cix].rateCode; - /* - * Compute the transmit duration based on the frame - * size and the size of an ACK frame. We call into the - * HAL to do the computation since it depends on the - * characteristics of the actual PHY being used. - * - * NB: CTS is assumed the same size as an ACK so we can - * use the precalculated ACK durations. - */ - if (shortPreamble) { - ctsrate |= rt->info[cix].shortPreamble; - if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ - ctsduration += rt->info[cix].spAckDuration; - ctsduration += ath_hal_computetxtime(ah, - rt, pktlen, rix, AH_TRUE); - if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ - ctsduration += rt->info[rix].spAckDuration; - } else { - if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ - ctsduration += rt->info[cix].lpAckDuration; - ctsduration += ath_hal_computetxtime(ah, - rt, pktlen, rix, AH_FALSE); - if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ - ctsduration += rt->info[rix].lpAckDuration; - } - /* - * Must disable multi-rate retry when using RTS/CTS. - */ - ismrr = 0; - try0 = ATH_TXMGTTRY; /* XXX */ - } else - ctsrate = 0; - - /* - * At this point we are committed to sending the frame - * and we don't need to look at m_nextpkt; clear it in - * case this frame is part of frag chain. - */ - m0->m_nextpkt = NULL; - - if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT)) - ieee80211_dump_pkt(ic, mtod(m0, const uint8_t *), m0->m_len, - sc->sc_hwmap[rix].ieeerate, -1); - - if (ieee80211_radiotap_active_vap(vap)) { - u_int64_t tsf = ath_hal_gettsf64(ah); - - sc->sc_tx_th.wt_tsf = htole64(tsf); - sc->sc_tx_th.wt_flags = sc->sc_hwmap[rix].txflags; - if (iswep) - sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; - if (isfrag) - sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG; - sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate; - sc->sc_tx_th.wt_txpower = ni->ni_txpower; - sc->sc_tx_th.wt_antenna = sc->sc_txantenna; - - ieee80211_radiotap_tx(vap, m0); - } - - /* - * 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 - * when the descriptor is specifically marked to generate - * an interrupt. We periodically mark descriptors in this - * way to insure timely replenishing of the supply needed - * for sending frames. Defering interrupts reduces system - * load and potentially allows more concurrent work to be - * done but if done to aggressively can cause senders to - * backup. - * - * NB: use >= to deal with sc_txintrperiod changing - * dynamically through sysctl. - */ - if (flags & HAL_TXDESC_INTREQ) { - txq->axq_intrcnt = 0; - } else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) { - flags |= HAL_TXDESC_INTREQ; - txq->axq_intrcnt = 0; - } - - /* - * Formulate first tx descriptor with tx controls. - */ - /* XXX check return value? */ - ath_hal_setuptxdesc(ah, ds - , pktlen /* packet length */ - , hdrlen /* header length */ - , atype /* Atheros packet type */ - , ni->ni_txpower /* txpower */ - , txrate, try0 /* series 0 rate/tries */ - , keyix /* key cache index */ - , sc->sc_txantenna /* antenna mode */ - , flags /* flags */ - , ctsrate /* rts/cts rate */ - , ctsduration /* rts/cts duration */ - ); - bf->bf_txflags = flags; - /* - * Setup the multi-rate retry state only when we're - * going to use it. This assumes ath_hal_setuptxdesc - * initializes the descriptors (so we don't have to) - * when the hardware supports multi-rate retry and - * we don't use it. - */ - if (ismrr) - ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix); - - ath_tx_handoff(sc, txq, bf); - return 0; -} - -/* * Process completed xmit descriptors from the specified queue. */ static int @@ -6586,276 +5909,6 @@ ath_sysctlattach(struct ath_softc *sc) #endif } -static int -ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, - struct ath_buf *bf, struct mbuf *m0, - const struct ieee80211_bpf_params *params) -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ath_hal *ah = sc->sc_ah; - struct ieee80211vap *vap = ni->ni_vap; - int error, ismcast, ismrr; - int keyix, hdrlen, pktlen, try0, txantenna; - u_int8_t rix, cix, txrate, ctsrate, rate1, rate2, rate3; - struct ieee80211_frame *wh; - u_int flags, ctsduration; - HAL_PKT_TYPE atype; - const HAL_RATE_TABLE *rt; - struct ath_desc *ds; - u_int pri; - - wh = mtod(m0, struct ieee80211_frame *); - ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); - hdrlen = ieee80211_anyhdrsize(wh); - /* - * Packet length must not include any - * pad bytes; deduct them here. - */ - /* XXX honor IEEE80211_BPF_DATAPAD */ - pktlen = m0->m_pkthdr.len - (hdrlen & 3) + IEEE80211_CRC_LEN; - - if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { - const struct ieee80211_cipher *cip; - struct ieee80211_key *k; - - /* - * Construct the 802.11 header+trailer for an encrypted - * frame. The only reason this can fail is because of an - * unknown or unsupported cipher/key type. - */ - k = ieee80211_crypto_encap(ni, m0); - if (k == NULL) { - /* - * This can happen when the key is yanked after the - * frame was queued. Just discard the frame; the - * 802.11 layer counts failures and provides - * debugging/diagnostics. - */ - ath_freetx(m0); - return EIO; - } - /* - * Adjust the packet + header lengths for the crypto - * additions and calculate the h/w key index. When - * a s/w mic is done the frame will have had any mic - * added to it prior to entry so m0->m_pkthdr.len will - * account for it. Otherwise we need to add it to the - * packet length. - */ - cip = k->wk_cipher; - hdrlen += cip->ic_header; - pktlen += cip->ic_header + cip->ic_trailer; - /* NB: frags always have any TKIP MIC done in s/w */ - if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0) - pktlen += cip->ic_miclen; - keyix = k->wk_keyix; - - /* packet header may have moved, reset our local pointer */ - wh = mtod(m0, struct ieee80211_frame *); - } else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) { - /* - * Use station key cache slot, if assigned. - */ - keyix = ni->ni_ucastkey.wk_keyix; - if (keyix == IEEE80211_KEYIX_NONE) - keyix = HAL_TXKEYIX_INVALID; - } else - keyix = HAL_TXKEYIX_INVALID; - - error = ath_tx_dmasetup(sc, bf, m0); - if (error != 0) - return error; - m0 = bf->bf_m; /* NB: may have changed */ - wh = mtod(m0, struct ieee80211_frame *); - bf->bf_node = ni; /* NB: held reference */ - - flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ - flags |= HAL_TXDESC_INTREQ; /* force interrupt */ - if (params->ibp_flags & IEEE80211_BPF_RTS) - flags |= HAL_TXDESC_RTSENA; - else if (params->ibp_flags & IEEE80211_BPF_CTS) - flags |= HAL_TXDESC_CTSENA; - /* XXX leave ismcast to injector? */ - if ((params->ibp_flags & IEEE80211_BPF_NOACK) || ismcast) - flags |= HAL_TXDESC_NOACK; - - rt = sc->sc_currates; - KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); - rix = ath_tx_findrix(sc, params->ibp_rate0); - txrate = rt->info[rix].rateCode; - if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) - txrate |= rt->info[rix].shortPreamble; - sc->sc_txrix = rix; - try0 = params->ibp_try0; - ismrr = (params->ibp_try1 != 0); - txantenna = params->ibp_pri >> 2; - if (txantenna == 0) /* XXX? */ - txantenna = sc->sc_txantenna; - ctsduration = 0; - if (flags & (HAL_TXDESC_CTSENA | HAL_TXDESC_RTSENA)) { - cix = ath_tx_findrix(sc, params->ibp_ctsrate); - ctsrate = rt->info[cix].rateCode; - if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) { - ctsrate |= rt->info[cix].shortPreamble; - if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ - ctsduration += rt->info[cix].spAckDuration; - ctsduration += ath_hal_computetxtime(ah, - rt, pktlen, rix, AH_TRUE); - if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ - ctsduration += rt->info[rix].spAckDuration; - } else { - if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ - ctsduration += rt->info[cix].lpAckDuration; - ctsduration += ath_hal_computetxtime(ah, - rt, pktlen, rix, AH_FALSE); - if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ - ctsduration += rt->info[rix].lpAckDuration; - } - ismrr = 0; /* XXX */ - } else - ctsrate = 0; - pri = params->ibp_pri & 3; - /* - * NB: we mark all packets as type PSPOLL so the h/w won't - * set the sequence number, duration, etc. - */ - atype = HAL_PKT_TYPE_PSPOLL; - - if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT)) - ieee80211_dump_pkt(ic, mtod(m0, caddr_t), m0->m_len, - sc->sc_hwmap[rix].ieeerate, -1); - - if (ieee80211_radiotap_active_vap(vap)) { - u_int64_t tsf = ath_hal_gettsf64(ah); - - sc->sc_tx_th.wt_tsf = htole64(tsf); - sc->sc_tx_th.wt_flags = sc->sc_hwmap[rix].txflags; - if (wh->i_fc[1] & IEEE80211_FC1_WEP) - sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; - if (m0->m_flags & M_FRAG) - sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG; - sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate; - sc->sc_tx_th.wt_txpower = ni->ni_txpower; - sc->sc_tx_th.wt_antenna = sc->sc_txantenna; - - ieee80211_radiotap_tx(vap, m0); - } - - /* - * Formulate first tx descriptor with tx controls. - */ - ds = bf->bf_desc; - /* XXX check return value? */ - ath_hal_setuptxdesc(ah, ds - , pktlen /* packet length */ - , hdrlen /* header length */ - , atype /* Atheros packet type */ - , params->ibp_power /* txpower */ - , txrate, try0 /* series 0 rate/tries */ - , keyix /* key cache index */ - , txantenna /* antenna mode */ - , flags /* flags */ - , ctsrate /* rts/cts rate */ - , ctsduration /* rts/cts duration */ - ); - bf->bf_txflags = flags; - - if (ismrr) { - rix = ath_tx_findrix(sc, params->ibp_rate1); - rate1 = rt->info[rix].rateCode; - if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) - rate1 |= rt->info[rix].shortPreamble; - if (params->ibp_try2) { - rix = ath_tx_findrix(sc, params->ibp_rate2); - rate2 = rt->info[rix].rateCode; - if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) - rate2 |= rt->info[rix].shortPreamble; - } else - rate2 = 0; - if (params->ibp_try3) { - rix = ath_tx_findrix(sc, params->ibp_rate3); - rate3 = rt->info[rix].rateCode; - if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) - rate3 |= rt->info[rix].shortPreamble; - } else - rate3 = 0; - ath_hal_setupxtxdesc(ah, ds - , rate1, params->ibp_try1 /* series 1 */ - , rate2, params->ibp_try2 /* series 2 */ - , rate3, params->ibp_try3 /* series 3 */ - ); - } - - /* NB: no buffered multicast in power save support */ - ath_tx_handoff(sc, sc->sc_ac2q[pri], bf); - return 0; -} - -static int -ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, - const struct ieee80211_bpf_params *params) -{ - struct ieee80211com *ic = ni->ni_ic; - struct ifnet *ifp = ic->ic_ifp; - struct ath_softc *sc = ifp->if_softc; - struct ath_buf *bf; - int error; - - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) { - DPRINTF(sc, ATH_DEBUG_XMIT, "%s: discard frame, %s", __func__, - (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ? - "!running" : "invalid"); - m_freem(m); - error = ENETDOWN; - goto bad; - } - /* - * Grab a TX buffer and associated resources. - */ - bf = ath_getbuf(sc); - if (bf == NULL) { - sc->sc_stats.ast_tx_nobuf++; - m_freem(m); - error = ENOBUFS; - goto bad; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101291135.p0TBZNqf030328>