svn commit: r218065 - in head/sys: conf dev/ath modules/ath
Adrian Chadd
adrian at FreeBSD.org
Sat Jan 29 11:35:24 UTC 2011
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 ***
More information about the svn-src-all
mailing list