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> 763fdfc330SAdrian Chadd #include <net/if_dl.h> 773fdfc330SAdrian Chadd #include <net/if_media.h> 783fdfc330SAdrian Chadd #include <net/if_types.h> 793fdfc330SAdrian Chadd #include <net/if_arp.h> 803fdfc330SAdrian Chadd #include <net/ethernet.h> 813fdfc330SAdrian Chadd #include <net/if_llc.h> 823fdfc330SAdrian Chadd 833fdfc330SAdrian Chadd #include <net80211/ieee80211_var.h> 843fdfc330SAdrian Chadd #include <net80211/ieee80211_regdomain.h> 853fdfc330SAdrian Chadd #ifdef IEEE80211_SUPPORT_SUPERG 863fdfc330SAdrian Chadd #include <net80211/ieee80211_superg.h> 873fdfc330SAdrian Chadd #endif 883fdfc330SAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA 893fdfc330SAdrian Chadd #include <net80211/ieee80211_tdma.h> 903fdfc330SAdrian Chadd #endif 913fdfc330SAdrian Chadd 923fdfc330SAdrian Chadd #include <net/bpf.h> 933fdfc330SAdrian Chadd 943fdfc330SAdrian Chadd #ifdef INET 953fdfc330SAdrian Chadd #include <netinet/in.h> 963fdfc330SAdrian Chadd #include <netinet/if_ether.h> 973fdfc330SAdrian Chadd #endif 983fdfc330SAdrian Chadd 993fdfc330SAdrian Chadd #include <dev/ath/if_athvar.h> 1003fdfc330SAdrian Chadd #include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */ 1013fdfc330SAdrian Chadd #include <dev/ath/ath_hal/ah_diagcodes.h> 1023fdfc330SAdrian Chadd 1033fdfc330SAdrian Chadd #include <dev/ath/if_ath_debug.h> 1043fdfc330SAdrian Chadd #include <dev/ath/if_ath_misc.h> 1053fdfc330SAdrian Chadd #include <dev/ath/if_ath_tsf.h> 1063fdfc330SAdrian Chadd #include <dev/ath/if_ath_tx.h> 1073fdfc330SAdrian Chadd #include <dev/ath/if_ath_sysctl.h> 1083fdfc330SAdrian Chadd #include <dev/ath/if_ath_led.h> 1093fdfc330SAdrian Chadd #include <dev/ath/if_ath_keycache.h> 1103fdfc330SAdrian Chadd #include <dev/ath/if_ath_rx.h> 1113fdfc330SAdrian Chadd #include <dev/ath/if_ath_beacon.h> 1123fdfc330SAdrian Chadd #include <dev/ath/if_athdfs.h> 1133fdfc330SAdrian Chadd 1143fdfc330SAdrian Chadd #ifdef ATH_TX99_DIAG 1153fdfc330SAdrian Chadd #include <dev/ath/ath_tx99/ath_tx99.h> 1163fdfc330SAdrian Chadd #endif 1173fdfc330SAdrian Chadd 1183fdfc330SAdrian Chadd #include <dev/ath/if_ath_tx_edma.h> 1193fdfc330SAdrian Chadd 1203fdfc330SAdrian Chadd /* 1213fdfc330SAdrian Chadd * some general macros 1223fdfc330SAdrian Chadd */ 1233fdfc330SAdrian Chadd #define INCR(_l, _sz) (_l) ++; (_l) &= ((_sz) - 1) 1243fdfc330SAdrian Chadd #define DECR(_l, _sz) (_l) --; (_l) &= ((_sz) - 1) 1253fdfc330SAdrian Chadd 126ba3fd9d8SAdrian Chadd /* 127ba3fd9d8SAdrian Chadd * XXX doesn't belong here, and should be tunable 128ba3fd9d8SAdrian Chadd */ 129ba3fd9d8SAdrian Chadd #define ATH_TXSTATUS_RING_SIZE 512 130ba3fd9d8SAdrian Chadd 1313fdfc330SAdrian Chadd MALLOC_DECLARE(M_ATHDEV); 1323fdfc330SAdrian Chadd 133746bab5bSAdrian Chadd /* 134746bab5bSAdrian Chadd * Re-initialise the DMA FIFO with the current contents of 1353ae723d4SAdrian Chadd * said TXQ. 136746bab5bSAdrian Chadd * 137746bab5bSAdrian Chadd * This should only be called as part of the chip reset path, as it 138746bab5bSAdrian Chadd * assumes the FIFO is currently empty. 139746bab5bSAdrian Chadd * 140746bab5bSAdrian Chadd * TODO: verify that a cold/warm reset does clear the TX FIFO, so 141746bab5bSAdrian Chadd * writing in a partially-filled FIFO will not cause double-entries 142746bab5bSAdrian Chadd * to appear. 143746bab5bSAdrian Chadd */ 144746bab5bSAdrian Chadd static void 145746bab5bSAdrian Chadd ath_edma_dma_restart(struct ath_softc *sc, struct ath_txq *txq) 146746bab5bSAdrian Chadd { 147746bab5bSAdrian Chadd 148746bab5bSAdrian Chadd device_printf(sc->sc_dev, "%s: called: txq=%p, qnum=%d\n", 149746bab5bSAdrian Chadd __func__, 150746bab5bSAdrian Chadd txq, 151746bab5bSAdrian Chadd txq->axq_qnum); 152746bab5bSAdrian Chadd } 153746bab5bSAdrian Chadd 154746bab5bSAdrian Chadd /* 1553ae723d4SAdrian Chadd * Hand off this frame to a hardware queue. 1563ae723d4SAdrian Chadd * 1573ae723d4SAdrian Chadd * Things are a bit hairy in the EDMA world. The TX FIFO is only 1583ae723d4SAdrian Chadd * 8 entries deep, so we need to keep track of exactly what we've 1593ae723d4SAdrian Chadd * pushed into the FIFO and what's just sitting in the TX queue, 1603ae723d4SAdrian Chadd * waiting to go out. 1613ae723d4SAdrian Chadd * 1623ae723d4SAdrian Chadd * So this is split into two halves - frames get appended to the 1633ae723d4SAdrian Chadd * TXQ; then a scheduler is called to push some frames into the 1643ae723d4SAdrian Chadd * actual TX FIFO. 1653ae723d4SAdrian Chadd */ 1663ae723d4SAdrian Chadd static void 1673ae723d4SAdrian Chadd ath_edma_xmit_handoff_hw(struct ath_softc *sc, struct ath_txq *txq, 1683ae723d4SAdrian Chadd struct ath_buf *bf) 1693ae723d4SAdrian Chadd { 1703ae723d4SAdrian Chadd struct ath_hal *ah = sc->sc_ah; 1713ae723d4SAdrian Chadd 1723ae723d4SAdrian Chadd ATH_TXQ_LOCK_ASSERT(txq); 1733ae723d4SAdrian Chadd 1743ae723d4SAdrian Chadd KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0, 1753ae723d4SAdrian Chadd ("%s: busy status 0x%x", __func__, bf->bf_flags)); 1763ae723d4SAdrian Chadd 1773ae723d4SAdrian Chadd /* 1783ae723d4SAdrian Chadd * XXX TODO: write a hard-coded check to ensure that 1793ae723d4SAdrian Chadd * the queue id in the TX descriptor matches txq->axq_qnum. 1803ae723d4SAdrian Chadd */ 1813ae723d4SAdrian Chadd 1823ae723d4SAdrian Chadd /* Update aggr stats */ 1833ae723d4SAdrian Chadd if (bf->bf_state.bfs_aggr) 1843ae723d4SAdrian Chadd txq->axq_aggr_depth++; 1853ae723d4SAdrian Chadd 1863ae723d4SAdrian Chadd /* Push and update frame stats */ 1873ae723d4SAdrian Chadd ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 1883ae723d4SAdrian Chadd 1893ae723d4SAdrian Chadd /* Only schedule to the FIFO if there's space */ 1903ae723d4SAdrian Chadd if (txq->axq_fifo_depth < HAL_TXFIFO_DEPTH) { 1913ae723d4SAdrian Chadd ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); 1923ae723d4SAdrian Chadd ath_hal_txstart(ah, txq->axq_qnum); 1933ae723d4SAdrian Chadd } 1943ae723d4SAdrian Chadd } 1953ae723d4SAdrian Chadd 1963ae723d4SAdrian Chadd /* 1973ae723d4SAdrian Chadd * Hand off this frame to a multicast software queue. 1983ae723d4SAdrian Chadd * 1993ae723d4SAdrian Chadd * Unlike legacy DMA, this doesn't chain together frames via the 2003ae723d4SAdrian Chadd * link pointer. Instead, they're just added to the queue. 2013ae723d4SAdrian Chadd * When it comes time to populate the CABQ, these frames should 2023ae723d4SAdrian Chadd * be individually pushed into the FIFO as appropriate. 2033ae723d4SAdrian Chadd * 2043ae723d4SAdrian Chadd * Yes, this does mean that I'll eventually have to flesh out some 2053ae723d4SAdrian Chadd * replacement code to handle populating the CABQ, rather than 2063ae723d4SAdrian Chadd * what's done in ath_beacon_generate(). It'll have to push each 2073ae723d4SAdrian Chadd * frame from the HW CABQ to the FIFO rather than just appending 2083ae723d4SAdrian Chadd * it to the existing TXQ and kicking off DMA. 2093ae723d4SAdrian Chadd */ 2103ae723d4SAdrian Chadd static void 2113ae723d4SAdrian Chadd ath_edma_xmit_handoff_mcast(struct ath_softc *sc, struct ath_txq *txq, 2123ae723d4SAdrian Chadd struct ath_buf *bf) 2133ae723d4SAdrian Chadd { 2143ae723d4SAdrian Chadd 2153ae723d4SAdrian Chadd ATH_TXQ_LOCK_ASSERT(txq); 2163ae723d4SAdrian Chadd KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0, 2173ae723d4SAdrian Chadd ("%s: busy status 0x%x", __func__, bf->bf_flags)); 2183ae723d4SAdrian Chadd 2193ae723d4SAdrian Chadd /* 2203ae723d4SAdrian Chadd * XXX this is mostly duplicated in ath_tx_handoff_mcast(). 2213ae723d4SAdrian Chadd */ 2223ae723d4SAdrian Chadd if (ATH_TXQ_FIRST(txq) != NULL) { 2233ae723d4SAdrian Chadd struct ath_buf *bf_last = ATH_TXQ_LAST(txq, axq_q_s); 2243ae723d4SAdrian Chadd struct ieee80211_frame *wh; 2253ae723d4SAdrian Chadd 2263ae723d4SAdrian Chadd /* mark previous frame */ 2273ae723d4SAdrian Chadd wh = mtod(bf_last->bf_m, struct ieee80211_frame *); 2283ae723d4SAdrian Chadd wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 2293ae723d4SAdrian Chadd 2303ae723d4SAdrian Chadd /* sync descriptor to memory */ 2313ae723d4SAdrian Chadd bus_dmamap_sync(sc->sc_dmat, bf_last->bf_dmamap, 2323ae723d4SAdrian Chadd BUS_DMASYNC_PREWRITE); 2333ae723d4SAdrian Chadd } 2343ae723d4SAdrian Chadd 2353ae723d4SAdrian Chadd ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 2363ae723d4SAdrian Chadd } 2373ae723d4SAdrian Chadd 2383ae723d4SAdrian Chadd /* 239746bab5bSAdrian Chadd * Handoff this frame to the hardware. 240746bab5bSAdrian Chadd * 241746bab5bSAdrian Chadd * For the multicast queue, this will treat it as a software queue 242746bab5bSAdrian Chadd * and append it to the list, after updating the MORE_DATA flag 243746bab5bSAdrian Chadd * in the previous frame. The cabq processing code will ensure 244746bab5bSAdrian Chadd * that the queue contents gets transferred over. 245746bab5bSAdrian Chadd * 246746bab5bSAdrian Chadd * For the hardware queues, this will queue a frame to the queue 247746bab5bSAdrian Chadd * like before, then populate the FIFO from that. Since the 248746bab5bSAdrian Chadd * EDMA hardware has 8 FIFO slots per TXQ, this ensures that 249746bab5bSAdrian Chadd * frames such as management frames don't get prematurely dropped. 250746bab5bSAdrian Chadd * 251746bab5bSAdrian Chadd * This does imply that a similar flush-hwq-to-fifoq method will 252746bab5bSAdrian Chadd * need to be called from the processq function, before the 253746bab5bSAdrian Chadd * per-node software scheduler is called. 254746bab5bSAdrian Chadd */ 255746bab5bSAdrian Chadd static void 256746bab5bSAdrian Chadd ath_edma_xmit_handoff(struct ath_softc *sc, struct ath_txq *txq, 257746bab5bSAdrian Chadd struct ath_buf *bf) 258746bab5bSAdrian Chadd { 259746bab5bSAdrian Chadd 2603ae723d4SAdrian Chadd ATH_TXQ_LOCK_ASSERT(txq); 2613ae723d4SAdrian Chadd 262746bab5bSAdrian Chadd device_printf(sc->sc_dev, "%s: called; bf=%p, txq=%p, qnum=%d\n", 263746bab5bSAdrian Chadd __func__, 264746bab5bSAdrian Chadd bf, 265746bab5bSAdrian Chadd txq, 266746bab5bSAdrian Chadd txq->axq_qnum); 267746bab5bSAdrian Chadd 2683ae723d4SAdrian Chadd if (txq->axq_qnum == ATH_TXQ_SWQ) 2693ae723d4SAdrian Chadd ath_edma_xmit_handoff_mcast(sc, txq, bf); 2703ae723d4SAdrian Chadd else 2713ae723d4SAdrian Chadd ath_edma_xmit_handoff_hw(sc, txq, bf); 2723ae723d4SAdrian Chadd 2733ae723d4SAdrian Chadd #if 0 274746bab5bSAdrian Chadd /* 275746bab5bSAdrian Chadd * XXX For now this is a placeholder; free the buffer 276746bab5bSAdrian Chadd * and inform the stack that the TX failed. 277746bab5bSAdrian Chadd */ 278746bab5bSAdrian Chadd ath_tx_default_comp(sc, bf, 1); 2793ae723d4SAdrian Chadd #endif 280746bab5bSAdrian Chadd } 281746bab5bSAdrian Chadd 2823fdfc330SAdrian Chadd static int 28379607afeSAdrian Chadd ath_edma_setup_txfifo(struct ath_softc *sc, int qnum) 28479607afeSAdrian Chadd { 28579607afeSAdrian Chadd struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum]; 28679607afeSAdrian Chadd 28779607afeSAdrian Chadd te->m_fifo = malloc(sizeof(struct ath_buf *) * HAL_TXFIFO_DEPTH, 28879607afeSAdrian Chadd M_ATHDEV, 28979607afeSAdrian Chadd M_NOWAIT | M_ZERO); 29079607afeSAdrian Chadd if (te->m_fifo == NULL) { 29179607afeSAdrian Chadd device_printf(sc->sc_dev, "%s: malloc failed\n", 29279607afeSAdrian Chadd __func__); 29379607afeSAdrian Chadd return (-ENOMEM); 29479607afeSAdrian Chadd } 29579607afeSAdrian Chadd 29679607afeSAdrian Chadd /* 29779607afeSAdrian Chadd * Set initial "empty" state. 29879607afeSAdrian Chadd */ 29979607afeSAdrian Chadd te->m_fifo_head = te->m_fifo_tail = te->m_fifo_depth = 0; 30079607afeSAdrian Chadd 30179607afeSAdrian Chadd return (0); 30279607afeSAdrian Chadd } 30379607afeSAdrian Chadd 30479607afeSAdrian Chadd static int 30579607afeSAdrian Chadd ath_edma_free_txfifo(struct ath_softc *sc, int qnum) 30679607afeSAdrian Chadd { 30779607afeSAdrian Chadd struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum]; 30879607afeSAdrian Chadd 30979607afeSAdrian Chadd /* XXX TODO: actually deref the ath_buf entries? */ 31079607afeSAdrian Chadd free(te->m_fifo, M_ATHDEV); 31179607afeSAdrian Chadd return (0); 31279607afeSAdrian Chadd } 31379607afeSAdrian Chadd 31479607afeSAdrian Chadd static int 3153fdfc330SAdrian Chadd ath_edma_dma_txsetup(struct ath_softc *sc) 3163fdfc330SAdrian Chadd { 317ba3fd9d8SAdrian Chadd int error; 31879607afeSAdrian Chadd int i; 3193fdfc330SAdrian Chadd 320ba3fd9d8SAdrian Chadd error = ath_descdma_alloc_desc(sc, &sc->sc_txsdma, 321ba3fd9d8SAdrian Chadd NULL, "txcomp", sc->sc_tx_statuslen, ATH_TXSTATUS_RING_SIZE); 322ba3fd9d8SAdrian Chadd if (error != 0) 323ba3fd9d8SAdrian Chadd return (error); 324ba3fd9d8SAdrian Chadd 325ba3fd9d8SAdrian Chadd ath_hal_setuptxstatusring(sc->sc_ah, 326ba3fd9d8SAdrian Chadd (void *) sc->sc_txsdma.dd_desc, 327ba3fd9d8SAdrian Chadd sc->sc_txsdma.dd_desc_paddr, 328ba3fd9d8SAdrian Chadd ATH_TXSTATUS_RING_SIZE); 329ba3fd9d8SAdrian Chadd 33079607afeSAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 33179607afeSAdrian Chadd ath_edma_setup_txfifo(sc, i); 33279607afeSAdrian Chadd } 33379607afeSAdrian Chadd 334ba3fd9d8SAdrian Chadd 3353fdfc330SAdrian Chadd return (0); 3363fdfc330SAdrian Chadd } 3373fdfc330SAdrian Chadd 3383fdfc330SAdrian Chadd static int 3393fdfc330SAdrian Chadd ath_edma_dma_txteardown(struct ath_softc *sc) 3403fdfc330SAdrian Chadd { 34179607afeSAdrian Chadd int i; 34279607afeSAdrian Chadd 34379607afeSAdrian Chadd for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 34479607afeSAdrian Chadd ath_edma_free_txfifo(sc, i); 34579607afeSAdrian Chadd } 3463fdfc330SAdrian Chadd 347ba3fd9d8SAdrian Chadd ath_descdma_cleanup(sc, &sc->sc_txsdma, NULL); 3483fdfc330SAdrian Chadd return (0); 3493fdfc330SAdrian Chadd } 3503fdfc330SAdrian Chadd 3513ae723d4SAdrian Chadd /* 352*788e6aa9SAdrian Chadd * Drain all TXQs, potentially after completing the existing completed 353*788e6aa9SAdrian Chadd * frames. 3543ae723d4SAdrian Chadd */ 355*788e6aa9SAdrian Chadd static void 356*788e6aa9SAdrian Chadd ath_edma_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type) 357f8418db5SAdrian Chadd { 358f8418db5SAdrian Chadd 3593ae723d4SAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 360f8418db5SAdrian Chadd } 361f8418db5SAdrian Chadd 3623ae723d4SAdrian Chadd /* 3633ae723d4SAdrian Chadd * Completely drain the TXQ, completing frames that were completed. 3643ae723d4SAdrian Chadd * 365*788e6aa9SAdrian Chadd * This is only called to _explictly_ drain the frames from a queue 366*788e6aa9SAdrian Chadd * without caring if they were completed or not. 3673ae723d4SAdrian Chadd */ 368f8418db5SAdrian Chadd static void 369f8418db5SAdrian Chadd ath_edma_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) 370f8418db5SAdrian Chadd { 371f8418db5SAdrian Chadd 3723ae723d4SAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 373f8418db5SAdrian Chadd } 374f8418db5SAdrian Chadd 3753ae723d4SAdrian Chadd /* 3763ae723d4SAdrian Chadd * Process the TX status queue. 3773ae723d4SAdrian Chadd */ 378f8418db5SAdrian Chadd static void 379f8418db5SAdrian Chadd ath_edma_tx_proc(void *arg, int npending) 380f8418db5SAdrian Chadd { 381f8418db5SAdrian Chadd struct ath_softc *sc = (struct ath_softc *) arg; 3823ae723d4SAdrian Chadd struct ath_hal *ah = sc->sc_ah; 3833ae723d4SAdrian Chadd HAL_STATUS status; 3843ae723d4SAdrian Chadd struct ath_tx_status ts; 3853ae723d4SAdrian Chadd struct ath_txq *txq; 386f8418db5SAdrian Chadd 387f8418db5SAdrian Chadd device_printf(sc->sc_dev, "%s: called, npending=%d\n", 388f8418db5SAdrian Chadd __func__, npending); 3893ae723d4SAdrian Chadd 3903ae723d4SAdrian Chadd for (;;) { 3913ae723d4SAdrian Chadd ATH_TXSTATUS_LOCK(sc); 3923ae723d4SAdrian Chadd status = ath_hal_txprocdesc(ah, NULL, (void *) &ts); 3933ae723d4SAdrian Chadd ATH_TXSTATUS_UNLOCK(sc); 3943ae723d4SAdrian Chadd 3953ae723d4SAdrian Chadd if (status != HAL_OK) 3963ae723d4SAdrian Chadd break; 3973ae723d4SAdrian Chadd 3983ae723d4SAdrian Chadd /* 3993ae723d4SAdrian Chadd * At this point we have a valid status descriptor. 4003ae723d4SAdrian Chadd * The QID and descriptor ID (which currently isn't set) 4013ae723d4SAdrian Chadd * is part of the status. 4023ae723d4SAdrian Chadd * 4033ae723d4SAdrian Chadd * We then assume that the descriptor in question is the 4043ae723d4SAdrian Chadd * -head- of the given QID. Eventually we should verify 4053ae723d4SAdrian Chadd * this by using the descriptor ID. 4063ae723d4SAdrian Chadd */ 4073ae723d4SAdrian Chadd device_printf(sc->sc_dev, "%s: qcuid=%d\n", 4083ae723d4SAdrian Chadd __func__, 4093ae723d4SAdrian Chadd ts.ts_queue_id); 4103ae723d4SAdrian Chadd 4113ae723d4SAdrian Chadd txq = &sc->sc_txq[ts.ts_queue_id]; 4123ae723d4SAdrian Chadd } 413f8418db5SAdrian Chadd } 414f8418db5SAdrian Chadd 415f8418db5SAdrian Chadd static void 416f8418db5SAdrian Chadd ath_edma_attach_comp_func(struct ath_softc *sc) 417f8418db5SAdrian Chadd { 418f8418db5SAdrian Chadd 419f8418db5SAdrian Chadd TASK_INIT(&sc->sc_txtask, 0, ath_edma_tx_proc, sc); 420f8418db5SAdrian Chadd } 421f8418db5SAdrian Chadd 4223fdfc330SAdrian Chadd void 4233fdfc330SAdrian Chadd ath_xmit_setup_edma(struct ath_softc *sc) 4243fdfc330SAdrian Chadd { 4253fdfc330SAdrian Chadd 4263fdfc330SAdrian Chadd /* Fetch EDMA field and buffer sizes */ 4273fdfc330SAdrian Chadd (void) ath_hal_gettxdesclen(sc->sc_ah, &sc->sc_tx_desclen); 4283fdfc330SAdrian Chadd (void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen); 4293fdfc330SAdrian Chadd (void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps); 4303fdfc330SAdrian Chadd 4313fdfc330SAdrian Chadd device_printf(sc->sc_dev, "TX descriptor length: %d\n", 4323fdfc330SAdrian Chadd sc->sc_tx_desclen); 4333fdfc330SAdrian Chadd device_printf(sc->sc_dev, "TX status length: %d\n", 4343fdfc330SAdrian Chadd sc->sc_tx_statuslen); 4353fdfc330SAdrian Chadd device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n", 4363fdfc330SAdrian Chadd sc->sc_tx_nmaps); 4373fdfc330SAdrian Chadd 4383fdfc330SAdrian Chadd sc->sc_tx.xmit_setup = ath_edma_dma_txsetup; 4393fdfc330SAdrian Chadd sc->sc_tx.xmit_teardown = ath_edma_dma_txteardown; 440f8418db5SAdrian Chadd sc->sc_tx.xmit_attach_comp_func = ath_edma_attach_comp_func; 441746bab5bSAdrian Chadd 442746bab5bSAdrian Chadd sc->sc_tx.xmit_dma_restart = ath_edma_dma_restart; 443746bab5bSAdrian Chadd sc->sc_tx.xmit_handoff = ath_edma_xmit_handoff; 444f8418db5SAdrian Chadd sc->sc_tx.xmit_drainq = ath_edma_tx_draintxq; 445*788e6aa9SAdrian Chadd sc->sc_tx.xmit_drain = ath_edma_tx_drain; 4463fdfc330SAdrian Chadd } 447