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 _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"