From 0b59717b4baf96da3001d9037414a130b869c1fb Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sat, 14 Jul 2012 02:52:48 +0000 Subject: [PATCH] Change the RX EDMA path to first complete the FIFO, then re-populate it with fresh descriptors, before handling the frames. Wrap it all in the RX locks. Since the FIFO is very shallow (16 for HP, 128 for LP) it needs to be drained and replenished very quickly. Ideally, I'll eventually move this RX FIFO drain/fill into the interrupt handler, only deferring the actual frame completion. --- sys/dev/ath/if_ath_rx_edma.c | 90 +++++++++++++++++++++++++++--------- sys/dev/ath/if_athvar.h | 1 + 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/sys/dev/ath/if_ath_rx_edma.c b/sys/dev/ath/if_ath_rx_edma.c index 9ed3a91afa3d..78d4fdc51f79 100644 --- a/sys/dev/ath/if_ath_rx_edma.c +++ b/sys/dev/ath/if_ath_rx_edma.c @@ -156,6 +156,7 @@ ath_edma_stoprecv(struct ath_softc *sc, int dodelay) { struct ath_hal *ah = sc->sc_ah; + ATH_RX_LOCK(sc); ath_hal_stoppcurecv(ah); ath_hal_setrxfilter(ah, 0); ath_hal_stopdmarecv(ah); @@ -173,6 +174,7 @@ ath_edma_stoprecv(struct ath_softc *sc, int dodelay) m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending); sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL; } + ATH_RX_UNLOCK(sc); } /* @@ -187,6 +189,8 @@ ath_edma_reinit_fifo(struct ath_softc *sc, HAL_RX_QUEUE qtype) struct ath_buf *bf; int i, j; + ATH_RX_LOCK_ASSERT(sc); + i = re->m_fifo_head; for (j = 0; j < re->m_fifo_depth; j++) { bf = re->m_fifo[i]; @@ -221,6 +225,8 @@ ath_edma_startrecv(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; + ATH_RX_LOCK(sc); + /* Enable RX FIFO */ ath_hal_rxena(ah); @@ -266,6 +272,9 @@ ath_edma_startrecv(struct ath_softc *sc) ath_mode_init(sc); ath_hal_startpcurecv(ah); + + ATH_RX_UNLOCK(sc); + return (0); } @@ -300,16 +309,21 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, struct ath_desc *ds; struct ath_buf *bf; struct mbuf *m; - HAL_STATUS status; struct ath_hal *ah = sc->sc_ah; uint64_t tsf; int16_t nf; int ngood = 0; + ath_bufhead rxlist; + struct ath_buf *next; + + TAILQ_INIT(&rxlist); tsf = ath_hal_gettsf64(ah); nf = ath_hal_getchannoise(ah, sc->sc_curchan); sc->sc_stats.ast_rx_noise = nf; + ATH_RX_LOCK(sc); + do { bf = re->m_fifo[re->m_fifo_head]; /* This shouldn't occur! */ @@ -330,12 +344,13 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_POSTREAD); rs = &bf->bf_status.ds_rxstat; - status = ath_hal_rxprocdesc(ah, ds, bf->bf_daddr, NULL, rs); + bf->bf_rxstatus = ath_hal_rxprocdesc(ah, ds, bf->bf_daddr, + NULL, rs); #ifdef ATH_DEBUG if (sc->sc_debug & ATH_DEBUG_RECV_DESC) - ath_printrxbuf(sc, bf, 0, status == HAL_OK); + ath_printrxbuf(sc, bf, 0, bf->bf_rxstatus == HAL_OK); #endif - if (status == HAL_EINPROGRESS) + if (bf->bf_rxstatus == HAL_EINPROGRESS) break; /* @@ -349,21 +364,11 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, "%s: Q%d: completed!\n", __func__, qtype); /* - * Remove the FIFO entry! + * Remove the FIFO entry and place it on the completion + * queue. */ re->m_fifo[re->m_fifo_head] = NULL; - - /* - * Skip the RX descriptor status - start at the data offset - */ - m_adj(m, sc->sc_rx_statuslen); - - /* Handle the frame */ - if (ath_rx_pkt(sc, rs, status, tsf, nf, qtype, bf)) - ngood++; - - /* Free the buffer/mbuf */ - ath_edma_rxbuf_free(sc, bf); + TAILQ_INSERT_TAIL(&rxlist, bf, bf_list); /* Bump the descriptor FIFO stats */ INCR(re->m_fifo_head, re->m_fifolen); @@ -371,6 +376,36 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, /* XXX check it doesn't fall below 0 */ } while (re->m_fifo_depth > 0); + /* Append some more fresh frames to the FIFO */ + if (dosched) + ath_edma_rxfifo_alloc(sc, qtype, re->m_fifolen); + + ATH_RX_UNLOCK(sc); + + /* Handle the completed descriptors */ + TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) { + /* + * Skip the RX descriptor status - start at the data offset + */ + m_adj(bf->bf_m, sc->sc_rx_statuslen); + + /* Handle the frame */ + /* + * Note: this may or may not free bf->bf_m and sync/unmap + * the frame. + */ + if (ath_rx_pkt(sc, rs, bf->bf_rxstatus, tsf, nf, qtype, bf)) + ngood++; + } + + /* Free in one set, inside the lock */ + ATH_RX_LOCK(sc); + TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) { + /* Free the buffer/mbuf */ + ath_edma_rxbuf_free(sc, bf); + } + ATH_RX_UNLOCK(sc); + /* Handle resched and kickpcu appropriately */ ATH_PCU_LOCK(sc); if (dosched && sc->sc_kickpcu) { @@ -386,10 +421,6 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, } ATH_PCU_UNLOCK(sc); - /* Append some more fresh frames to the FIFO */ - if (dosched) - ath_edma_rxfifo_alloc(sc, qtype, re->m_fifolen); - return (ngood); } @@ -435,6 +466,8 @@ ath_edma_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) int error; int len; + ATH_RX_LOCK_ASSERT(sc); + // device_printf(sc->sc_dev, "%s: called; bf=%p\n", __func__, bf); m = m_getm(NULL, sc->sc_edma_bufsize, M_DONTWAIT, MT_DATA); @@ -498,6 +531,8 @@ ath_edma_rxbuf_alloc(struct ath_softc *sc) struct ath_buf *bf; int error; + ATH_RX_LOCK_ASSERT(sc); + /* Allocate buffer */ bf = TAILQ_FIRST(&sc->sc_rxbuf); /* XXX shouldn't happen upon startup? */ @@ -526,6 +561,9 @@ static void ath_edma_rxbuf_free(struct ath_softc *sc, struct ath_buf *bf) { + ATH_RX_LOCK_ASSERT(sc); + + /* We're doing this multiple times? */ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); if (bf->bf_m) { @@ -550,6 +588,8 @@ ath_edma_rxfifo_alloc(struct ath_softc *sc, HAL_RX_QUEUE qtype, int nbufs) struct ath_buf *bf; int i; + ATH_RX_LOCK_ASSERT(sc); + /* * Allocate buffers until the FIFO is full or nbufs is reached. */ @@ -616,6 +656,8 @@ ath_edma_rxfifo_flush(struct ath_softc *sc, HAL_RX_QUEUE qtype) struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; int i; + ATH_RX_LOCK_ASSERT(sc); + for (i = 0; i < re->m_fifolen; i++) { if (re->m_fifo[i] != NULL) { #ifdef ATH_DEBUG @@ -647,6 +689,8 @@ ath_edma_setup_rxfifo(struct ath_softc *sc, HAL_RX_QUEUE qtype) { struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; + ATH_RX_LOCK_ASSERT(sc); + if (! ath_hal_getrxfifodepth(sc->sc_ah, qtype, &re->m_fifolen)) { device_printf(sc->sc_dev, "%s: qtype=%d, failed\n", __func__, @@ -704,8 +748,10 @@ ath_edma_dma_rxsetup(struct ath_softc *sc) if (error != 0) return error; + ATH_RX_LOCK(sc); (void) ath_edma_setup_rxfifo(sc, HAL_RX_QUEUE_HP); (void) ath_edma_setup_rxfifo(sc, HAL_RX_QUEUE_LP); + ATH_RX_UNLOCK(sc); return (0); } @@ -716,11 +762,13 @@ ath_edma_dma_rxteardown(struct ath_softc *sc) device_printf(sc->sc_dev, "%s: called\n", __func__); + ATH_RX_LOCK(sc); ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_HP); ath_edma_rxfifo_free(sc, HAL_RX_QUEUE_HP); ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_LP); ath_edma_rxfifo_free(sc, HAL_RX_QUEUE_LP); + ATH_RX_UNLOCK(sc); /* Free RX ath_buf */ /* Free RX DMA tag */ diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 63bf3d413b78..4331ffaef3c1 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -189,6 +189,7 @@ struct ath_buf { TAILQ_ENTRY(ath_buf) bf_list; struct ath_buf * bf_next; /* next buffer in the aggregate */ int bf_nseg; + HAL_STATUS bf_rxstatus; uint16_t bf_flags; /* status flags (below) */ struct ath_desc *bf_desc; /* virtual addr of desc */ struct ath_desc_status bf_status; /* tx/rx status */