svn commit: r191142 - head/sys/dev/mge

Rafal Jaworowski raj at FreeBSD.org
Thu Apr 16 11:38:07 UTC 2009


Author: raj
Date: Thu Apr 16 11:38:06 2009
New Revision: 191142
URL: http://svn.freebsd.org/changeset/base/191142

Log:
  mge(4): fix two bugs, which were leading to crash/hang under very heavy
  network load.
  
  1. Leave the RX interrupt routine if there is no mbuf available.
  
  2. Properly initialize and track tx_desc_used_count counter so as not to
  leak mbuf while traversing used descriptors.
  
  Obtained from:	Semihalf

Modified:
  head/sys/dev/mge/if_mge.c

Modified: head/sys/dev/mge/if_mge.c
==============================================================================
--- head/sys/dev/mge/if_mge.c	Thu Apr 16 11:21:52 2009	(r191141)
+++ head/sys/dev/mge/if_mge.c	Thu Apr 16 11:38:06 2009	(r191142)
@@ -642,6 +642,7 @@ mge_attach(device_t dev)
 	sc->tx_desc_curr = 0;
 	sc->rx_desc_curr = 0;
 	sc->tx_desc_used_idx = 0;
+	sc->tx_desc_used_count = 0;
 
 	/* Configure defaults for interrupts coalescing */
 	sc->rx_ic_time = 768;
@@ -899,6 +900,7 @@ mge_init_locked(void *arg)
 	sc->tx_desc_curr = 0;
 	sc->rx_desc_curr = 0;
 	sc->tx_desc_used_idx = 0;
+	sc->tx_desc_used_count = 0;
 
 	/* Enable RX descriptors */
 	for (i = 0; i < MGE_RX_DESC_NUM; i++) {
@@ -1022,7 +1024,7 @@ mge_intr_rx_locked(struct mge_softc *sc,
 
 	MGE_RECEIVE_LOCK_ASSERT(sc);
 
-	while(count != 0) {
+	while (count != 0) {
 		dw = &sc->mge_rx_desc[sc->rx_desc_curr];
 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
 		    BUS_DMASYNC_POSTREAD);
@@ -1033,7 +1035,6 @@ mge_intr_rx_locked(struct mge_softc *sc,
 		if ((status & MGE_DMA_OWNED) != 0)
 			break;
 
-		sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM);
 		if (dw->mge_desc->byte_count &&
 		    ~(status & MGE_ERR_SUMMARY)) {
 
@@ -1044,6 +1045,10 @@ mge_intr_rx_locked(struct mge_softc *sc,
 			    dw->mge_desc->byte_count - ETHER_CRC_LEN,
 			    0, ifp, NULL);
 
+			if (mb == NULL)
+				/* Give up if no mbufs */
+				break;
+
 			mb->m_len -= 2;
 			mb->m_pkthdr.len -= 2;
 			mb->m_data += 2;
@@ -1058,6 +1063,7 @@ mge_intr_rx_locked(struct mge_softc *sc,
 
 		dw->mge_desc->byte_count = 0;
 		dw->mge_desc->cmd_status = MGE_RX_ENABLE_INT | MGE_DMA_OWNED;
+		sc->rx_desc_curr = (++sc->rx_desc_curr % MGE_RX_DESC_NUM);
 		bus_dmamap_sync(sc->mge_desc_dtag, dw->desc_dmap,
 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 
@@ -1514,7 +1520,8 @@ mge_stop(struct mge_softc *sc)
 	MGE_WRITE(sc, MGE_RX_QUEUE_CMD, MGE_DISABLE_RXQ_ALL);
 
 	/* Remove pending data from TX queue */
-	while (sc->tx_desc_used_idx < sc->tx_desc_curr) {
+	while (sc->tx_desc_used_idx != sc->tx_desc_curr &&
+	    sc->tx_desc_used_count) {
 		/* Get the descriptor */
 		dw = &sc->mge_tx_desc[sc->tx_desc_used_idx];
 		desc = dw->mge_desc;
@@ -1529,6 +1536,7 @@ mge_stop(struct mge_softc *sc)
 
 		sc->tx_desc_used_idx = (++sc->tx_desc_used_idx) %
 		    MGE_TX_DESC_NUM;
+		sc->tx_desc_used_count--;
 
 		bus_dmamap_sync(sc->mge_tx_dtag, dw->buffer_dmap,
 		    BUS_DMASYNC_POSTWRITE);


More information about the svn-src-head mailing list