Index: if_ste.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_ste.c,v
retrieving revision 1.25.2.2
diff -u -r1.25.2.2 if_ste.c
--- if_ste.c	22 Oct 2007 20:33:46 -0000	1.25.2.2
+++ if_ste.c	19 Jan 2013 10:22:49 -0000
@@ -45,6 +45,7 @@
 __KERNEL_RCSID(0, "$NetBSD: if_ste.c,v 1.25.2.2 2007/10/22 20:33:46 pavel Exp $");
 
 #include "bpfilter.h"
+#include "rnd.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -60,6 +61,10 @@
 
 #include <uvm/uvm_extern.h>		/* for PAGE_SIZE */
 
+#if NRND > 0
+#include <sys/rnd.h>
+#endif
+
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
@@ -169,6 +174,15 @@
 	uint16_t sc_IntEnable;		/* prototype IntEnable register */
 	uint16_t sc_MacCtrl0;		/* prototype MacCtrl0 register */
 	uint8_t	sc_ReceiveMode;		/* prototype ReceiveMode register */
+
+#define STE_USE_DFE580TX_FIX
+#ifdef STE_USE_DFE580TX_FIX
+	int	sc_dfe580tx;
+#endif
+
+#if NRND > 0
+	rndsource_element_t rnd_source;	/* random source */
+#endif
 };
 
 #define	STE_CDTXADDR(sc, x)	((sc)->sc_cddma + STE_CDTXOFF((x)))
@@ -331,6 +345,14 @@
 
 	printf(": %s\n", sp->ste_name);
 
+#ifdef STE_USE_DFE580TX_FIX
+	if (PCI_REVISION(pa->pa_class) >= 0x14) {
+		printf("%s: enable DFE-580TX fix\n",
+		    sc->sc_dev.dv_xname);
+		sc->sc_dfe580tx = 1;
+	}
+#endif
+
 	/*
 	 * Map the device.
 	 */
@@ -517,6 +539,10 @@
 	 */
 	if_attach(ifp);
 	ether_ifattach(ifp, enaddr);
+#if NRND > 0
+	rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
+		RND_TYPE_NET, 0);
+#endif
 
 	/*
 	 * Make sure the interface is shutdown during reboot.
@@ -646,6 +672,7 @@
 				    sc->sc_dev.dv_xname);
 				break;
 			}
+			MCLAIM(m, &sc->sc_ethercom.ec_tx_mowner);
 			if (m0->m_pkthdr.len > MHLEN) {
 				MCLGET(m, M_DONTWAIT);
 				if ((m->m_flags & M_EXT) == 0) {
@@ -760,13 +787,13 @@
 		if (bus_space_read_4(sc->sc_st, sc->sc_sh,
 		    STE_TxDMAListPtr) == 0) {
 			bus_space_write_4(sc->sc_st, sc->sc_sh,
-			    STE_DMACtrl, DC_TxDMAHalt);
+			    STE_DMACtrl, sc->sc_DMACtrl | DC_TxDMAHalt);
 			ste_dmahalt_wait(sc);
 			bus_space_write_4(sc->sc_st, sc->sc_sh,
 			    STE_TxDMAListPtr,
 			    STE_CDTXADDR(sc, STE_NEXTTX(olasttx)));
 			bus_space_write_4(sc->sc_st, sc->sc_sh,
-			    STE_DMACtrl, DC_TxDMAResume);
+			    STE_DMACtrl, sc->sc_DMACtrl | DC_TxDMAResume);
 		}
 
 		/* Set a watchdog timer in case the chip flakes out. */
@@ -784,12 +811,17 @@
 {
 	struct ste_softc *sc = ifp->if_softc;
 
-	printf("%s: device timeout\n", sc->sc_dev.dv_xname);
 	ifp->if_oerrors++;
 
+	/* in case interrupts were lost, try processing these */
 	ste_txintr(sc);
 	ste_rxintr(sc);
-	(void) ste_init(ifp);
+
+	/* if the timeout condition is still met, reset the chip */
+	if (sc->sc_txpending > 0) {
+		printf("%s: re-init\n", sc->sc_dev.dv_xname);
+		(void) ste_init(ifp);
+	}
 
 	/* Try to get more packets going. */
 	ste_start(ifp);
@@ -850,15 +882,20 @@
 	uint8_t txstat;
 	int wantinit;
 
-	if ((bus_space_read_2(sc->sc_st, sc->sc_sh, STE_IntStatus) &
-	     IS_InterruptStatus) == 0)
+	isr = bus_space_read_2(sc->sc_st, sc->sc_sh, STE_IntStatus);
+	if ((isr & IS_InterruptStatus) == 0)
 		return (0);
 
 	for (wantinit = 0; wantinit == 0;) {
-		isr = bus_space_read_2(sc->sc_st, sc->sc_sh, STE_IntStatusAck);
+		bus_space_write_2(sc->sc_st, sc->sc_sh, STE_IntStatus, isr);
 		if ((isr & sc->sc_IntEnable) == 0)
 			break;
 
+#if NRND > 0
+		if (RND_ENABLED(&sc->rnd_source))
+			rnd_add_uint32(&sc->rnd_source, isr);
+#endif
+
 		/* Receive interrupts. */
 		if (isr & IE_RxDMAComplete)
 			ste_rxintr(sc);
@@ -921,14 +958,15 @@
 			    sc->sc_dev.dv_xname);
 			wantinit = 1;
 		}
+
+		isr = bus_space_read_2(sc->sc_st, sc->sc_sh, STE_IntStatus);
+		if ((isr & IS_InterruptStatus) == 0)
+			break;
 	}
 
 	if (wantinit)
 		ste_init(ifp);
 
