Subject: Re: nfe(4) hardware checksum support
To: None <jmarin@embedtronics.fi>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: tech-net
Date: 01/26/2007 00:01:26
jmarin@embedtronics.fi wrote:

> There seems to be no problem under regular use - but when I try to edit
> video files located on a remote machine, the problems begin.

How about the attached patch?
(though I can't test it on so heavy load)
---
Izumi Tsutsui


Index: if_nfe.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_nfe.c,v
retrieving revision 1.13
diff -u -r1.13 if_nfe.c
--- if_nfe.c	9 Jan 2007 10:29:27 -0000	1.13
+++ if_nfe.c	25 Jan 2007 14:59:48 -0000
@@ -490,36 +490,50 @@
 	struct nfe_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 	uint32_t r;
+	int handled;
 
-	if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0)
-		return 0;	/* not for us */
-	NFE_WRITE(sc, NFE_IRQ_STATUS, r);
+	if ((ifp->if_flags & IFF_UP) == 0)
+		return 0;
 
-	DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r));
+	handled = 0;
 
 	NFE_WRITE(sc, NFE_IRQ_MASK, 0);
 
-	if (r & NFE_IRQ_LINK) {
-		NFE_READ(sc, NFE_PHY_STATUS);
-		NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
-		DPRINTF(("%s: link state changed\n", sc->sc_dev.dv_xname));
-	}
-
-	if (ifp->if_flags & IFF_RUNNING) {
-		/* check Rx ring */
-		nfe_rxeof(sc);
+	for (;;) {
+		r = NFE_READ(sc, NFE_IRQ_STATUS);
+		if ((r & NFE_IRQ_WANTED) == 0)
+			break;
 
-		/* check Tx ring */
-		nfe_txeof(sc);
+		NFE_WRITE(sc, NFE_IRQ_STATUS, r);
+		handled = 1;
+		DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r));
+
+		if ((r & (NFE_IRQ_RXERR | NFE_IRQ_RX_NOBUF | NFE_IRQ_RX))
+		    != 0) {
+			/* check Rx ring */
+			nfe_rxeof(sc);
+		}
+
+		if ((r & (NFE_IRQ_TXERR | NFE_IRQ_TXERR2 | NFE_IRQ_TX_DONE))
+		    != 0) {
+			/* check Tx ring */
+			nfe_txeof(sc);
+		}
+
+		if ((r & NFE_IRQ_LINK) != 0) {
+			NFE_READ(sc, NFE_PHY_STATUS);
+			NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
+			DPRINTF(("%s: link state changed\n",
+			    sc->sc_dev.dv_xname));
+		}
 	}
 
 	NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED);
 
-	if (ifp->if_flags & IFF_RUNNING &&
-	    !IF_IS_EMPTY(&ifp->if_snd))
+	if (handled && !IF_IS_EMPTY(&ifp->if_snd))
 		nfe_start(ifp);
 
-	return 1;
+	return handled;
 }
 
 int
@@ -692,32 +706,34 @@
 	struct mbuf *m, *mnew;
 	bus_addr_t physaddr;
 	uint16_t flags;
-	int error, len;
+	int error, len, i;
 
 	desc32 = NULL;
 	desc64 = NULL;
