Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-6]: src/sys/dev/ic Pull up following revision(s) (requested by jd...



details:   https://anonhg.NetBSD.org/src/rev/bd924dd25afb
branches:  netbsd-6
changeset: 774313:bd924dd25afb
user:      riz <riz%NetBSD.org@localhost>
date:      Thu Jul 05 17:59:12 2012 +0000

description:
Pull up following revision(s) (requested by jdc in ticket #401):
        sys/dev/ic/gem.c: revision 1.99
        sys/dev/ic/gemvar.h: revision 1.24
        sys/dev/ic/gemreg.h: revision 1.15
Apply lockup fixes from Havard Eidnes/OpenBSD in PR port-sparc64/46260:
- add an additional watchdog for RX overflow
- re-initialise the chip on device timeout
Also alter the interrupt blanking rate to 8 packets, as per OpenSolaris.

diffstat:

 sys/dev/ic/gem.c    |  84 +++++++++++++++++++++++++++++++++++++++++++++++++---
 sys/dev/ic/gemreg.h |   4 +-
 sys/dev/ic/gemvar.h |   7 +++-
 3 files changed, 87 insertions(+), 8 deletions(-)

diffs (210 lines):

diff -r 8f13092e28e5 -r bd924dd25afb sys/dev/ic/gem.c
--- a/sys/dev/ic/gem.c  Thu Jul 05 17:54:15 2012 +0000
+++ b/sys/dev/ic/gem.c  Thu Jul 05 17:59:12 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gem.c,v 1.98 2012/02/02 19:43:03 tls Exp $ */
+/*     $NetBSD: gem.c,v 1.98.2.1 2012/07/05 17:59:12 riz Exp $ */
 
 /*
  *
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.98 2012/02/02 19:43:03 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gem.c,v 1.98.2.1 2012/07/05 17:59:12 riz Exp $");
 
 #include "opt_inet.h"
 
@@ -89,6 +89,7 @@
 int            gem_ioctl(struct ifnet *, u_long, void *);
 void           gem_tick(void *);
 void           gem_watchdog(struct ifnet *);
+void           gem_rx_watchdog(void *);
 void           gem_pcs_start(struct gem_softc *sc);
 void           gem_pcs_stop(struct gem_softc *sc, int);
 int            gem_init(struct ifnet *);
@@ -177,6 +178,7 @@
                ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
 
                callout_destroy(&sc->sc_tick_ch);
+               callout_destroy(&sc->sc_rx_watchdog);
 
                /*FALLTHROUGH*/
        case GEM_ATT_MII:
@@ -613,6 +615,8 @@
 #endif
 
        callout_init(&sc->sc_tick_ch, 0);
+       callout_init(&sc->sc_rx_watchdog, 0);
+       callout_setfunc(&sc->sc_rx_watchdog, gem_rx_watchdog, sc);
 
        sc->sc_att_stage = GEM_ATT_FINISHED;
 
@@ -764,6 +768,8 @@
        /* Wait till it finishes */
        if (!gem_bitwait(sc, h, GEM_RX_CONFIG, 1, 0))
                aprint_error_dev(sc->sc_dev, "cannot disable read dma\n");
+       /* Wait 5ms extra. */
+       delay(5000);
 
        /* Finally, reset the ERX */
        bus_space_write_4(t, h2, GEM_RESET, GEM_RESET_RX);
@@ -848,7 +854,7 @@
            (3 * sc->sc_rxfifosize / 256) |
            ((sc->sc_rxfifosize / 256) << 12));
        bus_space_write_4(t, h, GEM_RX_BLANKING,
-           (6 << GEM_RX_BLANKING_TIME_SHIFT) | 6);
+           (6 << GEM_RX_BLANKING_TIME_SHIFT) | 8);
 }
 
 /*
@@ -1824,6 +1830,8 @@
                if (gem_add_rxbuf(sc, i) != 0) {
                        GEM_COUNTER_INCR(sc, sc_ev_rxnobuf);
                        ifp->if_ierrors++;
+                       aprint_error_dev(sc->sc_dev,
+                           "receive error: RX no buffer space\n");
                        GEM_INIT_RXDESC(sc, i);
                        bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
                            rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
@@ -2204,12 +2212,20 @@
                /*
                 * At least with GEM_SUN_GEM and some GEM_SUN_ERI
                 * revisions GEM_MAC_RX_OVERFLOW happen often due to a
-                * silicon bug so handle them silently. Moreover, it's
-                * likely that the receiver has hung so we reset it.
+                * silicon bug so handle them silently.  So if we detect
+                * an RX FIFO overflow, we fire off a timer, and check
+                * whether we're still making progress by looking at the
+                * RX FIFO write and read pointers.
                 */
                if (rxstat & GEM_MAC_RX_OVERFLOW) {
                        ifp->if_ierrors++;
-                       gem_reset_rxdma(sc);
+                       aprint_error_dev(sc->sc_dev,
+                           "receive error: RX overflow sc->rxptr %d, complete %d\n", sc->sc_rxptr, bus_space_read_4(t, h, GEM_RX_COMPLETION));
+                       sc->sc_rx_fifo_wr_ptr =
+                               bus_space_read_4(t, h, GEM_RX_FIFO_WR_PTR);
+                       sc->sc_rx_fifo_rd_ptr =
+                               bus_space_read_4(t, h, GEM_RX_FIFO_RD_PTR);
+                       callout_schedule(&sc->sc_rx_watchdog, 400);
                } else if (rxstat & ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT))
                        printf("%s: MAC rx fault, status 0x%02x\n",
                            device_xname(sc->sc_dev), rxstat);