-	bus_space_write_2(sc->sc_st, sc->sc_sh, STE_IntEnable,
-	    sc->sc_IntEnable);
-
 	/* Try to get more packets going. */
 	ste_start(ifp);
 
@@ -946,10 +984,15 @@
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 	struct ste_descsoft *ds;
 	uint32_t control;
+	uint8_t frameid;
 	int i;
 
 	ifp->if_flags &= ~IFF_OACTIVE;
 
+#ifdef STE_USE_DFE580TX_FIX
+	frameid = bus_space_read_1(sc->sc_st, sc->sc_sh, STE_TxFrameId);
+#endif
+
 	/*
 	 * Go through our Tx list and free mbufs for those
 	 * frames which have been transmitted.
@@ -962,8 +1005,23 @@
 		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 
 		control = le32toh(sc->sc_txdescs[i].tfd_control);
+
+#ifdef STE_USE_DFE580TX_FIX
+		if (sc->sc_dfe580tx) {
+			uint8_t descid = control >> 2;
+			if ((descid == frameid) &&
+			    (control & TFD_TxDMAComplete) == 0)
+				break;
+			if (descid == STE_NEXTTX(frameid))
+				break;
+		} else {
+			if ((control & TFD_TxDMAComplete) == 0)
+				break;
+		}
+#else
 		if ((control & TFD_TxDMAComplete) == 0)
 			break;
+#endif
 
 		bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap,
 		    0, ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
@@ -1007,12 +1065,34 @@
 		if ((status & RFD_RxDMAComplete) == 0)
 			break;
 
+		if (status & RFD_RxDMAOverflow) {
+			printf("%s: RxDMAOverflow frame length = %d\n",
+				sc->sc_dev.dv_xname,
+				RFD_RxDMAFrameLen(status));
+		}
+
 		/*
 		 * If the packet had an error, simply recycle the
-		 * buffer.  Note, we count the error later in the
-		 * periodic stats update.
+		 * buffer.  Note, that these errors are not counted
+		 * in the periodic stats update.
 		 */
 		if (status & RFD_RxFrameError) {
+			ifp->if_ierrors++;
+			if (status & RFD_RxFIFOOverrun)
+				printf("%s: FIFO overflow\n",
+					sc->sc_dev.dv_xname);
+			if (status & RFD_RxRuntFrame)
+				printf("%s: received runt packet\n",
+					sc->sc_dev.dv_xname);
+			if (status & RFD_RxAlignmentError)
+				printf("%s: frame alignment error\n",
+					sc->sc_dev.dv_xname);
+			if (status & RFD_RxFCSError)
+				printf("%s: crc error\n",
+					sc->sc_dev.dv_xname);
+			if (status & RFD_RxOversizedFrame)
+				printf("%s: received giant packet\n",
+					sc->sc_dev.dv_xname);
 			STE_INIT_RXDESC(sc, i);
 			continue;
 		}
@@ -1042,6 +1122,7 @@
 			MGETHDR(m, M_DONTWAIT, MT_DATA);
 			if (m == NULL)
 				goto dropit;
+			MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner);
 			m->m_data += 2;
 			memcpy(mtod(m, caddr_t),
 			    mtod(ds->ds_mbuf, caddr_t), len);
@@ -1209,11 +1290,13 @@
 
 	bus_space_write_4(sc->sc_st, sc->sc_sh, STE_TxDMAListPtr, 0);
 	bus_space_write_2(sc->sc_st, sc->sc_sh, STE_MacCtrl1, MC1_TxEnable);
-	bus_space_write_4(sc->sc_st, sc->sc_sh, STE_DMACtrl, DC_TxDMAHalt);
+	bus_space_write_4(sc->sc_st, sc->sc_sh, STE_DMACtrl,
+		sc->sc_DMACtrl | DC_TxDMAHalt);
 	ste_dmahalt_wait(sc);
 	bus_space_write_4(sc->sc_st, sc->sc_sh, STE_TxDMAListPtr,
 	    STE_CDTXADDR(sc, id));
-	bus_space_write_4(sc->sc_st, sc->sc_sh, STE_DMACtrl, DC_TxDMAResume);
+	bus_space_write_4(sc->sc_st, sc->sc_sh, STE_DMACtrl,
+		sc->sc_DMACtrl | DC_TxDMAResume);
 }
 
 /*
@@ -1323,6 +1406,12 @@
 	bus_space_write_2(st, sh, STE_IntStatus, 0xffff);
 	bus_space_write_2(st, sh, STE_IntEnable, sc->sc_IntEnable);
 
+#ifdef STE_USE_DFE580TX_FIX
+	/* Fix DFE-580TX packet drop issue */
+	if (sc->sc_dfe580tx)
+		bus_space_write_1(st, sh, STE_DebugCtrl1, 1);
+#endif
+
 	/*
 	 * Start the receive DMA engine.
 	 */
@@ -1420,7 +1509,7 @@
 	 * Stop the transmit and receive DMA.
 	 */
 	bus_space_write_4(sc->sc_st, sc->sc_sh, STE_DMACtrl,
-	    DC_RxDMAHalt | DC_TxDMAHalt);
+	    sc->sc_DMACtrl | DC_RxDMAHalt | DC_TxDMAHalt);
 	ste_dmahalt_wait(sc);
 
 	/*
@@ -1496,6 +1585,7 @@
 	if (m == NULL)
 		return (ENOBUFS);
 
+	MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner);
 	MCLGET(m, M_DONTWAIT);
 	if ((m->m_flags & M_EXT) == 0) {
 		m_freem(m);