-	for (;;) {
-		data = &sc->rxq.data[sc->rxq.cur];
+	for (i = sc->rxq.cur;; i = NFE_RX_NEXTDESC(i)) {
+		data = &sc->rxq.data[i];
 
 		if (sc->sc_flags & NFE_40BIT_ADDR) {
-			desc64 = &sc->rxq.desc64[sc->rxq.cur];
-			nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD);
+			desc64 = &sc->rxq.desc64[i];
+			nfe_rxdesc64_sync(sc, desc64,
+			    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 
 			flags = le16toh(desc64->flags);
 			len = le16toh(desc64->length) & 0x3fff;
 		} else {
-			desc32 = &sc->rxq.desc32[sc->rxq.cur];
-			nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD);
+			desc32 = &sc->rxq.desc32[i];
+			nfe_rxdesc32_sync(sc, desc32,
+			    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 
 			flags = le16toh(desc32->flags);
 			len = le16toh(desc32->length) & 0x3fff;
 		}
 
-		if (flags & NFE_RX_READY)
+		if ((flags & NFE_RX_READY) != 0)
 			break;
 
 		if ((sc->sc_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
-			if (!(flags & NFE_RX_VALID_V1))
+			if ((flags & NFE_RX_VALID_V1) == 0)
 				goto skip;
 
 			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
@@ -725,7 +741,7 @@
 				len--;	/* fix buffer length */
 			}
 		} else {
-			if (!(flags & NFE_RX_VALID_V2))
+			if ((flags & NFE_RX_VALID_V2) == 0)
 				goto skip;
 
 			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
@@ -767,7 +783,7 @@
 			physaddr = jbuf->physaddr;
 		} else {
 			MCLGET(mnew, M_DONTWAIT);
-			if (!(mnew->m_flags & M_EXT)) {
+			if ((mnew->m_flags & M_EXT) == 0) {
 				m_freem(mnew);
 				ifp->if_ierrors++;
 				goto skip;
@@ -777,15 +793,14 @@
 			    data->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
 			bus_dmamap_unload(sc->sc_dmat, data->map);
 
-			error = bus_dmamap_load(sc->sc_dmat, data->map,
-			    mtod(mnew, void *), MCLBYTES, NULL,
-			    BUS_DMA_READ | BUS_DMA_NOWAIT);
+			error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map,
+			    mnew, BUS_DMA_READ | BUS_DMA_NOWAIT);
 			if (error != 0) {
 				m_freem(mnew);
 
 				/* try to reload the old mbuf */
-				error = bus_dmamap_load(sc->sc_dmat, data->map,
-				    mtod(data->m, void *), MCLBYTES, NULL,
+				error = bus_dmamap_load_mbuf(sc->sc_dmat,
+				    data->map, data->m,
 				    BUS_DMA_READ | BUS_DMA_NOWAIT);
 				if (error != 0) {
 					/* very unlikely that it will fail.. */
@@ -852,20 +867,23 @@
 			desc32->physaddr = htole32(physaddr);
 		}
 
-skip:		if (sc->sc_flags & NFE_40BIT_ADDR) {
+ skip:
+		if (sc->sc_flags & NFE_40BIT_ADDR) {
 			desc64->length = htole16(sc->rxq.bufsz);
 			desc64->flags = htole16(NFE_RX_READY);
 
-			nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE);
+			nfe_rxdesc64_sync(sc, desc64,
+			    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
 		} else {
 			desc32->length = htole16(sc->rxq.bufsz);
 			desc32->flags = htole16(NFE_RX_READY);
 
-			nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE);
+			nfe_rxdesc32_sync(sc, desc32,
+			    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
 		}
-
-		sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT;
 	}
+	/* update current RX pointer */
+	sc->rxq.cur = i;
 }
 
 void
@@ -875,29 +893,35 @@
 	struct nfe_desc32 *desc32;
 	struct nfe_desc64 *desc64;
 	struct nfe_tx_data *data = NULL;
+	int i;
 	uint16_t flags;
 
-	while (sc->txq.next != sc->txq.cur) {
+	for (i = sc->txq.next;
+	    sc->txq.queued > 0;
+	    i = NFE_TX_NEXTDESC(i), sc->txq.queued--) {
 		if (sc->sc_flags & NFE_40BIT_ADDR) {
-			desc64 = &sc->txq.desc64[sc->txq.next];
-			nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD);
+			desc64 = &sc->txq.desc64[i];
+			nfe_txdesc64_sync(sc, desc64,
+			    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 
 			flags = le16toh(desc64->flags);
 		} else {
-			desc32 = &sc->txq.desc32[sc->txq.next];
-			nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD);
+			desc32 = &sc->txq.desc32[i];
+			nfe_txdesc32_sync(sc, desc32,
+			    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 
 			flags = le16toh(desc32->flags);
 		}
 
-		if (flags & NFE_TX_VALID)
+		if ((flags & NFE_TX_VALID) != 0)
 			break;
 
-		data = &sc->txq.data[sc->txq.next];
+		data = &sc->txq.data[i];
 
 		if ((sc->sc_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
-			if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL)
-				goto skip;
+			if ((flags & NFE_TX_LASTFRAG_V1) == 0 &&
+			    data->m == NULL)
+				continue;
 
 			if ((flags & NFE_TX_ERROR_V1) != 0) {
 				printf("%s: tx v1 error 0x%04x\n",
@@ -906,8 +930,9 @@
 			} else
 				ifp->if_opackets++;
 		} else {
-			if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL)
-				goto skip;
+			if ((flags & NFE_TX_LASTFRAG_V2) == 0 &&
+			    data->m == NULL)
+				continue;
 
 			if ((flags & NFE_TX_ERROR_V2) != 0) {
 				printf("%s: tx v2 error 0x%04x\n",
@@ -920,7 +945,7 @@
 		if (data->m == NULL) {	/* should not get there */
 			printf("%s: last fragment bit w/o associated mbuf!\n",
 			    sc->sc_dev.dv_xname);
-			goto skip;
+			continue;
 		}
 
 		/* last fragment of the mbuf chain transmitted */
@@ -929,16 +954,18 @@
 		bus_dmamap_unload(sc->sc_dmat, data->active);
 		m_freem(data->m);
 		data->m = NULL;
+	}
 
-		ifp->if_timer = 0;
+	sc->txq.next = i;
 
-skip:		sc->txq.queued--;
-		sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT;
+	if (sc->txq.queued < NFE_TX_RING_COUNT) {
+		/* at least one slot freed */
+		ifp->if_flags &= ~IFF_OACTIVE;
 	}
 
-	if (data != NULL) {	/* at least one slot freed */
-		ifp->if_flags &= ~IFF_OACTIVE;
-		nfe_start(ifp);
+	if (sc->txq.queued == 0) {
+		/* all queued packets are sent */
+		ifp->if_timer = 0;
 	}
 }
 
@@ -1019,7 +1046,7 @@
 		flags |= NFE_TX_VALID;
 
 		sc->txq.queued++;
-		sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT;
+		sc->txq.cur = NFE_TX_NEXTDESC(sc->txq.cur);
 	}
 
 	/* the whole mbuf chain has been setup */
@@ -1064,7 +1091,7 @@
 nfe_start(struct ifnet *ifp)
 {
 	struct nfe_softc *sc = ifp->if_softc;
-	int old = sc->txq.cur;
+	int old = sc->txq.queued;
 	struct mbuf *m0;
 
 	for (;;) {
@@ -1085,21 +1112,23 @@
 			bpf_mtap(ifp->if_bpf, m0);
 #endif
 	}
-	if (sc->txq.cur == old)	/* nothing sent */
-		return;
 
-	if (sc->sc_flags & NFE_40BIT_ADDR)
-		nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE);
-	else
-		nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE);
-
-	/* kick Tx */
-	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
+	if (sc->txq.queued != old) {
+		/* packets are queued */
+		if (sc->sc_flags & NFE_40BIT_ADDR)
+			nfe_txdesc64_rsync(sc, old, sc->txq.cur,
+			    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+		else
+			nfe_txdesc32_rsync(sc, old, sc->txq.cur,
+			    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+		/* kick Tx */
+		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
 
-	/*
-	 * Set a timeout in case the chip goes out to lunch.
-	 */
-	ifp->if_timer = 5;
+		/*
+		 * Set a timeout in case the chip goes out to lunch.
+		 */
+		ifp->if_timer = 5;
+	}
 }
 
 void
Index: if_nfereg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_nfereg.h,v
retrieving revision 1.3
diff -u -r1.3 if_nfereg.h
--- if_nfereg.h	9 Jan 2007 10:29:27 -0000	1.3
+++ if_nfereg.h	25 Jan 2007 14:59:48 -0000
@@ -22,6 +22,9 @@
 #define NFE_RX_RING_COUNT	128
 #define NFE_TX_RING_COUNT	64
 
+#define NFE_RX_NEXTDESC(x)	(((x) + 1) & (NFE_RX_RING_COUNT - 1))
+#define NFE_TX_NEXTDESC(x)	(((x) + 1) & (NFE_TX_RING_COUNT - 1))
+
 #define	ETHER_ALIGN		2
 #define NFE_JBYTES		(ETHER_MAX_LEN_JUMBO + ETHER_ALIGN)
 #define NFE_JPOOL_COUNT		(NFE_RX_RING_COUNT + 64)