@@ -2236,6 +2252,61 @@
        return (r);
 }
 
+void
+gem_rx_watchdog(void *arg)
+{
+       struct gem_softc *sc = arg;
+       struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+       bus_space_tag_t t = sc->sc_bustag;
+       bus_space_handle_t h = sc->sc_h1;
+       u_int32_t rx_fifo_wr_ptr;
+       u_int32_t rx_fifo_rd_ptr;
+       u_int32_t state;
+
+       if ((ifp->if_flags & IFF_RUNNING) == 0) {
+               aprint_error_dev(sc->sc_dev, "receiver not running\n");
+               return;
+       }
+
+       rx_fifo_wr_ptr = bus_space_read_4(t, h, GEM_RX_FIFO_WR_PTR);
+       rx_fifo_rd_ptr = bus_space_read_4(t, h, GEM_RX_FIFO_RD_PTR);
+       state = bus_space_read_4(t, h, GEM_MAC_MAC_STATE);
+       if ((state & GEM_MAC_STATE_OVERFLOW) == GEM_MAC_STATE_OVERFLOW &&
+           ((rx_fifo_wr_ptr == rx_fifo_rd_ptr) ||
+            ((sc->sc_rx_fifo_wr_ptr == rx_fifo_wr_ptr) &&
+             (sc->sc_rx_fifo_rd_ptr == rx_fifo_rd_ptr))))
+       {
+               /*
+                * The RX state machine is still in overflow state and
+                * the RX FIFO write and read pointers seem to be
+                * stuck.  Whack the chip over the head to get things
+                * going again.
+                */
+               aprint_error_dev(sc->sc_dev,
+                   "receiver stuck in overflow, resetting\n");
+               gem_init(ifp);
+       } else {
+               if ((state & GEM_MAC_STATE_OVERFLOW) != GEM_MAC_STATE_OVERFLOW) {
+                       aprint_error_dev(sc->sc_dev,
+                               "rx_watchdog: not in overflow state: 0x%x\n",
+                               state);
+               }
+               if (rx_fifo_wr_ptr != rx_fifo_rd_ptr) {
+                       aprint_error_dev(sc->sc_dev,
+                               "rx_watchdog: wr & rd ptr different\n");
+               }
+               if (sc->sc_rx_fifo_wr_ptr != rx_fifo_wr_ptr) {
+                       aprint_error_dev(sc->sc_dev,
+                               "rx_watchdog: wr pointer != saved\n");
+               }
+               if (sc->sc_rx_fifo_rd_ptr != rx_fifo_rd_ptr) {
+                       aprint_error_dev(sc->sc_dev,
+                               "rx_watchdog: rd pointer != saved\n");
+               }
+               aprint_error_dev(sc->sc_dev, "resetting anyway\n");
+               gem_init(ifp);
+       }
+}
 
 void
 gem_watchdog(struct ifnet *ifp)
@@ -2252,6 +2323,7 @@
        ++ifp->if_oerrors;
 
        /* Try to get more packets going. */
+       gem_init(ifp);
        gem_start(ifp);
 }
 
diff -r 8f13092e28e5 -r bd924dd25afb sys/dev/ic/gemreg.h
--- a/sys/dev/ic/gemreg.h       Thu Jul 05 17:54:15 2012 +0000
+++ b/sys/dev/ic/gemreg.h       Thu Jul 05 17:59:12 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gemreg.h,v 1.14 2008/09/15 19:43:24 jdc Exp $ */
+/*     $NetBSD: gemreg.h,v 1.14.34.1 2012/07/05 17:59:12 riz Exp $ */
 
 /*
  *
@@ -516,6 +516,8 @@
 #define        GEM_MAC_CC_PASS_PAUSE   0x00000004      /* pass pause up */
 #define        GEM_MAC_CC_BITS         "\177\020b\0TXPAUSE\0b\1RXPAUSE\0b\2NOPAUSE\0\0"
 
+/* GEM_MAC_MAC_STATE register bits */
+#define GEM_MAC_STATE_OVERFLOW 0x03800000
 
 /* 
  * Bits in GEM_MAC_SLOT_TIME register
diff -r 8f13092e28e5 -r bd924dd25afb sys/dev/ic/gemvar.h
--- a/sys/dev/ic/gemvar.h       Thu Jul 05 17:54:15 2012 +0000
+++ b/sys/dev/ic/gemvar.h       Thu Jul 05 17:59:12 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gemvar.h,v 1.23 2012/02/02 19:43:03 tls Exp $ */
+/*     $NetBSD: gemvar.h,v 1.23.2.1 2012/07/05 17:59:12 riz Exp $ */
 
 /*
  *
@@ -130,6 +130,7 @@
        struct ethercom sc_ethercom;    /* ethernet common data */
        struct mii_data sc_mii;         /* MII media control */
        struct callout  sc_tick_ch;     /* tick callout */
+       struct callout  sc_rx_watchdog; /* RX watchdog callout */
 
        /* The following bus handles are to be provided by the bus front-end */
        bus_space_tag_t sc_bustag;      /* bus tag */
@@ -223,6 +224,10 @@
        struct evcnt sc_ev_rxhist[9];
 #endif
 
+       /* For use by the RX watchdog */
+       u_int32_t       sc_rx_fifo_wr_ptr;
+       u_int32_t       sc_rx_fifo_rd_ptr;
+
        enum gem_attach_stage   sc_att_stage;
 };
 



Home | Main Index | Thread Index | Old Index