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> 114b45de1ebSAdrian Chadd #include <dev/ath/if_ath_descdma.h> 1153fdfc330SAdrian Chadd 1163fdfc330SAdrian Chadd #ifdef ATH_TX99_DIAG 1173fdfc330SAdrian Chadd #include <dev/ath/ath_tx99/ath_tx99.h> 1183fdfc330SAdrian Chadd #endif 1193fdfc330SAdrian Chadd 1203fdfc330SAdrian Chadd #include <dev/ath/if_ath_tx_edma.h> 1213fdfc330SAdrian Chadd 122b69b0dccSAdrian Chadd #ifdef ATH_DEBUG_ALQ 123b69b0dccSAdrian Chadd #include <dev/ath/if_ath_alq.h> 124b69b0dccSAdrian Chadd #endif 125b69b0dccSAdrian Chadd 1263fdfc330SAdrian Chadd /* 1273fdfc330SAdrian Chadd * some general macros 1283fdfc330SAdrian Chadd */ 1293fdfc330SAdrian Chadd #define INCR(_l, _sz) (_l) ++; (_l) &= ((_sz) - 1) 1303fdfc330SAdrian Chadd #define DECR(_l, _sz) (_l) --; (_l) &= ((_sz) - 1) 1313fdfc330SAdrian Chadd 132ba3fd9d8SAdrian Chadd /* 133ba3fd9d8SAdrian Chadd * XXX doesn't belong here, and should be tunable 134ba3fd9d8SAdrian Chadd */ 135ba3fd9d8SAdrian Chadd #define ATH_TXSTATUS_RING_SIZE 512 136ba3fd9d8SAdrian Chadd 1373fdfc330SAdrian Chadd MALLOC_DECLARE(M_ATHDEV); 1383fdfc330SAdrian Chadd 139ae3815fdSAdrian Chadd static void ath_edma_tx_processq(struct ath_softc *sc, int dosched); 140ae3815fdSAdrian Chadd 141*49236b4eSAdrian Chadd #ifdef ATH_DEBUG_ALQ 142*49236b4eSAdrian Chadd static void 143*49236b4eSAdrian Chadd ath_tx_alq_edma_push(struct ath_softc *sc, int txq, int nframes, 144*49236b4eSAdrian Chadd int fifo_depth, int frame_cnt) 145*49236b4eSAdrian Chadd { 146*49236b4eSAdrian Chadd struct if_ath_alq_tx_fifo_push aq; 147*49236b4eSAdrian Chadd 148*49236b4eSAdrian Chadd aq.txq = htobe32(txq); 149*49236b4eSAdrian Chadd aq.nframes = htobe32(nframes); 150*49236b4eSAdrian Chadd aq.fifo_depth = htobe32(fifo_depth); 151*49236b4eSAdrian Chadd aq.frame_cnt = htobe32(frame_cnt); 152*49236b4eSAdrian Chadd 153*49236b4eSAdrian Chadd if_ath_alq_post(&sc->sc_alq, ATH_ALQ_TX_FIFO_PUSH, 154*49236b4eSAdrian Chadd sizeof(aq), 155*49236b4eSAdrian Chadd (const char *) &aq); 156*49236b4eSAdrian Chadd } 157*49236b4eSAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 158*49236b4eSAdrian Chadd 159*49236b4eSAdrian Chadd static void 160*49236b4eSAdrian Chadd ath_tx_edma_push_staging_list(struct ath_softc *sc, struct ath_txq *txq, 161*49236b4eSAdrian Chadd int limit) 162*49236b4eSAdrian Chadd { 163*49236b4eSAdrian Chadd struct ath_buf *bf, *bf_last; 164*49236b4eSAdrian Chadd struct ath_buf *bfi, *bfp; 165*49236b4eSAdrian Chadd int i, sqdepth; 166*49236b4eSAdrian Chadd TAILQ_HEAD(axq_q_f_s, ath_buf) sq; 167*49236b4eSAdrian Chadd 168*49236b4eSAdrian Chadd ATH_TXQ_LOCK_ASSERT(txq); 169*49236b4eSAdrian Chadd 170*49236b4eSAdrian Chadd /* 171*49236b4eSAdrian Chadd * Don't bother doing any work if it's full. 172*49236b4eSAdrian Chadd */ 173*49236b4eSAdrian Chadd if (txq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) 174*49236b4eSAdrian Chadd return; 175*49236b4eSAdrian Chadd 176*49236b4eSAdrian Chadd if (TAILQ_EMPTY(&txq->axq_q)) 177*49236b4eSAdrian Chadd return; 178*49236b4eSAdrian Chadd 179*49236b4eSAdrian Chadd TAILQ_INIT(&sq); 180*49236b4eSAdrian Chadd 181*49236b4eSAdrian Chadd /* 182*49236b4eSAdrian Chadd * First pass - walk sq, queue up to 'limit' entries, 183*49236b4eSAdrian Chadd * subtract them from the staging queue. 184*49236b4eSAdrian Chadd */ 185*49236b4eSAdrian Chadd sqdepth = 0; 186*49236b4eSAdrian Chadd for (i = 0; i < limit; i++) { 187*49236b4eSAdrian Chadd /* Grab the head entry */ 188*49236b4eSAdrian Chadd bf = ATH_TXQ_FIRST(txq); 189*49236b4eSAdrian Chadd if (bf == NULL) 190*49236b4eSAdrian Chadd break; 191*49236b4eSAdrian Chadd ATH_TXQ_REMOVE(txq, bf, bf_list); 192*49236b4eSAdrian Chadd 193*49236b4eSAdrian Chadd /* Queue it into our staging list */ 194*49236b4eSAdrian Chadd TAILQ_INSERT_TAIL(&sq, bf, bf_list); 195*49236b4eSAdrian Chadd sqdepth++; 196*49236b4eSAdrian Chadd } 197*49236b4eSAdrian Chadd 198*49236b4eSAdrian Chadd /* 199*49236b4eSAdrian Chadd * Ok, so now we have a staging list of up to 'limit' 200*49236b4eSAdrian Chadd * frames from the txq. Now let's wrap that up 201*49236b4eSAdrian Chadd * into its own list and pass that to the hardware 202*49236b4eSAdrian Chadd * as one FIFO entry. 203*49236b4eSAdrian Chadd */ 204*49236b4eSAdrian Chadd 205*49236b4eSAdrian Chadd bf = TAILQ_FIRST(&sq); 206*49236b4eSAdrian Chadd bf_last = TAILQ_LAST(&sq, axq_q_s); 207*49236b4eSAdrian Chadd 208*49236b4eSAdrian Chadd /* 209*49236b4eSAdrian Chadd * Ok, so here's the gymnastics reqiured to make this 210*49236b4eSAdrian Chadd * all sensible. 211*49236b4eSAdrian Chadd */ 212*49236b4eSAdrian Chadd 213*49236b4eSAdrian Chadd /* 214*49236b4eSAdrian Chadd * Tag the first/last buffer appropriately. 215*49236b4eSAdrian Chadd */ 216*49236b4eSAdrian Chadd bf->bf_flags |= ATH_BUF_FIFOPTR; 217*49236b4eSAdrian Chadd bf_last->bf_flags |= ATH_BUF_FIFOEND; 218*49236b4eSAdrian Chadd 219*49236b4eSAdrian Chadd /* 220*49236b4eSAdrian Chadd * Walk the descriptor list and link them appropriately. 221*49236b4eSAdrian Chadd */ 222*49236b4eSAdrian Chadd bfp = NULL; 223*49236b4eSAdrian Chadd TAILQ_FOREACH(bfi, &sq, bf_list) { 224*49236b4eSAdrian Chadd if (bfp != NULL) { 225*49236b4eSAdrian Chadd ath_hal_settxdesclink(sc->sc_ah, bfp->bf_lastds, 226*49236b4eSAdrian Chadd bfi->bf_daddr); 227*49236b4eSAdrian Chadd } 228*49236b4eSAdrian Chadd bfp = bfi; 229*49236b4eSAdrian Chadd } 230*49236b4eSAdrian Chadd 231*49236b4eSAdrian Chadd i = 0; 232*49236b4eSAdrian Chadd TAILQ_FOREACH(bfi, &sq, bf_list) { 233*49236b4eSAdrian Chadd #ifdef ATH_DEBUG 234*49236b4eSAdrian Chadd if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) 235*49236b4eSAdrian Chadd ath_printtxbuf(sc, bfi, txq->axq_qnum, i, 0); 236*49236b4eSAdrian Chadd #endif/* ATH_DEBUG */ 237*49236b4eSAdrian Chadd #ifdef ATH_DEBUG_ALQ 238*49236b4eSAdrian Chadd if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC)) 239*49236b4eSAdrian Chadd ath_tx_alq_post(sc, bfi); 240*49236b4eSAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 241*49236b4eSAdrian Chadd i++; 242*49236b4eSAdrian Chadd } 243*49236b4eSAdrian Chadd 244*49236b4eSAdrian Chadd /* 245*49236b4eSAdrian Chadd * We now need to push this set of frames onto the tail 246*49236b4eSAdrian Chadd * of the FIFO queue. We don't adjust the aggregate 247*49236b4eSAdrian Chadd * count, only the queue depth counter(s). 248*49236b4eSAdrian Chadd * We also need to blank the link pointer now. 249*49236b4eSAdrian Chadd */ 250*49236b4eSAdrian Chadd 251*49236b4eSAdrian Chadd TAILQ_CONCAT(&txq->fifo.axq_q, &sq, bf_list); 252*49236b4eSAdrian Chadd /* Bump total queue tracking in FIFO queue */ 253*49236b4eSAdrian Chadd txq->fifo.axq_depth += sqdepth; 254*49236b4eSAdrian Chadd 255*49236b4eSAdrian Chadd /* Bump FIFO queue */ 256*49236b4eSAdrian Chadd txq->axq_fifo_depth++; 257*49236b4eSAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT, 258*49236b4eSAdrian Chadd "%s: queued %d packets; depth=%d, fifo depth=%d\n", 259*49236b4eSAdrian Chadd __func__, sqdepth, txq->fifo.axq_depth, txq->axq_fifo_depth); 260*49236b4eSAdrian Chadd 261*49236b4eSAdrian Chadd /* Push the first entry into the hardware */ 262*49236b4eSAdrian Chadd ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr); 263*49236b4eSAdrian Chadd 264*49236b4eSAdrian Chadd /* Push start on the DMA if it's not already started */ 265*49236b4eSAdrian Chadd ath_hal_txstart(sc->sc_ah, txq->axq_qnum); 266*49236b4eSAdrian Chadd 267*49236b4eSAdrian Chadd #ifdef ATH_DEBUG_ALQ 268*49236b4eSAdrian Chadd ath_tx_alq_edma_push(sc, txq->axq_qnum, sqdepth, 269*49236b4eSAdrian Chadd txq->axq_fifo_depth, 270*49236b4eSAdrian Chadd txq->fifo.axq_depth); 271*49236b4eSAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 272*49236b4eSAdrian Chadd } 273*49236b4eSAdrian Chadd 27492e84e43SAdrian Chadd /* 27592e84e43SAdrian Chadd * Push some frames into the TX FIFO if we have space. 27692e84e43SAdrian Chadd */ 2774aa8818bSAdrian Chadd static void 2784aa8818bSAdrian Chadd ath_edma_tx_fifo_fill(struct ath_softc *sc, struct ath_txq *txq) 2794aa8818bSAdrian Chadd { 2804aa8818bSAdrian Chadd 281b837332dSAdrian Chadd ATH_TXQ_LOCK_ASSERT(txq); 2824aa8818bSAdrian Chadd 28392e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d: called\n", 28492e84e43SAdrian Chadd __func__, 28592e84e43SAdrian Chadd txq->axq_qnum); 2864aa8818bSAdrian Chadd 28792e84e43SAdrian Chadd /* 288*49236b4eSAdrian Chadd * For now, push up to 4 frames per TX FIFO slot. 289*49236b4eSAdrian Chadd * If more are in the hardware queue then they'll 290*49236b4eSAdrian Chadd * get populated when we try to send another frame 291*49236b4eSAdrian Chadd * or complete a frame - so at most there'll be 292*49236b4eSAdrian Chadd * 32 non-AMPDU frames per TXQ. 29392e84e43SAdrian Chadd * 294*49236b4eSAdrian Chadd * Note that the hardware staging queue will limit 295*49236b4eSAdrian Chadd * how many frames in total we will have pushed into 296*49236b4eSAdrian Chadd * here. 297*49236b4eSAdrian Chadd * 298*49236b4eSAdrian Chadd * Later on, we'll want to push less frames into 299*49236b4eSAdrian Chadd * the TX FIFO since we don't want to necessarily 300*49236b4eSAdrian Chadd * fill tens or hundreds of milliseconds of potential 301*49236b4eSAdrian Chadd * frames. 302*49236b4eSAdrian Chadd * 303*49236b4eSAdrian Chadd * However, we need more frames right now because of 304*49236b4eSAdrian Chadd * how the MAC implements the frame scheduling policy. 305*49236b4eSAdrian Chadd * It only ungates a single FIFO entry at a time, 306*49236b4eSAdrian Chadd * and will run that until CHNTIME expires or the 307*49236b4eSAdrian Chadd * end of that FIFO entry descriptor list is reached. 308*49236b4eSAdrian Chadd * So for TDMA we suffer a big performance penalty - 309*49236b4eSAdrian Chadd * single TX FIFO entries mean the MAC only sends out 310*49236b4eSAdrian Chadd * one frame per DBA event, which turned out on average 311*49236b4eSAdrian Chadd * 6ms per TX frame. 312*49236b4eSAdrian Chadd * 313*49236b4eSAdrian Chadd * So, for aggregates it's okay - it'll push two at a 314*49236b4eSAdrian Chadd * time and this will just do them more efficiently. 315*49236b4eSAdrian Chadd * For non-aggregates it'll do 4 at a time, up to the 316*49236b4eSAdrian Chadd * non-aggr limit (non_aggr, which is 32.) They should 317*49236b4eSAdrian Chadd * be time based rather than a hard count, but I also 318*49236b4eSAdrian Chadd * do need sleep. 31992e84e43SAdrian Chadd */ 320*49236b4eSAdrian Chadd ath_tx_edma_push_staging_list(sc, txq, 4); 3214aa8818bSAdrian Chadd } 3224aa8818bSAdrian Chadd 323746bab5bSAdrian Chadd /* 324746bab5bSAdrian Chadd * Re-initialise the DMA FIFO with the current contents of 3253ae723d4SAdrian Chadd * said TXQ. 326746bab5bSAdrian Chadd * 327746bab5bSAdrian Chadd * This should only be called as part of the chip reset path, as it 328746bab5bSAdrian Chadd * assumes the FIFO is currently empty. 329746bab5bSAdrian Chadd */ 330746bab5bSAdrian Chadd static void 331746bab5bSAdrian Chadd ath_edma_dma_restart(struct ath_softc *sc, struct ath_txq *txq) 332746bab5bSAdrian Chadd { 33392e84e43SAdrian Chadd struct ath_buf *bf; 33492e84e43SAdrian Chadd int i = 0; 33592e84e43SAdrian Chadd int fifostart = 1; 33692e84e43SAdrian Chadd int old_fifo_depth; 337746bab5bSAdrian Chadd 33892e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_RESET, "%s: Q%d: called\n", 339746bab5bSAdrian Chadd __func__, 340746bab5bSAdrian Chadd txq->axq_qnum); 3414aa8818bSAdrian Chadd 342b837332dSAdrian Chadd ATH_TXQ_LOCK_ASSERT(txq); 34392e84e43SAdrian Chadd 34492e84e43SAdrian Chadd /* 34592e84e43SAdrian Chadd * Let's log if the tracked FIFO depth doesn't match 34692e84e43SAdrian Chadd * what we actually push in. 34792e84e43SAdrian Chadd */ 34892e84e43SAdrian Chadd old_fifo_depth = txq->axq_fifo_depth; 34992e84e43SAdrian Chadd txq->axq_fifo_depth = 0; 35092e84e43SAdrian Chadd 35192e84e43SAdrian Chadd /* 35292e84e43SAdrian Chadd * Walk the FIFO staging list, looking for "head" entries. 35392e84e43SAdrian Chadd * Since we may have a partially completed list of frames, 35492e84e43SAdrian Chadd * we push the first frame we see into the FIFO and re-mark 35592e84e43SAdrian Chadd * it as the head entry. We then skip entries until we see 35692e84e43SAdrian Chadd * FIFO end, at which point we get ready to push another 35792e84e43SAdrian Chadd * entry into the FIFO. 35892e84e43SAdrian Chadd */ 35992e84e43SAdrian Chadd TAILQ_FOREACH(bf, &txq->fifo.axq_q, bf_list) { 36092e84e43SAdrian Chadd /* 36192e84e43SAdrian Chadd * If we're looking for FIFOEND and we haven't found 36292e84e43SAdrian Chadd * it, skip. 36392e84e43SAdrian Chadd * 36492e84e43SAdrian Chadd * If we're looking for FIFOEND and we've found it, 36592e84e43SAdrian Chadd * reset for another descriptor. 36692e84e43SAdrian Chadd */ 36792e84e43SAdrian Chadd #ifdef ATH_DEBUG 36892e84e43SAdrian Chadd if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) 36992e84e43SAdrian Chadd ath_printtxbuf(sc, bf, txq->axq_qnum, i, 0); 37092e84e43SAdrian Chadd #endif/* ATH_DEBUG */ 37192e84e43SAdrian Chadd #ifdef ATH_DEBUG_ALQ 37292e84e43SAdrian Chadd if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC)) 37392e84e43SAdrian Chadd ath_tx_alq_post(sc, bf); 37492e84e43SAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 37592e84e43SAdrian Chadd 37692e84e43SAdrian Chadd if (fifostart == 0) { 37792e84e43SAdrian Chadd if (bf->bf_flags & ATH_BUF_FIFOEND) 37892e84e43SAdrian Chadd fifostart = 1; 37992e84e43SAdrian Chadd continue; 38092e84e43SAdrian Chadd } 38192e84e43SAdrian Chadd 38292e84e43SAdrian Chadd /* Make sure we're not overflowing the FIFO! */ 38392e84e43SAdrian Chadd if (txq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) { 38492e84e43SAdrian Chadd device_printf(sc->sc_dev, 38592e84e43SAdrian Chadd "%s: Q%d: more frames in the queue; FIFO depth=%d?!\n", 38692e84e43SAdrian Chadd __func__, 38792e84e43SAdrian Chadd txq->axq_qnum, 38892e84e43SAdrian Chadd txq->axq_fifo_depth); 38992e84e43SAdrian Chadd } 39092e84e43SAdrian Chadd 39192e84e43SAdrian Chadd #if 0 39292e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_RESET, 39392e84e43SAdrian Chadd "%s: Q%d: depth=%d: pushing bf=%p; start=%d, end=%d\n", 39492e84e43SAdrian Chadd __func__, 39592e84e43SAdrian Chadd txq->axq_qnum, 39692e84e43SAdrian Chadd txq->axq_fifo_depth, 39792e84e43SAdrian Chadd bf, 39892e84e43SAdrian Chadd !! (bf->bf_flags & ATH_BUF_FIFOPTR), 39992e84e43SAdrian Chadd !! (bf->bf_flags & ATH_BUF_FIFOEND)); 40092e84e43SAdrian Chadd #endif 40192e84e43SAdrian Chadd 40292e84e43SAdrian Chadd /* 40392e84e43SAdrian Chadd * Set this to be the first buffer in the FIFO 40492e84e43SAdrian Chadd * list - even if it's also the last buffer in 40592e84e43SAdrian Chadd * a FIFO list! 40692e84e43SAdrian Chadd */ 40792e84e43SAdrian Chadd bf->bf_flags |= ATH_BUF_FIFOPTR; 40892e84e43SAdrian Chadd 40992e84e43SAdrian Chadd /* Push it into the FIFO and bump the FIFO count */ 41092e84e43SAdrian Chadd ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr); 41192e84e43SAdrian Chadd txq->axq_fifo_depth++; 41292e84e43SAdrian Chadd 41392e84e43SAdrian Chadd /* 41492e84e43SAdrian Chadd * If this isn't the last entry either, let's 41592e84e43SAdrian Chadd * clear fifostart so we continue looking for 41692e84e43SAdrian Chadd * said last entry. 41792e84e43SAdrian Chadd */ 41892e84e43SAdrian Chadd if (! (bf->bf_flags & ATH_BUF_FIFOEND)) 41992e84e43SAdrian Chadd fifostart = 0; 42092e84e43SAdrian Chadd i++; 42192e84e43SAdrian Chadd } 42292e84e43SAdrian Chadd 42392e84e43SAdrian Chadd /* Only bother starting the queue if there's something in it */ 42492e84e43SAdrian Chadd if (i > 0) 42592e84e43SAdrian Chadd ath_hal_txstart(sc->sc_ah, txq->axq_qnum); 42692e84e43SAdrian Chadd 42792e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_RESET, "%s: Q%d: FIFO depth was %d, is %d\n", 42892e84e43SAdrian Chadd __func__, 42992e84e43SAdrian Chadd txq->axq_qnum, 43092e84e43SAdrian Chadd old_fifo_depth, 43192e84e43SAdrian Chadd txq->axq_fifo_depth); 43292e84e43SAdrian Chadd 43392e84e43SAdrian Chadd /* And now, let's check! */ 43492e84e43SAdrian Chadd if (txq->axq_fifo_depth != old_fifo_depth) { 43592e84e43SAdrian Chadd device_printf(sc->sc_dev, 43692e84e43SAdrian Chadd "%s: Q%d: FIFO depth should be %d, is %d\n", 43792e84e43SAdrian Chadd __func__, 43892e84e43SAdrian Chadd txq->axq_qnum, 43992e84e43SAdrian Chadd old_fifo_depth, 44092e84e43SAdrian Chadd txq->axq_fifo_depth); 44192e84e43SAdrian Chadd } 442746bab5bSAdrian Chadd } 443746bab5bSAdrian Chadd 444746bab5bSAdrian Chadd /* 4453ae723d4SAdrian Chadd * Hand off this frame to a hardware queue. 4463ae723d4SAdrian Chadd * 4473ae723d4SAdrian Chadd * Things are a bit hairy in the EDMA world. The TX FIFO is only 4483ae723d4SAdrian Chadd * 8 entries deep, so we need to keep track of exactly what we've 4493ae723d4SAdrian Chadd * pushed into the FIFO and what's just sitting in the TX queue, 4503ae723d4SAdrian Chadd * waiting to go out. 4513ae723d4SAdrian Chadd * 4523ae723d4SAdrian Chadd * So this is split into two halves - frames get appended to the 4533ae723d4SAdrian Chadd * TXQ; then a scheduler is called to push some frames into the 4543ae723d4SAdrian Chadd * actual TX FIFO. 4553ae723d4SAdrian Chadd */ 4563ae723d4SAdrian Chadd static void 4573ae723d4SAdrian Chadd ath_edma_xmit_handoff_hw(struct ath_softc *sc, struct ath_txq *txq, 4583ae723d4SAdrian Chadd struct ath_buf *bf) 4593ae723d4SAdrian Chadd { 4603ae723d4SAdrian Chadd 4610acf45edSAdrian Chadd ATH_TXQ_LOCK(txq); 4623ae723d4SAdrian Chadd 4633ae723d4SAdrian Chadd KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0, 4643ae723d4SAdrian Chadd ("%s: busy status 0x%x", __func__, bf->bf_flags)); 4653ae723d4SAdrian Chadd 4663ae723d4SAdrian Chadd /* 4673ae723d4SAdrian Chadd * XXX TODO: write a hard-coded check to ensure that 4683ae723d4SAdrian Chadd * the queue id in the TX descriptor matches txq->axq_qnum. 4693ae723d4SAdrian Chadd */ 4703ae723d4SAdrian Chadd 4713ae723d4SAdrian Chadd /* Update aggr stats */ 4723ae723d4SAdrian Chadd if (bf->bf_state.bfs_aggr) 4733ae723d4SAdrian Chadd txq->axq_aggr_depth++; 4743ae723d4SAdrian Chadd 4753ae723d4SAdrian Chadd /* Push and update frame stats */ 4763ae723d4SAdrian Chadd ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 4773ae723d4SAdrian Chadd 47892e84e43SAdrian Chadd /* For now, set the link pointer in the last descriptor 47992e84e43SAdrian Chadd * to be NULL. 48092e84e43SAdrian Chadd * 48192e84e43SAdrian Chadd * Later on, when it comes time to handling multiple descriptors 48292e84e43SAdrian Chadd * in one FIFO push, we can link descriptors together this way. 48392e84e43SAdrian Chadd */ 48492e84e43SAdrian Chadd 48592e84e43SAdrian Chadd /* 48692e84e43SAdrian Chadd * Finally, call the FIFO schedule routine to schedule some 48792e84e43SAdrian Chadd * frames to the FIFO. 48892e84e43SAdrian Chadd */ 48992e84e43SAdrian Chadd ath_edma_tx_fifo_fill(sc, txq); 4900acf45edSAdrian Chadd ATH_TXQ_UNLOCK(txq); 4913ae723d4SAdrian Chadd } 4923ae723d4SAdrian Chadd 4933ae723d4SAdrian Chadd /* 4943ae723d4SAdrian Chadd * Hand off this frame to a multicast software queue. 4953ae723d4SAdrian Chadd * 496e3f06688SAdrian Chadd * The EDMA TX CABQ will get a list of chained frames, chained 497e3f06688SAdrian Chadd * together using the next pointer. The single head of that 498e3f06688SAdrian Chadd * particular queue is pushed to the hardware CABQ. 4993ae723d4SAdrian Chadd */ 5003ae723d4SAdrian Chadd static void 5013ae723d4SAdrian Chadd ath_edma_xmit_handoff_mcast(struct ath_softc *sc, struct ath_txq *txq, 5023ae723d4SAdrian Chadd struct ath_buf *bf) 5033ae723d4SAdrian Chadd { 5043ae723d4SAdrian Chadd 5059e7259a2SAdrian Chadd ATH_TX_LOCK_ASSERT(sc); 5063ae723d4SAdrian Chadd KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0, 5073ae723d4SAdrian Chadd ("%s: busy status 0x%x", __func__, bf->bf_flags)); 5083ae723d4SAdrian Chadd 5090acf45edSAdrian Chadd ATH_TXQ_LOCK(txq); 5103ae723d4SAdrian Chadd /* 5113ae723d4SAdrian Chadd * XXX this is mostly duplicated in ath_tx_handoff_mcast(). 5123ae723d4SAdrian Chadd */ 5139e7259a2SAdrian Chadd if (ATH_TXQ_LAST(txq, axq_q_s) != NULL) { 5143ae723d4SAdrian Chadd struct ath_buf *bf_last = ATH_TXQ_LAST(txq, axq_q_s); 5153ae723d4SAdrian Chadd struct ieee80211_frame *wh; 5163ae723d4SAdrian Chadd 5173ae723d4SAdrian Chadd /* mark previous frame */ 5183ae723d4SAdrian Chadd wh = mtod(bf_last->bf_m, struct ieee80211_frame *); 5193ae723d4SAdrian Chadd wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 5203ae723d4SAdrian Chadd 521caedab2cSAdrian Chadd /* re-sync buffer to memory */ 5223ae723d4SAdrian Chadd bus_dmamap_sync(sc->sc_dmat, bf_last->bf_dmamap, 5233ae723d4SAdrian Chadd BUS_DMASYNC_PREWRITE); 5249cda8c80SAdrian Chadd 5259cda8c80SAdrian Chadd /* link descriptor */ 5269e7259a2SAdrian Chadd ath_hal_settxdesclink(sc->sc_ah, 5279e7259a2SAdrian Chadd bf_last->bf_lastds, 5289e7259a2SAdrian Chadd bf->bf_daddr); 5293ae723d4SAdrian Chadd } 530e3f06688SAdrian Chadd #ifdef ATH_DEBUG_ALQ 531e3f06688SAdrian Chadd if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC)) 532e3f06688SAdrian Chadd ath_tx_alq_post(sc, bf); 533e3f06688SAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 5343ae723d4SAdrian Chadd ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 5350acf45edSAdrian Chadd ATH_TXQ_UNLOCK(txq); 5363ae723d4SAdrian Chadd } 5373ae723d4SAdrian Chadd 5383ae723d4SAdrian Chadd /* 539746bab5bSAdrian Chadd * Handoff this frame to the hardware. 540746bab5bSAdrian Chadd * 541746bab5bSAdrian Chadd * For the multicast queue, this will treat it as a software queue 542746bab5bSAdrian Chadd * and append it to the list, after updating the MORE_DATA flag 543746bab5bSAdrian Chadd * in the previous frame. The cabq processing code will ensure 544746bab5bSAdrian Chadd * that the queue contents gets transferred over. 545746bab5bSAdrian Chadd * 546746bab5bSAdrian Chadd * For the hardware queues, this will queue a frame to the queue 547746bab5bSAdrian Chadd * like before, then populate the FIFO from that. Since the 548746bab5bSAdrian Chadd * EDMA hardware has 8 FIFO slots per TXQ, this ensures that 549746bab5bSAdrian Chadd * frames such as management frames don't get prematurely dropped. 550746bab5bSAdrian Chadd * 551746bab5bSAdrian Chadd * This does imply that a similar flush-hwq-to-fifoq method will 552746bab5bSAdrian Chadd * need to be called from the processq function, before the 553746bab5bSAdrian Chadd * per-node software scheduler is called. 554746bab5bSAdrian Chadd */ 555746bab5bSAdrian Chadd static void 556746bab5bSAdrian Chadd ath_edma_xmit_handoff(struct ath_softc *sc, struct ath_txq *txq, 557746bab5bSAdrian Chadd struct ath_buf *bf) 558746bab5bSAdrian Chadd { 559746bab5bSAdrian Chadd 5604aa8818bSAdrian Chadd DPRINTF(sc, ATH_DEBUG_XMIT_DESC, 5614aa8818bSAdrian Chadd "%s: called; bf=%p, txq=%p, qnum=%d\n", 562746bab5bSAdrian Chadd __func__, 563746bab5bSAdrian Chadd bf, 564746bab5bSAdrian Chadd txq, 565746bab5bSAdrian Chadd txq->axq_qnum); 566746bab5bSAdrian Chadd 5673ae723d4SAdrian Chadd if (txq->axq_qnum == ATH_TXQ_SWQ) 5683ae723d4SAdrian Chadd ath_edma_xmit_handoff_mcast(sc, txq, bf); 5693ae723d4SAdrian Chadd else 5703ae723d4SAdrian Chadd ath_edma_xmit_handoff_hw(sc, txq, bf); 571746bab5bSAdrian Chadd } 572746bab5bSAdrian Chadd 5733fdfc330SAdrian Chadd static int 57479607afeSAdrian Chadd ath_edma_setup_txfifo(struct ath_softc *sc, int qnum) 57579607afeSAdrian Chadd { 57679607afeSAdrian Chadd struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum]; 57779607afeSAdrian Chadd 57879607afeSAdrian Chadd te->m_fifo = malloc(sizeof(struct ath_buf *) * HAL_TXFIFO_DEPTH, 57979607afeSAdrian Chadd M_ATHDEV, 58079607afeSAdrian Chadd M_NOWAIT | M_ZERO); 58179607afeSAdrian Chadd if (te->m_fifo == NULL) { 58279607afeSAdrian Chadd device_printf(sc->sc_dev, "%s: malloc failed\n", 58379607afeSAdrian Chadd __func__); 58479607afeSAdrian Chadd return (-ENOMEM); 58579607afeSAdrian Chadd } 58679607afeSAdrian Chadd 58779607afeSAdrian Chadd /* 58879607afeSAdrian Chadd * Set initial "empty" state. 58979607afeSAdrian Chadd */ 59079607afeSAdrian Chadd te->m_fifo_head = te->m_fifo_tail = te->m_fifo_depth = 0; 59179607afeSAdrian Chadd 59279607afeSAdrian Chadd return (0); 59379607afeSAdrian Chadd } 59479607afeSAdrian Chadd 59579607afeSAdrian Chadd static int 59679607afeSAdrian Chadd ath_edma_free_txfifo(struct ath_softc *sc, int qnum) 59779607afeSAdrian Chadd { 59879607afeSAdrian Chadd struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum]; 59979607afeSAdrian Chadd 60079607afeSAdrian Chadd /* XXX TODO: actually deref the ath_buf entries? */ 60179607afeSAdrian Chadd free(te->m_fifo, M_ATHDEV); 60279607afeSAdrian Chadd return (0); 60379607afeSAdrian Chadd } 60479607afeSAdrian Chadd 60579607afeSAdrian Chadd static int 6063fdfc330SAdrian Chadd ath_edma_dma_txsetup(struct ath_softc *sc) 6073fdfc330SAdrian Chadd { 608ba3fd9d8SAdrian Chadd int error; 60979607afeSAdrian Chadd int i; 6103fdfc330SAdrian Chadd 611ba3fd9d8SAdrian Chadd error = ath_descdma_alloc_desc(sc, &sc->sc_txsdma, 612ba3fd9d8SAdrian Chadd NULL, "txcomp", sc->sc_tx_statuslen, ATH_TXSTATUS_RING_SIZE); 613ba3fd9d8SAdrian Chadd if (error != 0) 614ba3fd9d8SAdrian Chadd return (error); 615ba3fd9d8SAdrian Chadd 616ba3fd9d8SAdrian Chadd ath_hal_setuptxstatusring(sc->sc_ah, 617ba3fd9d8SAdrian Chadd (void *) sc->sc_txsdma.dd_desc, 618ba3fd9d8SAdrian Chadd sc->sc_txsdma.dd_desc_paddr, 619ba3fd9d8SAdrian Chadd ATH_TXSTATUS_RING_SIZE); 620ba3fd9d8SAdrian Chadd 62179607afeSAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 62279607afeSAdrian Chadd ath_edma_setup_txfifo(sc, i); 62379607afeSAdrian Chadd } 62479607afeSAdrian Chadd 6253fdfc330SAdrian Chadd return (0); 6263fdfc330SAdrian Chadd } 6273fdfc330SAdrian Chadd 6283fdfc330SAdrian Chadd static int 6293fdfc330SAdrian Chadd ath_edma_dma_txteardown(struct ath_softc *sc) 6303fdfc330SAdrian Chadd { 63179607afeSAdrian Chadd int i; 63279607afeSAdrian Chadd 63379607afeSAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 63479607afeSAdrian Chadd ath_edma_free_txfifo(sc, i); 63579607afeSAdrian Chadd } 6363fdfc330SAdrian Chadd 637ba3fd9d8SAdrian Chadd ath_descdma_cleanup(sc, &sc->sc_txsdma, NULL); 6383fdfc330SAdrian Chadd return (0); 6393fdfc330SAdrian Chadd } 6403fdfc330SAdrian Chadd 6413ae723d4SAdrian Chadd /* 642788e6aa9SAdrian Chadd * Drain all TXQs, potentially after completing the existing completed 643788e6aa9SAdrian Chadd * frames. 6443ae723d4SAdrian Chadd */ 645788e6aa9SAdrian Chadd static void 646788e6aa9SAdrian Chadd ath_edma_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type) 647f8418db5SAdrian Chadd { 6484aa8818bSAdrian Chadd int i; 649f8418db5SAdrian Chadd 650ae3815fdSAdrian Chadd DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__); 6514aa8818bSAdrian Chadd 6524aa8818bSAdrian Chadd (void) ath_stoptxdma(sc); 6534aa8818bSAdrian Chadd 6544aa8818bSAdrian Chadd /* 6554aa8818bSAdrian Chadd * If reset type is noloss, the TX FIFO needs to be serviced 6564aa8818bSAdrian Chadd * and those frames need to be handled. 6574aa8818bSAdrian Chadd * 6584aa8818bSAdrian Chadd * Otherwise, just toss everything in each TX queue. 6594aa8818bSAdrian Chadd */ 660ae3815fdSAdrian Chadd if (reset_type == ATH_RESET_NOLOSS) { 661ae3815fdSAdrian Chadd ath_edma_tx_processq(sc, 0); 6628328d6e4SAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 6638328d6e4SAdrian Chadd if (ATH_TXQ_SETUP(sc, i)) { 6648328d6e4SAdrian Chadd ATH_TXQ_LOCK(&sc->sc_txq[i]); 6658328d6e4SAdrian Chadd /* 6668328d6e4SAdrian Chadd * Free the holding buffer; DMA is now 6678328d6e4SAdrian Chadd * stopped. 6688328d6e4SAdrian Chadd */ 6698328d6e4SAdrian Chadd ath_txq_freeholdingbuf(sc, &sc->sc_txq[i]); 6708328d6e4SAdrian Chadd /* 6718328d6e4SAdrian Chadd * Reset the link pointer to NULL; there's 6728328d6e4SAdrian Chadd * no frames to chain DMA to. 6738328d6e4SAdrian Chadd */ 6748328d6e4SAdrian Chadd sc->sc_txq[i].axq_link = NULL; 6758328d6e4SAdrian Chadd ATH_TXQ_UNLOCK(&sc->sc_txq[i]); 6768328d6e4SAdrian Chadd } 6778328d6e4SAdrian Chadd } 678ae3815fdSAdrian Chadd } else { 6794aa8818bSAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 6804aa8818bSAdrian Chadd if (ATH_TXQ_SETUP(sc, i)) 6814aa8818bSAdrian Chadd ath_tx_draintxq(sc, &sc->sc_txq[i]); 6824aa8818bSAdrian Chadd } 683ae3815fdSAdrian Chadd } 684ae3815fdSAdrian Chadd 685ae3815fdSAdrian Chadd /* XXX dump out the TX completion FIFO contents */ 686ae3815fdSAdrian Chadd 687ae3815fdSAdrian Chadd /* XXX dump out the frames */ 6884aa8818bSAdrian Chadd 6894aa8818bSAdrian Chadd sc->sc_wd_timer = 0; 690f8418db5SAdrian Chadd } 691f8418db5SAdrian Chadd 6923ae723d4SAdrian Chadd /* 693ae3815fdSAdrian Chadd * TX completion tasklet. 6943ae723d4SAdrian Chadd */ 695ae3815fdSAdrian Chadd 696f8418db5SAdrian Chadd static void 697f8418db5SAdrian Chadd ath_edma_tx_proc(void *arg, int npending) 698f8418db5SAdrian Chadd { 699f8418db5SAdrian Chadd struct ath_softc *sc = (struct ath_softc *) arg; 700ae3815fdSAdrian Chadd 70192e84e43SAdrian Chadd #if 0 702ae3815fdSAdrian Chadd DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: called, npending=%d\n", 703ae3815fdSAdrian Chadd __func__, npending); 70492e84e43SAdrian Chadd #endif 705ae3815fdSAdrian Chadd ath_edma_tx_processq(sc, 1); 706ae3815fdSAdrian Chadd } 707ae3815fdSAdrian Chadd 708ae3815fdSAdrian Chadd /* 709ae3815fdSAdrian Chadd * Process the TX status queue. 710ae3815fdSAdrian Chadd */ 711ae3815fdSAdrian Chadd static void 712ae3815fdSAdrian Chadd ath_edma_tx_processq(struct ath_softc *sc, int dosched) 713ae3815fdSAdrian Chadd { 7143ae723d4SAdrian Chadd struct ath_hal *ah = sc->sc_ah; 7153ae723d4SAdrian Chadd HAL_STATUS status; 7163ae723d4SAdrian Chadd struct ath_tx_status ts; 7173ae723d4SAdrian Chadd struct ath_txq *txq; 7184aa8818bSAdrian Chadd struct ath_buf *bf; 7194aa8818bSAdrian Chadd struct ieee80211_node *ni; 720208be709SAdrian Chadd int nacked = 0; 721d40c846aSAdrian Chadd int idx; 722d40c846aSAdrian Chadd 723d40c846aSAdrian Chadd #ifdef ATH_DEBUG 724d40c846aSAdrian Chadd /* XXX */ 725d40c846aSAdrian Chadd uint32_t txstatus[32]; 726d40c846aSAdrian Chadd #endif 727f8418db5SAdrian Chadd 728d40c846aSAdrian Chadd for (idx = 0; ; idx++) { 7294aa8818bSAdrian Chadd bzero(&ts, sizeof(ts)); 7304aa8818bSAdrian Chadd 7313ae723d4SAdrian Chadd ATH_TXSTATUS_LOCK(sc); 7324c5038c7SAdrian Chadd #ifdef ATH_DEBUG 733d40c846aSAdrian Chadd ath_hal_gettxrawtxdesc(ah, txstatus); 7344c5038c7SAdrian Chadd #endif 735ae3815fdSAdrian Chadd status = ath_hal_txprocdesc(ah, NULL, (void *) &ts); 7363ae723d4SAdrian Chadd ATH_TXSTATUS_UNLOCK(sc); 7373ae723d4SAdrian Chadd 73892e84e43SAdrian Chadd if (status == HAL_EINPROGRESS) 73992e84e43SAdrian Chadd break; 74092e84e43SAdrian Chadd 741d40c846aSAdrian Chadd #ifdef ATH_DEBUG 742d40c846aSAdrian Chadd if (sc->sc_debug & ATH_DEBUG_TX_PROC) 74392e84e43SAdrian Chadd if (ts.ts_queue_id != sc->sc_bhalq) 744d40c846aSAdrian Chadd ath_printtxstatbuf(sc, NULL, txstatus, ts.ts_queue_id, 745d40c846aSAdrian Chadd idx, (status == HAL_OK)); 746d40c846aSAdrian Chadd #endif 747d40c846aSAdrian Chadd 7483ae723d4SAdrian Chadd /* 7494aa8818bSAdrian Chadd * If there is an error with this descriptor, continue 7504aa8818bSAdrian Chadd * processing. 7514aa8818bSAdrian Chadd * 7524aa8818bSAdrian Chadd * XXX TBD: log some statistics? 7534aa8818bSAdrian Chadd */ 7544aa8818bSAdrian Chadd if (status == HAL_EIO) { 7554aa8818bSAdrian Chadd device_printf(sc->sc_dev, "%s: invalid TX status?\n", 7564aa8818bSAdrian Chadd __func__); 757b92b5f6eSAdrian Chadd break; 7584aa8818bSAdrian Chadd } 7594aa8818bSAdrian Chadd 76069cbcb21SAdrian Chadd #if defined(ATH_DEBUG_ALQ) && defined(ATH_DEBUG) 761b69b0dccSAdrian Chadd if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXSTATUS)) 762b69b0dccSAdrian Chadd if_ath_alq_post(&sc->sc_alq, ATH_ALQ_EDMA_TXSTATUS, 763b69b0dccSAdrian Chadd sc->sc_tx_statuslen, 764b69b0dccSAdrian Chadd (char *) txstatus); 765b69b0dccSAdrian Chadd #endif /* ATH_DEBUG_ALQ */ 766b69b0dccSAdrian Chadd 7674aa8818bSAdrian Chadd /* 7683ae723d4SAdrian Chadd * At this point we have a valid status descriptor. 7693ae723d4SAdrian Chadd * The QID and descriptor ID (which currently isn't set) 7703ae723d4SAdrian Chadd * is part of the status. 7713ae723d4SAdrian Chadd * 7723ae723d4SAdrian Chadd * We then assume that the descriptor in question is the 7733ae723d4SAdrian Chadd * -head- of the given QID. Eventually we should verify 7743ae723d4SAdrian Chadd * this by using the descriptor ID. 7753ae723d4SAdrian Chadd */ 7764aa8818bSAdrian Chadd 7774aa8818bSAdrian Chadd /* 7784aa8818bSAdrian Chadd * The beacon queue is not currently a "real" queue. 7794aa8818bSAdrian Chadd * Frames aren't pushed onto it and the lock isn't setup. 7804aa8818bSAdrian Chadd * So skip it for now; the beacon handling code will 7814aa8818bSAdrian Chadd * free and alloc more beacon buffers as appropriate. 7824aa8818bSAdrian Chadd */ 7834aa8818bSAdrian Chadd if (ts.ts_queue_id == sc->sc_bhalq) 7844aa8818bSAdrian Chadd continue; 7853ae723d4SAdrian Chadd 7863ae723d4SAdrian Chadd txq = &sc->sc_txq[ts.ts_queue_id]; 7874aa8818bSAdrian Chadd 788b837332dSAdrian Chadd ATH_TXQ_LOCK(txq); 78992e84e43SAdrian Chadd bf = ATH_TXQ_FIRST(&txq->fifo); 7904aa8818bSAdrian Chadd 79192e84e43SAdrian Chadd /* 79292e84e43SAdrian Chadd * Work around the situation where I'm seeing notifications 79392e84e43SAdrian Chadd * for Q1 when no frames are available. That needs to be 79492e84e43SAdrian Chadd * debugged but not by crashing _here_. 79592e84e43SAdrian Chadd */ 79692e84e43SAdrian Chadd if (bf == NULL) { 79792e84e43SAdrian Chadd device_printf(sc->sc_dev, "%s: Q%d: empty?\n", 7984aa8818bSAdrian Chadd __func__, 79992e84e43SAdrian Chadd ts.ts_queue_id); 800b92b5f6eSAdrian Chadd ATH_TXQ_UNLOCK(txq); 80192e84e43SAdrian Chadd continue; 80292e84e43SAdrian Chadd } 80392e84e43SAdrian Chadd 80492e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d, bf=%p, start=%d, end=%d\n", 80592e84e43SAdrian Chadd __func__, 80692e84e43SAdrian Chadd ts.ts_queue_id, bf, 80792e84e43SAdrian Chadd !! (bf->bf_flags & ATH_BUF_FIFOPTR), 80892e84e43SAdrian Chadd !! (bf->bf_flags & ATH_BUF_FIFOEND)); 8094aa8818bSAdrian Chadd 810d40c846aSAdrian Chadd /* XXX TODO: actually output debugging info about this */ 811d40c846aSAdrian Chadd 8124aa8818bSAdrian Chadd #if 0 8134aa8818bSAdrian Chadd /* XXX assert the buffer/descriptor matches the status descid */ 8144aa8818bSAdrian Chadd if (ts.ts_desc_id != bf->bf_descid) { 8154aa8818bSAdrian Chadd device_printf(sc->sc_dev, 8164aa8818bSAdrian Chadd "%s: mismatched descid (qid=%d, tsdescid=%d, " 8174aa8818bSAdrian Chadd "bfdescid=%d\n", 8184aa8818bSAdrian Chadd __func__, 8194aa8818bSAdrian Chadd ts.ts_queue_id, 8204aa8818bSAdrian Chadd ts.ts_desc_id, 8214aa8818bSAdrian Chadd bf->bf_descid); 8223ae723d4SAdrian Chadd } 8234aa8818bSAdrian Chadd #endif 8244aa8818bSAdrian Chadd 8254aa8818bSAdrian Chadd /* This removes the buffer and decrements the queue depth */ 82692e84e43SAdrian Chadd ATH_TXQ_REMOVE(&txq->fifo, bf, bf_list); 8274aa8818bSAdrian Chadd if (bf->bf_state.bfs_aggr) 8284aa8818bSAdrian Chadd txq->axq_aggr_depth--; 82992e84e43SAdrian Chadd 83092e84e43SAdrian Chadd /* 83192e84e43SAdrian Chadd * If this was the end of a FIFO set, decrement FIFO depth 83292e84e43SAdrian Chadd */ 83392e84e43SAdrian Chadd if (bf->bf_flags & ATH_BUF_FIFOEND) 8344aa8818bSAdrian Chadd txq->axq_fifo_depth--; 83592e84e43SAdrian Chadd 83692e84e43SAdrian Chadd /* 83792e84e43SAdrian Chadd * If this isn't the final buffer in a FIFO set, mark 83892e84e43SAdrian Chadd * the buffer as busy so it goes onto the holding queue. 83992e84e43SAdrian Chadd */ 84092e84e43SAdrian Chadd if (! (bf->bf_flags & ATH_BUF_FIFOEND)) 84192e84e43SAdrian Chadd bf->bf_flags |= ATH_BUF_BUSY; 84292e84e43SAdrian Chadd 84392e84e43SAdrian Chadd DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d: FIFO depth is now %d (%d)\n", 84492e84e43SAdrian Chadd __func__, 84592e84e43SAdrian Chadd txq->axq_qnum, 84692e84e43SAdrian Chadd txq->axq_fifo_depth, 84792e84e43SAdrian Chadd txq->fifo.axq_depth); 84892e84e43SAdrian Chadd 8494aa8818bSAdrian Chadd /* XXX assert FIFO depth >= 0 */ 850b837332dSAdrian Chadd ATH_TXQ_UNLOCK(txq); 8514aa8818bSAdrian Chadd 8524aa8818bSAdrian Chadd /* 85392e84e43SAdrian Chadd * Outside of the TX lock - if the buffer is end 85492e84e43SAdrian Chadd * end buffer in this FIFO, we don't need a holding 85592e84e43SAdrian Chadd * buffer any longer. 85692e84e43SAdrian Chadd */ 85792e84e43SAdrian Chadd if (bf->bf_flags & ATH_BUF_FIFOEND) { 858caedab2cSAdrian Chadd ATH_TXQ_LOCK(txq); 85992e84e43SAdrian Chadd ath_txq_freeholdingbuf(sc, txq); 860caedab2cSAdrian Chadd ATH_TXQ_UNLOCK(txq); 86192e84e43SAdrian Chadd } 86292e84e43SAdrian Chadd 86392e84e43SAdrian Chadd /* 8644aa8818bSAdrian Chadd * First we need to make sure ts_rate is valid. 8654aa8818bSAdrian Chadd * 8664aa8818bSAdrian Chadd * Pre-EDMA chips pass the whole TX descriptor to 8674aa8818bSAdrian Chadd * the proctxdesc function which will then fill out 8684aa8818bSAdrian Chadd * ts_rate based on the ts_finaltsi (final TX index) 8694aa8818bSAdrian Chadd * in the TX descriptor. However the TX completion 8704aa8818bSAdrian Chadd * FIFO doesn't have this information. So here we 8714aa8818bSAdrian Chadd * do a separate HAL call to populate that information. 8723345c65bSAdrian Chadd * 8733345c65bSAdrian Chadd * The same problem exists with ts_longretry. 8743345c65bSAdrian Chadd * The FreeBSD HAL corrects ts_longretry in the HAL layer; 8753345c65bSAdrian Chadd * the AR9380 HAL currently doesn't. So until the HAL 8763345c65bSAdrian Chadd * is imported and this can be added, we correct for it 8773345c65bSAdrian Chadd * here. 8784aa8818bSAdrian Chadd */ 8794aa8818bSAdrian Chadd /* XXX TODO */ 8804aa8818bSAdrian Chadd /* XXX faked for now. Ew. */ 8814aa8818bSAdrian Chadd if (ts.ts_finaltsi < 4) { 8824aa8818bSAdrian Chadd ts.ts_rate = 8834aa8818bSAdrian Chadd bf->bf_state.bfs_rc[ts.ts_finaltsi].ratecode; 8843345c65bSAdrian Chadd switch (ts.ts_finaltsi) { 8853345c65bSAdrian Chadd case 3: ts.ts_longretry += 8863345c65bSAdrian Chadd bf->bf_state.bfs_rc[2].tries; 8873345c65bSAdrian Chadd case 2: ts.ts_longretry += 8883345c65bSAdrian Chadd bf->bf_state.bfs_rc[1].tries; 8893345c65bSAdrian Chadd case 1: ts.ts_longretry += 8903345c65bSAdrian Chadd bf->bf_state.bfs_rc[0].tries; 8913345c65bSAdrian Chadd } 8924aa8818bSAdrian Chadd } else { 8934aa8818bSAdrian Chadd device_printf(sc->sc_dev, "%s: finaltsi=%d\n", 8944aa8818bSAdrian Chadd __func__, 8954aa8818bSAdrian Chadd ts.ts_finaltsi); 8964aa8818bSAdrian Chadd ts.ts_rate = bf->bf_state.bfs_rc[0].ratecode; 8974aa8818bSAdrian Chadd } 8984aa8818bSAdrian Chadd 8994aa8818bSAdrian Chadd /* 9004aa8818bSAdrian Chadd * XXX This is terrible. 9014aa8818bSAdrian Chadd * 9024aa8818bSAdrian Chadd * Right now, some code uses the TX status that is 9034aa8818bSAdrian Chadd * passed in here, but the completion handlers in the 9044aa8818bSAdrian Chadd * software TX path also use bf_status.ds_txstat. 9054aa8818bSAdrian Chadd * Ew. That should all go away. 9064aa8818bSAdrian Chadd * 9074aa8818bSAdrian Chadd * XXX It's also possible the rate control completion 9084aa8818bSAdrian Chadd * routine is called twice. 9094aa8818bSAdrian Chadd */ 9104aa8818bSAdrian Chadd memcpy(&bf->bf_status, &ts, sizeof(ts)); 9114aa8818bSAdrian Chadd 9124aa8818bSAdrian Chadd ni = bf->bf_node; 9134aa8818bSAdrian Chadd 9144aa8818bSAdrian Chadd /* Update RSSI */ 9154aa8818bSAdrian Chadd /* XXX duplicate from ath_tx_processq */ 9164aa8818bSAdrian Chadd if (ni != NULL && ts.ts_status == 0 && 9174aa8818bSAdrian Chadd ((bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0)) { 9184aa8818bSAdrian Chadd nacked++; 9194aa8818bSAdrian Chadd sc->sc_stats.ast_tx_rssi = ts.ts_rssi; 9204aa8818bSAdrian Chadd ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi, 9214aa8818bSAdrian Chadd ts.ts_rssi); 9224aa8818bSAdrian Chadd } 9234aa8818bSAdrian Chadd 9244aa8818bSAdrian Chadd /* Handle frame completion and rate control update */ 9254aa8818bSAdrian Chadd ath_tx_process_buf_completion(sc, txq, &ts, bf); 9264aa8818bSAdrian Chadd 9274aa8818bSAdrian Chadd /* bf is invalid at this point */ 9284aa8818bSAdrian Chadd 9294aa8818bSAdrian Chadd /* 9304aa8818bSAdrian Chadd * Now that there's space in the FIFO, let's push some 9314aa8818bSAdrian Chadd * more frames into it. 9324aa8818bSAdrian Chadd */ 933b837332dSAdrian Chadd ATH_TXQ_LOCK(txq); 93492e84e43SAdrian Chadd if (dosched) 9354aa8818bSAdrian Chadd ath_edma_tx_fifo_fill(sc, txq); 936b837332dSAdrian Chadd ATH_TXQ_UNLOCK(txq); 9374aa8818bSAdrian Chadd } 9384aa8818bSAdrian Chadd 9394aa8818bSAdrian Chadd sc->sc_wd_timer = 0; 9404aa8818bSAdrian Chadd 9414aa8818bSAdrian Chadd /* Kick software scheduler */ 9424aa8818bSAdrian Chadd /* 9434aa8818bSAdrian Chadd * XXX It's inefficient to do this if the FIFO queue is full, 9444aa8818bSAdrian Chadd * but there's no easy way right now to only populate 9454aa8818bSAdrian Chadd * the txq task for _one_ TXQ. This should be fixed. 9464aa8818bSAdrian Chadd */ 947ae3815fdSAdrian Chadd if (dosched) 94821bca442SAdrian Chadd ath_tx_swq_kick(sc); 949f8418db5SAdrian Chadd } 950f8418db5SAdrian Chadd 951f8418db5SAdrian Chadd static void 952f8418db5SAdrian Chadd ath_edma_attach_comp_func(struct ath_softc *sc) 953f8418db5SAdrian Chadd { 954f8418db5SAdrian Chadd 955f8418db5SAdrian Chadd TASK_INIT(&sc->sc_txtask, 0, ath_edma_tx_proc, sc); 956f8418db5SAdrian Chadd } 957f8418db5SAdrian Chadd 9583fdfc330SAdrian Chadd void 9593fdfc330SAdrian Chadd ath_xmit_setup_edma(struct ath_softc *sc) 9603fdfc330SAdrian Chadd { 9613fdfc330SAdrian Chadd 9623fdfc330SAdrian Chadd /* Fetch EDMA field and buffer sizes */ 9633fdfc330SAdrian Chadd (void) ath_hal_gettxdesclen(sc->sc_ah, &sc->sc_tx_desclen); 9643fdfc330SAdrian Chadd (void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen); 9653fdfc330SAdrian Chadd (void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps); 9663fdfc330SAdrian Chadd 967516a0ac2SAdrian Chadd if (bootverbose) { 9683fdfc330SAdrian Chadd device_printf(sc->sc_dev, "TX descriptor length: %d\n", 9693fdfc330SAdrian Chadd sc->sc_tx_desclen); 9703fdfc330SAdrian Chadd device_printf(sc->sc_dev, "TX status length: %d\n", 9713fdfc330SAdrian Chadd sc->sc_tx_statuslen); 9723fdfc330SAdrian Chadd device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n", 9733fdfc330SAdrian Chadd sc->sc_tx_nmaps); 974516a0ac2SAdrian Chadd } 9753fdfc330SAdrian Chadd 9763fdfc330SAdrian Chadd sc->sc_tx.xmit_setup = ath_edma_dma_txsetup; 9773fdfc330SAdrian Chadd sc->sc_tx.xmit_teardown = ath_edma_dma_txteardown; 978f8418db5SAdrian Chadd sc->sc_tx.xmit_attach_comp_func = ath_edma_attach_comp_func; 979746bab5bSAdrian Chadd 980746bab5bSAdrian Chadd sc->sc_tx.xmit_dma_restart = ath_edma_dma_restart; 981746bab5bSAdrian Chadd sc->sc_tx.xmit_handoff = ath_edma_xmit_handoff; 982788e6aa9SAdrian Chadd sc->sc_tx.xmit_drain = ath_edma_tx_drain; 9833fdfc330SAdrian Chadd } 984