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> 100b8e788a5SAdrian Chadd 10181a82688SAdrian Chadd /* 10281a82688SAdrian Chadd * Whether to use the 11n rate scenario functions or not 10381a82688SAdrian Chadd */ 10481a82688SAdrian Chadd static inline int 10581a82688SAdrian Chadd ath_tx_is_11n(struct ath_softc *sc) 10681a82688SAdrian Chadd { 10781a82688SAdrian Chadd return (sc->sc_ah->ah_magic == 0x20065416); 10881a82688SAdrian Chadd } 10981a82688SAdrian Chadd 110b8e788a5SAdrian Chadd void 111b8e788a5SAdrian Chadd ath_txfrag_cleanup(struct ath_softc *sc, 112b8e788a5SAdrian Chadd ath_bufhead *frags, struct ieee80211_node *ni) 113b8e788a5SAdrian Chadd { 114b8e788a5SAdrian Chadd struct ath_buf *bf, *next; 115b8e788a5SAdrian Chadd 116b8e788a5SAdrian Chadd ATH_TXBUF_LOCK_ASSERT(sc); 117b8e788a5SAdrian Chadd 118b8e788a5SAdrian Chadd STAILQ_FOREACH_SAFE(bf, frags, bf_list, next) { 119b8e788a5SAdrian Chadd /* NB: bf assumed clean */ 120b8e788a5SAdrian Chadd STAILQ_REMOVE_HEAD(frags, bf_list); 121b8e788a5SAdrian Chadd STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); 122b8e788a5SAdrian Chadd ieee80211_node_decref(ni); 123b8e788a5SAdrian Chadd } 124b8e788a5SAdrian Chadd } 125b8e788a5SAdrian Chadd 126b8e788a5SAdrian Chadd /* 127b8e788a5SAdrian Chadd * Setup xmit of a fragmented frame. Allocate a buffer 128b8e788a5SAdrian Chadd * for each frag and bump the node reference count to 129b8e788a5SAdrian Chadd * reflect the held reference to be setup by ath_tx_start. 130b8e788a5SAdrian Chadd */ 131b8e788a5SAdrian Chadd int 132b8e788a5SAdrian Chadd ath_txfrag_setup(struct ath_softc *sc, ath_bufhead *frags, 133b8e788a5SAdrian Chadd struct mbuf *m0, struct ieee80211_node *ni) 134b8e788a5SAdrian Chadd { 135b8e788a5SAdrian Chadd struct mbuf *m; 136b8e788a5SAdrian Chadd struct ath_buf *bf; 137b8e788a5SAdrian Chadd 138b8e788a5SAdrian Chadd ATH_TXBUF_LOCK(sc); 139b8e788a5SAdrian Chadd for (m = m0->m_nextpkt; m != NULL; m = m->m_nextpkt) { 140b8e788a5SAdrian Chadd bf = _ath_getbuf_locked(sc); 141b8e788a5SAdrian Chadd if (bf == NULL) { /* out of buffers, cleanup */ 142b8e788a5SAdrian Chadd ath_txfrag_cleanup(sc, frags, ni); 143b8e788a5SAdrian Chadd break; 144b8e788a5SAdrian Chadd } 145b8e788a5SAdrian Chadd ieee80211_node_incref(ni); 146b8e788a5SAdrian Chadd STAILQ_INSERT_TAIL(frags, bf, bf_list); 147b8e788a5SAdrian Chadd } 148b8e788a5SAdrian Chadd ATH_TXBUF_UNLOCK(sc); 149b8e788a5SAdrian Chadd 150b8e788a5SAdrian Chadd return !STAILQ_EMPTY(frags); 151b8e788a5SAdrian Chadd } 152b8e788a5SAdrian Chadd 153b8e788a5SAdrian Chadd /* 154b8e788a5SAdrian Chadd * Reclaim mbuf resources. For fragmented frames we 155b8e788a5SAdrian Chadd * need to claim each frag chained with m_nextpkt. 156b8e788a5SAdrian Chadd */ 157b8e788a5SAdrian Chadd void 158b8e788a5SAdrian Chadd ath_freetx(struct mbuf *m) 159b8e788a5SAdrian Chadd { 160b8e788a5SAdrian Chadd struct mbuf *next; 161b8e788a5SAdrian Chadd 162b8e788a5SAdrian Chadd do { 163b8e788a5SAdrian Chadd next = m->m_nextpkt; 164b8e788a5SAdrian Chadd m->m_nextpkt = NULL; 165b8e788a5SAdrian Chadd m_freem(m); 166b8e788a5SAdrian Chadd } while ((m = next) != NULL); 167b8e788a5SAdrian Chadd } 168b8e788a5SAdrian Chadd 169b8e788a5SAdrian Chadd static int 170b8e788a5SAdrian Chadd ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0) 171b8e788a5SAdrian Chadd { 172b8e788a5SAdrian Chadd struct mbuf *m; 173b8e788a5SAdrian Chadd int error; 174b8e788a5SAdrian Chadd 175b8e788a5SAdrian Chadd /* 176b8e788a5SAdrian Chadd * Load the DMA map so any coalescing is done. This 177b8e788a5SAdrian Chadd * also calculates the number of descriptors we need. 178b8e788a5SAdrian Chadd */ 179b8e788a5SAdrian Chadd error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0, 180b8e788a5SAdrian Chadd bf->bf_segs, &bf->bf_nseg, 181b8e788a5SAdrian Chadd BUS_DMA_NOWAIT); 182b8e788a5SAdrian Chadd if (error == EFBIG) { 183b8e788a5SAdrian Chadd /* XXX packet requires too many descriptors */ 184b8e788a5SAdrian Chadd bf->bf_nseg = ATH_TXDESC+1; 185b8e788a5SAdrian Chadd } else if (error != 0) { 186b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_busdma++; 187b8e788a5SAdrian Chadd ath_freetx(m0); 188b8e788a5SAdrian Chadd return error; 189b8e788a5SAdrian Chadd } 190b8e788a5SAdrian Chadd /* 191b8e788a5SAdrian Chadd * Discard null packets and check for packets that 192b8e788a5SAdrian Chadd * require too many TX descriptors. We try to convert 193b8e788a5SAdrian Chadd * the latter to a cluster. 194b8e788a5SAdrian Chadd */ 195b8e788a5SAdrian Chadd if (bf->bf_nseg > ATH_TXDESC) { /* too many desc's, linearize */ 196b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_linear++; 197b8e788a5SAdrian Chadd m = m_collapse(m0, M_DONTWAIT, ATH_TXDESC); 198b8e788a5SAdrian Chadd if (m == NULL) { 199b8e788a5SAdrian Chadd ath_freetx(m0); 200b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_nombuf++; 201b8e788a5SAdrian Chadd return ENOMEM; 202b8e788a5SAdrian Chadd } 203b8e788a5SAdrian Chadd m0 = m; 204b8e788a5SAdrian Chadd error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0, 205b8e788a5SAdrian Chadd bf->bf_segs, &bf->bf_nseg, 206b8e788a5SAdrian Chadd BUS_DMA_NOWAIT); 207b8e788a5SAdrian Chadd if (error != 0) { 208b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_busdma++; 209b8e788a5SAdrian Chadd ath_freetx(m0); 210b8e788a5SAdrian Chadd return error; 211b8e788a5SAdrian Chadd } 212b8e788a5SAdrian Chadd KASSERT(bf->bf_nseg <= ATH_TXDESC, 213b8e788a5SAdrian Chadd ("too many segments after defrag; nseg %u", bf->bf_nseg)); 214b8e788a5SAdrian Chadd } else if (bf->bf_nseg == 0) { /* null packet, discard */ 215b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_nodata++; 216b8e788a5SAdrian Chadd ath_freetx(m0); 217b8e788a5SAdrian Chadd return EIO; 218b8e788a5SAdrian Chadd } 219b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT, "%s: m %p len %u\n", 220b8e788a5SAdrian Chadd __func__, m0, m0->m_pkthdr.len); 221b8e788a5SAdrian Chadd bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); 222b8e788a5SAdrian Chadd bf->bf_m = m0; 223b8e788a5SAdrian Chadd 224b8e788a5SAdrian Chadd return 0; 225b8e788a5SAdrian Chadd } 226b8e788a5SAdrian Chadd 227b8e788a5SAdrian Chadd static void 22881a82688SAdrian Chadd ath_tx_chaindesclist(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf) 229b8e788a5SAdrian Chadd { 230b8e788a5SAdrian Chadd struct ath_hal *ah = sc->sc_ah; 231b8e788a5SAdrian Chadd struct ath_desc *ds, *ds0; 232b8e788a5SAdrian Chadd int i; 233b8e788a5SAdrian Chadd 234b8e788a5SAdrian Chadd /* 235b8e788a5SAdrian Chadd * Fillin the remainder of the descriptor info. 236b8e788a5SAdrian Chadd */ 237b8e788a5SAdrian Chadd ds0 = ds = bf->bf_desc; 238b8e788a5SAdrian Chadd for (i = 0; i < bf->bf_nseg; i++, ds++) { 239b8e788a5SAdrian Chadd ds->ds_data = bf->bf_segs[i].ds_addr; 240b8e788a5SAdrian Chadd if (i == bf->bf_nseg - 1) 241b8e788a5SAdrian Chadd ds->ds_link = 0; 242b8e788a5SAdrian Chadd else 243b8e788a5SAdrian Chadd ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1); 244b8e788a5SAdrian Chadd ath_hal_filltxdesc(ah, ds 245b8e788a5SAdrian Chadd , bf->bf_segs[i].ds_len /* segment length */ 246b8e788a5SAdrian Chadd , i == 0 /* first segment */ 247b8e788a5SAdrian Chadd , i == bf->bf_nseg - 1 /* last segment */ 248b8e788a5SAdrian Chadd , ds0 /* first descriptor */ 249b8e788a5SAdrian Chadd ); 250b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT, 251b8e788a5SAdrian Chadd "%s: %d: %08x %08x %08x %08x %08x %08x\n", 252b8e788a5SAdrian Chadd __func__, i, ds->ds_link, ds->ds_data, 253b8e788a5SAdrian Chadd ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1]); 254b8e788a5SAdrian Chadd } 25581a82688SAdrian Chadd 25681a82688SAdrian Chadd } 25781a82688SAdrian Chadd 25881a82688SAdrian Chadd static void 25981a82688SAdrian Chadd ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf) 26081a82688SAdrian Chadd { 26181a82688SAdrian Chadd struct ath_hal *ah = sc->sc_ah; 26281a82688SAdrian Chadd 26381a82688SAdrian Chadd /* Fill in the details in the descriptor list */ 26481a82688SAdrian Chadd ath_tx_chaindesclist(sc, txq, bf); 26581a82688SAdrian Chadd 266b8e788a5SAdrian Chadd /* 267b8e788a5SAdrian Chadd * Insert the frame on the outbound list and pass it on 268b8e788a5SAdrian Chadd * to the hardware. Multicast frames buffered for power 269b8e788a5SAdrian Chadd * save stations and transmit from the CAB queue are stored 270b8e788a5SAdrian Chadd * on a s/w only queue and loaded on to the CAB queue in 271b8e788a5SAdrian Chadd * the SWBA handler since frames only go out on DTIM and 272b8e788a5SAdrian Chadd * to avoid possible races. 273b8e788a5SAdrian Chadd */ 274b8e788a5SAdrian Chadd ATH_TXQ_LOCK(txq); 275b8e788a5SAdrian Chadd KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0, 276b8e788a5SAdrian Chadd ("busy status 0x%x", bf->bf_flags)); 277b8e788a5SAdrian Chadd if (txq->axq_qnum != ATH_TXQ_SWQ) { 278b8e788a5SAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA 279b8e788a5SAdrian Chadd int qbusy; 280b8e788a5SAdrian Chadd 281b8e788a5SAdrian Chadd ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 282b8e788a5SAdrian Chadd qbusy = ath_hal_txqenabled(ah, txq->axq_qnum); 283b8e788a5SAdrian Chadd if (txq->axq_link == NULL) { 284b8e788a5SAdrian Chadd /* 285b8e788a5SAdrian Chadd * Be careful writing the address to TXDP. If 286b8e788a5SAdrian Chadd * the tx q is enabled then this write will be 287b8e788a5SAdrian Chadd * ignored. Normally this is not an issue but 288b8e788a5SAdrian Chadd * when tdma is in use and the q is beacon gated 289b8e788a5SAdrian Chadd * this race can occur. If the q is busy then 290b8e788a5SAdrian Chadd * defer the work to later--either when another 291b8e788a5SAdrian Chadd * packet comes along or when we prepare a beacon 292b8e788a5SAdrian Chadd * frame at SWBA. 293b8e788a5SAdrian Chadd */ 294b8e788a5SAdrian Chadd if (!qbusy) { 295b8e788a5SAdrian Chadd ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); 296b8e788a5SAdrian Chadd txq->axq_flags &= ~ATH_TXQ_PUTPENDING; 297b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT, 298b8e788a5SAdrian Chadd "%s: TXDP[%u] = %p (%p) depth %d\n", 299b8e788a5SAdrian Chadd __func__, txq->axq_qnum, 300b8e788a5SAdrian Chadd (caddr_t)bf->bf_daddr, bf->bf_desc, 301b8e788a5SAdrian Chadd txq->axq_depth); 302b8e788a5SAdrian Chadd } else { 303b8e788a5SAdrian Chadd txq->axq_flags |= ATH_TXQ_PUTPENDING; 304b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT, 305b8e788a5SAdrian Chadd "%s: Q%u busy, defer enable\n", __func__, 306b8e788a5SAdrian Chadd txq->axq_qnum); 307b8e788a5SAdrian Chadd } 308b8e788a5SAdrian Chadd } else { 309b8e788a5SAdrian Chadd *txq->axq_link = bf->bf_daddr; 310b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT, 311b8e788a5SAdrian Chadd "%s: link[%u](%p)=%p (%p) depth %d\n", __func__, 312b8e788a5SAdrian Chadd txq->axq_qnum, txq->axq_link, 313b8e788a5SAdrian Chadd (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth); 314b8e788a5SAdrian Chadd if ((txq->axq_flags & ATH_TXQ_PUTPENDING) && !qbusy) { 315b8e788a5SAdrian Chadd /* 316b8e788a5SAdrian Chadd * The q was busy when we previously tried 317b8e788a5SAdrian Chadd * to write the address of the first buffer 318b8e788a5SAdrian Chadd * in the chain. Since it's not busy now 319b8e788a5SAdrian Chadd * handle this chore. We are certain the 320b8e788a5SAdrian Chadd * buffer at the front is the right one since 321b8e788a5SAdrian Chadd * axq_link is NULL only when the buffer list 322b8e788a5SAdrian Chadd * is/was empty. 323b8e788a5SAdrian Chadd */ 324b8e788a5SAdrian Chadd ath_hal_puttxbuf(ah, txq->axq_qnum, 325b8e788a5SAdrian Chadd STAILQ_FIRST(&txq->axq_q)->bf_daddr); 326b8e788a5SAdrian Chadd txq->axq_flags &= ~ATH_TXQ_PUTPENDING; 327b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT, 328b8e788a5SAdrian Chadd "%s: Q%u restarted\n", __func__, 329b8e788a5SAdrian Chadd txq->axq_qnum); 330b8e788a5SAdrian Chadd } 331b8e788a5SAdrian Chadd } 332b8e788a5SAdrian Chadd #else 333b8e788a5SAdrian Chadd ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 334b8e788a5SAdrian Chadd if (txq->axq_link == NULL) { 335b8e788a5SAdrian Chadd ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); 336b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT, 337b8e788a5SAdrian Chadd "%s: TXDP[%u] = %p (%p) depth %d\n", 338b8e788a5SAdrian Chadd __func__, txq->axq_qnum, 339b8e788a5SAdrian Chadd (caddr_t)bf->bf_daddr, bf->bf_desc, 340b8e788a5SAdrian Chadd txq->axq_depth); 341b8e788a5SAdrian Chadd } else { 342b8e788a5SAdrian Chadd *txq->axq_link = bf->bf_daddr; 343b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT, 344b8e788a5SAdrian Chadd "%s: link[%u](%p)=%p (%p) depth %d\n", __func__, 345b8e788a5SAdrian Chadd txq->axq_qnum, txq->axq_link, 346b8e788a5SAdrian Chadd (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth); 347b8e788a5SAdrian Chadd } 348b8e788a5SAdrian Chadd #endif /* IEEE80211_SUPPORT_TDMA */ 349b8e788a5SAdrian Chadd txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link; 350b8e788a5SAdrian Chadd ath_hal_txstart(ah, txq->axq_qnum); 351b8e788a5SAdrian Chadd } else { 352b8e788a5SAdrian Chadd if (txq->axq_link != NULL) { 353b8e788a5SAdrian Chadd struct ath_buf *last = ATH_TXQ_LAST(txq); 354b8e788a5SAdrian Chadd struct ieee80211_frame *wh; 355b8e788a5SAdrian Chadd 356b8e788a5SAdrian Chadd /* mark previous frame */ 357b8e788a5SAdrian Chadd wh = mtod(last->bf_m, struct ieee80211_frame *); 358b8e788a5SAdrian Chadd wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 359b8e788a5SAdrian Chadd bus_dmamap_sync(sc->sc_dmat, last->bf_dmamap, 360b8e788a5SAdrian Chadd BUS_DMASYNC_PREWRITE); 361b8e788a5SAdrian Chadd 362b8e788a5SAdrian Chadd /* link descriptor */ 363b8e788a5SAdrian Chadd *txq->axq_link = bf->bf_daddr; 364b8e788a5SAdrian Chadd } 365b8e788a5SAdrian Chadd ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 366b8e788a5SAdrian Chadd txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link; 367b8e788a5SAdrian Chadd } 368b8e788a5SAdrian Chadd ATH_TXQ_UNLOCK(txq); 369b8e788a5SAdrian Chadd } 370b8e788a5SAdrian Chadd 37181a82688SAdrian Chadd static int 37281a82688SAdrian Chadd ath_tx_tag_crypto(struct ath_softc *sc, struct ieee80211_node *ni, 37381a82688SAdrian Chadd struct mbuf *m0, int iswep, int isfrag, int *hdrlen, int *pktlen, int *keyix) 37481a82688SAdrian Chadd { 37581a82688SAdrian Chadd if (iswep) { 37681a82688SAdrian Chadd const struct ieee80211_cipher *cip; 37781a82688SAdrian Chadd struct ieee80211_key *k; 37881a82688SAdrian Chadd 37981a82688SAdrian Chadd /* 38081a82688SAdrian Chadd * Construct the 802.11 header+trailer for an encrypted 38181a82688SAdrian Chadd * frame. The only reason this can fail is because of an 38281a82688SAdrian Chadd * unknown or unsupported cipher/key type. 38381a82688SAdrian Chadd */ 38481a82688SAdrian Chadd k = ieee80211_crypto_encap(ni, m0); 38581a82688SAdrian Chadd if (k == NULL) { 38681a82688SAdrian Chadd /* 38781a82688SAdrian Chadd * This can happen when the key is yanked after the 38881a82688SAdrian Chadd * frame was queued. Just discard the frame; the 38981a82688SAdrian Chadd * 802.11 layer counts failures and provides 39081a82688SAdrian Chadd * debugging/diagnostics. 39181a82688SAdrian Chadd */ 39281a82688SAdrian Chadd return 0; 39381a82688SAdrian Chadd } 39481a82688SAdrian Chadd /* 39581a82688SAdrian Chadd * Adjust the packet + header lengths for the crypto 39681a82688SAdrian Chadd * additions and calculate the h/w key index. When 39781a82688SAdrian Chadd * a s/w mic is done the frame will have had any mic 39881a82688SAdrian Chadd * added to it prior to entry so m0->m_pkthdr.len will 39981a82688SAdrian Chadd * account for it. Otherwise we need to add it to the 40081a82688SAdrian Chadd * packet length. 40181a82688SAdrian Chadd */ 40281a82688SAdrian Chadd cip = k->wk_cipher; 40381a82688SAdrian Chadd (*hdrlen) += cip->ic_header; 40481a82688SAdrian Chadd (*pktlen) += cip->ic_header + cip->ic_trailer; 40581a82688SAdrian Chadd /* NB: frags always have any TKIP MIC done in s/w */ 40681a82688SAdrian Chadd if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && !isfrag) 40781a82688SAdrian Chadd (*pktlen) += cip->ic_miclen; 40881a82688SAdrian Chadd (*keyix) = k->wk_keyix; 40981a82688SAdrian Chadd } else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) { 41081a82688SAdrian Chadd /* 41181a82688SAdrian Chadd * Use station key cache slot, if assigned. 41281a82688SAdrian Chadd */ 41381a82688SAdrian Chadd (*keyix) = ni->ni_ucastkey.wk_keyix; 41481a82688SAdrian Chadd if ((*keyix) == IEEE80211_KEYIX_NONE) 41581a82688SAdrian Chadd (*keyix) = HAL_TXKEYIX_INVALID; 41681a82688SAdrian Chadd } else 41781a82688SAdrian Chadd (*keyix) = HAL_TXKEYIX_INVALID; 41881a82688SAdrian Chadd 41981a82688SAdrian Chadd return 1; 42081a82688SAdrian Chadd } 42181a82688SAdrian Chadd 422*79f02dbfSAdrian Chadd static void 423*79f02dbfSAdrian Chadd ath_tx_calc_ctsduration(struct ath_hal *ah, int rix, int cix, 424*79f02dbfSAdrian Chadd int shortPreamble, int pktlen, const HAL_RATE_TABLE *rt, 425*79f02dbfSAdrian Chadd int flags, u_int8_t *ctsrate, int *ctsduration) 426*79f02dbfSAdrian Chadd { 427*79f02dbfSAdrian Chadd /* 428*79f02dbfSAdrian Chadd * CTS transmit rate is derived from the transmit rate 429*79f02dbfSAdrian Chadd * by looking in the h/w rate table. We must also factor 430*79f02dbfSAdrian Chadd * in whether or not a short preamble is to be used. 431*79f02dbfSAdrian Chadd */ 432*79f02dbfSAdrian Chadd /* NB: cix is set above where RTS/CTS is enabled */ 433*79f02dbfSAdrian Chadd KASSERT(cix != 0xff, ("cix not setup")); 434*79f02dbfSAdrian Chadd (*ctsrate) = rt->info[cix].rateCode; 435*79f02dbfSAdrian Chadd /* 436*79f02dbfSAdrian Chadd * Compute the transmit duration based on the frame 437*79f02dbfSAdrian Chadd * size and the size of an ACK frame. We call into the 438*79f02dbfSAdrian Chadd * HAL to do the computation since it depends on the 439*79f02dbfSAdrian Chadd * characteristics of the actual PHY being used. 440*79f02dbfSAdrian Chadd * 441*79f02dbfSAdrian Chadd * NB: CTS is assumed the same size as an ACK so we can 442*79f02dbfSAdrian Chadd * use the precalculated ACK durations. 443*79f02dbfSAdrian Chadd */ 444*79f02dbfSAdrian Chadd if (shortPreamble) { 445*79f02dbfSAdrian Chadd (*ctsrate) |= rt->info[cix].shortPreamble; 446*79f02dbfSAdrian Chadd if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 447*79f02dbfSAdrian Chadd (*ctsduration) += rt->info[cix].spAckDuration; 448*79f02dbfSAdrian Chadd (*ctsduration) += ath_hal_computetxtime(ah, 449*79f02dbfSAdrian Chadd rt, pktlen, rix, AH_TRUE); 450*79f02dbfSAdrian Chadd if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 451*79f02dbfSAdrian Chadd (*ctsduration) += rt->info[rix].spAckDuration; 452*79f02dbfSAdrian Chadd } else { 453*79f02dbfSAdrian Chadd if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 454*79f02dbfSAdrian Chadd (*ctsduration) += rt->info[cix].lpAckDuration; 455*79f02dbfSAdrian Chadd (*ctsduration) += ath_hal_computetxtime(ah, 456*79f02dbfSAdrian Chadd rt, pktlen, rix, AH_FALSE); 457*79f02dbfSAdrian Chadd if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 458*79f02dbfSAdrian Chadd (*ctsduration) += rt->info[rix].lpAckDuration; 459*79f02dbfSAdrian Chadd } 460*79f02dbfSAdrian Chadd } 461*79f02dbfSAdrian Chadd 462b8e788a5SAdrian Chadd int 463b8e788a5SAdrian Chadd ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf, 464b8e788a5SAdrian Chadd struct mbuf *m0) 465b8e788a5SAdrian Chadd { 466b8e788a5SAdrian Chadd struct ieee80211vap *vap = ni->ni_vap; 467b8e788a5SAdrian Chadd struct ath_vap *avp = ATH_VAP(vap); 468b8e788a5SAdrian Chadd struct ath_hal *ah = sc->sc_ah; 469b8e788a5SAdrian Chadd struct ifnet *ifp = sc->sc_ifp; 470b8e788a5SAdrian Chadd struct ieee80211com *ic = ifp->if_l2com; 471b8e788a5SAdrian Chadd const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams; 472b8e788a5SAdrian Chadd int error, iswep, ismcast, isfrag, ismrr; 473b8e788a5SAdrian Chadd int keyix, hdrlen, pktlen, try0; 474b8e788a5SAdrian Chadd u_int8_t rix, txrate, ctsrate; 475b8e788a5SAdrian Chadd u_int8_t cix = 0xff; /* NB: silence compiler */ 476b8e788a5SAdrian Chadd struct ath_desc *ds; 477b8e788a5SAdrian Chadd struct ath_txq *txq; 478b8e788a5SAdrian Chadd struct ieee80211_frame *wh; 479b8e788a5SAdrian Chadd u_int subtype, flags, ctsduration; 480b8e788a5SAdrian Chadd HAL_PKT_TYPE atype; 481b8e788a5SAdrian Chadd const HAL_RATE_TABLE *rt; 482b8e788a5SAdrian Chadd HAL_BOOL shortPreamble; 483b8e788a5SAdrian Chadd struct ath_node *an; 484b8e788a5SAdrian Chadd u_int pri; 485b8e788a5SAdrian Chadd 486b8e788a5SAdrian Chadd wh = mtod(m0, struct ieee80211_frame *); 487b8e788a5SAdrian Chadd iswep = wh->i_fc[1] & IEEE80211_FC1_WEP; 488b8e788a5SAdrian Chadd ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 489b8e788a5SAdrian Chadd isfrag = m0->m_flags & M_FRAG; 490b8e788a5SAdrian Chadd hdrlen = ieee80211_anyhdrsize(wh); 491b8e788a5SAdrian Chadd /* 492b8e788a5SAdrian Chadd * Packet length must not include any 493b8e788a5SAdrian Chadd * pad bytes; deduct them here. 494b8e788a5SAdrian Chadd */ 495b8e788a5SAdrian Chadd pktlen = m0->m_pkthdr.len - (hdrlen & 3); 496b8e788a5SAdrian Chadd 49781a82688SAdrian Chadd /* Handle encryption twiddling if needed */ 49881a82688SAdrian Chadd if (! ath_tx_tag_crypto(sc, ni, m0, iswep, isfrag, &hdrlen, &pktlen, &keyix)) { 499b8e788a5SAdrian Chadd ath_freetx(m0); 500b8e788a5SAdrian Chadd return EIO; 501b8e788a5SAdrian Chadd } 502b8e788a5SAdrian Chadd 503b8e788a5SAdrian Chadd /* packet header may have moved, reset our local pointer */ 504b8e788a5SAdrian Chadd wh = mtod(m0, struct ieee80211_frame *); 505b8e788a5SAdrian Chadd 506b8e788a5SAdrian Chadd pktlen += IEEE80211_CRC_LEN; 507b8e788a5SAdrian Chadd 508b8e788a5SAdrian Chadd /* 509b8e788a5SAdrian Chadd * Load the DMA map so any coalescing is done. This 510b8e788a5SAdrian Chadd * also calculates the number of descriptors we need. 511b8e788a5SAdrian Chadd */ 512b8e788a5SAdrian Chadd error = ath_tx_dmasetup(sc, bf, m0); 513b8e788a5SAdrian Chadd if (error != 0) 514b8e788a5SAdrian Chadd return error; 515b8e788a5SAdrian Chadd bf->bf_node = ni; /* NB: held reference */ 516b8e788a5SAdrian Chadd m0 = bf->bf_m; /* NB: may have changed */ 517b8e788a5SAdrian Chadd wh = mtod(m0, struct ieee80211_frame *); 518b8e788a5SAdrian Chadd 519b8e788a5SAdrian Chadd /* setup descriptors */ 520b8e788a5SAdrian Chadd ds = bf->bf_desc; 521b8e788a5SAdrian Chadd rt = sc->sc_currates; 522b8e788a5SAdrian Chadd KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 523b8e788a5SAdrian Chadd 524b8e788a5SAdrian Chadd /* 525b8e788a5SAdrian Chadd * NB: the 802.11 layer marks whether or not we should 526b8e788a5SAdrian Chadd * use short preamble based on the current mode and 527b8e788a5SAdrian Chadd * negotiated parameters. 528b8e788a5SAdrian Chadd */ 529b8e788a5SAdrian Chadd if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 530b8e788a5SAdrian Chadd (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) { 531b8e788a5SAdrian Chadd shortPreamble = AH_TRUE; 532b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_shortpre++; 533b8e788a5SAdrian Chadd } else { 534b8e788a5SAdrian Chadd shortPreamble = AH_FALSE; 535b8e788a5SAdrian Chadd } 536b8e788a5SAdrian Chadd 537b8e788a5SAdrian Chadd an = ATH_NODE(ni); 538b8e788a5SAdrian Chadd flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ 539b8e788a5SAdrian Chadd ismrr = 0; /* default no multi-rate retry*/ 540b8e788a5SAdrian Chadd pri = M_WME_GETAC(m0); /* honor classification */ 541b8e788a5SAdrian Chadd /* XXX use txparams instead of fixed values */ 542b8e788a5SAdrian Chadd /* 543b8e788a5SAdrian Chadd * Calculate Atheros packet type from IEEE80211 packet header, 544b8e788a5SAdrian Chadd * setup for rate calculations, and select h/w transmit queue. 545b8e788a5SAdrian Chadd */ 546b8e788a5SAdrian Chadd switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 547b8e788a5SAdrian Chadd case IEEE80211_FC0_TYPE_MGT: 548b8e788a5SAdrian Chadd subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 549b8e788a5SAdrian Chadd if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) 550b8e788a5SAdrian Chadd atype = HAL_PKT_TYPE_BEACON; 551b8e788a5SAdrian Chadd else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 552b8e788a5SAdrian Chadd atype = HAL_PKT_TYPE_PROBE_RESP; 553b8e788a5SAdrian Chadd else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM) 554b8e788a5SAdrian Chadd atype = HAL_PKT_TYPE_ATIM; 555b8e788a5SAdrian Chadd else 556b8e788a5SAdrian Chadd atype = HAL_PKT_TYPE_NORMAL; /* XXX */ 557b8e788a5SAdrian Chadd rix = an->an_mgmtrix; 558b8e788a5SAdrian Chadd txrate = rt->info[rix].rateCode; 559b8e788a5SAdrian Chadd if (shortPreamble) 560b8e788a5SAdrian Chadd txrate |= rt->info[rix].shortPreamble; 561b8e788a5SAdrian Chadd try0 = ATH_TXMGTTRY; 562b8e788a5SAdrian Chadd flags |= HAL_TXDESC_INTREQ; /* force interrupt */ 563b8e788a5SAdrian Chadd break; 564b8e788a5SAdrian Chadd case IEEE80211_FC0_TYPE_CTL: 565b8e788a5SAdrian Chadd atype = HAL_PKT_TYPE_PSPOLL; /* stop setting of duration */ 566b8e788a5SAdrian Chadd rix = an->an_mgmtrix; 567b8e788a5SAdrian Chadd txrate = rt->info[rix].rateCode; 568b8e788a5SAdrian Chadd if (shortPreamble) 569b8e788a5SAdrian Chadd txrate |= rt->info[rix].shortPreamble; 570b8e788a5SAdrian Chadd try0 = ATH_TXMGTTRY; 571b8e788a5SAdrian Chadd flags |= HAL_TXDESC_INTREQ; /* force interrupt */ 572b8e788a5SAdrian Chadd break; 573b8e788a5SAdrian Chadd case IEEE80211_FC0_TYPE_DATA: 574b8e788a5SAdrian Chadd atype = HAL_PKT_TYPE_NORMAL; /* default */ 575b8e788a5SAdrian Chadd /* 576b8e788a5SAdrian Chadd * Data frames: multicast frames go out at a fixed rate, 577b8e788a5SAdrian Chadd * EAPOL frames use the mgmt frame rate; otherwise consult 578b8e788a5SAdrian Chadd * the rate control module for the rate to use. 579b8e788a5SAdrian Chadd */ 580b8e788a5SAdrian Chadd if (ismcast) { 581b8e788a5SAdrian Chadd rix = an->an_mcastrix; 582b8e788a5SAdrian Chadd txrate = rt->info[rix].rateCode; 583b8e788a5SAdrian Chadd if (shortPreamble) 584b8e788a5SAdrian Chadd txrate |= rt->info[rix].shortPreamble; 585b8e788a5SAdrian Chadd try0 = 1; 586b8e788a5SAdrian Chadd } else if (m0->m_flags & M_EAPOL) { 587b8e788a5SAdrian Chadd /* XXX? maybe always use long preamble? */ 588b8e788a5SAdrian Chadd rix = an->an_mgmtrix; 589b8e788a5SAdrian Chadd txrate = rt->info[rix].rateCode; 590b8e788a5SAdrian Chadd if (shortPreamble) 591b8e788a5SAdrian Chadd txrate |= rt->info[rix].shortPreamble; 592b8e788a5SAdrian Chadd try0 = ATH_TXMAXTRY; /* XXX?too many? */ 593b8e788a5SAdrian Chadd } else { 594b8e788a5SAdrian Chadd ath_rate_findrate(sc, an, shortPreamble, pktlen, 595b8e788a5SAdrian Chadd &rix, &try0, &txrate); 596b8e788a5SAdrian Chadd sc->sc_txrix = rix; /* for LED blinking */ 597b8e788a5SAdrian Chadd sc->sc_lastdatarix = rix; /* for fast frames */ 598b8e788a5SAdrian Chadd if (try0 != ATH_TXMAXTRY) 599b8e788a5SAdrian Chadd ismrr = 1; 600b8e788a5SAdrian Chadd } 601b8e788a5SAdrian Chadd if (cap->cap_wmeParams[pri].wmep_noackPolicy) 602b8e788a5SAdrian Chadd flags |= HAL_TXDESC_NOACK; 603b8e788a5SAdrian Chadd break; 604b8e788a5SAdrian Chadd default: 605b8e788a5SAdrian Chadd if_printf(ifp, "bogus frame type 0x%x (%s)\n", 606b8e788a5SAdrian Chadd wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__); 607b8e788a5SAdrian Chadd /* XXX statistic */ 608b8e788a5SAdrian Chadd ath_freetx(m0); 609b8e788a5SAdrian Chadd return EIO; 610b8e788a5SAdrian Chadd } 611b8e788a5SAdrian Chadd txq = sc->sc_ac2q[pri]; 612b8e788a5SAdrian Chadd 613b8e788a5SAdrian Chadd /* 614b8e788a5SAdrian Chadd * When servicing one or more stations in power-save mode 615b8e788a5SAdrian Chadd * (or) if there is some mcast data waiting on the mcast 616b8e788a5SAdrian Chadd * queue (to prevent out of order delivery) multicast 617b8e788a5SAdrian Chadd * frames must be buffered until after the beacon. 618b8e788a5SAdrian Chadd */ 619b8e788a5SAdrian Chadd if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth)) 620b8e788a5SAdrian Chadd txq = &avp->av_mcastq; 621b8e788a5SAdrian Chadd 622b8e788a5SAdrian Chadd /* 623b8e788a5SAdrian Chadd * Calculate miscellaneous flags. 624b8e788a5SAdrian Chadd */ 625b8e788a5SAdrian Chadd if (ismcast) { 626b8e788a5SAdrian Chadd flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */ 627b8e788a5SAdrian Chadd } else if (pktlen > vap->iv_rtsthreshold && 628b8e788a5SAdrian Chadd (ni->ni_ath_flags & IEEE80211_NODE_FF) == 0) { 629b8e788a5SAdrian Chadd flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */ 630b8e788a5SAdrian Chadd cix = rt->info[rix].controlRate; 631b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_rts++; 632b8e788a5SAdrian Chadd } 633b8e788a5SAdrian Chadd if (flags & HAL_TXDESC_NOACK) /* NB: avoid double counting */ 634b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_noack++; 635b8e788a5SAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA 636b8e788a5SAdrian Chadd if (sc->sc_tdma && (flags & HAL_TXDESC_NOACK) == 0) { 637b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TDMA, 638b8e788a5SAdrian Chadd "%s: discard frame, ACK required w/ TDMA\n", __func__); 639b8e788a5SAdrian Chadd sc->sc_stats.ast_tdma_ack++; 640b8e788a5SAdrian Chadd ath_freetx(m0); 641b8e788a5SAdrian Chadd return EIO; 642b8e788a5SAdrian Chadd } 643b8e788a5SAdrian Chadd #endif 644b8e788a5SAdrian Chadd 645b8e788a5SAdrian Chadd /* 646b8e788a5SAdrian Chadd * If 802.11g protection is enabled, determine whether 647b8e788a5SAdrian Chadd * to use RTS/CTS or just CTS. Note that this is only 648b8e788a5SAdrian Chadd * done for OFDM unicast frames. 649b8e788a5SAdrian Chadd */ 650b8e788a5SAdrian Chadd if ((ic->ic_flags & IEEE80211_F_USEPROT) && 651b8e788a5SAdrian Chadd rt->info[rix].phy == IEEE80211_T_OFDM && 652b8e788a5SAdrian Chadd (flags & HAL_TXDESC_NOACK) == 0) { 653b8e788a5SAdrian Chadd /* XXX fragments must use CCK rates w/ protection */ 654b8e788a5SAdrian Chadd if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 655b8e788a5SAdrian Chadd flags |= HAL_TXDESC_RTSENA; 656b8e788a5SAdrian Chadd else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 657b8e788a5SAdrian Chadd flags |= HAL_TXDESC_CTSENA; 658b8e788a5SAdrian Chadd if (isfrag) { 659b8e788a5SAdrian Chadd /* 660b8e788a5SAdrian Chadd * For frags it would be desirable to use the 661b8e788a5SAdrian Chadd * highest CCK rate for RTS/CTS. But stations 662b8e788a5SAdrian Chadd * farther away may detect it at a lower CCK rate 663b8e788a5SAdrian Chadd * so use the configured protection rate instead 664b8e788a5SAdrian Chadd * (for now). 665b8e788a5SAdrian Chadd */ 666b8e788a5SAdrian Chadd cix = rt->info[sc->sc_protrix].controlRate; 667b8e788a5SAdrian Chadd } else 668b8e788a5SAdrian Chadd cix = rt->info[sc->sc_protrix].controlRate; 669b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_protect++; 670b8e788a5SAdrian Chadd } 671b8e788a5SAdrian Chadd 672b8e788a5SAdrian Chadd /* 673b8e788a5SAdrian Chadd * Calculate duration. This logically belongs in the 802.11 674b8e788a5SAdrian Chadd * layer but it lacks sufficient information to calculate it. 675b8e788a5SAdrian Chadd */ 676b8e788a5SAdrian Chadd if ((flags & HAL_TXDESC_NOACK) == 0 && 677b8e788a5SAdrian Chadd (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) { 678b8e788a5SAdrian Chadd u_int16_t dur; 679b8e788a5SAdrian Chadd if (shortPreamble) 680b8e788a5SAdrian Chadd dur = rt->info[rix].spAckDuration; 681b8e788a5SAdrian Chadd else 682b8e788a5SAdrian Chadd dur = rt->info[rix].lpAckDuration; 683b8e788a5SAdrian Chadd if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) { 684b8e788a5SAdrian Chadd dur += dur; /* additional SIFS+ACK */ 685b8e788a5SAdrian Chadd KASSERT(m0->m_nextpkt != NULL, ("no fragment")); 686b8e788a5SAdrian Chadd /* 687b8e788a5SAdrian Chadd * Include the size of next fragment so NAV is 688b8e788a5SAdrian Chadd * updated properly. The last fragment uses only 689b8e788a5SAdrian Chadd * the ACK duration 690b8e788a5SAdrian Chadd */ 691b8e788a5SAdrian Chadd dur += ath_hal_computetxtime(ah, rt, 692b8e788a5SAdrian Chadd m0->m_nextpkt->m_pkthdr.len, 693b8e788a5SAdrian Chadd rix, shortPreamble); 694b8e788a5SAdrian Chadd } 695b8e788a5SAdrian Chadd if (isfrag) { 696b8e788a5SAdrian Chadd /* 697b8e788a5SAdrian Chadd * Force hardware to use computed duration for next 698b8e788a5SAdrian Chadd * fragment by disabling multi-rate retry which updates 699b8e788a5SAdrian Chadd * duration based on the multi-rate duration table. 700b8e788a5SAdrian Chadd */ 701b8e788a5SAdrian Chadd ismrr = 0; 702b8e788a5SAdrian Chadd try0 = ATH_TXMGTTRY; /* XXX? */ 703b8e788a5SAdrian Chadd } 704b8e788a5SAdrian Chadd *(u_int16_t *)wh->i_dur = htole16(dur); 705b8e788a5SAdrian Chadd } 706b8e788a5SAdrian Chadd 707b8e788a5SAdrian Chadd /* 708b8e788a5SAdrian Chadd * Calculate RTS/CTS rate and duration if needed. 709b8e788a5SAdrian Chadd */ 710b8e788a5SAdrian Chadd ctsduration = 0; 711b8e788a5SAdrian Chadd if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) { 712*79f02dbfSAdrian Chadd (void) ath_tx_calc_ctsduration(ah, rix, cix, shortPreamble, pktlen, 713*79f02dbfSAdrian Chadd rt, flags, &ctsrate, &ctsduration); 714b8e788a5SAdrian Chadd /* 715b8e788a5SAdrian Chadd * Must disable multi-rate retry when using RTS/CTS. 716b8e788a5SAdrian Chadd */ 717b8e788a5SAdrian Chadd ismrr = 0; 718b8e788a5SAdrian Chadd try0 = ATH_TXMGTTRY; /* XXX */ 719b8e788a5SAdrian Chadd } else 720b8e788a5SAdrian Chadd ctsrate = 0; 721b8e788a5SAdrian Chadd 722b8e788a5SAdrian Chadd /* 723b8e788a5SAdrian Chadd * At this point we are committed to sending the frame 724b8e788a5SAdrian Chadd * and we don't need to look at m_nextpkt; clear it in 725b8e788a5SAdrian Chadd * case this frame is part of frag chain. 726b8e788a5SAdrian Chadd */ 727b8e788a5SAdrian Chadd m0->m_nextpkt = NULL; 728b8e788a5SAdrian Chadd 729b8e788a5SAdrian Chadd if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT)) 730b8e788a5SAdrian Chadd ieee80211_dump_pkt(ic, mtod(m0, const uint8_t *), m0->m_len, 731b8e788a5SAdrian Chadd sc->sc_hwmap[rix].ieeerate, -1); 732b8e788a5SAdrian Chadd 733b8e788a5SAdrian Chadd if (ieee80211_radiotap_active_vap(vap)) { 734b8e788a5SAdrian Chadd u_int64_t tsf = ath_hal_gettsf64(ah); 735b8e788a5SAdrian Chadd 736b8e788a5SAdrian Chadd sc->sc_tx_th.wt_tsf = htole64(tsf); 737b8e788a5SAdrian Chadd sc->sc_tx_th.wt_flags = sc->sc_hwmap[rix].txflags; 738b8e788a5SAdrian Chadd if (iswep) 739b8e788a5SAdrian Chadd sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; 740b8e788a5SAdrian Chadd if (isfrag) 741b8e788a5SAdrian Chadd sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG; 742b8e788a5SAdrian Chadd sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate; 743b8e788a5SAdrian Chadd sc->sc_tx_th.wt_txpower = ni->ni_txpower; 744b8e788a5SAdrian Chadd sc->sc_tx_th.wt_antenna = sc->sc_txantenna; 745b8e788a5SAdrian Chadd 746b8e788a5SAdrian Chadd ieee80211_radiotap_tx(vap, m0); 747b8e788a5SAdrian Chadd } 748b8e788a5SAdrian Chadd 749b8e788a5SAdrian Chadd /* 750b8e788a5SAdrian Chadd * Determine if a tx interrupt should be generated for 751b8e788a5SAdrian Chadd * this descriptor. We take a tx interrupt to reap 752b8e788a5SAdrian Chadd * descriptors when the h/w hits an EOL condition or 753b8e788a5SAdrian Chadd * when the descriptor is specifically marked to generate 754b8e788a5SAdrian Chadd * an interrupt. We periodically mark descriptors in this 755b8e788a5SAdrian Chadd * way to insure timely replenishing of the supply needed 756b8e788a5SAdrian Chadd * for sending frames. Defering interrupts reduces system 757b8e788a5SAdrian Chadd * load and potentially allows more concurrent work to be 758b8e788a5SAdrian Chadd * done but if done to aggressively can cause senders to 759b8e788a5SAdrian Chadd * backup. 760b8e788a5SAdrian Chadd * 761b8e788a5SAdrian Chadd * NB: use >= to deal with sc_txintrperiod changing 762b8e788a5SAdrian Chadd * dynamically through sysctl. 763b8e788a5SAdrian Chadd */ 764b8e788a5SAdrian Chadd if (flags & HAL_TXDESC_INTREQ) { 765b8e788a5SAdrian Chadd txq->axq_intrcnt = 0; 766b8e788a5SAdrian Chadd } else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) { 767b8e788a5SAdrian Chadd flags |= HAL_TXDESC_INTREQ; 768b8e788a5SAdrian Chadd txq->axq_intrcnt = 0; 769b8e788a5SAdrian Chadd } 770b8e788a5SAdrian Chadd 771b8e788a5SAdrian Chadd /* 772b8e788a5SAdrian Chadd * Formulate first tx descriptor with tx controls. 773b8e788a5SAdrian Chadd */ 774b8e788a5SAdrian Chadd /* XXX check return value? */ 775b8e788a5SAdrian Chadd ath_hal_setuptxdesc(ah, ds 776b8e788a5SAdrian Chadd , pktlen /* packet length */ 777b8e788a5SAdrian Chadd , hdrlen /* header length */ 778b8e788a5SAdrian Chadd , atype /* Atheros packet type */ 779b8e788a5SAdrian Chadd , ni->ni_txpower /* txpower */ 780b8e788a5SAdrian Chadd , txrate, try0 /* series 0 rate/tries */ 781b8e788a5SAdrian Chadd , keyix /* key cache index */ 782b8e788a5SAdrian Chadd , sc->sc_txantenna /* antenna mode */ 783b8e788a5SAdrian Chadd , flags /* flags */ 784b8e788a5SAdrian Chadd , ctsrate /* rts/cts rate */ 785b8e788a5SAdrian Chadd , ctsduration /* rts/cts duration */ 786b8e788a5SAdrian Chadd ); 787b8e788a5SAdrian Chadd bf->bf_txflags = flags; 788b8e788a5SAdrian Chadd /* 789b8e788a5SAdrian Chadd * Setup the multi-rate retry state only when we're 790b8e788a5SAdrian Chadd * going to use it. This assumes ath_hal_setuptxdesc 791b8e788a5SAdrian Chadd * initializes the descriptors (so we don't have to) 792b8e788a5SAdrian Chadd * when the hardware supports multi-rate retry and 793b8e788a5SAdrian Chadd * we don't use it. 794b8e788a5SAdrian Chadd */ 795b8e788a5SAdrian Chadd if (ismrr) 796b8e788a5SAdrian Chadd ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix); 797b8e788a5SAdrian Chadd 798b8e788a5SAdrian Chadd ath_tx_handoff(sc, txq, bf); 799b8e788a5SAdrian Chadd return 0; 800b8e788a5SAdrian Chadd } 801b8e788a5SAdrian Chadd 802b8e788a5SAdrian Chadd static int 803b8e788a5SAdrian Chadd ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, 804b8e788a5SAdrian Chadd struct ath_buf *bf, struct mbuf *m0, 805b8e788a5SAdrian Chadd const struct ieee80211_bpf_params *params) 806b8e788a5SAdrian Chadd { 807b8e788a5SAdrian Chadd struct ifnet *ifp = sc->sc_ifp; 808b8e788a5SAdrian Chadd struct ieee80211com *ic = ifp->if_l2com; 809b8e788a5SAdrian Chadd struct ath_hal *ah = sc->sc_ah; 810b8e788a5SAdrian Chadd struct ieee80211vap *vap = ni->ni_vap; 811b8e788a5SAdrian Chadd int error, ismcast, ismrr; 812b8e788a5SAdrian Chadd int keyix, hdrlen, pktlen, try0, txantenna; 813b8e788a5SAdrian Chadd u_int8_t rix, cix, txrate, ctsrate, rate1, rate2, rate3; 814b8e788a5SAdrian Chadd struct ieee80211_frame *wh; 815b8e788a5SAdrian Chadd u_int flags, ctsduration; 816b8e788a5SAdrian Chadd HAL_PKT_TYPE atype; 817b8e788a5SAdrian Chadd const HAL_RATE_TABLE *rt; 818b8e788a5SAdrian Chadd struct ath_desc *ds; 819b8e788a5SAdrian Chadd u_int pri; 820b8e788a5SAdrian Chadd 821b8e788a5SAdrian Chadd wh = mtod(m0, struct ieee80211_frame *); 822b8e788a5SAdrian Chadd ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 823b8e788a5SAdrian Chadd hdrlen = ieee80211_anyhdrsize(wh); 824b8e788a5SAdrian Chadd /* 825b8e788a5SAdrian Chadd * Packet length must not include any 826b8e788a5SAdrian Chadd * pad bytes; deduct them here. 827b8e788a5SAdrian Chadd */ 828b8e788a5SAdrian Chadd /* XXX honor IEEE80211_BPF_DATAPAD */ 829b8e788a5SAdrian Chadd pktlen = m0->m_pkthdr.len - (hdrlen & 3) + IEEE80211_CRC_LEN; 830b8e788a5SAdrian Chadd 83181a82688SAdrian Chadd /* Handle encryption twiddling if needed */ 83281a82688SAdrian Chadd if (! ath_tx_tag_crypto(sc, ni, m0, params->ibp_flags & IEEE80211_BPF_CRYPTO, 0, &hdrlen, &pktlen, &keyix)) { 833b8e788a5SAdrian Chadd ath_freetx(m0); 834b8e788a5SAdrian Chadd return EIO; 835b8e788a5SAdrian Chadd } 836b8e788a5SAdrian Chadd /* packet header may have moved, reset our local pointer */ 837b8e788a5SAdrian Chadd wh = mtod(m0, struct ieee80211_frame *); 838b8e788a5SAdrian Chadd 839b8e788a5SAdrian Chadd error = ath_tx_dmasetup(sc, bf, m0); 840b8e788a5SAdrian Chadd if (error != 0) 841b8e788a5SAdrian Chadd return error; 842b8e788a5SAdrian Chadd m0 = bf->bf_m; /* NB: may have changed */ 843b8e788a5SAdrian Chadd wh = mtod(m0, struct ieee80211_frame *); 844b8e788a5SAdrian Chadd bf->bf_node = ni; /* NB: held reference */ 845b8e788a5SAdrian Chadd 846b8e788a5SAdrian Chadd flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ 847b8e788a5SAdrian Chadd flags |= HAL_TXDESC_INTREQ; /* force interrupt */ 848b8e788a5SAdrian Chadd if (params->ibp_flags & IEEE80211_BPF_RTS) 849b8e788a5SAdrian Chadd flags |= HAL_TXDESC_RTSENA; 850b8e788a5SAdrian Chadd else if (params->ibp_flags & IEEE80211_BPF_CTS) 851b8e788a5SAdrian Chadd flags |= HAL_TXDESC_CTSENA; 852b8e788a5SAdrian Chadd /* XXX leave ismcast to injector? */ 853b8e788a5SAdrian Chadd if ((params->ibp_flags & IEEE80211_BPF_NOACK) || ismcast) 854b8e788a5SAdrian Chadd flags |= HAL_TXDESC_NOACK; 855b8e788a5SAdrian Chadd 856b8e788a5SAdrian Chadd rt = sc->sc_currates; 857b8e788a5SAdrian Chadd KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 858b8e788a5SAdrian Chadd rix = ath_tx_findrix(sc, params->ibp_rate0); 859b8e788a5SAdrian Chadd txrate = rt->info[rix].rateCode; 860b8e788a5SAdrian Chadd if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 861b8e788a5SAdrian Chadd txrate |= rt->info[rix].shortPreamble; 862b8e788a5SAdrian Chadd sc->sc_txrix = rix; 863b8e788a5SAdrian Chadd try0 = params->ibp_try0; 864b8e788a5SAdrian Chadd ismrr = (params->ibp_try1 != 0); 865b8e788a5SAdrian Chadd txantenna = params->ibp_pri >> 2; 866b8e788a5SAdrian Chadd if (txantenna == 0) /* XXX? */ 867b8e788a5SAdrian Chadd txantenna = sc->sc_txantenna; 868*79f02dbfSAdrian Chadd 869b8e788a5SAdrian Chadd ctsduration = 0; 870*79f02dbfSAdrian Chadd if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) { 871b8e788a5SAdrian Chadd cix = ath_tx_findrix(sc, params->ibp_ctsrate); 872*79f02dbfSAdrian Chadd (void) ath_tx_calc_ctsduration(ah, rix, cix, 873*79f02dbfSAdrian Chadd params->ibp_flags & IEEE80211_BPF_SHORTPRE, pktlen, 874*79f02dbfSAdrian Chadd rt, flags, &ctsrate, &ctsduration); 875*79f02dbfSAdrian Chadd /* 876*79f02dbfSAdrian Chadd * Must disable multi-rate retry when using RTS/CTS. 877*79f02dbfSAdrian Chadd */ 878b8e788a5SAdrian Chadd ismrr = 0; /* XXX */ 879b8e788a5SAdrian Chadd } else 880b8e788a5SAdrian Chadd ctsrate = 0; 881*79f02dbfSAdrian Chadd 882b8e788a5SAdrian Chadd pri = params->ibp_pri & 3; 883b8e788a5SAdrian Chadd /* 884b8e788a5SAdrian Chadd * NB: we mark all packets as type PSPOLL so the h/w won't 885b8e788a5SAdrian Chadd * set the sequence number, duration, etc. 886b8e788a5SAdrian Chadd */ 887b8e788a5SAdrian Chadd atype = HAL_PKT_TYPE_PSPOLL; 888b8e788a5SAdrian Chadd 889b8e788a5SAdrian Chadd if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT)) 890b8e788a5SAdrian Chadd ieee80211_dump_pkt(ic, mtod(m0, caddr_t), m0->m_len, 891b8e788a5SAdrian Chadd sc->sc_hwmap[rix].ieeerate, -1); 892b8e788a5SAdrian Chadd 893b8e788a5SAdrian Chadd if (ieee80211_radiotap_active_vap(vap)) { 894b8e788a5SAdrian Chadd u_int64_t tsf = ath_hal_gettsf64(ah); 895b8e788a5SAdrian Chadd 896b8e788a5SAdrian Chadd sc->sc_tx_th.wt_tsf = htole64(tsf); 897b8e788a5SAdrian Chadd sc->sc_tx_th.wt_flags = sc->sc_hwmap[rix].txflags; 898b8e788a5SAdrian Chadd if (wh->i_fc[1] & IEEE80211_FC1_WEP) 899b8e788a5SAdrian Chadd sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; 900b8e788a5SAdrian Chadd if (m0->m_flags & M_FRAG) 901b8e788a5SAdrian Chadd sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG; 902b8e788a5SAdrian Chadd sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate; 903b8e788a5SAdrian Chadd sc->sc_tx_th.wt_txpower = ni->ni_txpower; 904b8e788a5SAdrian Chadd sc->sc_tx_th.wt_antenna = sc->sc_txantenna; 905b8e788a5SAdrian Chadd 906b8e788a5SAdrian Chadd ieee80211_radiotap_tx(vap, m0); 907b8e788a5SAdrian Chadd } 908b8e788a5SAdrian Chadd 909b8e788a5SAdrian Chadd /* 910b8e788a5SAdrian Chadd * Formulate first tx descriptor with tx controls. 911b8e788a5SAdrian Chadd */ 912b8e788a5SAdrian Chadd ds = bf->bf_desc; 913b8e788a5SAdrian Chadd /* XXX check return value? */ 914b8e788a5SAdrian Chadd ath_hal_setuptxdesc(ah, ds 915b8e788a5SAdrian Chadd , pktlen /* packet length */ 916b8e788a5SAdrian Chadd , hdrlen /* header length */ 917b8e788a5SAdrian Chadd , atype /* Atheros packet type */ 918b8e788a5SAdrian Chadd , params->ibp_power /* txpower */ 919b8e788a5SAdrian Chadd , txrate, try0 /* series 0 rate/tries */ 920b8e788a5SAdrian Chadd , keyix /* key cache index */ 921b8e788a5SAdrian Chadd , txantenna /* antenna mode */ 922b8e788a5SAdrian Chadd , flags /* flags */ 923b8e788a5SAdrian Chadd , ctsrate /* rts/cts rate */ 924b8e788a5SAdrian Chadd , ctsduration /* rts/cts duration */ 925b8e788a5SAdrian Chadd ); 926b8e788a5SAdrian Chadd bf->bf_txflags = flags; 927b8e788a5SAdrian Chadd 928b8e788a5SAdrian Chadd if (ismrr) { 929b8e788a5SAdrian Chadd rix = ath_tx_findrix(sc, params->ibp_rate1); 930b8e788a5SAdrian Chadd rate1 = rt->info[rix].rateCode; 931b8e788a5SAdrian Chadd if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 932b8e788a5SAdrian Chadd rate1 |= rt->info[rix].shortPreamble; 933b8e788a5SAdrian Chadd if (params->ibp_try2) { 934b8e788a5SAdrian Chadd rix = ath_tx_findrix(sc, params->ibp_rate2); 935b8e788a5SAdrian Chadd rate2 = rt->info[rix].rateCode; 936b8e788a5SAdrian Chadd if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 937b8e788a5SAdrian Chadd rate2 |= rt->info[rix].shortPreamble; 938b8e788a5SAdrian Chadd } else 939b8e788a5SAdrian Chadd rate2 = 0; 940b8e788a5SAdrian Chadd if (params->ibp_try3) { 941b8e788a5SAdrian Chadd rix = ath_tx_findrix(sc, params->ibp_rate3); 942b8e788a5SAdrian Chadd rate3 = rt->info[rix].rateCode; 943b8e788a5SAdrian Chadd if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 944b8e788a5SAdrian Chadd rate3 |= rt->info[rix].shortPreamble; 945b8e788a5SAdrian Chadd } else 946b8e788a5SAdrian Chadd rate3 = 0; 947b8e788a5SAdrian Chadd ath_hal_setupxtxdesc(ah, ds 948b8e788a5SAdrian Chadd , rate1, params->ibp_try1 /* series 1 */ 949b8e788a5SAdrian Chadd , rate2, params->ibp_try2 /* series 2 */ 950b8e788a5SAdrian Chadd , rate3, params->ibp_try3 /* series 3 */ 951b8e788a5SAdrian Chadd ); 952b8e788a5SAdrian Chadd } 953b8e788a5SAdrian Chadd 954b8e788a5SAdrian Chadd /* NB: no buffered multicast in power save support */ 955b8e788a5SAdrian Chadd ath_tx_handoff(sc, sc->sc_ac2q[pri], bf); 956b8e788a5SAdrian Chadd return 0; 957b8e788a5SAdrian Chadd } 958b8e788a5SAdrian Chadd 959b8e788a5SAdrian Chadd int 960b8e788a5SAdrian Chadd ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 961b8e788a5SAdrian Chadd const struct ieee80211_bpf_params *params) 962b8e788a5SAdrian Chadd { 963b8e788a5SAdrian Chadd struct ieee80211com *ic = ni->ni_ic; 964b8e788a5SAdrian Chadd struct ifnet *ifp = ic->ic_ifp; 965b8e788a5SAdrian Chadd struct ath_softc *sc = ifp->if_softc; 966b8e788a5SAdrian Chadd struct ath_buf *bf; 967b8e788a5SAdrian Chadd int error; 968b8e788a5SAdrian Chadd 969b8e788a5SAdrian Chadd if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) { 970b8e788a5SAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT, "%s: discard frame, %s", __func__, 971b8e788a5SAdrian Chadd (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ? 972b8e788a5SAdrian Chadd "!running" : "invalid"); 973b8e788a5SAdrian Chadd m_freem(m); 974b8e788a5SAdrian Chadd error = ENETDOWN; 975b8e788a5SAdrian Chadd goto bad; 976b8e788a5SAdrian Chadd } 977b8e788a5SAdrian Chadd /* 978b8e788a5SAdrian Chadd * Grab a TX buffer and associated resources. 979b8e788a5SAdrian Chadd */ 980b8e788a5SAdrian Chadd bf = ath_getbuf(sc); 981b8e788a5SAdrian Chadd if (bf == NULL) { 982b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_nobuf++; 983b8e788a5SAdrian Chadd m_freem(m); 984b8e788a5SAdrian Chadd error = ENOBUFS; 985b8e788a5SAdrian Chadd goto bad; 986b8e788a5SAdrian Chadd } 987b8e788a5SAdrian Chadd 988b8e788a5SAdrian Chadd if (params == NULL) { 989b8e788a5SAdrian Chadd /* 990b8e788a5SAdrian Chadd * Legacy path; interpret frame contents to decide 991b8e788a5SAdrian Chadd * precisely how to send the frame. 992b8e788a5SAdrian Chadd */ 993b8e788a5SAdrian Chadd if (ath_tx_start(sc, ni, bf, m)) { 994b8e788a5SAdrian Chadd error = EIO; /* XXX */ 995b8e788a5SAdrian Chadd goto bad2; 996b8e788a5SAdrian Chadd } 997b8e788a5SAdrian Chadd } else { 998b8e788a5SAdrian Chadd /* 999b8e788a5SAdrian Chadd * Caller supplied explicit parameters to use in 1000b8e788a5SAdrian Chadd * sending the frame. 1001b8e788a5SAdrian Chadd */ 1002b8e788a5SAdrian Chadd if (ath_tx_raw_start(sc, ni, bf, m, params)) { 1003b8e788a5SAdrian Chadd error = EIO; /* XXX */ 1004b8e788a5SAdrian Chadd goto bad2; 1005b8e788a5SAdrian Chadd } 1006b8e788a5SAdrian Chadd } 1007b8e788a5SAdrian Chadd sc->sc_wd_timer = 5; 1008b8e788a5SAdrian Chadd ifp->if_opackets++; 1009b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_raw++; 1010b8e788a5SAdrian Chadd 1011b8e788a5SAdrian Chadd return 0; 1012b8e788a5SAdrian Chadd bad2: 1013b8e788a5SAdrian Chadd ATH_TXBUF_LOCK(sc); 1014b8e788a5SAdrian Chadd STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); 1015b8e788a5SAdrian Chadd ATH_TXBUF_UNLOCK(sc); 1016b8e788a5SAdrian Chadd bad: 1017b8e788a5SAdrian Chadd ifp->if_oerrors++; 1018b8e788a5SAdrian Chadd sc->sc_stats.ast_tx_raw_fail++; 1019b8e788a5SAdrian Chadd ieee80211_free_node(ni); 1020b8e788a5SAdrian Chadd return error; 1021b8e788a5SAdrian Chadd } 1022