Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 Mar 2012 06:15:21 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r232912 - head/sys/mips/atheros
Message-ID:  <201203130615.q2D6FLso018634@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203130615.q2D6FLso018634>