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.
This commit is contained in:
Adrian Chadd 2012-03-13 06:15:20 +00:00
parent 505a01e936
commit eeaef4bae5

View File

@ -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)
@ -1550,6 +1567,32 @@ arge_rx_ring_init(struct arge_softc *sc)
return (0);
}
/*
* 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.
*/