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);