From owner-svn-src-head@FreeBSD.ORG Tue Mar 13 06:15:21 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 65D9C106566C; Tue, 13 Mar 2012 06:15:21 +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 46ECA8FC14; Tue, 13 Mar 2012 06:15:21 +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 q2D6FLmn018636; Tue, 13 Mar 2012 06:15:21 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q2D6FLso018634; Tue, 13 Mar 2012 06:15:21 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201203130615.q2D6FLso018634@svn.freebsd.org> From: Adrian Chadd Date: Tue, 13 Mar 2012 06:15:21 +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: r232912 - head/sys/mips/atheros X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 13 Mar 2012 06:15:21 -0000 Author: adrian Date: Tue Mar 13 06:15:20 2012 New Revision: 232912 URL: http://svn.freebsd.org/changeset/base/232912 Log: Correctly (I hope) deallocate the if_arge RX buffer ring on arge_stop(). I had some interesting hangs until I realised I should try flushing the DDR FIFO register and lo and behold, hangs stopped occuring. I've put in a few DDR flushes here and there in case people decide to reuse some of these functions. It's very very likely they're almost all superflous. To test: * Connect to a network with a _lot_ of broadcast traffic * Do this: # while true; do ifconfig arge0 down; ifconfig arge0 up; done This fixes the mbuf exhaustion that has been reported when the interface state flaps up/down. Modified: head/sys/mips/atheros/if_arge.c Modified: head/sys/mips/atheros/if_arge.c ============================================================================== --- head/sys/mips/atheros/if_arge.c Tue Mar 13 05:21:14 2012 (r232911) +++ head/sys/mips/atheros/if_arge.c Tue Mar 13 06:15:20 2012 (r232912) @@ -118,6 +118,7 @@ static int arge_probe(device_t); static void arge_reset_dma(struct arge_softc *); static int arge_resume(device_t); static int arge_rx_ring_init(struct arge_softc *); +static void arge_rx_ring_free(struct arge_softc *sc); static int arge_tx_ring_init(struct arge_softc *); #ifdef DEVICE_POLLING static int arge_poll(struct ifnet *, enum poll_cmd, int); @@ -807,6 +808,12 @@ arge_reset_dma(struct arge_softc *sc) DMA_RX_STATUS_BUS_ERROR | DMA_RX_STATUS_OVERFLOW); ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR | DMA_TX_STATUS_UNDERRUN); + + /* + * Force a DDR flush so any pending data is properly + * flushed to RAM before underlying buffers are freed. + */ + arge_flush_ddr(sc); } @@ -1083,6 +1090,10 @@ arge_stop(struct arge_softc *sc) ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); arge_reset_dma(sc); + + /* Flush FIFO and free any existing mbufs */ + arge_flush_ddr(sc); + arge_rx_ring_free(sc); } @@ -1531,6 +1542,12 @@ arge_rx_ring_init(struct arge_softc *sc) bzero(rd->arge_rx_ring, sizeof(rd->arge_rx_ring)); for (i = 0; i < ARGE_RX_RING_COUNT; i++) { rxd = &sc->arge_cdata.arge_rxdesc[i]; + if (rxd->rx_m != NULL) { + device_printf(sc->arge_dev, + "%s: ring[%d] rx_m wasn't free?\n", + __func__, + i); + } rxd->rx_m = NULL; rxd->desc = &rd->arge_rx_ring[i]; if (i == ARGE_RX_RING_COUNT - 1) @@ -1551,6 +1568,32 @@ arge_rx_ring_init(struct arge_softc *sc) } /* + * Free all the buffers in the RX ring. + * + * TODO: ensure that DMA is disabled and no pending DMA + * is lurking in the FIFO. + */ +static void +arge_rx_ring_free(struct arge_softc *sc) +{ + int i; + struct arge_rxdesc *rxd; + + ARGE_LOCK_ASSERT(sc); + + for (i = 0; i < ARGE_RX_RING_COUNT; i++) { + rxd = &sc->arge_cdata.arge_rxdesc[i]; + /* Unmap the mbuf */ + if (rxd->rx_m != NULL) { + bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, + rxd->rx_dmamap); + m_free(rxd->rx_m); + rxd->rx_m = NULL; + } + } +} + +/* * Initialize an RX descriptor and attach an MBUF cluster. */ static int