svn commit: r211974 - user/nwhitehorn/ps3/powerpc/ps3

Nathan Whitehorn nwhitehorn at FreeBSD.org
Sun Aug 29 21:05:35 UTC 2010


Author: nwhitehorn
Date: Sun Aug 29 21:05:34 2010
New Revision: 211974
URL: http://svn.freebsd.org/changeset/base/211974

Log:
  Fix a horrible memory leak in glc(4) where no TX buffers were ever freed.
  Performance is still bad (max 4.5 MB a second, so 40% wirespeed), but I
  can live with that.

Modified:
  user/nwhitehorn/ps3/powerpc/ps3/if_glc.c

Modified: user/nwhitehorn/ps3/powerpc/ps3/if_glc.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/if_glc.c	Sun Aug 29 20:53:24 2010	(r211973)
+++ user/nwhitehorn/ps3/powerpc/ps3/if_glc.c	Sun Aug 29 21:05:34 2010	(r211974)
@@ -126,7 +126,8 @@ glc_attach(device_t dev) 
 
 	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
 	    MTX_DEF);
-	sc->next_txdma_slot = sc->first_used_txdma_slot = 0;
+	sc->next_txdma_slot = 0;
+	sc->first_used_txdma_slot = -1;
 
 	/*
 	 * Shut down existing tasks.
@@ -333,14 +334,16 @@ static void
 glc_start_locked(struct ifnet *ifp)
 {
 	struct glc_softc *sc = ifp->if_softc;
-	struct glc_txsoft *txs;
 	bus_addr_t first, pktdesc;
-	int i, kickstart;
+	int kickstart = 0;
 	struct mbuf *mb_head;
 
 	mtx_assert(&sc->sc_mtx, MA_OWNED);
 	first = 0;
 
+	if (STAILQ_EMPTY(&sc->sc_txdirtyq))
+		kickstart = 1;
+
 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
 		IFQ_DRV_DEQUEUE(&ifp->if_snd, mb_head);
 
@@ -366,23 +369,8 @@ glc_start_locked(struct ifnet *ifp)
 	bus_dmamap_sync(sc->sc_dmadesc_tag, sc->sc_txdmadesc_map,
 	    BUS_DMASYNC_PREREAD);
 
+	/* XXX: kickstart always until problems are sorted out */
 	kickstart = 1;
-	STAILQ_FOREACH(txs, &sc->sc_txdirtyq, txs_q) {
-		for (i = txs->txs_firstdesc;
-		     i != (txs->txs_lastdesc+1) % GLC_MAX_TX_PACKETS;
-		     i = (i + 1) % GLC_MAX_TX_PACKETS) {
-			/*
-			 * Check if any segments are currently being processed.
-			 * If so, the DMA engine will pick up the bits we
-			 * added eventually, otherwise restart DMA
-			 */
-
-			if (sc->sc_txdmadesc[i].cmd_stat & GELIC_DESCR_OWNED) {
-				kickstart = 0;
-				break;
-			}
-		}
-	}
 
 	if (kickstart && first != 0) {
 		lv1_net_stop_tx_dma(sc->sc_bus, sc->sc_dev, 0);
@@ -505,6 +493,10 @@ glc_encap(struct glc_softc *sc, struct m
 	int nsegs = 16;
 	int err = 0;
 
+	/* Check if the ring buffer is full */
+	if (sc->next_txdma_slot == sc->first_used_txdma_slot)
+		return (-1);
+
 	/* Max number of segments is the number of free DMA slots */
 	if (sc->next_txdma_slot >= sc->first_used_txdma_slot)
 		nsegs = 128 - sc->next_txdma_slot + sc->first_used_txdma_slot;
@@ -578,16 +570,19 @@ glc_encap(struct glc_softc *sc, struct m
 		idx = (idx + 1) % GLC_MAX_TX_PACKETS;
 	}
 	sc->next_txdma_slot = idx;
-
-	bus_dmamap_sync(sc->sc_txdma_tag, txs->txs_dmamap,
-	    BUS_DMASYNC_PREWRITE);
-
 	idx = (txs->txs_firstdesc - 1) % GLC_MAX_TX_PACKETS;
 	sc->sc_txdmadesc[idx].next = firstslotphys;
 
+	if (sc->first_used_txdma_slot < 0)
+		sc->first_used_txdma_slot = txs->txs_firstdesc;
+
 	bus_dmamap_sync(sc->sc_txdma_tag, txs->txs_dmamap,
 	    BUS_DMASYNC_PREWRITE);
 
+	STAILQ_REMOVE_HEAD(&sc->sc_txfreeq, txs_q);
+	STAILQ_INSERT_TAIL(&sc->sc_txdirtyq, txs, txs_q);
+	txs->txs_mbuf = *m_head;
+
 	if (pktdesc != NULL)
 		*pktdesc = firstslotphys;
 
@@ -653,7 +648,7 @@ glc_txintr(struct glc_softc *sc)
 
 	while ((txs = STAILQ_FIRST(&sc->sc_txdirtyq)) != NULL) {
 		if (sc->sc_txdmadesc[txs->txs_lastdesc].cmd_stat
-		    != GELIC_CMDSTAT_DMA_DONE)
+		    & GELIC_DESCR_OWNED)
 			break;
 
 		STAILQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q);
@@ -670,6 +665,11 @@ glc_txintr(struct glc_softc *sc)
 		progress = 1;
 	}
 
+	if (txs != NULL)
+		sc->first_used_txdma_slot = txs->txs_firstdesc;
+	else
+		sc->first_used_txdma_slot = -1;
+
 	if (progress) {
 		/*
 		 * We freed some descriptors, so reset IFF_DRV_OACTIVE


More information about the svn-src-user mailing list