1238055Sadrian/*- 2238055Sadrian * Copyright (c) 2012 Adrian Chadd <adrian@FreeBSD.org> 3238055Sadrian * All rights reserved. 4238055Sadrian * 5238055Sadrian * Redistribution and use in source and binary forms, with or without 6238055Sadrian * modification, are permitted provided that the following conditions 7238055Sadrian * are met: 8238055Sadrian * 1. Redistributions of source code must retain the above copyright 9238055Sadrian * notice, this list of conditions and the following disclaimer, 10238055Sadrian * without modification. 11238055Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12238055Sadrian * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13238055Sadrian * redistribution must be conditioned upon including a substantially 14238055Sadrian * similar Disclaimer requirement for further binary redistribution. 15238055Sadrian * 16238055Sadrian * NO WARRANTY 17238055Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18238055Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19238055Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20238055Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21238055Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22238055Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23238055Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24238055Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25238055Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26238055Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27238055Sadrian * THE POSSIBILITY OF SUCH DAMAGES. 28238055Sadrian */ 29238055Sadrian 30238055Sadrian#include <sys/cdefs.h> 31238055Sadrian__FBSDID("$FreeBSD$"); 32238055Sadrian 33238055Sadrian/* 34238055Sadrian * Driver for the Atheros Wireless LAN controller. 35238055Sadrian * 36238055Sadrian * This software is derived from work of Atsushi Onoe; his contribution 37238055Sadrian * is greatly appreciated. 38238055Sadrian */ 39238055Sadrian 40238055Sadrian#include "opt_inet.h" 41238055Sadrian#include "opt_ath.h" 42238055Sadrian/* 43238055Sadrian * This is needed for register operations which are performed 44238055Sadrian * by the driver - eg, calls to ath_hal_gettsf32(). 45238055Sadrian * 46238055Sadrian * It's also required for any AH_DEBUG checks in here, eg the 47238055Sadrian * module dependencies. 48238055Sadrian */ 49238055Sadrian#include "opt_ah.h" 50238055Sadrian#include "opt_wlan.h" 51238055Sadrian 52238055Sadrian#include <sys/param.h> 53238055Sadrian#include <sys/systm.h> 54238055Sadrian#include <sys/sysctl.h> 55238055Sadrian#include <sys/mbuf.h> 56238055Sadrian#include <sys/malloc.h> 57238055Sadrian#include <sys/lock.h> 58238055Sadrian#include <sys/mutex.h> 59238055Sadrian#include <sys/kernel.h> 60238055Sadrian#include <sys/socket.h> 61238055Sadrian#include <sys/sockio.h> 62238055Sadrian#include <sys/errno.h> 63238055Sadrian#include <sys/callout.h> 64238055Sadrian#include <sys/bus.h> 65238055Sadrian#include <sys/endian.h> 66238055Sadrian#include <sys/kthread.h> 67238055Sadrian#include <sys/taskqueue.h> 68238055Sadrian#include <sys/priv.h> 69238055Sadrian#include <sys/module.h> 70238055Sadrian#include <sys/ktr.h> 71238055Sadrian#include <sys/smp.h> /* for mp_ncpus */ 72238055Sadrian 73238055Sadrian#include <machine/bus.h> 74238055Sadrian 75238055Sadrian#include <net/if.h> 76238055Sadrian#include <net/if_dl.h> 77238055Sadrian#include <net/if_media.h> 78238055Sadrian#include <net/if_types.h> 79238055Sadrian#include <net/if_arp.h> 80238055Sadrian#include <net/ethernet.h> 81238055Sadrian#include <net/if_llc.h> 82238055Sadrian 83238055Sadrian#include <net80211/ieee80211_var.h> 84238055Sadrian#include <net80211/ieee80211_regdomain.h> 85238055Sadrian#ifdef IEEE80211_SUPPORT_SUPERG 86238055Sadrian#include <net80211/ieee80211_superg.h> 87238055Sadrian#endif 88238055Sadrian#ifdef IEEE80211_SUPPORT_TDMA 89238055Sadrian#include <net80211/ieee80211_tdma.h> 90238055Sadrian#endif 91238055Sadrian 92238055Sadrian#include <net/bpf.h> 93238055Sadrian 94238055Sadrian#ifdef INET 95238055Sadrian#include <netinet/in.h> 96238055Sadrian#include <netinet/if_ether.h> 97238055Sadrian#endif 98238055Sadrian 99238055Sadrian#include <dev/ath/if_athvar.h> 100238055Sadrian#include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */ 101238055Sadrian#include <dev/ath/ath_hal/ah_diagcodes.h> 102238055Sadrian 103238055Sadrian#include <dev/ath/if_ath_debug.h> 104238055Sadrian#include <dev/ath/if_ath_misc.h> 105238055Sadrian#include <dev/ath/if_ath_tsf.h> 106238055Sadrian#include <dev/ath/if_ath_tx.h> 107238055Sadrian#include <dev/ath/if_ath_sysctl.h> 108238055Sadrian#include <dev/ath/if_ath_led.h> 109238055Sadrian#include <dev/ath/if_ath_keycache.h> 110238055Sadrian#include <dev/ath/if_ath_rx.h> 111238055Sadrian#include <dev/ath/if_ath_beacon.h> 112238055Sadrian#include <dev/ath/if_athdfs.h> 113238055Sadrian 114238055Sadrian#ifdef ATH_TX99_DIAG 115238055Sadrian#include <dev/ath/ath_tx99/ath_tx99.h> 116238055Sadrian#endif 117238055Sadrian 118238055Sadrian#include <dev/ath/if_ath_rx_edma.h> 119238055Sadrian 120242782Sadrian#ifdef ATH_DEBUG_ALQ 121242782Sadrian#include <dev/ath/if_ath_alq.h> 122242782Sadrian#endif 123242782Sadrian 124238317Sadrian/* 125238317Sadrian * some general macros 126238317Sadrian */ 127238317Sadrian#define INCR(_l, _sz) (_l) ++; (_l) &= ((_sz) - 1) 128238317Sadrian#define DECR(_l, _sz) (_l) --; (_l) &= ((_sz) - 1) 129238317Sadrian 130238317SadrianMALLOC_DECLARE(M_ATHDEV); 131238317Sadrian 132238317Sadrian/* 133238317Sadrian * XXX TODO: 134238317Sadrian * 135238317Sadrian * + Make sure the FIFO is correctly flushed and reinitialised 136238317Sadrian * through a reset; 137238317Sadrian * + Verify multi-descriptor frames work! 138238317Sadrian * + There's a "memory use after free" which needs to be tracked down 139238317Sadrian * and fixed ASAP. I've seen this in the legacy path too, so it 140238317Sadrian * may be a generic RX path issue. 141238317Sadrian */ 142238317Sadrian 143238317Sadrian/* 144238317Sadrian * XXX shuffle the function orders so these pre-declarations aren't 145238317Sadrian * required! 146238317Sadrian */ 147238317Sadrianstatic int ath_edma_rxfifo_alloc(struct ath_softc *sc, HAL_RX_QUEUE qtype, 148238317Sadrian int nbufs); 149238317Sadrianstatic int ath_edma_rxfifo_flush(struct ath_softc *sc, HAL_RX_QUEUE qtype); 150238317Sadrianstatic void ath_edma_rxbuf_free(struct ath_softc *sc, struct ath_buf *bf); 151248529Sadrianstatic void ath_edma_recv_proc_queue(struct ath_softc *sc, 152238337Sadrian HAL_RX_QUEUE qtype, int dosched); 153248529Sadrianstatic int ath_edma_recv_proc_deferred_queue(struct ath_softc *sc, 154248529Sadrian HAL_RX_QUEUE qtype, int dosched); 155238317Sadrian 156238055Sadrianstatic void 157238055Sadrianath_edma_stoprecv(struct ath_softc *sc, int dodelay) 158238055Sadrian{ 159238055Sadrian struct ath_hal *ah = sc->sc_ah; 160238055Sadrian 161238436Sadrian ATH_RX_LOCK(sc); 162238055Sadrian ath_hal_stoppcurecv(ah); 163238055Sadrian ath_hal_setrxfilter(ah, 0); 164238055Sadrian ath_hal_stopdmarecv(ah); 165238055Sadrian 166238055Sadrian DELAY(3000); 167238055Sadrian 168238317Sadrian /* Flush RX pending for each queue */ 169238317Sadrian /* XXX should generic-ify this */ 170238317Sadrian if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending) { 171238317Sadrian m_freem(sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending); 172238317Sadrian sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL; 173238055Sadrian } 174238055Sadrian 175238317Sadrian if (sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending) { 176238317Sadrian m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending); 177238317Sadrian sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL; 178238317Sadrian } 179238436Sadrian ATH_RX_UNLOCK(sc); 180238055Sadrian} 181238055Sadrian 182238317Sadrian/* 183238337Sadrian * Re-initialise the FIFO given the current buffer contents. 184238337Sadrian * Specifically, walk from head -> tail, pushing the FIFO contents 185238337Sadrian * back into the FIFO. 186238337Sadrian */ 187238337Sadrianstatic void 188238337Sadrianath_edma_reinit_fifo(struct ath_softc *sc, HAL_RX_QUEUE qtype) 189238337Sadrian{ 190238337Sadrian struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; 191238337Sadrian struct ath_buf *bf; 192238337Sadrian int i, j; 193238337Sadrian 194238436Sadrian ATH_RX_LOCK_ASSERT(sc); 195238436Sadrian 196238337Sadrian i = re->m_fifo_head; 197238337Sadrian for (j = 0; j < re->m_fifo_depth; j++) { 198238337Sadrian bf = re->m_fifo[i]; 199238344Sadrian DPRINTF(sc, ATH_DEBUG_EDMA_RX, 200238365Sjhb "%s: Q%d: pos=%i, addr=0x%jx\n", 201238344Sadrian __func__, 202238344Sadrian qtype, 203238344Sadrian i, 204238365Sjhb (uintmax_t)bf->bf_daddr); 205238337Sadrian ath_hal_putrxbuf(sc->sc_ah, bf->bf_daddr, qtype); 206238337Sadrian INCR(i, re->m_fifolen); 207238337Sadrian } 208238337Sadrian 209238337Sadrian /* Ensure this worked out right */ 210238337Sadrian if (i != re->m_fifo_tail) { 211238337Sadrian device_printf(sc->sc_dev, "%s: i (%d) != tail! (%d)\n", 212238337Sadrian __func__, 213238337Sadrian i, 214238337Sadrian re->m_fifo_tail); 215238337Sadrian } 216238337Sadrian} 217238337Sadrian 218238337Sadrian/* 219238317Sadrian * Start receive. 220238317Sadrian * 221238317Sadrian * XXX TODO: this needs to reallocate the FIFO entries when a reset 222238317Sadrian * occurs, in case the FIFO is filled up and no new descriptors get 223238317Sadrian * thrown into the FIFO. 224238317Sadrian */ 225238055Sadrianstatic int 226238055Sadrianath_edma_startrecv(struct ath_softc *sc) 227238055Sadrian{ 228238055Sadrian struct ath_hal *ah = sc->sc_ah; 229238055Sadrian 230238436Sadrian ATH_RX_LOCK(sc); 231238436Sadrian 232238317Sadrian /* Enable RX FIFO */ 233238317Sadrian ath_hal_rxena(ah); 234238055Sadrian 235238317Sadrian /* 236238337Sadrian * Entries should only be written out if the 237238337Sadrian * FIFO is empty. 238238344Sadrian * 239238344Sadrian * XXX This isn't correct. I should be looking 240238344Sadrian * at the value of AR_RXDP_SIZE (0x0070) to determine 241238344Sadrian * how many entries are in here. 242238344Sadrian * 243238344Sadrian * A warm reset will clear the registers but not the FIFO. 244238344Sadrian * 245238344Sadrian * And I believe this is actually the address of the last 246238344Sadrian * handled buffer rather than the current FIFO pointer. 247238344Sadrian * So if no frames have been (yet) seen, we'll reinit the 248238344Sadrian * FIFO. 249238344Sadrian * 250238344Sadrian * I'll chase that up at some point. 251238317Sadrian */ 252238344Sadrian if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_HP) == 0) { 253238337Sadrian DPRINTF(sc, ATH_DEBUG_EDMA_RX, 254238337Sadrian "%s: Re-initing HP FIFO\n", __func__); 255238337Sadrian ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_HP); 256238337Sadrian } 257238337Sadrian if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_LP) == 0) { 258238337Sadrian DPRINTF(sc, ATH_DEBUG_EDMA_RX, 259238337Sadrian "%s: Re-initing LP FIFO\n", __func__); 260238337Sadrian ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_LP); 261238337Sadrian } 262238317Sadrian 263238317Sadrian /* Add up to m_fifolen entries in each queue */ 264238317Sadrian /* 265238317Sadrian * These must occur after the above write so the FIFO buffers 266238317Sadrian * are pushed/tracked in the same order as the hardware will 267238317Sadrian * process them. 268238317Sadrian */ 269238317Sadrian ath_edma_rxfifo_alloc(sc, HAL_RX_QUEUE_HP, 270238317Sadrian sc->sc_rxedma[HAL_RX_QUEUE_HP].m_fifolen); 271238317Sadrian 272238317Sadrian ath_edma_rxfifo_alloc(sc, HAL_RX_QUEUE_LP, 273238317Sadrian sc->sc_rxedma[HAL_RX_QUEUE_LP].m_fifolen); 274238317Sadrian 275238055Sadrian ath_mode_init(sc); 276238055Sadrian ath_hal_startpcurecv(ah); 277238436Sadrian 278238436Sadrian ATH_RX_UNLOCK(sc); 279238436Sadrian 280238055Sadrian return (0); 281238055Sadrian} 282238055Sadrian 283238055Sadrianstatic void 284248529Sadrianath_edma_recv_sched_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, 285248529Sadrian int dosched) 286248529Sadrian{ 287248529Sadrian 288248529Sadrian ath_edma_recv_proc_queue(sc, qtype, dosched); 289248529Sadrian taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); 290248529Sadrian} 291248529Sadrian 292248529Sadrianstatic void 293248529Sadrianath_edma_recv_sched(struct ath_softc *sc, int dosched) 294248529Sadrian{ 295248529Sadrian 296248529Sadrian ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, dosched); 297248529Sadrian ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, dosched); 298248529Sadrian taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); 299248529Sadrian} 300248529Sadrian 301248529Sadrianstatic void 302238055Sadrianath_edma_recv_flush(struct ath_softc *sc) 303238055Sadrian{ 304238055Sadrian 305242778Sadrian DPRINTF(sc, ATH_DEBUG_RECV, "%s: called\n", __func__); 306238317Sadrian 307238445Sadrian ATH_PCU_LOCK(sc); 308238445Sadrian sc->sc_rxproc_cnt++; 309238445Sadrian ATH_PCU_UNLOCK(sc); 310238445Sadrian 311248529Sadrian /* 312248529Sadrian * Flush any active frames from FIFO -> deferred list 313248529Sadrian */ 314238337Sadrian ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 0); 315238337Sadrian ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 0); 316238445Sadrian 317248529Sadrian /* 318248529Sadrian * Process what's in the deferred queue 319248529Sadrian */ 320248529Sadrian ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 0); 321248529Sadrian ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_LP, 0); 322248529Sadrian 323238445Sadrian ATH_PCU_LOCK(sc); 324238445Sadrian sc->sc_rxproc_cnt--; 325238445Sadrian ATH_PCU_UNLOCK(sc); 326238055Sadrian} 327238055Sadrian 328238317Sadrian/* 329248529Sadrian * Process frames from the current queue into the deferred queue. 330238317Sadrian */ 331248529Sadrianstatic void 332238337Sadrianath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, 333238337Sadrian int dosched) 334238317Sadrian{ 335238317Sadrian struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; 336238317Sadrian struct ath_rx_status *rs; 337238317Sadrian struct ath_desc *ds; 338238317Sadrian struct ath_buf *bf; 339238317Sadrian struct mbuf *m; 340238317Sadrian struct ath_hal *ah = sc->sc_ah; 341238317Sadrian uint64_t tsf; 342248529Sadrian uint16_t nf; 343248529Sadrian int npkts = 0; 344238317Sadrian 345238317Sadrian tsf = ath_hal_gettsf64(ah); 346238317Sadrian nf = ath_hal_getchannoise(ah, sc->sc_curchan); 347238317Sadrian sc->sc_stats.ast_rx_noise = nf; 348238317Sadrian 349238436Sadrian ATH_RX_LOCK(sc); 350238436Sadrian 351238317Sadrian do { 352238317Sadrian bf = re->m_fifo[re->m_fifo_head]; 353238317Sadrian /* This shouldn't occur! */ 354238317Sadrian if (bf == NULL) { 355238317Sadrian device_printf(sc->sc_dev, "%s: Q%d: NULL bf?\n", 356238317Sadrian __func__, 357238317Sadrian qtype); 358238317Sadrian break; 359238317Sadrian } 360238317Sadrian m = bf->bf_m; 361238317Sadrian ds = bf->bf_desc; 362238317Sadrian 363238317Sadrian /* 364238317Sadrian * Sync descriptor memory - this also syncs the buffer for us. 365238317Sadrian * EDMA descriptors are in cached memory. 366238317Sadrian */ 367238317Sadrian bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 368249085Sadrian BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 369238317Sadrian rs = &bf->bf_status.ds_rxstat; 370238436Sadrian bf->bf_rxstatus = ath_hal_rxprocdesc(ah, ds, bf->bf_daddr, 371238436Sadrian NULL, rs); 372238317Sadrian#ifdef ATH_DEBUG 373238317Sadrian if (sc->sc_debug & ATH_DEBUG_RECV_DESC) 374238436Sadrian ath_printrxbuf(sc, bf, 0, bf->bf_rxstatus == HAL_OK); 375242782Sadrian#endif /* ATH_DEBUG */ 376242782Sadrian#ifdef ATH_DEBUG_ALQ 377242782Sadrian if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_RXSTATUS)) 378242782Sadrian if_ath_alq_post(&sc->sc_alq, ATH_ALQ_EDMA_RXSTATUS, 379242782Sadrian sc->sc_rx_statuslen, (char *) ds); 380242782Sadrian#endif /* ATH_DEBUG */ 381238436Sadrian if (bf->bf_rxstatus == HAL_EINPROGRESS) 382238317Sadrian break; 383238317Sadrian 384238317Sadrian /* 385238317Sadrian * Completed descriptor. 386238317Sadrian */ 387238317Sadrian DPRINTF(sc, ATH_DEBUG_EDMA_RX, 388238317Sadrian "%s: Q%d: completed!\n", __func__, qtype); 389238445Sadrian npkts++; 390238317Sadrian 391238317Sadrian /* 392249085Sadrian * We've been synced already, so unmap. 393249085Sadrian */ 394249085Sadrian bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 395249085Sadrian 396249085Sadrian /* 397238436Sadrian * Remove the FIFO entry and place it on the completion 398238436Sadrian * queue. 399238317Sadrian */ 400238317Sadrian re->m_fifo[re->m_fifo_head] = NULL; 401249565Sadrian TAILQ_INSERT_TAIL(&sc->sc_rx_rxlist[qtype], bf, bf_list); 402238317Sadrian 403238436Sadrian /* Bump the descriptor FIFO stats */ 404238436Sadrian INCR(re->m_fifo_head, re->m_fifolen); 405238436Sadrian re->m_fifo_depth--; 406238436Sadrian /* XXX check it doesn't fall below 0 */ 407238436Sadrian } while (re->m_fifo_depth > 0); 408238436Sadrian 409238436Sadrian /* Append some more fresh frames to the FIFO */ 410238436Sadrian if (dosched) 411238436Sadrian ath_edma_rxfifo_alloc(sc, qtype, re->m_fifolen); 412238436Sadrian 413238436Sadrian ATH_RX_UNLOCK(sc); 414238436Sadrian 415248529Sadrian /* rx signal state monitoring */ 416248529Sadrian ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan); 417248529Sadrian 418248529Sadrian ATH_KTR(sc, ATH_KTR_INTERRUPTS, 1, 419248529Sadrian "ath edma rx proc: npkts=%d\n", 420248529Sadrian npkts); 421248529Sadrian 422248529Sadrian /* Handle resched and kickpcu appropriately */ 423248529Sadrian ATH_PCU_LOCK(sc); 424248529Sadrian if (dosched && sc->sc_kickpcu) { 425248529Sadrian ATH_KTR(sc, ATH_KTR_ERROR, 0, 426248529Sadrian "ath_edma_recv_proc_queue(): kickpcu"); 427252385Sadrian if (npkts > 0) 428252385Sadrian device_printf(sc->sc_dev, 429252385Sadrian "%s: handled npkts %d\n", 430252385Sadrian __func__, npkts); 431248529Sadrian 432248529Sadrian /* 433248529Sadrian * XXX TODO: what should occur here? Just re-poke and 434248529Sadrian * re-enable the RX FIFO? 435248529Sadrian */ 436248529Sadrian sc->sc_kickpcu = 0; 437248529Sadrian } 438248529Sadrian ATH_PCU_UNLOCK(sc); 439248529Sadrian 440248529Sadrian return; 441248529Sadrian} 442248529Sadrian 443248529Sadrian/* 444248529Sadrian * Flush the deferred queue. 445248529Sadrian * 446248529Sadrian * This destructively flushes the deferred queue - it doesn't 447248529Sadrian * call the wireless stack on each mbuf. 448248529Sadrian */ 449248529Sadrianstatic void 450248529Sadrianath_edma_flush_deferred_queue(struct ath_softc *sc) 451248529Sadrian{ 452248529Sadrian struct ath_buf *bf, *next; 453248529Sadrian 454248529Sadrian ATH_RX_LOCK_ASSERT(sc); 455249565Sadrian 456248529Sadrian /* Free in one set, inside the lock */ 457249565Sadrian TAILQ_FOREACH_SAFE(bf, 458249565Sadrian &sc->sc_rx_rxlist[HAL_RX_QUEUE_LP], bf_list, next) { 459248529Sadrian /* Free the buffer/mbuf */ 460248529Sadrian ath_edma_rxbuf_free(sc, bf); 461248529Sadrian } 462249565Sadrian TAILQ_FOREACH_SAFE(bf, 463249565Sadrian &sc->sc_rx_rxlist[HAL_RX_QUEUE_HP], bf_list, next) { 464249565Sadrian /* Free the buffer/mbuf */ 465249565Sadrian ath_edma_rxbuf_free(sc, bf); 466249565Sadrian } 467248529Sadrian} 468248529Sadrian 469248529Sadrianstatic int 470248529Sadrianath_edma_recv_proc_deferred_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, 471248529Sadrian int dosched) 472248529Sadrian{ 473248529Sadrian int ngood = 0; 474248529Sadrian uint64_t tsf; 475248529Sadrian struct ath_buf *bf, *next; 476248529Sadrian struct ath_rx_status *rs; 477248529Sadrian int16_t nf; 478248529Sadrian ath_bufhead rxlist; 479249085Sadrian struct mbuf *m; 480248529Sadrian 481248529Sadrian TAILQ_INIT(&rxlist); 482248529Sadrian 483248529Sadrian nf = ath_hal_getchannoise(sc->sc_ah, sc->sc_curchan); 484248529Sadrian /* 485248529Sadrian * XXX TODO: the NF/TSF should be stamped on the bufs themselves, 486248529Sadrian * otherwise we may end up adding in the wrong values if this 487248529Sadrian * is delayed too far.. 488248529Sadrian */ 489248529Sadrian tsf = ath_hal_gettsf64(sc->sc_ah); 490248529Sadrian 491248529Sadrian /* Copy the list over */ 492248529Sadrian ATH_RX_LOCK(sc); 493249565Sadrian TAILQ_CONCAT(&rxlist, &sc->sc_rx_rxlist[qtype], bf_list); 494248529Sadrian ATH_RX_UNLOCK(sc); 495248529Sadrian 496238436Sadrian /* Handle the completed descriptors */ 497238436Sadrian TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) { 498238317Sadrian /* 499238317Sadrian * Skip the RX descriptor status - start at the data offset 500238317Sadrian */ 501238436Sadrian m_adj(bf->bf_m, sc->sc_rx_statuslen); 502238317Sadrian 503238317Sadrian /* Handle the frame */ 504249085Sadrian 505238441Sadrian rs = &bf->bf_status.ds_rxstat; 506249085Sadrian m = bf->bf_m; 507249085Sadrian bf->bf_m = NULL; 508249085Sadrian if (ath_rx_pkt(sc, rs, bf->bf_rxstatus, tsf, nf, qtype, bf, m)) 509238337Sadrian ngood++; 510238436Sadrian } 511238317Sadrian 512248529Sadrian if (ngood) { 513248529Sadrian sc->sc_lastrx = tsf; 514248529Sadrian } 515248529Sadrian 516248529Sadrian ATH_KTR(sc, ATH_KTR_INTERRUPTS, 1, 517248529Sadrian "ath edma rx deferred proc: ngood=%d\n", 518248529Sadrian ngood); 519248529Sadrian 520238436Sadrian /* Free in one set, inside the lock */ 521238436Sadrian ATH_RX_LOCK(sc); 522238436Sadrian TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) { 523238317Sadrian /* Free the buffer/mbuf */ 524238317Sadrian ath_edma_rxbuf_free(sc, bf); 525238436Sadrian } 526238436Sadrian ATH_RX_UNLOCK(sc); 527238317Sadrian 528238337Sadrian return (ngood); 529238317Sadrian} 530238317Sadrian 531238055Sadrianstatic void 532238055Sadrianath_edma_recv_tasklet(void *arg, int npending) 533238055Sadrian{ 534238055Sadrian struct ath_softc *sc = (struct ath_softc *) arg; 535238445Sadrian struct ifnet *ifp = sc->sc_ifp; 536238449Sadrian#ifdef IEEE80211_SUPPORT_SUPERG 537238445Sadrian struct ieee80211com *ic = ifp->if_l2com; 538238449Sadrian#endif 539238055Sadrian 540238317Sadrian DPRINTF(sc, ATH_DEBUG_EDMA_RX, "%s: called; npending=%d\n", 541238055Sadrian __func__, 542238055Sadrian npending); 543238317Sadrian 544238337Sadrian ATH_PCU_LOCK(sc); 545238337Sadrian if (sc->sc_inreset_cnt > 0) { 546238337Sadrian device_printf(sc->sc_dev, "%s: sc_inreset_cnt > 0; skipping\n", 547238337Sadrian __func__); 548238337Sadrian ATH_PCU_UNLOCK(sc); 549238337Sadrian return; 550238337Sadrian } 551238445Sadrian sc->sc_rxproc_cnt++; 552238337Sadrian ATH_PCU_UNLOCK(sc); 553238337Sadrian 554238337Sadrian ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 1); 555238337Sadrian ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 1); 556238445Sadrian 557248529Sadrian ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 1); 558248529Sadrian ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_LP, 1); 559248529Sadrian 560238445Sadrian /* XXX inside IF_LOCK ? */ 561238445Sadrian if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { 562238445Sadrian#ifdef IEEE80211_SUPPORT_SUPERG 563238445Sadrian ieee80211_ff_age_all(ic, 100); 564238445Sadrian#endif 565238445Sadrian if (! IFQ_IS_EMPTY(&ifp->if_snd)) 566238445Sadrian ath_tx_kick(sc); 567238445Sadrian } 568238445Sadrian if (ath_dfs_tasklet_needed(sc, sc->sc_curchan)) 569238445Sadrian taskqueue_enqueue(sc->sc_tq, &sc->sc_dfstask); 570238445Sadrian 571238445Sadrian ATH_PCU_LOCK(sc); 572238445Sadrian sc->sc_rxproc_cnt--; 573238445Sadrian ATH_PCU_UNLOCK(sc); 574238055Sadrian} 575238055Sadrian 576238317Sadrian/* 577238317Sadrian * Allocate an RX mbuf for the given ath_buf and initialise 578238317Sadrian * it for EDMA. 579238317Sadrian * 580238317Sadrian * + Allocate a 4KB mbuf; 581238317Sadrian * + Setup the DMA map for the given buffer; 582238317Sadrian * + Return that. 583238317Sadrian */ 584238055Sadrianstatic int 585238055Sadrianath_edma_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) 586238055Sadrian{ 587238055Sadrian 588238317Sadrian struct mbuf *m; 589238317Sadrian int error; 590238317Sadrian int len; 591238317Sadrian 592238436Sadrian ATH_RX_LOCK_ASSERT(sc); 593238436Sadrian 594243857Sglebius m = m_getm(NULL, sc->sc_edma_bufsize, M_NOWAIT, MT_DATA); 595238317Sadrian if (! m) 596238317Sadrian return (ENOBUFS); /* XXX ?*/ 597238317Sadrian 598238317Sadrian /* XXX warn/enforce alignment */ 599238317Sadrian 600238317Sadrian len = m->m_ext.ext_size; 601238317Sadrian#if 0 602238317Sadrian device_printf(sc->sc_dev, "%s: called: m=%p, size=%d, mtod=%p\n", 603238317Sadrian __func__, 604238317Sadrian m, 605238317Sadrian len, 606238317Sadrian mtod(m, char *)); 607238317Sadrian#endif 608238317Sadrian 609238317Sadrian m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 610238317Sadrian 611238317Sadrian /* 612249085Sadrian * Populate ath_buf fields. 613249085Sadrian */ 614249085Sadrian bf->bf_desc = mtod(m, struct ath_desc *); 615249085Sadrian bf->bf_lastds = bf->bf_desc; /* XXX only really for TX? */ 616249085Sadrian bf->bf_m = m; 617249085Sadrian 618249085Sadrian /* 619249085Sadrian * Zero the descriptor and ensure it makes it out to the 620249085Sadrian * bounce buffer if one is required. 621249085Sadrian * 622249085Sadrian * XXX PREWRITE will copy the whole buffer; we only needed it 623249085Sadrian * to sync the first 32 DWORDS. Oh well. 624249085Sadrian */ 625249085Sadrian memset(bf->bf_desc, '\0', sc->sc_rx_statuslen); 626249085Sadrian 627249085Sadrian /* 628238317Sadrian * Create DMA mapping. 629238317Sadrian */ 630238317Sadrian error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, 631238317Sadrian bf->bf_dmamap, m, bf->bf_segs, &bf->bf_nseg, BUS_DMA_NOWAIT); 632249085Sadrian 633238317Sadrian if (error != 0) { 634238317Sadrian device_printf(sc->sc_dev, "%s: failed; error=%d\n", 635238317Sadrian __func__, 636238317Sadrian error); 637238317Sadrian m_freem(m); 638238317Sadrian return (error); 639238317Sadrian } 640238317Sadrian 641238317Sadrian /* 642249085Sadrian * Set daddr to the physical mapping page. 643238317Sadrian */ 644238317Sadrian bf->bf_daddr = bf->bf_segs[0].ds_addr; 645238317Sadrian 646238317Sadrian /* 647249085Sadrian * Prepare for the upcoming read. 648249085Sadrian * 649249085Sadrian * We need to both sync some data into the buffer (the zero'ed 650249085Sadrian * descriptor payload) and also prepare for the read that's going 651249085Sadrian * to occur. 652238317Sadrian */ 653249085Sadrian bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 654249085Sadrian BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 655238317Sadrian 656238317Sadrian /* Finish! */ 657238317Sadrian return (0); 658238055Sadrian} 659238055Sadrian 660249085Sadrian/* 661249085Sadrian * Allocate a RX buffer. 662249085Sadrian */ 663238317Sadrianstatic struct ath_buf * 664238317Sadrianath_edma_rxbuf_alloc(struct ath_softc *sc) 665238317Sadrian{ 666238317Sadrian struct ath_buf *bf; 667238317Sadrian int error; 668238317Sadrian 669238436Sadrian ATH_RX_LOCK_ASSERT(sc); 670238436Sadrian 671238317Sadrian /* Allocate buffer */ 672238317Sadrian bf = TAILQ_FIRST(&sc->sc_rxbuf); 673238317Sadrian /* XXX shouldn't happen upon startup? */ 674249085Sadrian if (bf == NULL) { 675249085Sadrian device_printf(sc->sc_dev, "%s: nothing on rxbuf?!\n", 676249085Sadrian __func__); 677238317Sadrian return (NULL); 678249085Sadrian } 679238317Sadrian 680238317Sadrian /* Remove it from the free list */ 681238317Sadrian TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list); 682238317Sadrian 683238317Sadrian /* Assign RX mbuf to it */ 684238317Sadrian error = ath_edma_rxbuf_init(sc, bf); 685238317Sadrian if (error != 0) { 686238317Sadrian device_printf(sc->sc_dev, 687238317Sadrian "%s: bf=%p, rxbuf alloc failed! error=%d\n", 688238317Sadrian __func__, 689238317Sadrian bf, 690238317Sadrian error); 691238317Sadrian TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); 692238317Sadrian return (NULL); 693238317Sadrian } 694238317Sadrian 695238317Sadrian return (bf); 696238317Sadrian} 697238317Sadrian 698238317Sadrianstatic void 699238317Sadrianath_edma_rxbuf_free(struct ath_softc *sc, struct ath_buf *bf) 700238317Sadrian{ 701238317Sadrian 702238436Sadrian ATH_RX_LOCK_ASSERT(sc); 703238436Sadrian 704248984Sadrian /* 705248984Sadrian * Only unload the frame if we haven't consumed 706248984Sadrian * the mbuf via ath_rx_pkt(). 707248984Sadrian */ 708238317Sadrian if (bf->bf_m) { 709248984Sadrian bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 710238317Sadrian m_freem(bf->bf_m); 711238317Sadrian bf->bf_m = NULL; 712238317Sadrian } 713238317Sadrian 714238317Sadrian /* XXX lock? */ 715238317Sadrian TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); 716238317Sadrian} 717238317Sadrian 718238317Sadrian/* 719238317Sadrian * Allocate up to 'n' entries and push them onto the hardware FIFO. 720238317Sadrian * 721238317Sadrian * Return how many entries were successfully pushed onto the 722238317Sadrian * FIFO. 723238317Sadrian */ 724238317Sadrianstatic int 725238317Sadrianath_edma_rxfifo_alloc(struct ath_softc *sc, HAL_RX_QUEUE qtype, int nbufs) 726238317Sadrian{ 727238317Sadrian struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; 728238317Sadrian struct ath_buf *bf; 729238317Sadrian int i; 730238317Sadrian 731238436Sadrian ATH_RX_LOCK_ASSERT(sc); 732238436Sadrian 733238317Sadrian /* 734238317Sadrian * Allocate buffers until the FIFO is full or nbufs is reached. 735238317Sadrian */ 736238317Sadrian for (i = 0; i < nbufs && re->m_fifo_depth < re->m_fifolen; i++) { 737238317Sadrian /* Ensure the FIFO is already blank, complain loudly! */ 738238317Sadrian if (re->m_fifo[re->m_fifo_tail] != NULL) { 739238317Sadrian device_printf(sc->sc_dev, 740238317Sadrian "%s: Q%d: fifo[%d] != NULL (%p)\n", 741238317Sadrian __func__, 742238317Sadrian qtype, 743238317Sadrian re->m_fifo_tail, 744238317Sadrian re->m_fifo[re->m_fifo_tail]); 745238317Sadrian 746238317Sadrian /* Free the slot */ 747238317Sadrian ath_edma_rxbuf_free(sc, re->m_fifo[re->m_fifo_tail]); 748238317Sadrian re->m_fifo_depth--; 749238317Sadrian /* XXX check it's not < 0 */ 750238317Sadrian re->m_fifo[re->m_fifo_tail] = NULL; 751238317Sadrian } 752238317Sadrian 753238317Sadrian bf = ath_edma_rxbuf_alloc(sc); 754238317Sadrian /* XXX should ensure the FIFO is not NULL? */ 755238317Sadrian if (bf == NULL) { 756248450Sadrian device_printf(sc->sc_dev, 757248450Sadrian "%s: Q%d: alloc failed: i=%d, nbufs=%d?\n", 758238317Sadrian __func__, 759248450Sadrian qtype, 760248450Sadrian i, 761248450Sadrian nbufs); 762238317Sadrian break; 763238317Sadrian } 764238317Sadrian 765238317Sadrian re->m_fifo[re->m_fifo_tail] = bf; 766238317Sadrian 767238317Sadrian /* Write to the RX FIFO */ 768249085Sadrian DPRINTF(sc, ATH_DEBUG_EDMA_RX, 769249085Sadrian "%s: Q%d: putrxbuf=%p (0x%jx)\n", 770238317Sadrian __func__, 771238317Sadrian qtype, 772249085Sadrian bf->bf_desc, 773249085Sadrian (uintmax_t) bf->bf_daddr); 774238317Sadrian ath_hal_putrxbuf(sc->sc_ah, bf->bf_daddr, qtype); 775238317Sadrian 776238317Sadrian re->m_fifo_depth++; 777238317Sadrian INCR(re->m_fifo_tail, re->m_fifolen); 778238317Sadrian } 779238317Sadrian 780238317Sadrian /* 781238317Sadrian * Return how many were allocated. 782238317Sadrian */ 783238317Sadrian DPRINTF(sc, ATH_DEBUG_EDMA_RX, "%s: Q%d: nbufs=%d, nalloced=%d\n", 784238317Sadrian __func__, 785238317Sadrian qtype, 786238317Sadrian nbufs, 787238317Sadrian i); 788238317Sadrian return (i); 789238317Sadrian} 790238317Sadrian 791238317Sadrianstatic int 792238317Sadrianath_edma_rxfifo_flush(struct ath_softc *sc, HAL_RX_QUEUE qtype) 793238317Sadrian{ 794238317Sadrian struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; 795238317Sadrian int i; 796238317Sadrian 797238436Sadrian ATH_RX_LOCK_ASSERT(sc); 798238436Sadrian 799238317Sadrian for (i = 0; i < re->m_fifolen; i++) { 800238317Sadrian if (re->m_fifo[i] != NULL) { 801238350Sjhb#ifdef ATH_DEBUG 802238317Sadrian struct ath_buf *bf = re->m_fifo[i]; 803238350Sjhb 804238317Sadrian if (sc->sc_debug & ATH_DEBUG_RECV_DESC) 805238317Sadrian ath_printrxbuf(sc, bf, 0, HAL_OK); 806238317Sadrian#endif 807238317Sadrian ath_edma_rxbuf_free(sc, re->m_fifo[i]); 808238317Sadrian re->m_fifo[i] = NULL; 809238317Sadrian re->m_fifo_depth--; 810238317Sadrian } 811238317Sadrian } 812238317Sadrian 813238317Sadrian if (re->m_rxpending != NULL) { 814238317Sadrian m_freem(re->m_rxpending); 815238317Sadrian re->m_rxpending = NULL; 816238317Sadrian } 817238317Sadrian re->m_fifo_head = re->m_fifo_tail = re->m_fifo_depth = 0; 818238317Sadrian 819238317Sadrian return (0); 820238317Sadrian} 821238317Sadrian 822238317Sadrian/* 823238317Sadrian * Setup the initial RX FIFO structure. 824238317Sadrian */ 825238317Sadrianstatic int 826238317Sadrianath_edma_setup_rxfifo(struct ath_softc *sc, HAL_RX_QUEUE qtype) 827238317Sadrian{ 828238317Sadrian struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; 829238317Sadrian 830238436Sadrian ATH_RX_LOCK_ASSERT(sc); 831238436Sadrian 832238317Sadrian if (! ath_hal_getrxfifodepth(sc->sc_ah, qtype, &re->m_fifolen)) { 833238317Sadrian device_printf(sc->sc_dev, "%s: qtype=%d, failed\n", 834238317Sadrian __func__, 835238317Sadrian qtype); 836238317Sadrian return (-EINVAL); 837238317Sadrian } 838238317Sadrian device_printf(sc->sc_dev, "%s: type=%d, FIFO depth = %d entries\n", 839238317Sadrian __func__, 840238317Sadrian qtype, 841238317Sadrian re->m_fifolen); 842238317Sadrian 843238317Sadrian /* Allocate ath_buf FIFO array, pre-zero'ed */ 844238317Sadrian re->m_fifo = malloc(sizeof(struct ath_buf *) * re->m_fifolen, 845238317Sadrian M_ATHDEV, 846238317Sadrian M_NOWAIT | M_ZERO); 847238317Sadrian if (re->m_fifo == NULL) { 848238317Sadrian device_printf(sc->sc_dev, "%s: malloc failed\n", 849238317Sadrian __func__); 850238317Sadrian return (-ENOMEM); 851238317Sadrian } 852238317Sadrian 853238317Sadrian /* 854238317Sadrian * Set initial "empty" state. 855238317Sadrian */ 856238317Sadrian re->m_rxpending = NULL; 857238317Sadrian re->m_fifo_head = re->m_fifo_tail = re->m_fifo_depth = 0; 858238317Sadrian 859238317Sadrian return (0); 860238317Sadrian} 861238317Sadrian 862238317Sadrianstatic int 863238317Sadrianath_edma_rxfifo_free(struct ath_softc *sc, HAL_RX_QUEUE qtype) 864238317Sadrian{ 865238317Sadrian struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; 866238317Sadrian 867238317Sadrian device_printf(sc->sc_dev, "%s: called; qtype=%d\n", 868238317Sadrian __func__, 869238317Sadrian qtype); 870238317Sadrian 871238317Sadrian free(re->m_fifo, M_ATHDEV); 872238317Sadrian 873238317Sadrian return (0); 874238317Sadrian} 875238317Sadrian 876238317Sadrianstatic int 877238317Sadrianath_edma_dma_rxsetup(struct ath_softc *sc) 878238317Sadrian{ 879238317Sadrian int error; 880238317Sadrian 881238432Sadrian /* 882238432Sadrian * Create RX DMA tag and buffers. 883238432Sadrian */ 884238432Sadrian error = ath_descdma_setup_rx_edma(sc, &sc->sc_rxdma, &sc->sc_rxbuf, 885238432Sadrian "rx", ath_rxbuf, sc->sc_rx_statuslen); 886238317Sadrian if (error != 0) 887238317Sadrian return error; 888238317Sadrian 889238436Sadrian ATH_RX_LOCK(sc); 890238317Sadrian (void) ath_edma_setup_rxfifo(sc, HAL_RX_QUEUE_HP); 891238317Sadrian (void) ath_edma_setup_rxfifo(sc, HAL_RX_QUEUE_LP); 892238436Sadrian ATH_RX_UNLOCK(sc); 893238317Sadrian 894238317Sadrian return (0); 895238317Sadrian} 896238317Sadrian 897238317Sadrianstatic int 898238317Sadrianath_edma_dma_rxteardown(struct ath_softc *sc) 899238317Sadrian{ 900238317Sadrian 901238436Sadrian ATH_RX_LOCK(sc); 902248529Sadrian ath_edma_flush_deferred_queue(sc); 903238317Sadrian ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_HP); 904238317Sadrian ath_edma_rxfifo_free(sc, HAL_RX_QUEUE_HP); 905238317Sadrian 906238317Sadrian ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_LP); 907238317Sadrian ath_edma_rxfifo_free(sc, HAL_RX_QUEUE_LP); 908238436Sadrian ATH_RX_UNLOCK(sc); 909238317Sadrian 910238317Sadrian /* Free RX ath_buf */ 911238317Sadrian /* Free RX DMA tag */ 912238317Sadrian if (sc->sc_rxdma.dd_desc_len != 0) 913238317Sadrian ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 914238317Sadrian 915238317Sadrian return (0); 916238317Sadrian} 917238317Sadrian 918238055Sadrianvoid 919238055Sadrianath_recv_setup_edma(struct ath_softc *sc) 920238055Sadrian{ 921238055Sadrian 922238317Sadrian /* Set buffer size to 4k */ 923238317Sadrian sc->sc_edma_bufsize = 4096; 924238317Sadrian 925238317Sadrian /* Fetch EDMA field and buffer sizes */ 926238317Sadrian (void) ath_hal_getrxstatuslen(sc->sc_ah, &sc->sc_rx_statuslen); 927238317Sadrian 928238432Sadrian /* Configure the hardware with the RX buffer size */ 929238432Sadrian (void) ath_hal_setrxbufsize(sc->sc_ah, sc->sc_edma_bufsize - 930238432Sadrian sc->sc_rx_statuslen); 931238432Sadrian 932238317Sadrian device_printf(sc->sc_dev, "RX status length: %d\n", 933238317Sadrian sc->sc_rx_statuslen); 934238710Sadrian device_printf(sc->sc_dev, "RX buffer size: %d\n", 935238317Sadrian sc->sc_edma_bufsize); 936238317Sadrian 937238055Sadrian sc->sc_rx.recv_stop = ath_edma_stoprecv; 938238055Sadrian sc->sc_rx.recv_start = ath_edma_startrecv; 939238055Sadrian sc->sc_rx.recv_flush = ath_edma_recv_flush; 940238055Sadrian sc->sc_rx.recv_tasklet = ath_edma_recv_tasklet; 941238055Sadrian sc->sc_rx.recv_rxbuf_init = ath_edma_rxbuf_init; 942238317Sadrian 943238317Sadrian sc->sc_rx.recv_setup = ath_edma_dma_rxsetup; 944238317Sadrian sc->sc_rx.recv_teardown = ath_edma_dma_rxteardown; 945248529Sadrian 946248529Sadrian sc->sc_rx.recv_sched = ath_edma_recv_sched; 947248529Sadrian sc->sc_rx.recv_sched_queue = ath_edma_recv_sched_queue; 948238055Sadrian} 949