svn commit: r232912 - head/sys/mips/atheros
Adrian Chadd
adrian at FreeBSD.org
Tue Mar 13 06:15:21 UTC 2012
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
More information about the svn-src-all
mailing list