13fdfc330SAdrian Chadd /*- 23fdfc330SAdrian Chadd * Copyright (c) 2012 Adrian Chadd <adrian@FreeBSD.org> 33fdfc330SAdrian Chadd * All rights reserved. 43fdfc330SAdrian Chadd * 53fdfc330SAdrian Chadd * Redistribution and use in source and binary forms, with or without 63fdfc330SAdrian Chadd * modification, are permitted provided that the following conditions 73fdfc330SAdrian Chadd * are met: 83fdfc330SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 93fdfc330SAdrian Chadd * notice, this list of conditions and the following disclaimer, 103fdfc330SAdrian Chadd * without modification. 113fdfc330SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 123fdfc330SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 133fdfc330SAdrian Chadd * redistribution must be conditioned upon including a substantially 143fdfc330SAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 153fdfc330SAdrian Chadd * 163fdfc330SAdrian Chadd * NO WARRANTY 173fdfc330SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 183fdfc330SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 193fdfc330SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 203fdfc330SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 213fdfc330SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 223fdfc330SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 233fdfc330SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 243fdfc330SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 253fdfc330SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 263fdfc330SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 273fdfc330SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 283fdfc330SAdrian Chadd */ 293fdfc330SAdrian Chadd 303fdfc330SAdrian Chadd #include <sys/cdefs.h> 313fdfc330SAdrian Chadd __FBSDID("$FreeBSD$"); 323fdfc330SAdrian Chadd 333fdfc330SAdrian Chadd /* 343fdfc330SAdrian Chadd * Driver for the Atheros Wireless LAN controller. 353fdfc330SAdrian Chadd * 363fdfc330SAdrian Chadd * This software is derived from work of Atsushi Onoe; his contribution 373fdfc330SAdrian Chadd * is greatly appreciated. 383fdfc330SAdrian Chadd */ 393fdfc330SAdrian Chadd 403fdfc330SAdrian Chadd #include "opt_inet.h" 413fdfc330SAdrian Chadd #include "opt_ath.h" 423fdfc330SAdrian Chadd /* 433fdfc330SAdrian Chadd * This is needed for register operations which are performed 443fdfc330SAdrian Chadd * by the driver - eg, calls to ath_hal_gettsf32(). 453fdfc330SAdrian Chadd * 463fdfc330SAdrian Chadd * It's also required for any AH_DEBUG checks in here, eg the 473fdfc330SAdrian Chadd * module dependencies. 483fdfc330SAdrian Chadd */ 493fdfc330SAdrian Chadd #include "opt_ah.h" 503fdfc330SAdrian Chadd #include "opt_wlan.h" 513fdfc330SAdrian Chadd 523fdfc330SAdrian Chadd #include <sys/param.h> 533fdfc330SAdrian Chadd #include <sys/systm.h> 543fdfc330SAdrian Chadd #include <sys/sysctl.h> 553fdfc330SAdrian Chadd #include <sys/mbuf.h> 563fdfc330SAdrian Chadd #include <sys/malloc.h> 573fdfc330SAdrian Chadd #include <sys/lock.h> 583fdfc330SAdrian Chadd #include <sys/mutex.h> 593fdfc330SAdrian Chadd #include <sys/kernel.h> 603fdfc330SAdrian Chadd #include <sys/socket.h> 613fdfc330SAdrian Chadd #include <sys/sockio.h> 623fdfc330SAdrian Chadd #include <sys/errno.h> 633fdfc330SAdrian Chadd #include <sys/callout.h> 643fdfc330SAdrian Chadd #include <sys/bus.h> 653fdfc330SAdrian Chadd #include <sys/endian.h> 663fdfc330SAdrian Chadd #include <sys/kthread.h> 673fdfc330SAdrian Chadd #include <sys/taskqueue.h> 683fdfc330SAdrian Chadd #include <sys/priv.h> 693fdfc330SAdrian Chadd #include <sys/module.h> 703fdfc330SAdrian Chadd #include <sys/ktr.h> 713fdfc330SAdrian Chadd #include <sys/smp.h> /* for mp_ncpus */ 723fdfc330SAdrian Chadd 733fdfc330SAdrian Chadd #include <machine/bus.h> 743fdfc330SAdrian Chadd 753fdfc330SAdrian Chadd #include <net/if.h> 7676039bc8SGleb Smirnoff #include <net/if_var.h> 773fdfc330SAdrian Chadd #include <net/if_dl.h> 783fdfc330SAdrian Chadd #include <net/if_media.h> 793fdfc330SAdrian Chadd #include <net/if_types.h> 803fdfc330SAdrian Chadd #include <net/if_arp.h> 813fdfc330SAdrian Chadd #include <net/ethernet.h> 823fdfc330SAdrian Chadd #include <net/if_llc.h> 833fdfc330SAdrian Chadd 843fdfc330SAdrian Chadd #include <net80211/ieee80211_var.h> 853fdfc330SAdrian Chadd #include <net80211/ieee80211_regdomain.h> 863fdfc330SAdrian Chadd #ifdef IEEE80211_SUPPORT_SUPERG 873fdfc330SAdrian Chadd #include <net80211/ieee80211_superg.h> 883fdfc330SAdrian Chadd #endif 893fdfc330SAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA 903fdfc330SAdrian Chadd #include <net80211/ieee80211_tdma.h> 913fdfc330SAdrian Chadd #endif 923fdfc330SAdrian Chadd 933fdfc330SAdrian Chadd #include <net/bpf.h> 943fdfc330SAdrian Chadd 953fdfc330SAdrian Chadd #ifdef INET 963fdfc330SAdrian Chadd #include <netinet/in.h> 973fdfc330SAdrian Chadd #include <netinet/if_ether.h> 983fdfc330SAdrian Chadd #endif 993fdfc330SAdrian Chadd 1003fdfc330SAdrian Chadd #include <dev/ath/if_athvar.h> 1013fdfc330SAdrian Chadd #include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */ 1023fdfc330SAdrian Chadd #include <dev/ath/ath_hal/ah_diagcodes.h> 1033fdfc330SAdrian Chadd 1043fdfc330SAdrian Chadd #include <dev/ath/if_ath_debug.h> 1053fdfc330SAdrian Chadd #include <dev/ath/if_ath_misc.h> 1063fdfc330SAdrian Chadd #include <dev/ath/if_ath_tsf.h> 1073fdfc330SAdrian Chadd #include <dev/ath/if_ath_tx.h> 1083fdfc330SAdrian Chadd #include <dev/ath/if_ath_sysctl.h> 1093fdfc330SAdrian Chadd #include <dev/ath/if_ath_led.h> 1103fdfc330SAdrian Chadd #include <dev/ath/if_ath_keycache.h> 1113fdfc330SAdrian Chadd #include <dev/ath/if_ath_rx.h> 1123fdfc330SAdrian Chadd #include <dev/ath/if_ath_beacon.h> 1133fdfc330SAdrian Chadd #include <dev/ath/if_athdfs.h> 1143fdfc330SAdrian Chadd 1153fdfc330SAdrian Chadd #ifdef ATH_TX99_DIAG 1163fdfc330SAdrian Chadd #include <dev/ath/ath_tx99/ath_tx99.h> 1173fdfc330SAdrian Chadd #endif 1183fdfc330SAdrian Chadd 1193fdfc330SAdrian Chadd #include <dev/ath/if_ath_tx_edma.h> 1203fdfc330SAdrian Chadd 121b69b0dccSAdrian Chadd #ifdef ATH_DEBUG_ALQ 122b69b0dccSAdrian Chadd #include <dev/ath/if_ath_alq.h> 123b69b0dccSAdrian Chadd #endif 124b69b0dccSAdrian Chadd 1253fdfc330SAdrian Chadd /* 1263fdfc330SAdrian Chadd * some general macros 1273fdfc330SAdrian Chadd */ 1283fdfc330SAdrian Chadd #define INCR(_l, _sz) (_l) ++; (_l) &= ((_sz) - 1) 1293fdfc330SAdrian Chadd #define DECR(_l, _sz) (_l) --; (_l) &= ((_sz) - 1) 1303fdfc330SAdrian Chadd 131ba3fd9d8SAdrian Chadd /* 132ba3fd9d8SAdrian Chadd * XXX doesn't belong here, and should be tunable 133ba3fd9d8SAdrian Chadd */ 134ba3fd9d8SAdrian Chadd #define ATH_TXSTATUS_RING_SIZE 512 135ba3fd9d8SAdrian Chadd 1363fdfc330SAdrian Chadd MALLOC_DECLARE(M_ATHDEV); 1373fdfc330SAdrian Chadd 138ae3815fdSAdrian Chadd static void ath_edma_tx_processq(struct ath_softc *sc, int dosched); 139ae3815fdSAdrian Chadd 14092e84e43SAdrian Chadd /* 14192e84e43SAdrian Chadd * Push some frames into the TX FIFO if we have space. 14292e84e43SAdrian Chadd */ 1434aa8818bSAdrian Chadd static void 1444aa8818bSAdrian Chadd ath_edma_tx_fifo_fill(struct ath_softc *sc, struct ath_txq *txq) 1454aa8818bSAdrian Chadd { 14692e84e43SAdrian Chadd struct ath_buf *bf, *bf_last; 147d40c846aSAdrian Chadd int i = 0; 1484aa8818bSAdrian Chadd 149b837332dSAdrian Chadd ATH_TXQ_LOCK_ASSERT(txq); 1504aa8818bSAdrian Chadd 15192e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d: called\n", 15292e84e43SAdrian Chadd __func__, 15392e84e43SAdrian Chadd txq->axq_qnum); 1544aa8818bSAdrian Chadd 1554aa8818bSAdrian Chadd TAILQ_FOREACH(bf, &txq->axq_q, bf_list) { 1564aa8818bSAdrian Chadd if (txq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) 1574aa8818bSAdrian Chadd break; 15892e84e43SAdrian Chadd 15992e84e43SAdrian Chadd /* 16092e84e43SAdrian Chadd * We have space in the FIFO - so let's push a frame 16192e84e43SAdrian Chadd * into it. 16292e84e43SAdrian Chadd */ 16392e84e43SAdrian Chadd 16492e84e43SAdrian Chadd /* 16592e84e43SAdrian Chadd * Remove it from the normal list 16692e84e43SAdrian Chadd */ 16792e84e43SAdrian Chadd ATH_TXQ_REMOVE(txq, bf, bf_list); 16892e84e43SAdrian Chadd 16992e84e43SAdrian Chadd /* 17092e84e43SAdrian Chadd * XXX for now, we only dequeue a frame at a time, so 17192e84e43SAdrian Chadd * that's only one buffer. Later on when we just 17292e84e43SAdrian Chadd * push this staging _list_ into the queue, we'll 17392e84e43SAdrian Chadd * set bf_last to the end pointer in the list. 17492e84e43SAdrian Chadd */ 17592e84e43SAdrian Chadd bf_last = bf; 17692e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TX_PROC, 17792e84e43SAdrian Chadd "%s: Q%d: depth=%d; pushing %p->%p\n", 17892e84e43SAdrian Chadd __func__, 17992e84e43SAdrian Chadd txq->axq_qnum, 18092e84e43SAdrian Chadd txq->axq_fifo_depth, 18192e84e43SAdrian Chadd bf, 18292e84e43SAdrian Chadd bf_last); 18392e84e43SAdrian Chadd 18492e84e43SAdrian Chadd /* 18592e84e43SAdrian Chadd * Append it to the FIFO staging list 18692e84e43SAdrian Chadd */ 18792e84e43SAdrian Chadd ATH_TXQ_INSERT_TAIL(&txq->fifo, bf, bf_list); 18892e84e43SAdrian Chadd 18992e84e43SAdrian Chadd /* 19092e84e43SAdrian Chadd * Set fifo start / fifo end flags appropriately 19192e84e43SAdrian Chadd * 19292e84e43SAdrian Chadd */ 19392e84e43SAdrian Chadd bf->bf_flags |= ATH_BUF_FIFOPTR; 19492e84e43SAdrian Chadd bf_last->bf_flags |= ATH_BUF_FIFOEND; 19592e84e43SAdrian Chadd 19692e84e43SAdrian Chadd /* 19792e84e43SAdrian Chadd * Push _into_ the FIFO. 19892e84e43SAdrian Chadd */ 1994aa8818bSAdrian Chadd ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr); 200d40c846aSAdrian Chadd #ifdef ATH_DEBUG 201d40c846aSAdrian Chadd if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) 202d40c846aSAdrian Chadd ath_printtxbuf(sc, bf, txq->axq_qnum, i, 0); 203b69b0dccSAdrian Chadd #endif/* ATH_DEBUG */ 204b69b0dccSAdrian Chadd #ifdef ATH_DEBUG_ALQ 205b69b0dccSAdrian Chadd if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC)) 206e3f06688SAdrian Chadd ath_tx_alq_post(sc, bf); 207b69b0dccSAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 2084aa8818bSAdrian Chadd txq->axq_fifo_depth++; 209d40c846aSAdrian Chadd i++; 2104aa8818bSAdrian Chadd } 211d40c846aSAdrian Chadd if (i > 0) 2124aa8818bSAdrian Chadd ath_hal_txstart(sc->sc_ah, txq->axq_qnum); 2134aa8818bSAdrian Chadd } 2144aa8818bSAdrian Chadd 215746bab5bSAdrian Chadd /* 216746bab5bSAdrian Chadd * Re-initialise the DMA FIFO with the current contents of 2173ae723d4SAdrian Chadd * said TXQ. 218746bab5bSAdrian Chadd * 219746bab5bSAdrian Chadd * This should only be called as part of the chip reset path, as it 220746bab5bSAdrian Chadd * assumes the FIFO is currently empty. 221746bab5bSAdrian Chadd */ 222746bab5bSAdrian Chadd static void 223746bab5bSAdrian Chadd ath_edma_dma_restart(struct ath_softc *sc, struct ath_txq *txq) 224746bab5bSAdrian Chadd { 22592e84e43SAdrian Chadd struct ath_buf *bf; 22692e84e43SAdrian Chadd int i = 0; 22792e84e43SAdrian Chadd int fifostart = 1; 22892e84e43SAdrian Chadd int old_fifo_depth; 229746bab5bSAdrian Chadd 23092e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_RESET, "%s: Q%d: called\n", 231746bab5bSAdrian Chadd __func__, 232746bab5bSAdrian Chadd txq->axq_qnum); 2334aa8818bSAdrian Chadd 234b837332dSAdrian Chadd ATH_TXQ_LOCK_ASSERT(txq); 23592e84e43SAdrian Chadd 23692e84e43SAdrian Chadd /* 23792e84e43SAdrian Chadd * Let's log if the tracked FIFO depth doesn't match 23892e84e43SAdrian Chadd * what we actually push in. 23992e84e43SAdrian Chadd */ 24092e84e43SAdrian Chadd old_fifo_depth = txq->axq_fifo_depth; 24192e84e43SAdrian Chadd txq->axq_fifo_depth = 0; 24292e84e43SAdrian Chadd 24392e84e43SAdrian Chadd /* 24492e84e43SAdrian Chadd * Walk the FIFO staging list, looking for "head" entries. 24592e84e43SAdrian Chadd * Since we may have a partially completed list of frames, 24692e84e43SAdrian Chadd * we push the first frame we see into the FIFO and re-mark 24792e84e43SAdrian Chadd * it as the head entry. We then skip entries until we see 24892e84e43SAdrian Chadd * FIFO end, at which point we get ready to push another 24992e84e43SAdrian Chadd * entry into the FIFO. 25092e84e43SAdrian Chadd */ 25192e84e43SAdrian Chadd TAILQ_FOREACH(bf, &txq->fifo.axq_q, bf_list) { 25292e84e43SAdrian Chadd /* 25392e84e43SAdrian Chadd * If we're looking for FIFOEND and we haven't found 25492e84e43SAdrian Chadd * it, skip. 25592e84e43SAdrian Chadd * 25692e84e43SAdrian Chadd * If we're looking for FIFOEND and we've found it, 25792e84e43SAdrian Chadd * reset for another descriptor. 25892e84e43SAdrian Chadd */ 25992e84e43SAdrian Chadd #ifdef ATH_DEBUG 26092e84e43SAdrian Chadd if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) 26192e84e43SAdrian Chadd ath_printtxbuf(sc, bf, txq->axq_qnum, i, 0); 26292e84e43SAdrian Chadd #endif/* ATH_DEBUG */ 26392e84e43SAdrian Chadd #ifdef ATH_DEBUG_ALQ 26492e84e43SAdrian Chadd if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC)) 26592e84e43SAdrian Chadd ath_tx_alq_post(sc, bf); 26692e84e43SAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 26792e84e43SAdrian Chadd 26892e84e43SAdrian Chadd if (fifostart == 0) { 26992e84e43SAdrian Chadd if (bf->bf_flags & ATH_BUF_FIFOEND) 27092e84e43SAdrian Chadd fifostart = 1; 27192e84e43SAdrian Chadd continue; 27292e84e43SAdrian Chadd } 27392e84e43SAdrian Chadd 27492e84e43SAdrian Chadd /* Make sure we're not overflowing the FIFO! */ 27592e84e43SAdrian Chadd if (txq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) { 27692e84e43SAdrian Chadd device_printf(sc->sc_dev, 27792e84e43SAdrian Chadd "%s: Q%d: more frames in the queue; FIFO depth=%d?!\n", 27892e84e43SAdrian Chadd __func__, 27992e84e43SAdrian Chadd txq->axq_qnum, 28092e84e43SAdrian Chadd txq->axq_fifo_depth); 28192e84e43SAdrian Chadd } 28292e84e43SAdrian Chadd 28392e84e43SAdrian Chadd #if 0 28492e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_RESET, 28592e84e43SAdrian Chadd "%s: Q%d: depth=%d: pushing bf=%p; start=%d, end=%d\n", 28692e84e43SAdrian Chadd __func__, 28792e84e43SAdrian Chadd txq->axq_qnum, 28892e84e43SAdrian Chadd txq->axq_fifo_depth, 28992e84e43SAdrian Chadd bf, 29092e84e43SAdrian Chadd !! (bf->bf_flags & ATH_BUF_FIFOPTR), 29192e84e43SAdrian Chadd !! (bf->bf_flags & ATH_BUF_FIFOEND)); 29292e84e43SAdrian Chadd #endif 29392e84e43SAdrian Chadd 29492e84e43SAdrian Chadd /* 29592e84e43SAdrian Chadd * Set this to be the first buffer in the FIFO 29692e84e43SAdrian Chadd * list - even if it's also the last buffer in 29792e84e43SAdrian Chadd * a FIFO list! 29892e84e43SAdrian Chadd */ 29992e84e43SAdrian Chadd bf->bf_flags |= ATH_BUF_FIFOPTR; 30092e84e43SAdrian Chadd 30192e84e43SAdrian Chadd /* Push it into the FIFO and bump the FIFO count */ 30292e84e43SAdrian Chadd ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr); 30392e84e43SAdrian Chadd txq->axq_fifo_depth++; 30492e84e43SAdrian Chadd 30592e84e43SAdrian Chadd /* 30692e84e43SAdrian Chadd * If this isn't the last entry either, let's 30792e84e43SAdrian Chadd * clear fifostart so we continue looking for 30892e84e43SAdrian Chadd * said last entry. 30992e84e43SAdrian Chadd */ 31092e84e43SAdrian Chadd if (! (bf->bf_flags & ATH_BUF_FIFOEND)) 31192e84e43SAdrian Chadd fifostart = 0; 31292e84e43SAdrian Chadd i++; 31392e84e43SAdrian Chadd } 31492e84e43SAdrian Chadd 31592e84e43SAdrian Chadd /* Only bother starting the queue if there's something in it */ 31692e84e43SAdrian Chadd if (i > 0) 31792e84e43SAdrian Chadd ath_hal_txstart(sc->sc_ah, txq->axq_qnum); 31892e84e43SAdrian Chadd 31992e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_RESET, "%s: Q%d: FIFO depth was %d, is %d\n", 32092e84e43SAdrian Chadd __func__, 32192e84e43SAdrian Chadd txq->axq_qnum, 32292e84e43SAdrian Chadd old_fifo_depth, 32392e84e43SAdrian Chadd txq->axq_fifo_depth); 32492e84e43SAdrian Chadd 32592e84e43SAdrian Chadd /* And now, let's check! */ 32692e84e43SAdrian Chadd if (txq->axq_fifo_depth != old_fifo_depth) { 32792e84e43SAdrian Chadd device_printf(sc->sc_dev, 32892e84e43SAdrian Chadd "%s: Q%d: FIFO depth should be %d, is %d\n", 32992e84e43SAdrian Chadd __func__, 33092e84e43SAdrian Chadd txq->axq_qnum, 33192e84e43SAdrian Chadd old_fifo_depth, 33292e84e43SAdrian Chadd txq->axq_fifo_depth); 33392e84e43SAdrian Chadd } 334746bab5bSAdrian Chadd } 335746bab5bSAdrian Chadd 336746bab5bSAdrian Chadd /* 3373ae723d4SAdrian Chadd * Hand off this frame to a hardware queue. 3383ae723d4SAdrian Chadd * 3393ae723d4SAdrian Chadd * Things are a bit hairy in the EDMA world. The TX FIFO is only 3403ae723d4SAdrian Chadd * 8 entries deep, so we need to keep track of exactly what we've 3413ae723d4SAdrian Chadd * pushed into the FIFO and what's just sitting in the TX queue, 3423ae723d4SAdrian Chadd * waiting to go out. 3433ae723d4SAdrian Chadd * 3443ae723d4SAdrian Chadd * So this is split into two halves - frames get appended to the 3453ae723d4SAdrian Chadd * TXQ; then a scheduler is called to push some frames into the 3463ae723d4SAdrian Chadd * actual TX FIFO. 3473ae723d4SAdrian Chadd */ 3483ae723d4SAdrian Chadd static void 3493ae723d4SAdrian Chadd ath_edma_xmit_handoff_hw(struct ath_softc *sc, struct ath_txq *txq, 3503ae723d4SAdrian Chadd struct ath_buf *bf) 3513ae723d4SAdrian Chadd { 3523ae723d4SAdrian Chadd 3530acf45edSAdrian Chadd ATH_TXQ_LOCK(txq); 3543ae723d4SAdrian Chadd 3553ae723d4SAdrian Chadd KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0, 3563ae723d4SAdrian Chadd ("%s: busy status 0x%x", __func__, bf->bf_flags)); 3573ae723d4SAdrian Chadd 3583ae723d4SAdrian Chadd /* 3593ae723d4SAdrian Chadd * XXX TODO: write a hard-coded check to ensure that 3603ae723d4SAdrian Chadd * the queue id in the TX descriptor matches txq->axq_qnum. 3613ae723d4SAdrian Chadd */ 3623ae723d4SAdrian Chadd 3633ae723d4SAdrian Chadd /* Update aggr stats */ 3643ae723d4SAdrian Chadd if (bf->bf_state.bfs_aggr) 3653ae723d4SAdrian Chadd txq->axq_aggr_depth++; 3663ae723d4SAdrian Chadd 3673ae723d4SAdrian Chadd /* Push and update frame stats */ 3683ae723d4SAdrian Chadd ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 3693ae723d4SAdrian Chadd 37092e84e43SAdrian Chadd /* For now, set the link pointer in the last descriptor 37192e84e43SAdrian Chadd * to be NULL. 37292e84e43SAdrian Chadd * 37392e84e43SAdrian Chadd * Later on, when it comes time to handling multiple descriptors 37492e84e43SAdrian Chadd * in one FIFO push, we can link descriptors together this way. 37592e84e43SAdrian Chadd */ 37692e84e43SAdrian Chadd 37792e84e43SAdrian Chadd /* 37892e84e43SAdrian Chadd * Finally, call the FIFO schedule routine to schedule some 37992e84e43SAdrian Chadd * frames to the FIFO. 38092e84e43SAdrian Chadd */ 38192e84e43SAdrian Chadd ath_edma_tx_fifo_fill(sc, txq); 3820acf45edSAdrian Chadd ATH_TXQ_UNLOCK(txq); 3833ae723d4SAdrian Chadd } 3843ae723d4SAdrian Chadd 3853ae723d4SAdrian Chadd /* 3863ae723d4SAdrian Chadd * Hand off this frame to a multicast software queue. 3873ae723d4SAdrian Chadd * 388e3f06688SAdrian Chadd * The EDMA TX CABQ will get a list of chained frames, chained 389e3f06688SAdrian Chadd * together using the next pointer. The single head of that 390e3f06688SAdrian Chadd * particular queue is pushed to the hardware CABQ. 3913ae723d4SAdrian Chadd */ 3923ae723d4SAdrian Chadd static void 3933ae723d4SAdrian Chadd ath_edma_xmit_handoff_mcast(struct ath_softc *sc, struct ath_txq *txq, 3943ae723d4SAdrian Chadd struct ath_buf *bf) 3953ae723d4SAdrian Chadd { 3963ae723d4SAdrian Chadd 3979e7259a2SAdrian Chadd ATH_TX_LOCK_ASSERT(sc); 3983ae723d4SAdrian Chadd KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0, 3993ae723d4SAdrian Chadd ("%s: busy status 0x%x", __func__, bf->bf_flags)); 4003ae723d4SAdrian Chadd 4010acf45edSAdrian Chadd ATH_TXQ_LOCK(txq); 4023ae723d4SAdrian Chadd /* 4033ae723d4SAdrian Chadd * XXX this is mostly duplicated in ath_tx_handoff_mcast(). 4043ae723d4SAdrian Chadd */ 4059e7259a2SAdrian Chadd if (ATH_TXQ_LAST(txq, axq_q_s) != NULL) { 4063ae723d4SAdrian Chadd struct ath_buf *bf_last = ATH_TXQ_LAST(txq, axq_q_s); 4073ae723d4SAdrian Chadd struct ieee80211_frame *wh; 4083ae723d4SAdrian Chadd 4093ae723d4SAdrian Chadd /* mark previous frame */ 4103ae723d4SAdrian Chadd wh = mtod(bf_last->bf_m, struct ieee80211_frame *); 4113ae723d4SAdrian Chadd wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 4123ae723d4SAdrian Chadd 413caedab2cSAdrian Chadd /* re-sync buffer to memory */ 4143ae723d4SAdrian Chadd bus_dmamap_sync(sc->sc_dmat, bf_last->bf_dmamap, 4153ae723d4SAdrian Chadd BUS_DMASYNC_PREWRITE); 4169cda8c80SAdrian Chadd 4179cda8c80SAdrian Chadd /* link descriptor */ 4189e7259a2SAdrian Chadd ath_hal_settxdesclink(sc->sc_ah, 4199e7259a2SAdrian Chadd bf_last->bf_lastds, 4209e7259a2SAdrian Chadd bf->bf_daddr); 4213ae723d4SAdrian Chadd } 422e3f06688SAdrian Chadd #ifdef ATH_DEBUG_ALQ 423e3f06688SAdrian Chadd if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC)) 424e3f06688SAdrian Chadd ath_tx_alq_post(sc, bf); 425e3f06688SAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 4263ae723d4SAdrian Chadd ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 4270acf45edSAdrian Chadd ATH_TXQ_UNLOCK(txq); 4283ae723d4SAdrian Chadd } 4293ae723d4SAdrian Chadd 4303ae723d4SAdrian Chadd /* 431746bab5bSAdrian Chadd * Handoff this frame to the hardware. 432746bab5bSAdrian Chadd * 433746bab5bSAdrian Chadd * For the multicast queue, this will treat it as a software queue 434746bab5bSAdrian Chadd * and append it to the list, after updating the MORE_DATA flag 435746bab5bSAdrian Chadd * in the previous frame. The cabq processing code will ensure 436746bab5bSAdrian Chadd * that the queue contents gets transferred over. 437746bab5bSAdrian Chadd * 438746bab5bSAdrian Chadd * For the hardware queues, this will queue a frame to the queue 439746bab5bSAdrian Chadd * like before, then populate the FIFO from that. Since the 440746bab5bSAdrian Chadd * EDMA hardware has 8 FIFO slots per TXQ, this ensures that 441746bab5bSAdrian Chadd * frames such as management frames don't get prematurely dropped. 442746bab5bSAdrian Chadd * 443746bab5bSAdrian Chadd * This does imply that a similar flush-hwq-to-fifoq method will 444746bab5bSAdrian Chadd * need to be called from the processq function, before the 445746bab5bSAdrian Chadd * per-node software scheduler is called. 446746bab5bSAdrian Chadd */ 447746bab5bSAdrian Chadd static void 448746bab5bSAdrian Chadd ath_edma_xmit_handoff(struct ath_softc *sc, struct ath_txq *txq, 449746bab5bSAdrian Chadd struct ath_buf *bf) 450746bab5bSAdrian Chadd { 451746bab5bSAdrian Chadd 4524aa8818bSAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT_DESC, 4534aa8818bSAdrian Chadd "%s: called; bf=%p, txq=%p, qnum=%d\n", 454746bab5bSAdrian Chadd __func__, 455746bab5bSAdrian Chadd bf, 456746bab5bSAdrian Chadd txq, 457746bab5bSAdrian Chadd txq->axq_qnum); 458746bab5bSAdrian Chadd 4593ae723d4SAdrian Chadd if (txq->axq_qnum == ATH_TXQ_SWQ) 4603ae723d4SAdrian Chadd ath_edma_xmit_handoff_mcast(sc, txq, bf); 4613ae723d4SAdrian Chadd else 4623ae723d4SAdrian Chadd ath_edma_xmit_handoff_hw(sc, txq, bf); 463746bab5bSAdrian Chadd } 464746bab5bSAdrian Chadd 4653fdfc330SAdrian Chadd static int 46679607afeSAdrian Chadd ath_edma_setup_txfifo(struct ath_softc *sc, int qnum) 46779607afeSAdrian Chadd { 46879607afeSAdrian Chadd struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum]; 46979607afeSAdrian Chadd 47079607afeSAdrian Chadd te->m_fifo = malloc(sizeof(struct ath_buf *) * HAL_TXFIFO_DEPTH, 47179607afeSAdrian Chadd M_ATHDEV, 47279607afeSAdrian Chadd M_NOWAIT | M_ZERO); 47379607afeSAdrian Chadd if (te->m_fifo == NULL) { 47479607afeSAdrian Chadd device_printf(sc->sc_dev, "%s: malloc failed\n", 47579607afeSAdrian Chadd __func__); 47679607afeSAdrian Chadd return (-ENOMEM); 47779607afeSAdrian Chadd } 47879607afeSAdrian Chadd 47979607afeSAdrian Chadd /* 48079607afeSAdrian Chadd * Set initial "empty" state. 48179607afeSAdrian Chadd */ 48279607afeSAdrian Chadd te->m_fifo_head = te->m_fifo_tail = te->m_fifo_depth = 0; 48379607afeSAdrian Chadd 48479607afeSAdrian Chadd return (0); 48579607afeSAdrian Chadd } 48679607afeSAdrian Chadd 48779607afeSAdrian Chadd static int 48879607afeSAdrian Chadd ath_edma_free_txfifo(struct ath_softc *sc, int qnum) 48979607afeSAdrian Chadd { 49079607afeSAdrian Chadd struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum]; 49179607afeSAdrian Chadd 49279607afeSAdrian Chadd /* XXX TODO: actually deref the ath_buf entries? */ 49379607afeSAdrian Chadd free(te->m_fifo, M_ATHDEV); 49479607afeSAdrian Chadd return (0); 49579607afeSAdrian Chadd } 49679607afeSAdrian Chadd 49779607afeSAdrian Chadd static int 4983fdfc330SAdrian Chadd ath_edma_dma_txsetup(struct ath_softc *sc) 4993fdfc330SAdrian Chadd { 500ba3fd9d8SAdrian Chadd int error; 50179607afeSAdrian Chadd int i; 5023fdfc330SAdrian Chadd 503ba3fd9d8SAdrian Chadd error = ath_descdma_alloc_desc(sc, &sc->sc_txsdma, 504ba3fd9d8SAdrian Chadd NULL, "txcomp", sc->sc_tx_statuslen, ATH_TXSTATUS_RING_SIZE); 505ba3fd9d8SAdrian Chadd if (error != 0) 506ba3fd9d8SAdrian Chadd return (error); 507ba3fd9d8SAdrian Chadd 508ba3fd9d8SAdrian Chadd ath_hal_setuptxstatusring(sc->sc_ah, 509ba3fd9d8SAdrian Chadd (void *) sc->sc_txsdma.dd_desc, 510ba3fd9d8SAdrian Chadd sc->sc_txsdma.dd_desc_paddr, 511ba3fd9d8SAdrian Chadd ATH_TXSTATUS_RING_SIZE); 512ba3fd9d8SAdrian Chadd 51379607afeSAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 51479607afeSAdrian Chadd ath_edma_setup_txfifo(sc, i); 51579607afeSAdrian Chadd } 51679607afeSAdrian Chadd 5173fdfc330SAdrian Chadd return (0); 5183fdfc330SAdrian Chadd } 5193fdfc330SAdrian Chadd 5203fdfc330SAdrian Chadd static int 5213fdfc330SAdrian Chadd ath_edma_dma_txteardown(struct ath_softc *sc) 5223fdfc330SAdrian Chadd { 52379607afeSAdrian Chadd int i; 52479607afeSAdrian Chadd 52579607afeSAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 52679607afeSAdrian Chadd ath_edma_free_txfifo(sc, i); 52779607afeSAdrian Chadd } 5283fdfc330SAdrian Chadd 529ba3fd9d8SAdrian Chadd ath_descdma_cleanup(sc, &sc->sc_txsdma, NULL); 5303fdfc330SAdrian Chadd return (0); 5313fdfc330SAdrian Chadd } 5323fdfc330SAdrian Chadd 5333ae723d4SAdrian Chadd /* 534788e6aa9SAdrian Chadd * Drain all TXQs, potentially after completing the existing completed 535788e6aa9SAdrian Chadd * frames. 5363ae723d4SAdrian Chadd */ 537788e6aa9SAdrian Chadd static void 538788e6aa9SAdrian Chadd ath_edma_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type) 539f8418db5SAdrian Chadd { 5404aa8818bSAdrian Chadd struct ifnet *ifp = sc->sc_ifp; 5414aa8818bSAdrian Chadd int i; 542f8418db5SAdrian Chadd 543ae3815fdSAdrian Chadd DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__); 5444aa8818bSAdrian Chadd 5454aa8818bSAdrian Chadd (void) ath_stoptxdma(sc); 5464aa8818bSAdrian Chadd 5474aa8818bSAdrian Chadd /* 5484aa8818bSAdrian Chadd * If reset type is noloss, the TX FIFO needs to be serviced 5494aa8818bSAdrian Chadd * and those frames need to be handled. 5504aa8818bSAdrian Chadd * 5514aa8818bSAdrian Chadd * Otherwise, just toss everything in each TX queue. 5524aa8818bSAdrian Chadd */ 553ae3815fdSAdrian Chadd if (reset_type == ATH_RESET_NOLOSS) { 554ae3815fdSAdrian Chadd ath_edma_tx_processq(sc, 0); 5558328d6e4SAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 5568328d6e4SAdrian Chadd if (ATH_TXQ_SETUP(sc, i)) { 5578328d6e4SAdrian Chadd ATH_TXQ_LOCK(&sc->sc_txq[i]); 5588328d6e4SAdrian Chadd /* 5598328d6e4SAdrian Chadd * Free the holding buffer; DMA is now 5608328d6e4SAdrian Chadd * stopped. 5618328d6e4SAdrian Chadd */ 5628328d6e4SAdrian Chadd ath_txq_freeholdingbuf(sc, &sc->sc_txq[i]); 5638328d6e4SAdrian Chadd /* 5648328d6e4SAdrian Chadd * Reset the link pointer to NULL; there's 5658328d6e4SAdrian Chadd * no frames to chain DMA to. 5668328d6e4SAdrian Chadd */ 5678328d6e4SAdrian Chadd sc->sc_txq[i].axq_link = NULL; 5688328d6e4SAdrian Chadd ATH_TXQ_UNLOCK(&sc->sc_txq[i]); 5698328d6e4SAdrian Chadd } 5708328d6e4SAdrian Chadd } 571ae3815fdSAdrian Chadd } else { 5724aa8818bSAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 5734aa8818bSAdrian Chadd if (ATH_TXQ_SETUP(sc, i)) 5744aa8818bSAdrian Chadd ath_tx_draintxq(sc, &sc->sc_txq[i]); 5754aa8818bSAdrian Chadd } 576ae3815fdSAdrian Chadd } 577ae3815fdSAdrian Chadd 578ae3815fdSAdrian Chadd /* XXX dump out the TX completion FIFO contents */ 579ae3815fdSAdrian Chadd 580ae3815fdSAdrian Chadd /* XXX dump out the frames */ 5814aa8818bSAdrian Chadd 5824aa8818bSAdrian Chadd IF_LOCK(&ifp->if_snd); 5834aa8818bSAdrian Chadd ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 5844aa8818bSAdrian Chadd IF_UNLOCK(&ifp->if_snd); 5854aa8818bSAdrian Chadd sc->sc_wd_timer = 0; 586f8418db5SAdrian Chadd } 587f8418db5SAdrian Chadd 5883ae723d4SAdrian Chadd /* 589ae3815fdSAdrian Chadd * TX completion tasklet. 5903ae723d4SAdrian Chadd */ 591ae3815fdSAdrian Chadd 592f8418db5SAdrian Chadd static void 593f8418db5SAdrian Chadd ath_edma_tx_proc(void *arg, int npending) 594f8418db5SAdrian Chadd { 595f8418db5SAdrian Chadd struct ath_softc *sc = (struct ath_softc *) arg; 596ae3815fdSAdrian Chadd 59792e84e43SAdrian Chadd #if 0 598ae3815fdSAdrian Chadd DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: called, npending=%d\n", 599ae3815fdSAdrian Chadd __func__, npending); 60092e84e43SAdrian Chadd #endif 601ae3815fdSAdrian Chadd ath_edma_tx_processq(sc, 1); 602ae3815fdSAdrian Chadd } 603ae3815fdSAdrian Chadd 604ae3815fdSAdrian Chadd /* 605ae3815fdSAdrian Chadd * Process the TX status queue. 606ae3815fdSAdrian Chadd */ 607ae3815fdSAdrian Chadd static void 608ae3815fdSAdrian Chadd ath_edma_tx_processq(struct ath_softc *sc, int dosched) 609ae3815fdSAdrian Chadd { 6103ae723d4SAdrian Chadd struct ath_hal *ah = sc->sc_ah; 6113ae723d4SAdrian Chadd HAL_STATUS status; 6123ae723d4SAdrian Chadd struct ath_tx_status ts; 6133ae723d4SAdrian Chadd struct ath_txq *txq; 6144aa8818bSAdrian Chadd struct ath_buf *bf; 6154aa8818bSAdrian Chadd struct ieee80211_node *ni; 616208be709SAdrian Chadd int nacked = 0; 617d40c846aSAdrian Chadd int idx; 618d40c846aSAdrian Chadd 619d40c846aSAdrian Chadd #ifdef ATH_DEBUG 620d40c846aSAdrian Chadd /* XXX */ 621d40c846aSAdrian Chadd uint32_t txstatus[32]; 622d40c846aSAdrian Chadd #endif 623f8418db5SAdrian Chadd 624d40c846aSAdrian Chadd for (idx = 0; ; idx++) { 6254aa8818bSAdrian Chadd bzero(&ts, sizeof(ts)); 6264aa8818bSAdrian Chadd 6273ae723d4SAdrian Chadd ATH_TXSTATUS_LOCK(sc); 6284c5038c7SAdrian Chadd #ifdef ATH_DEBUG 629d40c846aSAdrian Chadd ath_hal_gettxrawtxdesc(ah, txstatus); 6304c5038c7SAdrian Chadd #endif 631ae3815fdSAdrian Chadd status = ath_hal_txprocdesc(ah, NULL, (void *) &ts); 6323ae723d4SAdrian Chadd ATH_TXSTATUS_UNLOCK(sc); 6333ae723d4SAdrian Chadd 63492e84e43SAdrian Chadd if (status == HAL_EINPROGRESS) 63592e84e43SAdrian Chadd break; 63692e84e43SAdrian Chadd 637d40c846aSAdrian Chadd #ifdef ATH_DEBUG 638d40c846aSAdrian Chadd if (sc->sc_debug & ATH_DEBUG_TX_PROC) 63992e84e43SAdrian Chadd if (ts.ts_queue_id != sc->sc_bhalq) 640d40c846aSAdrian Chadd ath_printtxstatbuf(sc, NULL, txstatus, ts.ts_queue_id, 641d40c846aSAdrian Chadd idx, (status == HAL_OK)); 642d40c846aSAdrian Chadd #endif 643d40c846aSAdrian Chadd 6443ae723d4SAdrian Chadd /* 6454aa8818bSAdrian Chadd * If there is an error with this descriptor, continue 6464aa8818bSAdrian Chadd * processing. 6474aa8818bSAdrian Chadd * 6484aa8818bSAdrian Chadd * XXX TBD: log some statistics? 6494aa8818bSAdrian Chadd */ 6504aa8818bSAdrian Chadd if (status == HAL_EIO) { 6514aa8818bSAdrian Chadd device_printf(sc->sc_dev, "%s: invalid TX status?\n", 6524aa8818bSAdrian Chadd __func__); 653b92b5f6eSAdrian Chadd break; 6544aa8818bSAdrian Chadd } 6554aa8818bSAdrian Chadd 65669cbcb21SAdrian Chadd #if defined(ATH_DEBUG_ALQ) && defined(ATH_DEBUG) 657b69b0dccSAdrian Chadd if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXSTATUS)) 658b69b0dccSAdrian Chadd if_ath_alq_post(&sc->sc_alq, ATH_ALQ_EDMA_TXSTATUS, 659b69b0dccSAdrian Chadd sc->sc_tx_statuslen, 660b69b0dccSAdrian Chadd (char *) txstatus); 661b69b0dccSAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 662b69b0dccSAdrian Chadd 6634aa8818bSAdrian Chadd /* 6643ae723d4SAdrian Chadd * At this point we have a valid status descriptor. 6653ae723d4SAdrian Chadd * The QID and descriptor ID (which currently isn't set) 6663ae723d4SAdrian Chadd * is part of the status. 6673ae723d4SAdrian Chadd * 6683ae723d4SAdrian Chadd * We then assume that the descriptor in question is the 6693ae723d4SAdrian Chadd * -head- of the given QID. Eventually we should verify 6703ae723d4SAdrian Chadd * this by using the descriptor ID. 6713ae723d4SAdrian Chadd */ 6724aa8818bSAdrian Chadd 6734aa8818bSAdrian Chadd /* 6744aa8818bSAdrian Chadd * The beacon queue is not currently a "real" queue. 6754aa8818bSAdrian Chadd * Frames aren't pushed onto it and the lock isn't setup. 6764aa8818bSAdrian Chadd * So skip it for now; the beacon handling code will 6774aa8818bSAdrian Chadd * free and alloc more beacon buffers as appropriate. 6784aa8818bSAdrian Chadd */ 6794aa8818bSAdrian Chadd if (ts.ts_queue_id == sc->sc_bhalq) 6804aa8818bSAdrian Chadd continue; 6813ae723d4SAdrian Chadd 6823ae723d4SAdrian Chadd txq = &sc->sc_txq[ts.ts_queue_id]; 6834aa8818bSAdrian Chadd 684b837332dSAdrian Chadd ATH_TXQ_LOCK(txq); 68592e84e43SAdrian Chadd bf = ATH_TXQ_FIRST(&txq->fifo); 6864aa8818bSAdrian Chadd 68792e84e43SAdrian Chadd /* 68892e84e43SAdrian Chadd * Work around the situation where I'm seeing notifications 68992e84e43SAdrian Chadd * for Q1 when no frames are available. That needs to be 69092e84e43SAdrian Chadd * debugged but not by crashing _here_. 69192e84e43SAdrian Chadd */ 69292e84e43SAdrian Chadd if (bf == NULL) { 69392e84e43SAdrian Chadd device_printf(sc->sc_dev, "%s: Q%d: empty?\n", 6944aa8818bSAdrian Chadd __func__, 69592e84e43SAdrian Chadd ts.ts_queue_id); 696b92b5f6eSAdrian Chadd ATH_TXQ_UNLOCK(txq); 69792e84e43SAdrian Chadd continue; 69892e84e43SAdrian Chadd } 69992e84e43SAdrian Chadd 70092e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d, bf=%p, start=%d, end=%d\n", 70192e84e43SAdrian Chadd __func__, 70292e84e43SAdrian Chadd ts.ts_queue_id, bf, 70392e84e43SAdrian Chadd !! (bf->bf_flags & ATH_BUF_FIFOPTR), 70492e84e43SAdrian Chadd !! (bf->bf_flags & ATH_BUF_FIFOEND)); 7054aa8818bSAdrian Chadd 706d40c846aSAdrian Chadd /* XXX TODO: actually output debugging info about this */ 707d40c846aSAdrian Chadd 7084aa8818bSAdrian Chadd #if 0 7094aa8818bSAdrian Chadd /* XXX assert the buffer/descriptor matches the status descid */ 7104aa8818bSAdrian Chadd if (ts.ts_desc_id != bf->bf_descid) { 7114aa8818bSAdrian Chadd device_printf(sc->sc_dev, 7124aa8818bSAdrian Chadd "%s: mismatched descid (qid=%d, tsdescid=%d, " 7134aa8818bSAdrian Chadd "bfdescid=%d\n", 7144aa8818bSAdrian Chadd __func__, 7154aa8818bSAdrian Chadd ts.ts_queue_id, 7164aa8818bSAdrian Chadd ts.ts_desc_id, 7174aa8818bSAdrian Chadd bf->bf_descid); 7183ae723d4SAdrian Chadd } 7194aa8818bSAdrian Chadd #endif 7204aa8818bSAdrian Chadd 7214aa8818bSAdrian Chadd /* This removes the buffer and decrements the queue depth */ 72292e84e43SAdrian Chadd ATH_TXQ_REMOVE(&txq->fifo, bf, bf_list); 7234aa8818bSAdrian Chadd if (bf->bf_state.bfs_aggr) 7244aa8818bSAdrian Chadd txq->axq_aggr_depth--; 72592e84e43SAdrian Chadd 72692e84e43SAdrian Chadd /* 72792e84e43SAdrian Chadd * If this was the end of a FIFO set, decrement FIFO depth 72892e84e43SAdrian Chadd */ 72992e84e43SAdrian Chadd if (bf->bf_flags & ATH_BUF_FIFOEND) 7304aa8818bSAdrian Chadd txq->axq_fifo_depth--; 73192e84e43SAdrian Chadd 73292e84e43SAdrian Chadd /* 73392e84e43SAdrian Chadd * If this isn't the final buffer in a FIFO set, mark 73492e84e43SAdrian Chadd * the buffer as busy so it goes onto the holding queue. 73592e84e43SAdrian Chadd */ 73692e84e43SAdrian Chadd if (! (bf->bf_flags & ATH_BUF_FIFOEND)) 73792e84e43SAdrian Chadd bf->bf_flags |= ATH_BUF_BUSY; 73892e84e43SAdrian Chadd 73992e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d: FIFO depth is now %d (%d)\n", 74092e84e43SAdrian Chadd __func__, 74192e84e43SAdrian Chadd txq->axq_qnum, 74292e84e43SAdrian Chadd txq->axq_fifo_depth, 74392e84e43SAdrian Chadd txq->fifo.axq_depth); 74492e84e43SAdrian Chadd 7454aa8818bSAdrian Chadd /* XXX assert FIFO depth >= 0 */ 746b837332dSAdrian Chadd ATH_TXQ_UNLOCK(txq); 7474aa8818bSAdrian Chadd 7484aa8818bSAdrian Chadd /* 74992e84e43SAdrian Chadd * Outside of the TX lock - if the buffer is end 75092e84e43SAdrian Chadd * end buffer in this FIFO, we don't need a holding 75192e84e43SAdrian Chadd * buffer any longer. 75292e84e43SAdrian Chadd */ 75392e84e43SAdrian Chadd if (bf->bf_flags & ATH_BUF_FIFOEND) { 754caedab2cSAdrian Chadd ATH_TXQ_LOCK(txq); 75592e84e43SAdrian Chadd ath_txq_freeholdingbuf(sc, txq); 756caedab2cSAdrian Chadd ATH_TXQ_UNLOCK(txq); 75792e84e43SAdrian Chadd } 75892e84e43SAdrian Chadd 75992e84e43SAdrian Chadd /* 7604aa8818bSAdrian Chadd * First we need to make sure ts_rate is valid. 7614aa8818bSAdrian Chadd * 7624aa8818bSAdrian Chadd * Pre-EDMA chips pass the whole TX descriptor to 7634aa8818bSAdrian Chadd * the proctxdesc function which will then fill out 7644aa8818bSAdrian Chadd * ts_rate based on the ts_finaltsi (final TX index) 7654aa8818bSAdrian Chadd * in the TX descriptor. However the TX completion 7664aa8818bSAdrian Chadd * FIFO doesn't have this information. So here we 7674aa8818bSAdrian Chadd * do a separate HAL call to populate that information. 7683345c65bSAdrian Chadd * 7693345c65bSAdrian Chadd * The same problem exists with ts_longretry. 7703345c65bSAdrian Chadd * The FreeBSD HAL corrects ts_longretry in the HAL layer; 7713345c65bSAdrian Chadd * the AR9380 HAL currently doesn't. So until the HAL 7723345c65bSAdrian Chadd * is imported and this can be added, we correct for it 7733345c65bSAdrian Chadd * here. 7744aa8818bSAdrian Chadd */ 7754aa8818bSAdrian Chadd /* XXX TODO */ 7764aa8818bSAdrian Chadd /* XXX faked for now. Ew. */ 7774aa8818bSAdrian Chadd if (ts.ts_finaltsi < 4) { 7784aa8818bSAdrian Chadd ts.ts_rate = 7794aa8818bSAdrian Chadd bf->bf_state.bfs_rc[ts.ts_finaltsi].ratecode; 7803345c65bSAdrian Chadd switch (ts.ts_finaltsi) { 7813345c65bSAdrian Chadd case 3: ts.ts_longretry += 7823345c65bSAdrian Chadd bf->bf_state.bfs_rc[2].tries; 7833345c65bSAdrian Chadd case 2: ts.ts_longretry += 7843345c65bSAdrian Chadd bf->bf_state.bfs_rc[1].tries; 7853345c65bSAdrian Chadd case 1: ts.ts_longretry += 7863345c65bSAdrian Chadd bf->bf_state.bfs_rc[0].tries; 7873345c65bSAdrian Chadd } 7884aa8818bSAdrian Chadd } else { 7894aa8818bSAdrian Chadd device_printf(sc->sc_dev, "%s: finaltsi=%d\n", 7904aa8818bSAdrian Chadd __func__, 7914aa8818bSAdrian Chadd ts.ts_finaltsi); 7924aa8818bSAdrian Chadd ts.ts_rate = bf->bf_state.bfs_rc[0].ratecode; 7934aa8818bSAdrian Chadd } 7944aa8818bSAdrian Chadd 7954aa8818bSAdrian Chadd /* 7964aa8818bSAdrian Chadd * XXX This is terrible. 7974aa8818bSAdrian Chadd * 7984aa8818bSAdrian Chadd * Right now, some code uses the TX status that is 7994aa8818bSAdrian Chadd * passed in here, but the completion handlers in the 8004aa8818bSAdrian Chadd * software TX path also use bf_status.ds_txstat. 8014aa8818bSAdrian Chadd * Ew. That should all go away. 8024aa8818bSAdrian Chadd * 8034aa8818bSAdrian Chadd * XXX It's also possible the rate control completion 8044aa8818bSAdrian Chadd * routine is called twice. 8054aa8818bSAdrian Chadd */ 8064aa8818bSAdrian Chadd memcpy(&bf->bf_status, &ts, sizeof(ts)); 8074aa8818bSAdrian Chadd 8084aa8818bSAdrian Chadd ni = bf->bf_node; 8094aa8818bSAdrian Chadd 8104aa8818bSAdrian Chadd /* Update RSSI */ 8114aa8818bSAdrian Chadd /* XXX duplicate from ath_tx_processq */ 8124aa8818bSAdrian Chadd if (ni != NULL && ts.ts_status == 0 && 8134aa8818bSAdrian Chadd ((bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0)) { 8144aa8818bSAdrian Chadd nacked++; 8154aa8818bSAdrian Chadd sc->sc_stats.ast_tx_rssi = ts.ts_rssi; 8164aa8818bSAdrian Chadd ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi, 8174aa8818bSAdrian Chadd ts.ts_rssi); 8184aa8818bSAdrian Chadd } 8194aa8818bSAdrian Chadd 8204aa8818bSAdrian Chadd /* Handle frame completion and rate control update */ 8214aa8818bSAdrian Chadd ath_tx_process_buf_completion(sc, txq, &ts, bf); 8224aa8818bSAdrian Chadd 8234aa8818bSAdrian Chadd /* bf is invalid at this point */ 8244aa8818bSAdrian Chadd 8254aa8818bSAdrian Chadd /* 8264aa8818bSAdrian Chadd * Now that there's space in the FIFO, let's push some 8274aa8818bSAdrian Chadd * more frames into it. 8284aa8818bSAdrian Chadd */ 829b837332dSAdrian Chadd ATH_TXQ_LOCK(txq); 83092e84e43SAdrian Chadd if (dosched) 8314aa8818bSAdrian Chadd ath_edma_tx_fifo_fill(sc, txq); 832b837332dSAdrian Chadd ATH_TXQ_UNLOCK(txq); 8334aa8818bSAdrian Chadd } 8344aa8818bSAdrian Chadd 8354aa8818bSAdrian Chadd sc->sc_wd_timer = 0; 8364aa8818bSAdrian Chadd 837c19a2a1aSAdrian Chadd if (idx > 0) { 838c19a2a1aSAdrian Chadd IF_LOCK(&sc->sc_ifp->if_snd); 839c19a2a1aSAdrian Chadd sc->sc_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 840c19a2a1aSAdrian Chadd IF_UNLOCK(&sc->sc_ifp->if_snd); 841c19a2a1aSAdrian Chadd } 842c19a2a1aSAdrian Chadd 8434aa8818bSAdrian Chadd /* Kick software scheduler */ 8444aa8818bSAdrian Chadd /* 8454aa8818bSAdrian Chadd * XXX It's inefficient to do this if the FIFO queue is full, 8464aa8818bSAdrian Chadd * but there's no easy way right now to only populate 8474aa8818bSAdrian Chadd * the txq task for _one_ TXQ. This should be fixed. 8484aa8818bSAdrian Chadd */ 849ae3815fdSAdrian Chadd if (dosched) 85021bca442SAdrian Chadd ath_tx_swq_kick(sc); 851f8418db5SAdrian Chadd } 852f8418db5SAdrian Chadd 853f8418db5SAdrian Chadd static void 854f8418db5SAdrian Chadd ath_edma_attach_comp_func(struct ath_softc *sc) 855f8418db5SAdrian Chadd { 856f8418db5SAdrian Chadd 857f8418db5SAdrian Chadd TASK_INIT(&sc->sc_txtask, 0, ath_edma_tx_proc, sc); 858f8418db5SAdrian Chadd } 859f8418db5SAdrian Chadd 8603fdfc330SAdrian Chadd void 8613fdfc330SAdrian Chadd ath_xmit_setup_edma(struct ath_softc *sc) 8623fdfc330SAdrian Chadd { 8633fdfc330SAdrian Chadd 8643fdfc330SAdrian Chadd /* Fetch EDMA field and buffer sizes */ 8653fdfc330SAdrian Chadd (void) ath_hal_gettxdesclen(sc->sc_ah, &sc->sc_tx_desclen); 8663fdfc330SAdrian Chadd (void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen); 8673fdfc330SAdrian Chadd (void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps); 8683fdfc330SAdrian Chadd 869*516a0ac2SAdrian Chadd if (bootverbose) { 8703fdfc330SAdrian Chadd device_printf(sc->sc_dev, "TX descriptor length: %d\n", 8713fdfc330SAdrian Chadd sc->sc_tx_desclen); 8723fdfc330SAdrian Chadd device_printf(sc->sc_dev, "TX status length: %d\n", 8733fdfc330SAdrian Chadd sc->sc_tx_statuslen); 8743fdfc330SAdrian Chadd device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n", 8753fdfc330SAdrian Chadd sc->sc_tx_nmaps); 876*516a0ac2SAdrian Chadd } 8773fdfc330SAdrian Chadd 8783fdfc330SAdrian Chadd sc->sc_tx.xmit_setup = ath_edma_dma_txsetup; 8793fdfc330SAdrian Chadd sc->sc_tx.xmit_teardown = ath_edma_dma_txteardown; 880f8418db5SAdrian Chadd sc->sc_tx.xmit_attach_comp_func = ath_edma_attach_comp_func; 881746bab5bSAdrian Chadd 882746bab5bSAdrian Chadd sc->sc_tx.xmit_dma_restart = ath_edma_dma_restart; 883746bab5bSAdrian Chadd sc->sc_tx.xmit_handoff = ath_edma_xmit_handoff; 884788e6aa9SAdrian Chadd sc->sc_tx.xmit_drain = ath_edma_tx_drain; 8853fdfc330SAdrian Chadd } 886