xref: /freebsd/sys/dev/ath/if_ath_tx.c (revision 6edf1dc729487049fb8ccb1d6149c5ca385d9d98)
1b8e788a5SAdrian Chadd /*-
2b8e788a5SAdrian Chadd  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3b8e788a5SAdrian Chadd  * All rights reserved.
4b8e788a5SAdrian Chadd  *
5b8e788a5SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
6b8e788a5SAdrian Chadd  * modification, are permitted provided that the following conditions
7b8e788a5SAdrian Chadd  * are met:
8b8e788a5SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
9b8e788a5SAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
10b8e788a5SAdrian Chadd  *    without modification.
11b8e788a5SAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12b8e788a5SAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13b8e788a5SAdrian Chadd  *    redistribution must be conditioned upon including a substantially
14b8e788a5SAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
15b8e788a5SAdrian Chadd  *
16b8e788a5SAdrian Chadd  * NO WARRANTY
17b8e788a5SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18b8e788a5SAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19b8e788a5SAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20b8e788a5SAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21b8e788a5SAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22b8e788a5SAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23b8e788a5SAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24b8e788a5SAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25b8e788a5SAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26b8e788a5SAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27b8e788a5SAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
28b8e788a5SAdrian Chadd  */
29b8e788a5SAdrian Chadd 
30b8e788a5SAdrian Chadd #include <sys/cdefs.h>
31b8e788a5SAdrian Chadd __FBSDID("$FreeBSD$");
32b8e788a5SAdrian Chadd 
33b8e788a5SAdrian Chadd /*
34b8e788a5SAdrian Chadd  * Driver for the Atheros Wireless LAN controller.
35b8e788a5SAdrian Chadd  *
36b8e788a5SAdrian Chadd  * This software is derived from work of Atsushi Onoe; his contribution
37b8e788a5SAdrian Chadd  * is greatly appreciated.
38b8e788a5SAdrian Chadd  */
39b8e788a5SAdrian Chadd 
40b8e788a5SAdrian Chadd #include "opt_inet.h"
41b8e788a5SAdrian Chadd #include "opt_ath.h"
42b8e788a5SAdrian Chadd #include "opt_wlan.h"
43b8e788a5SAdrian Chadd 
44b8e788a5SAdrian Chadd #include <sys/param.h>
45b8e788a5SAdrian Chadd #include <sys/systm.h>
46b8e788a5SAdrian Chadd #include <sys/sysctl.h>
47b8e788a5SAdrian Chadd #include <sys/mbuf.h>
48b8e788a5SAdrian Chadd #include <sys/malloc.h>
49b8e788a5SAdrian Chadd #include <sys/lock.h>
50b8e788a5SAdrian Chadd #include <sys/mutex.h>
51b8e788a5SAdrian Chadd #include <sys/kernel.h>
52b8e788a5SAdrian Chadd #include <sys/socket.h>
53b8e788a5SAdrian Chadd #include <sys/sockio.h>
54b8e788a5SAdrian Chadd #include <sys/errno.h>
55b8e788a5SAdrian Chadd #include <sys/callout.h>
56b8e788a5SAdrian Chadd #include <sys/bus.h>
57b8e788a5SAdrian Chadd #include <sys/endian.h>
58b8e788a5SAdrian Chadd #include <sys/kthread.h>
59b8e788a5SAdrian Chadd #include <sys/taskqueue.h>
60b8e788a5SAdrian Chadd #include <sys/priv.h>
61b8e788a5SAdrian Chadd 
62b8e788a5SAdrian Chadd #include <machine/bus.h>
63b8e788a5SAdrian Chadd 
64b8e788a5SAdrian Chadd #include <net/if.h>
65b8e788a5SAdrian Chadd #include <net/if_dl.h>
66b8e788a5SAdrian Chadd #include <net/if_media.h>
67b8e788a5SAdrian Chadd #include <net/if_types.h>
68b8e788a5SAdrian Chadd #include <net/if_arp.h>
69b8e788a5SAdrian Chadd #include <net/ethernet.h>
70b8e788a5SAdrian Chadd #include <net/if_llc.h>
71b8e788a5SAdrian Chadd 
72b8e788a5SAdrian Chadd #include <net80211/ieee80211_var.h>
73b8e788a5SAdrian Chadd #include <net80211/ieee80211_regdomain.h>
74b8e788a5SAdrian Chadd #ifdef IEEE80211_SUPPORT_SUPERG
75b8e788a5SAdrian Chadd #include <net80211/ieee80211_superg.h>
76b8e788a5SAdrian Chadd #endif
77b8e788a5SAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA
78b8e788a5SAdrian Chadd #include <net80211/ieee80211_tdma.h>
79b8e788a5SAdrian Chadd #endif
80b8e788a5SAdrian Chadd 
81b8e788a5SAdrian Chadd #include <net/bpf.h>
82b8e788a5SAdrian Chadd 
83b8e788a5SAdrian Chadd #ifdef INET
84b8e788a5SAdrian Chadd #include <netinet/in.h>
85b8e788a5SAdrian Chadd #include <netinet/if_ether.h>
86b8e788a5SAdrian Chadd #endif
87b8e788a5SAdrian Chadd 
88b8e788a5SAdrian Chadd #include <dev/ath/if_athvar.h>
89b8e788a5SAdrian Chadd #include <dev/ath/ath_hal/ah_devid.h>		/* XXX for softled */
90b8e788a5SAdrian Chadd #include <dev/ath/ath_hal/ah_diagcodes.h>
91b8e788a5SAdrian Chadd 
92b8e788a5SAdrian Chadd #include <dev/ath/if_ath_debug.h>
93b8e788a5SAdrian Chadd 
94b8e788a5SAdrian Chadd #ifdef ATH_TX99_DIAG
95b8e788a5SAdrian Chadd #include <dev/ath/ath_tx99/ath_tx99.h>
96b8e788a5SAdrian Chadd #endif
97b8e788a5SAdrian Chadd 
98b8e788a5SAdrian Chadd #include <dev/ath/if_ath_misc.h>
99b8e788a5SAdrian Chadd #include <dev/ath/if_ath_tx.h>
100c1782ce0SAdrian Chadd #include <dev/ath/if_ath_tx_ht.h>
101b8e788a5SAdrian Chadd 
10281a82688SAdrian Chadd /*
10381a82688SAdrian Chadd  * Whether to use the 11n rate scenario functions or not
10481a82688SAdrian Chadd  */
10581a82688SAdrian Chadd static inline int
10681a82688SAdrian Chadd ath_tx_is_11n(struct ath_softc *sc)
10781a82688SAdrian Chadd {
10881a82688SAdrian Chadd 	return (sc->sc_ah->ah_magic == 0x20065416);
10981a82688SAdrian Chadd }
11081a82688SAdrian Chadd 
111b8e788a5SAdrian Chadd void
112b8e788a5SAdrian Chadd ath_txfrag_cleanup(struct ath_softc *sc,
113b8e788a5SAdrian Chadd 	ath_bufhead *frags, struct ieee80211_node *ni)
114b8e788a5SAdrian Chadd {
115b8e788a5SAdrian Chadd 	struct ath_buf *bf, *next;
116b8e788a5SAdrian Chadd 
117b8e788a5SAdrian Chadd 	ATH_TXBUF_LOCK_ASSERT(sc);
118b8e788a5SAdrian Chadd 
1196b349e5aSAdrian Chadd 	TAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
120b8e788a5SAdrian Chadd 		/* NB: bf assumed clean */
1216b349e5aSAdrian Chadd 		TAILQ_REMOVE(frags, bf, bf_list);
1226b349e5aSAdrian Chadd 		TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
123b8e788a5SAdrian Chadd 		ieee80211_node_decref(ni);
124b8e788a5SAdrian Chadd 	}
125b8e788a5SAdrian Chadd }
126b8e788a5SAdrian Chadd 
127b8e788a5SAdrian Chadd /*
128b8e788a5SAdrian Chadd  * Setup xmit of a fragmented frame.  Allocate a buffer
129b8e788a5SAdrian Chadd  * for each frag and bump the node reference count to
130b8e788a5SAdrian Chadd  * reflect the held reference to be setup by ath_tx_start.
131b8e788a5SAdrian Chadd  */
132b8e788a5SAdrian Chadd int
133b8e788a5SAdrian Chadd ath_txfrag_setup(struct ath_softc *sc, ath_bufhead *frags,
134b8e788a5SAdrian Chadd 	struct mbuf *m0, struct ieee80211_node *ni)
135b8e788a5SAdrian Chadd {
136b8e788a5SAdrian Chadd 	struct mbuf *m;
137b8e788a5SAdrian Chadd 	struct ath_buf *bf;
138b8e788a5SAdrian Chadd 
139b8e788a5SAdrian Chadd 	ATH_TXBUF_LOCK(sc);
140b8e788a5SAdrian Chadd 	for (m = m0->m_nextpkt; m != NULL; m = m->m_nextpkt) {
141b8e788a5SAdrian Chadd 		bf = _ath_getbuf_locked(sc);
142b8e788a5SAdrian Chadd 		if (bf == NULL) {	/* out of buffers, cleanup */
143b8e788a5SAdrian Chadd 			ath_txfrag_cleanup(sc, frags, ni);
144b8e788a5SAdrian Chadd 			break;
145b8e788a5SAdrian Chadd 		}
146b8e788a5SAdrian Chadd 		ieee80211_node_incref(ni);
1476b349e5aSAdrian Chadd 		TAILQ_INSERT_TAIL(frags, bf, bf_list);
148b8e788a5SAdrian Chadd 	}
149b8e788a5SAdrian Chadd 	ATH_TXBUF_UNLOCK(sc);
150b8e788a5SAdrian Chadd 
1516b349e5aSAdrian Chadd 	return !TAILQ_EMPTY(frags);
152b8e788a5SAdrian Chadd }
153b8e788a5SAdrian Chadd 
154b8e788a5SAdrian Chadd /*
155b8e788a5SAdrian Chadd  * Reclaim mbuf resources.  For fragmented frames we
156b8e788a5SAdrian Chadd  * need to claim each frag chained with m_nextpkt.
157b8e788a5SAdrian Chadd  */
158b8e788a5SAdrian Chadd void
159b8e788a5SAdrian Chadd ath_freetx(struct mbuf *m)
160b8e788a5SAdrian Chadd {
161b8e788a5SAdrian Chadd 	struct mbuf *next;
162b8e788a5SAdrian Chadd 
163b8e788a5SAdrian Chadd 	do {
164b8e788a5SAdrian Chadd 		next = m->m_nextpkt;
165b8e788a5SAdrian Chadd 		m->m_nextpkt = NULL;
166b8e788a5SAdrian Chadd 		m_freem(m);
167b8e788a5SAdrian Chadd 	} while ((m = next) != NULL);
168b8e788a5SAdrian Chadd }
169b8e788a5SAdrian Chadd 
170b8e788a5SAdrian Chadd static int
171b8e788a5SAdrian Chadd ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0)
172b8e788a5SAdrian Chadd {
173b8e788a5SAdrian Chadd 	struct mbuf *m;
174b8e788a5SAdrian Chadd 	int error;
175b8e788a5SAdrian Chadd 
176b8e788a5SAdrian Chadd 	/*
177b8e788a5SAdrian Chadd 	 * Load the DMA map so any coalescing is done.  This
178b8e788a5SAdrian Chadd 	 * also calculates the number of descriptors we need.
179b8e788a5SAdrian Chadd 	 */
180b8e788a5SAdrian Chadd 	error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0,
181b8e788a5SAdrian Chadd 				     bf->bf_segs, &bf->bf_nseg,
182b8e788a5SAdrian Chadd 				     BUS_DMA_NOWAIT);
183b8e788a5SAdrian Chadd 	if (error == EFBIG) {
184b8e788a5SAdrian Chadd 		/* XXX packet requires too many descriptors */
185b8e788a5SAdrian Chadd 		bf->bf_nseg = ATH_TXDESC+1;
186b8e788a5SAdrian Chadd 	} else if (error != 0) {
187b8e788a5SAdrian Chadd 		sc->sc_stats.ast_tx_busdma++;
188b8e788a5SAdrian Chadd 		ath_freetx(m0);
189b8e788a5SAdrian Chadd 		return error;
190b8e788a5SAdrian Chadd 	}
191b8e788a5SAdrian Chadd 	/*
192b8e788a5SAdrian Chadd 	 * Discard null packets and check for packets that
193b8e788a5SAdrian Chadd 	 * require too many TX descriptors.  We try to convert
194b8e788a5SAdrian Chadd 	 * the latter to a cluster.
195b8e788a5SAdrian Chadd 	 */
196b8e788a5SAdrian Chadd 	if (bf->bf_nseg > ATH_TXDESC) {		/* too many desc's, linearize */
197b8e788a5SAdrian Chadd 		sc->sc_stats.ast_tx_linear++;
198b8e788a5SAdrian Chadd 		m = m_collapse(m0, M_DONTWAIT, ATH_TXDESC);
199b8e788a5SAdrian Chadd 		if (m == NULL) {
200b8e788a5SAdrian Chadd 			ath_freetx(m0);
201b8e788a5SAdrian Chadd 			sc->sc_stats.ast_tx_nombuf++;
202b8e788a5SAdrian Chadd 			return ENOMEM;
203b8e788a5SAdrian Chadd 		}
204b8e788a5SAdrian Chadd 		m0 = m;
205b8e788a5SAdrian Chadd 		error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0,
206b8e788a5SAdrian Chadd 					     bf->bf_segs, &bf->bf_nseg,
207b8e788a5SAdrian Chadd 					     BUS_DMA_NOWAIT);
208b8e788a5SAdrian Chadd 		if (error != 0) {
209b8e788a5SAdrian Chadd 			sc->sc_stats.ast_tx_busdma++;
210b8e788a5SAdrian Chadd 			ath_freetx(m0);
211b8e788a5SAdrian Chadd 			return error;
212b8e788a5SAdrian Chadd 		}
213b8e788a5SAdrian Chadd 		KASSERT(bf->bf_nseg <= ATH_TXDESC,
214b8e788a5SAdrian Chadd 		    ("too many segments after defrag; nseg %u", bf->bf_nseg));
215b8e788a5SAdrian Chadd 	} else if (bf->bf_nseg == 0) {		/* null packet, discard */
216b8e788a5SAdrian Chadd 		sc->sc_stats.ast_tx_nodata++;
217b8e788a5SAdrian Chadd 		ath_freetx(m0);
218b8e788a5SAdrian Chadd 		return EIO;
219b8e788a5SAdrian Chadd 	}
220b8e788a5SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_XMIT, "%s: m %p len %u\n",
221b8e788a5SAdrian Chadd 		__func__, m0, m0->m_pkthdr.len);
222b8e788a5SAdrian Chadd 	bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
223b8e788a5SAdrian Chadd 	bf->bf_m = m0;
224b8e788a5SAdrian Chadd 
225b8e788a5SAdrian Chadd 	return 0;
226b8e788a5SAdrian Chadd }
227b8e788a5SAdrian Chadd 
228*6edf1dc7SAdrian Chadd /*
229*6edf1dc7SAdrian Chadd  * Chain together segments+descriptors for a non-11n frame.
230*6edf1dc7SAdrian Chadd  */
231b8e788a5SAdrian Chadd static void
23281a82688SAdrian Chadd ath_tx_chaindesclist(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
233b8e788a5SAdrian Chadd {
234b8e788a5SAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
235b8e788a5SAdrian Chadd 	struct ath_desc *ds, *ds0;
236b8e788a5SAdrian Chadd 	int i;
237b8e788a5SAdrian Chadd 
238b8e788a5SAdrian Chadd 	/*
239b8e788a5SAdrian Chadd 	 * Fillin the remainder of the descriptor info.
240b8e788a5SAdrian Chadd 	 */
241b8e788a5SAdrian Chadd 	ds0 = ds = bf->bf_desc;
242b8e788a5SAdrian Chadd 	for (i = 0; i < bf->bf_nseg; i++, ds++) {
243b8e788a5SAdrian Chadd 		ds->ds_data = bf->bf_segs[i].ds_addr;
244b8e788a5SAdrian Chadd 		if (i == bf->bf_nseg - 1)
245b8e788a5SAdrian Chadd 			ds->ds_link = 0;
246b8e788a5SAdrian Chadd 		else
247b8e788a5SAdrian Chadd 			ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1);
248b8e788a5SAdrian Chadd 		ath_hal_filltxdesc(ah, ds
249b8e788a5SAdrian Chadd 			, bf->bf_segs[i].ds_len	/* segment length */
250b8e788a5SAdrian Chadd 			, i == 0		/* first segment */
251b8e788a5SAdrian Chadd 			, i == bf->bf_nseg - 1	/* last segment */
252b8e788a5SAdrian Chadd 			, ds0			/* first descriptor */
253b8e788a5SAdrian Chadd 		);
254b8e788a5SAdrian Chadd 		DPRINTF(sc, ATH_DEBUG_XMIT,
255b8e788a5SAdrian Chadd 			"%s: %d: %08x %08x %08x %08x %08x %08x\n",
256b8e788a5SAdrian Chadd 			__func__, i, ds->ds_link, ds->ds_data,
257b8e788a5SAdrian Chadd 			ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1]);
258*6edf1dc7SAdrian Chadd 		bf->bf_lastds = ds;
259b8e788a5SAdrian Chadd 	}
26081a82688SAdrian Chadd }
26181a82688SAdrian Chadd 
26281a82688SAdrian Chadd static void
26381a82688SAdrian Chadd ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
26481a82688SAdrian Chadd {
26581a82688SAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
26681a82688SAdrian Chadd 
26781a82688SAdrian Chadd 	/* Fill in the details in the descriptor list */
26881a82688SAdrian Chadd 	ath_tx_chaindesclist(sc, txq, bf);
26981a82688SAdrian Chadd 
270b8e788a5SAdrian Chadd 	/*
271b8e788a5SAdrian Chadd 	 * Insert the frame on the outbound list and pass it on
272b8e788a5SAdrian Chadd 	 * to the hardware.  Multicast frames buffered for power
273b8e788a5SAdrian Chadd 	 * save stations and transmit from the CAB queue are stored
274b8e788a5SAdrian Chadd 	 * on a s/w only queue and loaded on to the CAB queue in
275b8e788a5SAdrian Chadd 	 * the SWBA handler since frames only go out on DTIM and
276b8e788a5SAdrian Chadd 	 * to avoid possible races.
277b8e788a5SAdrian Chadd 	 */
278b8e788a5SAdrian Chadd 	ATH_TXQ_LOCK(txq);
279b8e788a5SAdrian Chadd 	KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0,
280b8e788a5SAdrian Chadd 	     ("busy status 0x%x", bf->bf_flags));
281b8e788a5SAdrian Chadd 	if (txq->axq_qnum != ATH_TXQ_SWQ) {
282b8e788a5SAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA
283b8e788a5SAdrian Chadd 		int qbusy;
284b8e788a5SAdrian Chadd 
285b8e788a5SAdrian Chadd 		ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
286b8e788a5SAdrian Chadd 		qbusy = ath_hal_txqenabled(ah, txq->axq_qnum);
287b8e788a5SAdrian Chadd 		if (txq->axq_link == NULL) {
288b8e788a5SAdrian Chadd 			/*
289b8e788a5SAdrian Chadd 			 * Be careful writing the address to TXDP.  If
290b8e788a5SAdrian Chadd 			 * the tx q is enabled then this write will be
291b8e788a5SAdrian Chadd 			 * ignored.  Normally this is not an issue but
292b8e788a5SAdrian Chadd 			 * when tdma is in use and the q is beacon gated
293b8e788a5SAdrian Chadd 			 * this race can occur.  If the q is busy then
294b8e788a5SAdrian Chadd 			 * defer the work to later--either when another
295b8e788a5SAdrian Chadd 			 * packet comes along or when we prepare a beacon
296b8e788a5SAdrian Chadd 			 * frame at SWBA.
297b8e788a5SAdrian Chadd 			 */
298b8e788a5SAdrian Chadd 			if (!qbusy) {
299b8e788a5SAdrian Chadd 				ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
300b8e788a5SAdrian Chadd 				txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
301b8e788a5SAdrian Chadd 				DPRINTF(sc, ATH_DEBUG_XMIT,
302b8e788a5SAdrian Chadd 				    "%s: TXDP[%u] = %p (%p) depth %d\n",
303b8e788a5SAdrian Chadd 				    __func__, txq->axq_qnum,
304b8e788a5SAdrian Chadd 				    (caddr_t)bf->bf_daddr, bf->bf_desc,
305b8e788a5SAdrian Chadd 				    txq->axq_depth);
306b8e788a5SAdrian Chadd 			} else {
307b8e788a5SAdrian Chadd 				txq->axq_flags |= ATH_TXQ_PUTPENDING;
308b8e788a5SAdrian Chadd 				DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
309b8e788a5SAdrian Chadd 				    "%s: Q%u busy, defer enable\n", __func__,
310b8e788a5SAdrian Chadd 				    txq->axq_qnum);
311b8e788a5SAdrian Chadd 			}
312b8e788a5SAdrian Chadd 		} else {
313b8e788a5SAdrian Chadd 			*txq->axq_link = bf->bf_daddr;
314b8e788a5SAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_XMIT,
315b8e788a5SAdrian Chadd 			    "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
316b8e788a5SAdrian Chadd 			    txq->axq_qnum, txq->axq_link,
317b8e788a5SAdrian Chadd 			    (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth);
318b8e788a5SAdrian Chadd 			if ((txq->axq_flags & ATH_TXQ_PUTPENDING) && !qbusy) {
319b8e788a5SAdrian Chadd 				/*
320b8e788a5SAdrian Chadd 				 * The q was busy when we previously tried
321b8e788a5SAdrian Chadd 				 * to write the address of the first buffer
322b8e788a5SAdrian Chadd 				 * in the chain.  Since it's not busy now
323b8e788a5SAdrian Chadd 				 * handle this chore.  We are certain the
324b8e788a5SAdrian Chadd 				 * buffer at the front is the right one since
325b8e788a5SAdrian Chadd 				 * axq_link is NULL only when the buffer list
326b8e788a5SAdrian Chadd 				 * is/was empty.
327b8e788a5SAdrian Chadd 				 */
328b8e788a5SAdrian Chadd 				ath_hal_puttxbuf(ah, txq->axq_qnum,
3296b349e5aSAdrian Chadd 					TAILQ_FIRST(&txq->axq_q)->bf_daddr);
330b8e788a5SAdrian Chadd 				txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
331b8e788a5SAdrian Chadd 				DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
332b8e788a5SAdrian Chadd 				    "%s: Q%u restarted\n", __func__,
333b8e788a5SAdrian Chadd 				    txq->axq_qnum);
334b8e788a5SAdrian Chadd 			}
335b8e788a5SAdrian Chadd 		}
336b8e788a5SAdrian Chadd #else
337b8e788a5SAdrian Chadd 		ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
338b8e788a5SAdrian Chadd 		if (txq->axq_link == NULL) {
339b8e788a5SAdrian Chadd 			ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
340b8e788a5SAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_XMIT,
341b8e788a5SAdrian Chadd 			    "%s: TXDP[%u] = %p (%p) depth %d\n",
342b8e788a5SAdrian Chadd 			    __func__, txq->axq_qnum,
343b8e788a5SAdrian Chadd 			    (caddr_t)bf->bf_daddr, bf->bf_desc,
344b8e788a5SAdrian Chadd 			    txq->axq_depth);
345b8e788a5SAdrian Chadd 		} else {
346b8e788a5SAdrian Chadd 			*txq->axq_link = bf->bf_daddr;
347b8e788a5SAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_XMIT,
348b8e788a5SAdrian Chadd 			    "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
349b8e788a5SAdrian Chadd 			    txq->axq_qnum, txq->axq_link,
350b8e788a5SAdrian Chadd 			    (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth);
351b8e788a5SAdrian Chadd 		}
352b8e788a5SAdrian Chadd #endif /* IEEE80211_SUPPORT_TDMA */
353*6edf1dc7SAdrian Chadd 		if (bf->bf_state.bfs_aggr)
354*6edf1dc7SAdrian Chadd 			txq->axq_aggr_depth++;
355*6edf1dc7SAdrian Chadd 		txq->axq_link = &bf->bf_lastds->ds_link;
356b8e788a5SAdrian Chadd 		ath_hal_txstart(ah, txq->axq_qnum);
357b8e788a5SAdrian Chadd 	} else {
358b8e788a5SAdrian Chadd 		if (txq->axq_link != NULL) {
3596b349e5aSAdrian Chadd 			struct ath_buf *last = ATH_TXQ_LAST(txq, axq_q_s);
360b8e788a5SAdrian Chadd 			struct ieee80211_frame *wh;
361b8e788a5SAdrian Chadd 
362b8e788a5SAdrian Chadd 			/* mark previous frame */
363b8e788a5SAdrian Chadd 			wh = mtod(last->bf_m, struct ieee80211_frame *);
364b8e788a5SAdrian Chadd 			wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
365b8e788a5SAdrian Chadd 			bus_dmamap_sync(sc->sc_dmat, last->bf_dmamap,
366b8e788a5SAdrian Chadd 			    BUS_DMASYNC_PREWRITE);
367b8e788a5SAdrian Chadd 
368b8e788a5SAdrian Chadd 			/* link descriptor */
369b8e788a5SAdrian Chadd 			*txq->axq_link = bf->bf_daddr;
370b8e788a5SAdrian Chadd 		}
371b8e788a5SAdrian Chadd 		ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
372b8e788a5SAdrian Chadd 		txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
373b8e788a5SAdrian Chadd 	}
374b8e788a5SAdrian Chadd 	ATH_TXQ_UNLOCK(txq);
375b8e788a5SAdrian Chadd }
376b8e788a5SAdrian Chadd 
37781a82688SAdrian Chadd static int
37881a82688SAdrian Chadd ath_tx_tag_crypto(struct ath_softc *sc, struct ieee80211_node *ni,
37981a82688SAdrian Chadd     struct mbuf *m0, int iswep, int isfrag, int *hdrlen, int *pktlen, int *keyix)
38081a82688SAdrian Chadd {
38181a82688SAdrian Chadd 	if (iswep) {
38281a82688SAdrian Chadd 		const struct ieee80211_cipher *cip;
38381a82688SAdrian Chadd 		struct ieee80211_key *k;
38481a82688SAdrian Chadd 
38581a82688SAdrian Chadd 		/*
38681a82688SAdrian Chadd 		 * Construct the 802.11 header+trailer for an encrypted
38781a82688SAdrian Chadd 		 * frame. The only reason this can fail is because of an
38881a82688SAdrian Chadd 		 * unknown or unsupported cipher/key type.
38981a82688SAdrian Chadd 		 */
39081a82688SAdrian Chadd 		k = ieee80211_crypto_encap(ni, m0);
39181a82688SAdrian Chadd 		if (k == NULL) {
39281a82688SAdrian Chadd 			/*
39381a82688SAdrian Chadd 			 * This can happen when the key is yanked after the
39481a82688SAdrian Chadd 			 * frame was queued.  Just discard the frame; the
39581a82688SAdrian Chadd 			 * 802.11 layer counts failures and provides
39681a82688SAdrian Chadd 			 * debugging/diagnostics.
39781a82688SAdrian Chadd 			 */
39881a82688SAdrian Chadd 			return 0;
39981a82688SAdrian Chadd 		}
40081a82688SAdrian Chadd 		/*
40181a82688SAdrian Chadd 		 * Adjust the packet + header lengths for the crypto
40281a82688SAdrian Chadd 		 * additions and calculate the h/w key index.  When
40381a82688SAdrian Chadd 		 * a s/w mic is done the frame will have had any mic
40481a82688SAdrian Chadd 		 * added to it prior to entry so m0->m_pkthdr.len will
40581a82688SAdrian Chadd 		 * account for it. Otherwise we need to add it to the
40681a82688SAdrian Chadd 		 * packet length.
40781a82688SAdrian Chadd 		 */
40881a82688SAdrian Chadd 		cip = k->wk_cipher;
40981a82688SAdrian Chadd 		(*hdrlen) += cip->ic_header;
41081a82688SAdrian Chadd 		(*pktlen) += cip->ic_header + cip->ic_trailer;
41181a82688SAdrian Chadd 		/* NB: frags always have any TKIP MIC done in s/w */
41281a82688SAdrian Chadd 		if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && !isfrag)
41381a82688SAdrian Chadd 			(*pktlen) += cip->ic_miclen;
41481a82688SAdrian Chadd 		(*keyix) = k->wk_keyix;
41581a82688SAdrian Chadd 	} else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
41681a82688SAdrian Chadd 		/*
41781a82688SAdrian Chadd 		 * Use station key cache slot, if assigned.
41881a82688SAdrian Chadd 		 */
41981a82688SAdrian Chadd 		(*keyix) = ni->ni_ucastkey.wk_keyix;
42081a82688SAdrian Chadd 		if ((*keyix) == IEEE80211_KEYIX_NONE)
42181a82688SAdrian Chadd 			(*keyix) = HAL_TXKEYIX_INVALID;
42281a82688SAdrian Chadd 	} else
42381a82688SAdrian Chadd 		(*keyix) = HAL_TXKEYIX_INVALID;
42481a82688SAdrian Chadd 
42581a82688SAdrian Chadd 	return 1;
42681a82688SAdrian Chadd }
42781a82688SAdrian Chadd 
428e42b5dbaSAdrian Chadd static uint8_t
429e42b5dbaSAdrian Chadd ath_tx_get_rtscts_rate(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
430e42b5dbaSAdrian Chadd     int rix, int cix, int shortPreamble)
43179f02dbfSAdrian Chadd {
432e42b5dbaSAdrian Chadd 	uint8_t ctsrate;
433e42b5dbaSAdrian Chadd 
43479f02dbfSAdrian Chadd 	/*
43579f02dbfSAdrian Chadd 	 * CTS transmit rate is derived from the transmit rate
43679f02dbfSAdrian Chadd 	 * by looking in the h/w rate table.  We must also factor
43779f02dbfSAdrian Chadd 	 * in whether or not a short preamble is to be used.
43879f02dbfSAdrian Chadd 	 */
43979f02dbfSAdrian Chadd 	/* NB: cix is set above where RTS/CTS is enabled */
44079f02dbfSAdrian Chadd 	KASSERT(cix != 0xff, ("cix not setup"));
441e42b5dbaSAdrian Chadd 	ctsrate = rt->info[cix].rateCode;
442e42b5dbaSAdrian Chadd 
443e42b5dbaSAdrian Chadd 	/* XXX this should only matter for legacy rates */
444e42b5dbaSAdrian Chadd 	if (shortPreamble)
445e42b5dbaSAdrian Chadd 		ctsrate |= rt->info[cix].shortPreamble;
446e42b5dbaSAdrian Chadd 
447e42b5dbaSAdrian Chadd 	return ctsrate;
448e42b5dbaSAdrian Chadd }
449e42b5dbaSAdrian Chadd 
450e42b5dbaSAdrian Chadd 
451e42b5dbaSAdrian Chadd /*
452e42b5dbaSAdrian Chadd  * Calculate the RTS/CTS duration for legacy frames.
453e42b5dbaSAdrian Chadd  */
454e42b5dbaSAdrian Chadd static int
455e42b5dbaSAdrian Chadd ath_tx_calc_ctsduration(struct ath_hal *ah, int rix, int cix,
456e42b5dbaSAdrian Chadd     int shortPreamble, int pktlen, const HAL_RATE_TABLE *rt,
457e42b5dbaSAdrian Chadd     int flags)
458e42b5dbaSAdrian Chadd {
459e42b5dbaSAdrian Chadd 	int ctsduration = 0;
460e42b5dbaSAdrian Chadd 
461e42b5dbaSAdrian Chadd 	/* This mustn't be called for HT modes */
462e42b5dbaSAdrian Chadd 	if (rt->info[cix].phy == IEEE80211_T_HT) {
463e42b5dbaSAdrian Chadd 		printf("%s: HT rate where it shouldn't be (0x%x)\n",
464e42b5dbaSAdrian Chadd 		    __func__, rt->info[cix].rateCode);
465e42b5dbaSAdrian Chadd 		return -1;
466e42b5dbaSAdrian Chadd 	}
467e42b5dbaSAdrian Chadd 
46879f02dbfSAdrian Chadd 	/*
46979f02dbfSAdrian Chadd 	 * Compute the transmit duration based on the frame
47079f02dbfSAdrian Chadd 	 * size and the size of an ACK frame.  We call into the
47179f02dbfSAdrian Chadd 	 * HAL to do the computation since it depends on the
47279f02dbfSAdrian Chadd 	 * characteristics of the actual PHY being used.
47379f02dbfSAdrian Chadd 	 *
47479f02dbfSAdrian Chadd 	 * NB: CTS is assumed the same size as an ACK so we can
47579f02dbfSAdrian Chadd 	 *     use the precalculated ACK durations.
47679f02dbfSAdrian Chadd 	 */
47779f02dbfSAdrian Chadd 	if (shortPreamble) {
47879f02dbfSAdrian Chadd 		if (flags & HAL_TXDESC_RTSENA)		/* SIFS + CTS */
479e42b5dbaSAdrian Chadd 			ctsduration += rt->info[cix].spAckDuration;
480e42b5dbaSAdrian Chadd 		ctsduration += ath_hal_computetxtime(ah,
48179f02dbfSAdrian Chadd 			rt, pktlen, rix, AH_TRUE);
48279f02dbfSAdrian Chadd 		if ((flags & HAL_TXDESC_NOACK) == 0)	/* SIFS + ACK */
483e42b5dbaSAdrian Chadd 			ctsduration += rt->info[rix].spAckDuration;
48479f02dbfSAdrian Chadd 	} else {
48579f02dbfSAdrian Chadd 		if (flags & HAL_TXDESC_RTSENA)		/* SIFS + CTS */
486e42b5dbaSAdrian Chadd 			ctsduration += rt->info[cix].lpAckDuration;
487e42b5dbaSAdrian Chadd 		ctsduration += ath_hal_computetxtime(ah,
48879f02dbfSAdrian Chadd 			rt, pktlen, rix, AH_FALSE);
48979f02dbfSAdrian Chadd 		if ((flags & HAL_TXDESC_NOACK) == 0)	/* SIFS + ACK */
490e42b5dbaSAdrian Chadd 			ctsduration += rt->info[rix].lpAckDuration;
49179f02dbfSAdrian Chadd 	}
492e42b5dbaSAdrian Chadd 
493e42b5dbaSAdrian Chadd 	return ctsduration;
49479f02dbfSAdrian Chadd }
49579f02dbfSAdrian Chadd 
496b8e788a5SAdrian Chadd int
497b8e788a5SAdrian Chadd ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf,
498b8e788a5SAdrian Chadd     struct mbuf *m0)
499b8e788a5SAdrian Chadd {
500b8e788a5SAdrian Chadd 	struct ieee80211vap *vap = ni->ni_vap;
501b8e788a5SAdrian Chadd 	struct ath_vap *avp = ATH_VAP(vap);
502b8e788a5SAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
503b8e788a5SAdrian Chadd 	struct ifnet *ifp = sc->sc_ifp;
504b8e788a5SAdrian Chadd 	struct ieee80211com *ic = ifp->if_l2com;
505b8e788a5SAdrian Chadd 	const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams;
506b8e788a5SAdrian Chadd 	int error, iswep, ismcast, isfrag, ismrr;
507b8e788a5SAdrian Chadd 	int keyix, hdrlen, pktlen, try0;
508b8e788a5SAdrian Chadd 	u_int8_t rix, txrate, ctsrate;
509b8e788a5SAdrian Chadd 	u_int8_t cix = 0xff;		/* NB: silence compiler */
510b8e788a5SAdrian Chadd 	struct ath_desc *ds;
511b8e788a5SAdrian Chadd 	struct ath_txq *txq;
512b8e788a5SAdrian Chadd 	struct ieee80211_frame *wh;
513b8e788a5SAdrian Chadd 	u_int subtype, flags, ctsduration;
514b8e788a5SAdrian Chadd 	HAL_PKT_TYPE atype;
515b8e788a5SAdrian Chadd 	const HAL_RATE_TABLE *rt;
516b8e788a5SAdrian Chadd 	HAL_BOOL shortPreamble;
517b8e788a5SAdrian Chadd 	struct ath_node *an;
518b8e788a5SAdrian Chadd 	u_int pri;
519c1782ce0SAdrian Chadd 	uint8_t try[4], rate[4];
520c1782ce0SAdrian Chadd 
521c1782ce0SAdrian Chadd 	bzero(try, sizeof(try));
522c1782ce0SAdrian Chadd 	bzero(rate, sizeof(rate));
523b8e788a5SAdrian Chadd 
524b8e788a5SAdrian Chadd 	wh = mtod(m0, struct ieee80211_frame *);
525b8e788a5SAdrian Chadd 	iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
526b8e788a5SAdrian Chadd 	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
527b8e788a5SAdrian Chadd 	isfrag = m0->m_flags & M_FRAG;
528b8e788a5SAdrian Chadd 	hdrlen = ieee80211_anyhdrsize(wh);
529b8e788a5SAdrian Chadd 	/*
530b8e788a5SAdrian Chadd 	 * Packet length must not include any
531b8e788a5SAdrian Chadd 	 * pad bytes; deduct them here.
532b8e788a5SAdrian Chadd 	 */
533b8e788a5SAdrian Chadd 	pktlen = m0->m_pkthdr.len - (hdrlen & 3);
534b8e788a5SAdrian Chadd 
53581a82688SAdrian Chadd 	/* Handle encryption twiddling if needed */
53681a82688SAdrian Chadd 	if (! ath_tx_tag_crypto(sc, ni, m0, iswep, isfrag, &hdrlen, &pktlen, &keyix)) {
537b8e788a5SAdrian Chadd 		ath_freetx(m0);
538b8e788a5SAdrian Chadd 		return EIO;
539b8e788a5SAdrian Chadd 	}
540b8e788a5SAdrian Chadd 
541b8e788a5SAdrian Chadd 	/* packet header may have moved, reset our local pointer */
542b8e788a5SAdrian Chadd 	wh = mtod(m0, struct ieee80211_frame *);
543b8e788a5SAdrian Chadd 
544b8e788a5SAdrian Chadd 	pktlen += IEEE80211_CRC_LEN;
545b8e788a5SAdrian Chadd 
546b8e788a5SAdrian Chadd 	/*
547b8e788a5SAdrian Chadd 	 * Load the DMA map so any coalescing is done.  This
548b8e788a5SAdrian Chadd 	 * also calculates the number of descriptors we need.
549b8e788a5SAdrian Chadd 	 */
550b8e788a5SAdrian Chadd 	error = ath_tx_dmasetup(sc, bf, m0);
551b8e788a5SAdrian Chadd 	if (error != 0)
552b8e788a5SAdrian Chadd 		return error;
553b8e788a5SAdrian Chadd 	bf->bf_node = ni;			/* NB: held reference */
554b8e788a5SAdrian Chadd 	m0 = bf->bf_m;				/* NB: may have changed */
555b8e788a5SAdrian Chadd 	wh = mtod(m0, struct ieee80211_frame *);
556b8e788a5SAdrian Chadd 
557b8e788a5SAdrian Chadd 	/* setup descriptors */
558b8e788a5SAdrian Chadd 	ds = bf->bf_desc;
559b8e788a5SAdrian Chadd 	rt = sc->sc_currates;
560b8e788a5SAdrian Chadd 	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
561b8e788a5SAdrian Chadd 
562b8e788a5SAdrian Chadd 	/*
563b8e788a5SAdrian Chadd 	 * NB: the 802.11 layer marks whether or not we should
564b8e788a5SAdrian Chadd 	 * use short preamble based on the current mode and
565b8e788a5SAdrian Chadd 	 * negotiated parameters.
566b8e788a5SAdrian Chadd 	 */
567b8e788a5SAdrian Chadd 	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
568b8e788a5SAdrian Chadd 	    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
569b8e788a5SAdrian Chadd 		shortPreamble = AH_TRUE;
570b8e788a5SAdrian Chadd 		sc->sc_stats.ast_tx_shortpre++;
571b8e788a5SAdrian Chadd 	} else {
572b8e788a5SAdrian Chadd 		shortPreamble = AH_FALSE;
573b8e788a5SAdrian Chadd 	}
574b8e788a5SAdrian Chadd 
575b8e788a5SAdrian Chadd 	an = ATH_NODE(ni);
576b8e788a5SAdrian Chadd 	flags = HAL_TXDESC_CLRDMASK;		/* XXX needed for crypto errs */
577b8e788a5SAdrian Chadd 	ismrr = 0;				/* default no multi-rate retry*/
578b8e788a5SAdrian Chadd 	pri = M_WME_GETAC(m0);			/* honor classification */
579b8e788a5SAdrian Chadd 	/* XXX use txparams instead of fixed values */
580b8e788a5SAdrian Chadd 	/*
581b8e788a5SAdrian Chadd 	 * Calculate Atheros packet type from IEEE80211 packet header,
582b8e788a5SAdrian Chadd 	 * setup for rate calculations, and select h/w transmit queue.
583b8e788a5SAdrian Chadd 	 */
584b8e788a5SAdrian Chadd 	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
585b8e788a5SAdrian Chadd 	case IEEE80211_FC0_TYPE_MGT:
586b8e788a5SAdrian Chadd 		subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
587b8e788a5SAdrian Chadd 		if (subtype == IEEE80211_FC0_SUBTYPE_BEACON)
588b8e788a5SAdrian Chadd 			atype = HAL_PKT_TYPE_BEACON;
589b8e788a5SAdrian Chadd 		else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
590b8e788a5SAdrian Chadd 			atype = HAL_PKT_TYPE_PROBE_RESP;
591b8e788a5SAdrian Chadd 		else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM)
592b8e788a5SAdrian Chadd 			atype = HAL_PKT_TYPE_ATIM;
593b8e788a5SAdrian Chadd 		else
594b8e788a5SAdrian Chadd 			atype = HAL_PKT_TYPE_NORMAL;	/* XXX */
595b8e788a5SAdrian Chadd 		rix = an->an_mgmtrix;
596b8e788a5SAdrian Chadd 		txrate = rt->info[rix].rateCode;
597b8e788a5SAdrian Chadd 		if (shortPreamble)
598b8e788a5SAdrian Chadd 			txrate |= rt->info[rix].shortPreamble;
599b8e788a5SAdrian Chadd 		try0 = ATH_TXMGTTRY;
600b8e788a5SAdrian Chadd 		flags |= HAL_TXDESC_INTREQ;	/* force interrupt */
601b8e788a5SAdrian Chadd 		break;
602b8e788a5SAdrian Chadd 	case IEEE80211_FC0_TYPE_CTL:
603b8e788a5SAdrian Chadd 		atype = HAL_PKT_TYPE_PSPOLL;	/* stop setting of duration */
604b8e788a5SAdrian Chadd 		rix = an->an_mgmtrix;
605b8e788a5SAdrian Chadd 		txrate = rt->info[rix].rateCode;
606b8e788a5SAdrian Chadd 		if (shortPreamble)
607b8e788a5SAdrian Chadd 			txrate |= rt->info[rix].shortPreamble;
608b8e788a5SAdrian Chadd 		try0 = ATH_TXMGTTRY;
609b8e788a5SAdrian Chadd 		flags |= HAL_TXDESC_INTREQ;	/* force interrupt */
610b8e788a5SAdrian Chadd 		break;
611b8e788a5SAdrian Chadd 	case IEEE80211_FC0_TYPE_DATA:
612b8e788a5SAdrian Chadd 		atype = HAL_PKT_TYPE_NORMAL;		/* default */
613b8e788a5SAdrian Chadd 		/*
614b8e788a5SAdrian Chadd 		 * Data frames: multicast frames go out at a fixed rate,
615b8e788a5SAdrian Chadd 		 * EAPOL frames use the mgmt frame rate; otherwise consult
616b8e788a5SAdrian Chadd 		 * the rate control module for the rate to use.
617b8e788a5SAdrian Chadd 		 */
618b8e788a5SAdrian Chadd 		if (ismcast) {
619b8e788a5SAdrian Chadd 			rix = an->an_mcastrix;
620b8e788a5SAdrian Chadd 			txrate = rt->info[rix].rateCode;
621b8e788a5SAdrian Chadd 			if (shortPreamble)
622b8e788a5SAdrian Chadd 				txrate |= rt->info[rix].shortPreamble;
623b8e788a5SAdrian Chadd 			try0 = 1;
624b8e788a5SAdrian Chadd 		} else if (m0->m_flags & M_EAPOL) {
625b8e788a5SAdrian Chadd 			/* XXX? maybe always use long preamble? */
626b8e788a5SAdrian Chadd 			rix = an->an_mgmtrix;
627b8e788a5SAdrian Chadd 			txrate = rt->info[rix].rateCode;
628b8e788a5SAdrian Chadd 			if (shortPreamble)
629b8e788a5SAdrian Chadd 				txrate |= rt->info[rix].shortPreamble;
630b8e788a5SAdrian Chadd 			try0 = ATH_TXMAXTRY;	/* XXX?too many? */
631b8e788a5SAdrian Chadd 		} else {
632b8e788a5SAdrian Chadd 			ath_rate_findrate(sc, an, shortPreamble, pktlen,
633b8e788a5SAdrian Chadd 				&rix, &try0, &txrate);
634b8e788a5SAdrian Chadd 			sc->sc_txrix = rix;		/* for LED blinking */
635b8e788a5SAdrian Chadd 			sc->sc_lastdatarix = rix;	/* for fast frames */
636b8e788a5SAdrian Chadd 			if (try0 != ATH_TXMAXTRY)
637b8e788a5SAdrian Chadd 				ismrr = 1;
638b8e788a5SAdrian Chadd 		}
639b8e788a5SAdrian Chadd 		if (cap->cap_wmeParams[pri].wmep_noackPolicy)
640b8e788a5SAdrian Chadd 			flags |= HAL_TXDESC_NOACK;
641b8e788a5SAdrian Chadd 		break;
642b8e788a5SAdrian Chadd 	default:
643b8e788a5SAdrian Chadd 		if_printf(ifp, "bogus frame type 0x%x (%s)\n",
644b8e788a5SAdrian Chadd 			wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__);
645b8e788a5SAdrian Chadd 		/* XXX statistic */
646b8e788a5SAdrian Chadd 		ath_freetx(m0);
647b8e788a5SAdrian Chadd 		return EIO;
648b8e788a5SAdrian Chadd 	}
649b8e788a5SAdrian Chadd 	txq = sc->sc_ac2q[pri];
650b8e788a5SAdrian Chadd 
651b8e788a5SAdrian Chadd 	/*
652b8e788a5SAdrian Chadd 	 * When servicing one or more stations in power-save mode
653b8e788a5SAdrian Chadd 	 * (or) if there is some mcast data waiting on the mcast
654b8e788a5SAdrian Chadd 	 * queue (to prevent out of order delivery) multicast
655b8e788a5SAdrian Chadd 	 * frames must be buffered until after the beacon.
656b8e788a5SAdrian Chadd 	 */
657b8e788a5SAdrian Chadd 	if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth))
658b8e788a5SAdrian Chadd 		txq = &avp->av_mcastq;
659b8e788a5SAdrian Chadd 
660b8e788a5SAdrian Chadd 	/*
661b8e788a5SAdrian Chadd 	 * Calculate miscellaneous flags.
662b8e788a5SAdrian Chadd 	 */
663b8e788a5SAdrian Chadd 	if (ismcast) {
664b8e788a5SAdrian Chadd 		flags |= HAL_TXDESC_NOACK;	/* no ack on broad/multicast */
665b8e788a5SAdrian Chadd 	} else if (pktlen > vap->iv_rtsthreshold &&
666b8e788a5SAdrian Chadd 	    (ni->ni_ath_flags & IEEE80211_NODE_FF) == 0) {
667b8e788a5SAdrian Chadd 		flags |= HAL_TXDESC_RTSENA;	/* RTS based on frame length */
668b8e788a5SAdrian Chadd 		cix = rt->info[rix].controlRate;
669b8e788a5SAdrian Chadd 		sc->sc_stats.ast_tx_rts++;
670b8e788a5SAdrian Chadd 	}
671b8e788a5SAdrian Chadd 	if (flags & HAL_TXDESC_NOACK)		/* NB: avoid double counting */
672b8e788a5SAdrian Chadd 		sc->sc_stats.ast_tx_noack++;
673b8e788a5SAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA
674b8e788a5SAdrian Chadd 	if (sc->sc_tdma && (flags & HAL_TXDESC_NOACK) == 0) {
675b8e788a5SAdrian Chadd 		DPRINTF(sc, ATH_DEBUG_TDMA,
676b8e788a5SAdrian Chadd 		    "%s: discard frame, ACK required w/ TDMA\n", __func__);
677b8e788a5SAdrian Chadd 		sc->sc_stats.ast_tdma_ack++;
678b8e788a5SAdrian Chadd 		ath_freetx(m0);
679b8e788a5SAdrian Chadd 		return EIO;
680b8e788a5SAdrian Chadd 	}
681b8e788a5SAdrian Chadd #endif
682b8e788a5SAdrian Chadd 
683b8e788a5SAdrian Chadd 	/*
684b8e788a5SAdrian Chadd 	 * If 802.11g protection is enabled, determine whether
685b8e788a5SAdrian Chadd 	 * to use RTS/CTS or just CTS.  Note that this is only
686b8e788a5SAdrian Chadd 	 * done for OFDM unicast frames.
687b8e788a5SAdrian Chadd 	 */
688b8e788a5SAdrian Chadd 	if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
689b8e788a5SAdrian Chadd 	    rt->info[rix].phy == IEEE80211_T_OFDM &&
690b8e788a5SAdrian Chadd 	    (flags & HAL_TXDESC_NOACK) == 0) {
691b8e788a5SAdrian Chadd 		/* XXX fragments must use CCK rates w/ protection */
692b8e788a5SAdrian Chadd 		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
693b8e788a5SAdrian Chadd 			flags |= HAL_TXDESC_RTSENA;
694b8e788a5SAdrian Chadd 		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
695b8e788a5SAdrian Chadd 			flags |= HAL_TXDESC_CTSENA;
696b8e788a5SAdrian Chadd 		if (isfrag) {
697b8e788a5SAdrian Chadd 			/*
698b8e788a5SAdrian Chadd 			 * For frags it would be desirable to use the
699b8e788a5SAdrian Chadd 			 * highest CCK rate for RTS/CTS.  But stations
700b8e788a5SAdrian Chadd 			 * farther away may detect it at a lower CCK rate
701b8e788a5SAdrian Chadd 			 * so use the configured protection rate instead
702b8e788a5SAdrian Chadd 			 * (for now).
703b8e788a5SAdrian Chadd 			 */
704b8e788a5SAdrian Chadd 			cix = rt->info[sc->sc_protrix].controlRate;
705b8e788a5SAdrian Chadd 		} else
706b8e788a5SAdrian Chadd 			cix = rt->info[sc->sc_protrix].controlRate;
707b8e788a5SAdrian Chadd 		sc->sc_stats.ast_tx_protect++;
708b8e788a5SAdrian Chadd 	}
709b8e788a5SAdrian Chadd 
7104f545a2cSAdrian Chadd #if 0
7114f545a2cSAdrian Chadd 	/*
7124f545a2cSAdrian Chadd 	 * If 11n protection is enabled and it's a HT frame,
7134f545a2cSAdrian Chadd 	 * enable RTS.
7144f545a2cSAdrian Chadd 	 *
7154f545a2cSAdrian Chadd 	 * XXX ic_htprotmode or ic_curhtprotmode?
7164f545a2cSAdrian Chadd 	 * XXX should it_htprotmode only matter if ic_curhtprotmode
7174f545a2cSAdrian Chadd 	 * XXX indicates it's not a HT pure environment?
7184f545a2cSAdrian Chadd 	 */
7194f545a2cSAdrian Chadd 	if ((ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) &&
7204f545a2cSAdrian Chadd 	    rt->info[rix].phy == IEEE80211_T_HT &&
7214f545a2cSAdrian Chadd 	    (flags & HAL_TXDESC_NOACK) == 0) {
7224f545a2cSAdrian Chadd 		cix = rt->info[sc->sc_protrix].controlRate;
7234f545a2cSAdrian Chadd 	    	flags |= HAL_TXDESC_RTSENA;
7244f545a2cSAdrian Chadd 		sc->sc_stats.ast_tx_htprotect++;
7254f545a2cSAdrian Chadd 	}
7264f545a2cSAdrian Chadd #endif
7274f545a2cSAdrian Chadd 
728b8e788a5SAdrian Chadd 	/*
729b8e788a5SAdrian Chadd 	 * Calculate duration.  This logically belongs in the 802.11
730b8e788a5SAdrian Chadd 	 * layer but it lacks sufficient information to calculate it.
731b8e788a5SAdrian Chadd 	 */
732b8e788a5SAdrian Chadd 	if ((flags & HAL_TXDESC_NOACK) == 0 &&
733b8e788a5SAdrian Chadd 	    (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
734b8e788a5SAdrian Chadd 		u_int16_t dur;
735b8e788a5SAdrian Chadd 		if (shortPreamble)
736b8e788a5SAdrian Chadd 			dur = rt->info[rix].spAckDuration;
737b8e788a5SAdrian Chadd 		else
738b8e788a5SAdrian Chadd 			dur = rt->info[rix].lpAckDuration;
739b8e788a5SAdrian Chadd 		if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) {
740b8e788a5SAdrian Chadd 			dur += dur;		/* additional SIFS+ACK */
741b8e788a5SAdrian Chadd 			KASSERT(m0->m_nextpkt != NULL, ("no fragment"));
742b8e788a5SAdrian Chadd 			/*
743b8e788a5SAdrian Chadd 			 * Include the size of next fragment so NAV is
744b8e788a5SAdrian Chadd 			 * updated properly.  The last fragment uses only
745b8e788a5SAdrian Chadd 			 * the ACK duration
746b8e788a5SAdrian Chadd 			 */
747b8e788a5SAdrian Chadd 			dur += ath_hal_computetxtime(ah, rt,
748b8e788a5SAdrian Chadd 					m0->m_nextpkt->m_pkthdr.len,
749b8e788a5SAdrian Chadd 					rix, shortPreamble);
750b8e788a5SAdrian Chadd 		}
751b8e788a5SAdrian Chadd 		if (isfrag) {
752b8e788a5SAdrian Chadd 			/*
753b8e788a5SAdrian Chadd 			 * Force hardware to use computed duration for next
754b8e788a5SAdrian Chadd 			 * fragment by disabling multi-rate retry which updates
755b8e788a5SAdrian Chadd 			 * duration based on the multi-rate duration table.
756b8e788a5SAdrian Chadd 			 */
757b8e788a5SAdrian Chadd 			ismrr = 0;
758b8e788a5SAdrian Chadd 			try0 = ATH_TXMGTTRY;	/* XXX? */
759b8e788a5SAdrian Chadd 		}
760b8e788a5SAdrian Chadd 		*(u_int16_t *)wh->i_dur = htole16(dur);
761b8e788a5SAdrian Chadd 	}
762b8e788a5SAdrian Chadd 
763b8e788a5SAdrian Chadd 	/*
764b8e788a5SAdrian Chadd 	 * Calculate RTS/CTS rate and duration if needed.
765b8e788a5SAdrian Chadd 	 */
766b8e788a5SAdrian Chadd 	ctsduration = 0;
767b8e788a5SAdrian Chadd 	if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) {
768e42b5dbaSAdrian Chadd 		ctsrate = ath_tx_get_rtscts_rate(ah, rt, rix, cix, shortPreamble);
769e42b5dbaSAdrian Chadd 
770e42b5dbaSAdrian Chadd 		/* The 11n chipsets do ctsduration calculations for you */
771e42b5dbaSAdrian Chadd 		if (! ath_tx_is_11n(sc))
772e42b5dbaSAdrian Chadd 			ctsduration = ath_tx_calc_ctsduration(ah, rix, cix, shortPreamble,
773e42b5dbaSAdrian Chadd 			    pktlen, rt, flags);
774b8e788a5SAdrian Chadd 		/*
775b8e788a5SAdrian Chadd 		 * Must disable multi-rate retry when using RTS/CTS.
776b8e788a5SAdrian Chadd 		 */
777b8e788a5SAdrian Chadd 		ismrr = 0;
778b8e788a5SAdrian Chadd 		try0 = ATH_TXMGTTRY;		/* XXX */
779b8e788a5SAdrian Chadd 	} else
780b8e788a5SAdrian Chadd 		ctsrate = 0;
781b8e788a5SAdrian Chadd 
782b8e788a5SAdrian Chadd 	/*
783b8e788a5SAdrian Chadd 	 * At this point we are committed to sending the frame
784b8e788a5SAdrian Chadd 	 * and we don't need to look at m_nextpkt; clear it in
785b8e788a5SAdrian Chadd 	 * case this frame is part of frag chain.
786b8e788a5SAdrian Chadd 	 */
787b8e788a5SAdrian Chadd 	m0->m_nextpkt = NULL;
788b8e788a5SAdrian Chadd 
789b8e788a5SAdrian Chadd 	if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT))
790b8e788a5SAdrian Chadd 		ieee80211_dump_pkt(ic, mtod(m0, const uint8_t *), m0->m_len,
791b8e788a5SAdrian Chadd 		    sc->sc_hwmap[rix].ieeerate, -1);
792b8e788a5SAdrian Chadd 
793b8e788a5SAdrian Chadd 	if (ieee80211_radiotap_active_vap(vap)) {
794b8e788a5SAdrian Chadd 		u_int64_t tsf = ath_hal_gettsf64(ah);
795b8e788a5SAdrian Chadd 
796b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_tsf = htole64(tsf);
797b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_flags = sc->sc_hwmap[rix].txflags;
798b8e788a5SAdrian Chadd 		if (iswep)
799b8e788a5SAdrian Chadd 			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
800b8e788a5SAdrian Chadd 		if (isfrag)
801b8e788a5SAdrian Chadd 			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG;
802b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate;
803b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_txpower = ni->ni_txpower;
804b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
805b8e788a5SAdrian Chadd 
806b8e788a5SAdrian Chadd 		ieee80211_radiotap_tx(vap, m0);
807b8e788a5SAdrian Chadd 	}
808b8e788a5SAdrian Chadd 
809b8e788a5SAdrian Chadd 	/*
810b8e788a5SAdrian Chadd 	 * Determine if a tx interrupt should be generated for
811b8e788a5SAdrian Chadd 	 * this descriptor.  We take a tx interrupt to reap
812b8e788a5SAdrian Chadd 	 * descriptors when the h/w hits an EOL condition or
813b8e788a5SAdrian Chadd 	 * when the descriptor is specifically marked to generate
814b8e788a5SAdrian Chadd 	 * an interrupt.  We periodically mark descriptors in this
815b8e788a5SAdrian Chadd 	 * way to insure timely replenishing of the supply needed
816b8e788a5SAdrian Chadd 	 * for sending frames.  Defering interrupts reduces system
817b8e788a5SAdrian Chadd 	 * load and potentially allows more concurrent work to be
818b8e788a5SAdrian Chadd 	 * done but if done to aggressively can cause senders to
819b8e788a5SAdrian Chadd 	 * backup.
820b8e788a5SAdrian Chadd 	 *
821b8e788a5SAdrian Chadd 	 * NB: use >= to deal with sc_txintrperiod changing
822b8e788a5SAdrian Chadd 	 *     dynamically through sysctl.
823b8e788a5SAdrian Chadd 	 */
824b8e788a5SAdrian Chadd 	if (flags & HAL_TXDESC_INTREQ) {
825b8e788a5SAdrian Chadd 		txq->axq_intrcnt = 0;
826b8e788a5SAdrian Chadd 	} else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) {
827b8e788a5SAdrian Chadd 		flags |= HAL_TXDESC_INTREQ;
828b8e788a5SAdrian Chadd 		txq->axq_intrcnt = 0;
829b8e788a5SAdrian Chadd 	}
830b8e788a5SAdrian Chadd 
831c1782ce0SAdrian Chadd 	if (ath_tx_is_11n(sc)) {
832c1782ce0SAdrian Chadd 		rate[0] = rix;
833c1782ce0SAdrian Chadd 		try[0] = try0;
834c1782ce0SAdrian Chadd 	}
835c1782ce0SAdrian Chadd 
836b8e788a5SAdrian Chadd 	/*
837b8e788a5SAdrian Chadd 	 * Formulate first tx descriptor with tx controls.
838b8e788a5SAdrian Chadd 	 */
839b8e788a5SAdrian Chadd 	/* XXX check return value? */
840c1782ce0SAdrian Chadd 	/* XXX is this ok to call for 11n descriptors? */
841c1782ce0SAdrian Chadd 	/* XXX or should it go through the first, next, last 11n calls? */
842b8e788a5SAdrian Chadd 	ath_hal_setuptxdesc(ah, ds
843b8e788a5SAdrian Chadd 		, pktlen		/* packet length */
844b8e788a5SAdrian Chadd 		, hdrlen		/* header length */
845b8e788a5SAdrian Chadd 		, atype			/* Atheros packet type */
846b8e788a5SAdrian Chadd 		, ni->ni_txpower	/* txpower */
847b8e788a5SAdrian Chadd 		, txrate, try0		/* series 0 rate/tries */
848b8e788a5SAdrian Chadd 		, keyix			/* key cache index */
849b8e788a5SAdrian Chadd 		, sc->sc_txantenna	/* antenna mode */
850b8e788a5SAdrian Chadd 		, flags			/* flags */
851b8e788a5SAdrian Chadd 		, ctsrate		/* rts/cts rate */
852b8e788a5SAdrian Chadd 		, ctsduration		/* rts/cts duration */
853b8e788a5SAdrian Chadd 	);
854b8e788a5SAdrian Chadd 	bf->bf_txflags = flags;
855b8e788a5SAdrian Chadd 	/*
856b8e788a5SAdrian Chadd 	 * Setup the multi-rate retry state only when we're
857b8e788a5SAdrian Chadd 	 * going to use it.  This assumes ath_hal_setuptxdesc
858b8e788a5SAdrian Chadd 	 * initializes the descriptors (so we don't have to)
859b8e788a5SAdrian Chadd 	 * when the hardware supports multi-rate retry and
860b8e788a5SAdrian Chadd 	 * we don't use it.
861b8e788a5SAdrian Chadd 	 */
862c1782ce0SAdrian Chadd         if (ismrr) {
863c1782ce0SAdrian Chadd                 if (ath_tx_is_11n(sc))
864c1782ce0SAdrian Chadd                         ath_rate_getxtxrates(sc, an, rix, rate, try);
865c1782ce0SAdrian Chadd                 else
866b8e788a5SAdrian Chadd                         ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix);
867c1782ce0SAdrian Chadd         }
868c1782ce0SAdrian Chadd 
869c1782ce0SAdrian Chadd         if (ath_tx_is_11n(sc)) {
870bf26df36SAdrian Chadd                 ath_buf_set_rate(sc, ni, bf, pktlen, flags, ctsrate, (atype == HAL_PKT_TYPE_PSPOLL), rate, try);
871c1782ce0SAdrian Chadd         }
872b8e788a5SAdrian Chadd 
873b8e788a5SAdrian Chadd 	ath_tx_handoff(sc, txq, bf);
874b8e788a5SAdrian Chadd 	return 0;
875b8e788a5SAdrian Chadd }
876b8e788a5SAdrian Chadd 
877b8e788a5SAdrian Chadd static int
878b8e788a5SAdrian Chadd ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
879b8e788a5SAdrian Chadd 	struct ath_buf *bf, struct mbuf *m0,
880b8e788a5SAdrian Chadd 	const struct ieee80211_bpf_params *params)
881b8e788a5SAdrian Chadd {
882b8e788a5SAdrian Chadd 	struct ifnet *ifp = sc->sc_ifp;
883b8e788a5SAdrian Chadd 	struct ieee80211com *ic = ifp->if_l2com;
884b8e788a5SAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
885b8e788a5SAdrian Chadd 	struct ieee80211vap *vap = ni->ni_vap;
886b8e788a5SAdrian Chadd 	int error, ismcast, ismrr;
887b8e788a5SAdrian Chadd 	int keyix, hdrlen, pktlen, try0, txantenna;
888b8e788a5SAdrian Chadd 	u_int8_t rix, cix, txrate, ctsrate, rate1, rate2, rate3;
889b8e788a5SAdrian Chadd 	struct ieee80211_frame *wh;
890b8e788a5SAdrian Chadd 	u_int flags, ctsduration;
891b8e788a5SAdrian Chadd 	HAL_PKT_TYPE atype;
892b8e788a5SAdrian Chadd 	const HAL_RATE_TABLE *rt;
893b8e788a5SAdrian Chadd 	struct ath_desc *ds;
894b8e788a5SAdrian Chadd 	u_int pri;
895c1782ce0SAdrian Chadd 	uint8_t try[4], rate[4];
896c1782ce0SAdrian Chadd 
897c1782ce0SAdrian Chadd 	bzero(try, sizeof(try));
898c1782ce0SAdrian Chadd 	bzero(rate, sizeof(rate));
899b8e788a5SAdrian Chadd 
900b8e788a5SAdrian Chadd 	wh = mtod(m0, struct ieee80211_frame *);
901b8e788a5SAdrian Chadd 	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
902b8e788a5SAdrian Chadd 	hdrlen = ieee80211_anyhdrsize(wh);
903b8e788a5SAdrian Chadd 	/*
904b8e788a5SAdrian Chadd 	 * Packet length must not include any
905b8e788a5SAdrian Chadd 	 * pad bytes; deduct them here.
906b8e788a5SAdrian Chadd 	 */
907b8e788a5SAdrian Chadd 	/* XXX honor IEEE80211_BPF_DATAPAD */
908b8e788a5SAdrian Chadd 	pktlen = m0->m_pkthdr.len - (hdrlen & 3) + IEEE80211_CRC_LEN;
909b8e788a5SAdrian Chadd 
91081a82688SAdrian Chadd 	/* Handle encryption twiddling if needed */
91181a82688SAdrian Chadd 	if (! ath_tx_tag_crypto(sc, ni, m0, params->ibp_flags & IEEE80211_BPF_CRYPTO, 0, &hdrlen, &pktlen, &keyix)) {
912b8e788a5SAdrian Chadd 		ath_freetx(m0);
913b8e788a5SAdrian Chadd 		return EIO;
914b8e788a5SAdrian Chadd 	}
915b8e788a5SAdrian Chadd 	/* packet header may have moved, reset our local pointer */
916b8e788a5SAdrian Chadd 	wh = mtod(m0, struct ieee80211_frame *);
917b8e788a5SAdrian Chadd 
918b8e788a5SAdrian Chadd 	error = ath_tx_dmasetup(sc, bf, m0);
919b8e788a5SAdrian Chadd 	if (error != 0)
920b8e788a5SAdrian Chadd 		return error;
921b8e788a5SAdrian Chadd 	m0 = bf->bf_m;				/* NB: may have changed */
922b8e788a5SAdrian Chadd 	wh = mtod(m0, struct ieee80211_frame *);
923b8e788a5SAdrian Chadd 	bf->bf_node = ni;			/* NB: held reference */
924b8e788a5SAdrian Chadd 
925b8e788a5SAdrian Chadd 	flags = HAL_TXDESC_CLRDMASK;		/* XXX needed for crypto errs */
926b8e788a5SAdrian Chadd 	flags |= HAL_TXDESC_INTREQ;		/* force interrupt */
927b8e788a5SAdrian Chadd 	if (params->ibp_flags & IEEE80211_BPF_RTS)
928b8e788a5SAdrian Chadd 		flags |= HAL_TXDESC_RTSENA;
929b8e788a5SAdrian Chadd 	else if (params->ibp_flags & IEEE80211_BPF_CTS)
930b8e788a5SAdrian Chadd 		flags |= HAL_TXDESC_CTSENA;
931b8e788a5SAdrian Chadd 	/* XXX leave ismcast to injector? */
932b8e788a5SAdrian Chadd 	if ((params->ibp_flags & IEEE80211_BPF_NOACK) || ismcast)
933b8e788a5SAdrian Chadd 		flags |= HAL_TXDESC_NOACK;
934b8e788a5SAdrian Chadd 
935b8e788a5SAdrian Chadd 	rt = sc->sc_currates;
936b8e788a5SAdrian Chadd 	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
937b8e788a5SAdrian Chadd 	rix = ath_tx_findrix(sc, params->ibp_rate0);
938b8e788a5SAdrian Chadd 	txrate = rt->info[rix].rateCode;
939b8e788a5SAdrian Chadd 	if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
940b8e788a5SAdrian Chadd 		txrate |= rt->info[rix].shortPreamble;
941b8e788a5SAdrian Chadd 	sc->sc_txrix = rix;
942b8e788a5SAdrian Chadd 	try0 = params->ibp_try0;
943b8e788a5SAdrian Chadd 	ismrr = (params->ibp_try1 != 0);
944b8e788a5SAdrian Chadd 	txantenna = params->ibp_pri >> 2;
945b8e788a5SAdrian Chadd 	if (txantenna == 0)			/* XXX? */
946b8e788a5SAdrian Chadd 		txantenna = sc->sc_txantenna;
94779f02dbfSAdrian Chadd 
948b8e788a5SAdrian Chadd 	ctsduration = 0;
94979f02dbfSAdrian Chadd 	if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) {
950b8e788a5SAdrian Chadd 		cix = ath_tx_findrix(sc, params->ibp_ctsrate);
951e42b5dbaSAdrian Chadd 		ctsrate = ath_tx_get_rtscts_rate(ah, rt, rix, cix, params->ibp_flags & IEEE80211_BPF_SHORTPRE);
952e42b5dbaSAdrian Chadd 		/* The 11n chipsets do ctsduration calculations for you */
953e42b5dbaSAdrian Chadd 		if (! ath_tx_is_11n(sc))
954e42b5dbaSAdrian Chadd 			ctsduration = ath_tx_calc_ctsduration(ah, rix, cix,
95579f02dbfSAdrian Chadd 			    params->ibp_flags & IEEE80211_BPF_SHORTPRE, pktlen,
956e42b5dbaSAdrian Chadd 			    rt, flags);
95779f02dbfSAdrian Chadd 		/*
95879f02dbfSAdrian Chadd 		 * Must disable multi-rate retry when using RTS/CTS.
95979f02dbfSAdrian Chadd 		 */
960b8e788a5SAdrian Chadd 		ismrr = 0;			/* XXX */
961b8e788a5SAdrian Chadd 	} else
962b8e788a5SAdrian Chadd 		ctsrate = 0;
96379f02dbfSAdrian Chadd 
964b8e788a5SAdrian Chadd 	pri = params->ibp_pri & 3;
965b8e788a5SAdrian Chadd 	/*
966b8e788a5SAdrian Chadd 	 * NB: we mark all packets as type PSPOLL so the h/w won't
967b8e788a5SAdrian Chadd 	 * set the sequence number, duration, etc.
968b8e788a5SAdrian Chadd 	 */
969b8e788a5SAdrian Chadd 	atype = HAL_PKT_TYPE_PSPOLL;
970b8e788a5SAdrian Chadd 
971b8e788a5SAdrian Chadd 	if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT))
972b8e788a5SAdrian Chadd 		ieee80211_dump_pkt(ic, mtod(m0, caddr_t), m0->m_len,
973b8e788a5SAdrian Chadd 		    sc->sc_hwmap[rix].ieeerate, -1);
974b8e788a5SAdrian Chadd 
975b8e788a5SAdrian Chadd 	if (ieee80211_radiotap_active_vap(vap)) {
976b8e788a5SAdrian Chadd 		u_int64_t tsf = ath_hal_gettsf64(ah);
977b8e788a5SAdrian Chadd 
978b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_tsf = htole64(tsf);
979b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_flags = sc->sc_hwmap[rix].txflags;
980b8e788a5SAdrian Chadd 		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
981b8e788a5SAdrian Chadd 			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
982b8e788a5SAdrian Chadd 		if (m0->m_flags & M_FRAG)
983b8e788a5SAdrian Chadd 			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG;
984b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate;
985b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_txpower = ni->ni_txpower;
986b8e788a5SAdrian Chadd 		sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
987b8e788a5SAdrian Chadd 
988b8e788a5SAdrian Chadd 		ieee80211_radiotap_tx(vap, m0);
989b8e788a5SAdrian Chadd 	}
990b8e788a5SAdrian Chadd 
991b8e788a5SAdrian Chadd 	/*
992b8e788a5SAdrian Chadd 	 * Formulate first tx descriptor with tx controls.
993b8e788a5SAdrian Chadd 	 */
994b8e788a5SAdrian Chadd 	ds = bf->bf_desc;
995b8e788a5SAdrian Chadd 	/* XXX check return value? */
996b8e788a5SAdrian Chadd 	ath_hal_setuptxdesc(ah, ds
997b8e788a5SAdrian Chadd 		, pktlen		/* packet length */
998b8e788a5SAdrian Chadd 		, hdrlen		/* header length */
999b8e788a5SAdrian Chadd 		, atype			/* Atheros packet type */
1000b8e788a5SAdrian Chadd 		, params->ibp_power	/* txpower */
1001b8e788a5SAdrian Chadd 		, txrate, try0		/* series 0 rate/tries */
1002b8e788a5SAdrian Chadd 		, keyix			/* key cache index */
1003b8e788a5SAdrian Chadd 		, txantenna		/* antenna mode */
1004b8e788a5SAdrian Chadd 		, flags			/* flags */
1005b8e788a5SAdrian Chadd 		, ctsrate		/* rts/cts rate */
1006b8e788a5SAdrian Chadd 		, ctsduration		/* rts/cts duration */
1007b8e788a5SAdrian Chadd 	);
1008b8e788a5SAdrian Chadd 	bf->bf_txflags = flags;
1009b8e788a5SAdrian Chadd 
1010c1782ce0SAdrian Chadd 	if (ath_tx_is_11n(sc)) {
1011c1782ce0SAdrian Chadd 		rate[0] = ath_tx_findrix(sc, params->ibp_rate0);
1012c1782ce0SAdrian Chadd 		try[0] = params->ibp_try0;
1013c1782ce0SAdrian Chadd 
1014c1782ce0SAdrian Chadd 		if (ismrr) {
1015c1782ce0SAdrian Chadd 			/* Remember, rate[] is actually an array of rix's -adrian */
1016c1782ce0SAdrian Chadd 			rate[0] = ath_tx_findrix(sc, params->ibp_rate0);
1017c1782ce0SAdrian Chadd 			rate[1] = ath_tx_findrix(sc, params->ibp_rate1);
1018c1782ce0SAdrian Chadd 			rate[2] = ath_tx_findrix(sc, params->ibp_rate2);
1019c1782ce0SAdrian Chadd 			rate[3] = ath_tx_findrix(sc, params->ibp_rate3);
1020c1782ce0SAdrian Chadd 
1021c1782ce0SAdrian Chadd 			try[0] = params->ibp_try0;
1022c1782ce0SAdrian Chadd 			try[1] = params->ibp_try1;
1023c1782ce0SAdrian Chadd 			try[2] = params->ibp_try2;
1024c1782ce0SAdrian Chadd 			try[3] = params->ibp_try3;
1025c1782ce0SAdrian Chadd 		}
1026c1782ce0SAdrian Chadd 	} else {
1027b8e788a5SAdrian Chadd 		if (ismrr) {
1028b8e788a5SAdrian Chadd 			rix = ath_tx_findrix(sc, params->ibp_rate1);
1029b8e788a5SAdrian Chadd 			rate1 = rt->info[rix].rateCode;
1030b8e788a5SAdrian Chadd 			if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
1031b8e788a5SAdrian Chadd 				rate1 |= rt->info[rix].shortPreamble;
1032b8e788a5SAdrian Chadd 			if (params->ibp_try2) {
1033b8e788a5SAdrian Chadd 				rix = ath_tx_findrix(sc, params->ibp_rate2);
1034b8e788a5SAdrian Chadd 				rate2 = rt->info[rix].rateCode;
1035b8e788a5SAdrian Chadd 				if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
1036b8e788a5SAdrian Chadd 					rate2 |= rt->info[rix].shortPreamble;
1037b8e788a5SAdrian Chadd 			} else
1038b8e788a5SAdrian Chadd 				rate2 = 0;
1039b8e788a5SAdrian Chadd 			if (params->ibp_try3) {
1040b8e788a5SAdrian Chadd 				rix = ath_tx_findrix(sc, params->ibp_rate3);
1041b8e788a5SAdrian Chadd 				rate3 = rt->info[rix].rateCode;
1042b8e788a5SAdrian Chadd 				if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
1043b8e788a5SAdrian Chadd 					rate3 |= rt->info[rix].shortPreamble;
1044b8e788a5SAdrian Chadd 			} else
1045b8e788a5SAdrian Chadd 				rate3 = 0;
1046b8e788a5SAdrian Chadd 			ath_hal_setupxtxdesc(ah, ds
1047b8e788a5SAdrian Chadd 				, rate1, params->ibp_try1	/* series 1 */
1048b8e788a5SAdrian Chadd 				, rate2, params->ibp_try2	/* series 2 */
1049b8e788a5SAdrian Chadd 				, rate3, params->ibp_try3	/* series 3 */
1050b8e788a5SAdrian Chadd 			);
1051b8e788a5SAdrian Chadd 		}
1052c1782ce0SAdrian Chadd 	}
1053c1782ce0SAdrian Chadd 
1054c1782ce0SAdrian Chadd 	if (ath_tx_is_11n(sc)) {
1055c1782ce0SAdrian Chadd 		/*
1056c1782ce0SAdrian Chadd 		 * notice that rix doesn't include any of the "magic" flags txrate
1057c1782ce0SAdrian Chadd 		 * does for communicating "other stuff" to the HAL.
1058c1782ce0SAdrian Chadd 		 */
1059bf26df36SAdrian Chadd 		ath_buf_set_rate(sc, ni, bf, pktlen, flags, ctsrate, (atype == HAL_PKT_TYPE_PSPOLL), rate, try);
1060c1782ce0SAdrian Chadd 	}
1061b8e788a5SAdrian Chadd 
1062b8e788a5SAdrian Chadd 	/* NB: no buffered multicast in power save support */
1063b8e788a5SAdrian Chadd 	ath_tx_handoff(sc, sc->sc_ac2q[pri], bf);
1064b8e788a5SAdrian Chadd 	return 0;
1065b8e788a5SAdrian Chadd }
1066b8e788a5SAdrian Chadd 
1067b8e788a5SAdrian Chadd int
1068b8e788a5SAdrian Chadd ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
1069b8e788a5SAdrian Chadd 	const struct ieee80211_bpf_params *params)
1070b8e788a5SAdrian Chadd {
1071b8e788a5SAdrian Chadd 	struct ieee80211com *ic = ni->ni_ic;
1072b8e788a5SAdrian Chadd 	struct ifnet *ifp = ic->ic_ifp;
1073b8e788a5SAdrian Chadd 	struct ath_softc *sc = ifp->if_softc;
1074b8e788a5SAdrian Chadd 	struct ath_buf *bf;
1075b8e788a5SAdrian Chadd 	int error;
1076b8e788a5SAdrian Chadd 
1077b8e788a5SAdrian Chadd 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) {
1078b8e788a5SAdrian Chadd 		DPRINTF(sc, ATH_DEBUG_XMIT, "%s: discard frame, %s", __func__,
1079b8e788a5SAdrian Chadd 		    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ?
1080b8e788a5SAdrian Chadd 			"!running" : "invalid");
1081b8e788a5SAdrian Chadd 		m_freem(m);
1082b8e788a5SAdrian Chadd 		error = ENETDOWN;
1083b8e788a5SAdrian Chadd 		goto bad;
1084b8e788a5SAdrian Chadd 	}
1085b8e788a5SAdrian Chadd 	/*
1086b8e788a5SAdrian Chadd 	 * Grab a TX buffer and associated resources.
1087b8e788a5SAdrian Chadd 	 */
1088b8e788a5SAdrian Chadd 	bf = ath_getbuf(sc);
1089b8e788a5SAdrian Chadd 	if (bf == NULL) {
1090b8e788a5SAdrian Chadd 		sc->sc_stats.ast_tx_nobuf++;
1091b8e788a5SAdrian Chadd 		m_freem(m);
1092b8e788a5SAdrian Chadd 		error = ENOBUFS;
1093b8e788a5SAdrian Chadd 		goto bad;
1094b8e788a5SAdrian Chadd 	}
1095b8e788a5SAdrian Chadd 
1096b8e788a5SAdrian Chadd 	if (params == NULL) {
1097b8e788a5SAdrian Chadd 		/*
1098b8e788a5SAdrian Chadd 		 * Legacy path; interpret frame contents to decide
1099b8e788a5SAdrian Chadd 		 * precisely how to send the frame.
1100b8e788a5SAdrian Chadd 		 */
1101b8e788a5SAdrian Chadd 		if (ath_tx_start(sc, ni, bf, m)) {
1102b8e788a5SAdrian Chadd 			error = EIO;		/* XXX */
1103b8e788a5SAdrian Chadd 			goto bad2;
1104b8e788a5SAdrian Chadd 		}
1105b8e788a5SAdrian Chadd 	} else {
1106b8e788a5SAdrian Chadd 		/*
1107b8e788a5SAdrian Chadd 		 * Caller supplied explicit parameters to use in
1108b8e788a5SAdrian Chadd 		 * sending the frame.
1109b8e788a5SAdrian Chadd 		 */
1110b8e788a5SAdrian Chadd 		if (ath_tx_raw_start(sc, ni, bf, m, params)) {
1111b8e788a5SAdrian Chadd 			error = EIO;		/* XXX */
1112b8e788a5SAdrian Chadd 			goto bad2;
1113b8e788a5SAdrian Chadd 		}
1114b8e788a5SAdrian Chadd 	}
1115b8e788a5SAdrian Chadd 	sc->sc_wd_timer = 5;
1116b8e788a5SAdrian Chadd 	ifp->if_opackets++;
1117b8e788a5SAdrian Chadd 	sc->sc_stats.ast_tx_raw++;
1118b8e788a5SAdrian Chadd 
1119b8e788a5SAdrian Chadd 	return 0;
1120b8e788a5SAdrian Chadd bad2:
1121b8e788a5SAdrian Chadd 	ATH_TXBUF_LOCK(sc);
11226b349e5aSAdrian Chadd 	TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
1123b8e788a5SAdrian Chadd 	ATH_TXBUF_UNLOCK(sc);
1124b8e788a5SAdrian Chadd bad:
1125b8e788a5SAdrian Chadd 	ifp->if_oerrors++;
1126b8e788a5SAdrian Chadd 	sc->sc_stats.ast_tx_raw_fail++;
1127b8e788a5SAdrian Chadd 	ieee80211_free_node(ni);
1128b8e788a5SAdrian Chadd 	return error;
1129b8e788a5SAdrian Chadd }
1130