From owner-svn-src-all@FreeBSD.ORG Tue Jul 10 06:05:43 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3C299106566B; Tue, 10 Jul 2012 06:05:43 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 1CB868FC12; Tue, 10 Jul 2012 06:05:43 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q6A65g6L063599; Tue, 10 Jul 2012 06:05:42 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q6A65gWh063597; Tue, 10 Jul 2012 06:05:42 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201207100605.q6A65gWh063597@svn.freebsd.org> From: Adrian Chadd Date: Tue, 10 Jul 2012 06:05:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r238337 - head/sys/dev/ath X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 10 Jul 2012 06:05:43 -0000 Author: adrian Date: Tue Jul 10 06:05:42 2012 New Revision: 238337 URL: http://svn.freebsd.org/changeset/base/238337 Log: Add/fix EDMA RX behaviour. * For now, kickpcu should hopefully just do nothing - the PCU doesn't need 'kicking' for Osprey and later NICs. The PCU will just restart once the next FIFO entry is pushed in. * Teach "proc" about "dosched", so it can be used to just flush the FIFO contents without adding new FIFO entries. * .. and now, implement the RX "flush" routine. * Re-initialise the FIFO contents if the FIFO is empty (the DP is NULL.) When PCU RX is disabled (ie, writing RX_D to the RX configuration register) then the FIFO will be completely emptied. If the software FIFO is full, then no further descriptors are pushed into the FIFO and things stall. This all requires much, much more thorough stress testing. Modified: head/sys/dev/ath/if_ath_rx_edma.c Modified: head/sys/dev/ath/if_ath_rx_edma.c ============================================================================== --- head/sys/dev/ath/if_ath_rx_edma.c Tue Jul 10 05:45:13 2012 (r238336) +++ head/sys/dev/ath/if_ath_rx_edma.c Tue Jul 10 06:05:42 2012 (r238337) @@ -148,6 +148,8 @@ static int ath_edma_rxfifo_alloc(struct int nbufs); static int ath_edma_rxfifo_flush(struct ath_softc *sc, HAL_RX_QUEUE qtype); static void ath_edma_rxbuf_free(struct ath_softc *sc, struct ath_buf *bf); +static int ath_edma_recv_proc_queue(struct ath_softc *sc, + HAL_RX_QUEUE qtype, int dosched); static void ath_edma_stoprecv(struct ath_softc *sc, int dodelay) @@ -174,6 +176,34 @@ ath_edma_stoprecv(struct ath_softc *sc, } /* + * Re-initialise the FIFO given the current buffer contents. + * Specifically, walk from head -> tail, pushing the FIFO contents + * back into the FIFO. + */ +static void +ath_edma_reinit_fifo(struct ath_softc *sc, HAL_RX_QUEUE qtype) +{ + struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; + struct ath_buf *bf; + int i, j; + + i = re->m_fifo_head; + for (j = 0; j < re->m_fifo_depth; j++) { + bf = re->m_fifo[i]; + ath_hal_putrxbuf(sc->sc_ah, bf->bf_daddr, qtype); + INCR(i, re->m_fifolen); + } + + /* Ensure this worked out right */ + if (i != re->m_fifo_tail) { + device_printf(sc->sc_dev, "%s: i (%d) != tail! (%d)\n", + __func__, + i, + re->m_fifo_tail); + } +} + +/* * Start receive. * * XXX TODO: this needs to reallocate the FIFO entries when a reset @@ -189,9 +219,19 @@ ath_edma_startrecv(struct ath_softc *sc) ath_hal_rxena(ah); /* - * XXX write out a complete set of FIFO entries based on - * what's currently available. + * Entries should only be written out if the + * FIFO is empty. */ + if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_HP) == 0){ + DPRINTF(sc, ATH_DEBUG_EDMA_RX, + "%s: Re-initing HP FIFO\n", __func__); + ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_HP); + } + if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_LP) == 0) { + DPRINTF(sc, ATH_DEBUG_EDMA_RX, + "%s: Re-initing LP FIFO\n", __func__); + ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_LP); + } /* Add up to m_fifolen entries in each queue */ /* @@ -216,14 +256,8 @@ ath_edma_recv_flush(struct ath_softc *sc device_printf(sc->sc_dev, "%s: called\n", __func__); - /* - * XXX for now, free all descriptors. Later on, complete - * what can be completed! - */ -#if 0 - ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_HP); - ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_LP); -#endif + ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 0); + ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 0); } /* @@ -239,18 +273,19 @@ ath_edma_recv_flush(struct ath_softc *sc * "handle frames" in the RX tasklet. */ static int -ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype) +ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, + int dosched) { struct ath_rx_edma *re = &sc->sc_rxedma[qtype]; struct ath_rx_status *rs; struct ath_desc *ds; struct ath_buf *bf; - int n = 0; struct mbuf *m; HAL_STATUS status; struct ath_hal *ah = sc->sc_ah; uint64_t tsf; int16_t nf; + int ngood = 0; tsf = ath_hal_gettsf64(ah); nf = ath_hal_getchannoise(ah, sc->sc_curchan); @@ -305,7 +340,8 @@ ath_edma_recv_proc_queue(struct ath_soft m_adj(m, sc->sc_rx_statuslen); /* Handle the frame */ - (void) ath_rx_pkt(sc, rs, status, tsf, nf, qtype, bf); + if (ath_rx_pkt(sc, rs, status, tsf, nf, qtype, bf)) + ngood++; /* Free the buffer/mbuf */ ath_edma_rxbuf_free(sc, bf); @@ -317,11 +353,25 @@ ath_edma_recv_proc_queue(struct ath_soft } while (re->m_fifo_depth > 0); /* Handle resched and kickpcu appropriately */ + ATH_PCU_LOCK(sc); + if (dosched && sc->sc_kickpcu) { + CTR0(ATH_KTR_ERR, "ath_edma_recv_proc_queue(): kickpcu"); + device_printf(sc->sc_dev, "%s: handled %d descriptors\n", + __func__, ngood); + + /* + * XXX TODO: what should occur here? Just re-poke and + * re-enable the RX FIFO? + */ + sc->sc_kickpcu = 0; + } + ATH_PCU_UNLOCK(sc); /* Append some more fresh frames to the FIFO */ - ath_edma_rxfifo_alloc(sc, qtype, re->m_fifolen); + if (dosched) + ath_edma_rxfifo_alloc(sc, qtype, re->m_fifolen); - return (n); + return (ngood); } static void @@ -333,8 +383,17 @@ ath_edma_recv_tasklet(void *arg, int npe __func__, npending); - ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP); - ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP); + ATH_PCU_LOCK(sc); + if (sc->sc_inreset_cnt > 0) { + device_printf(sc->sc_dev, "%s: sc_inreset_cnt > 0; skipping\n", + __func__); + ATH_PCU_UNLOCK(sc); + return; + } + ATH_PCU_UNLOCK(sc); + + ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 1); + ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 1); } /*