svn commit: r245064 - head/sys/arm/ti/cpsw
Tim Kientzle
kientzle at FreeBSD.org
Sat Jan 5 17:59:45 UTC 2013
Author: kientzle
Date: Sat Jan 5 17:59:44 2013
New Revision: 245064
URL: http://svnweb.freebsd.org/changeset/base/245064
Log:
While trying to track down the root cause for
TX stalls in this driver, I've also had some
time to evaluate the effectiveness of different
watchdog strategies.
This is the latest attempt, which consolidates
all of the watchdog logic in one place and
consistently detects TX stalls and resets within
a couple of seconds.
Modified:
head/sys/arm/ti/cpsw/if_cpsw.c
head/sys/arm/ti/cpsw/if_cpswvar.h
Modified: head/sys/arm/ti/cpsw/if_cpsw.c
==============================================================================
--- head/sys/arm/ti/cpsw/if_cpsw.c Sat Jan 5 17:41:21 2013 (r245063)
+++ head/sys/arm/ti/cpsw/if_cpsw.c Sat Jan 5 17:59:44 2013 (r245064)
@@ -98,7 +98,7 @@ static int cpsw_ioctl(struct ifnet *ifp,
static int cpsw_init_slot_lists(struct cpsw_softc *sc);
static void cpsw_free_slot(struct cpsw_softc *sc, struct cpsw_slot *slot);
static void cpsw_fill_rx_queue_locked(struct cpsw_softc *sc);
-static void cpsw_watchdog(struct cpsw_softc *sc);
+static void cpsw_tx_watchdog(struct cpsw_softc *sc);
static void cpsw_intr_rx_thresh(void *arg);
static void cpsw_intr_rx(void *arg);
@@ -737,13 +737,7 @@ cpsw_start_locked(struct ifnet *ifp)
cpsw_cpdma_write_txbd_next(prev_slot->index,
cpsw_cpdma_txbd_paddr(first_new_slot->index));
}
- /* If tx_retires hasn't changed, then we may have
- lost a TX interrupt, so let the timer tick. */
sc->tx_enqueues += enqueued;
- if (sc->tx_retires_at_wd_reset != sc->tx_retires) {
- sc->tx_retires_at_wd_reset = sc->tx_retires;
- sc->wd_timer = 5;
- }
sc->tx_queued += enqueued;
if (sc->tx_queued > sc->tx_max_queued) {
sc->tx_max_queued = sc->tx_queued;
@@ -771,7 +765,6 @@ cpsw_stop_locked(struct cpsw_softc *sc)
/* Stop tick engine */
callout_stop(&sc->wd_callout);
- sc->wd_timer = 0;
/* Wait for hardware to clear pending ops. */
CPSW_GLOBAL_UNLOCK(sc);
@@ -1185,7 +1178,6 @@ cpsw_intr_tx_locked(void *arg)
}
sc->tx_retires += retires;
sc->tx_queued -= retires;
- sc->wd_timer = 0;
}
}
@@ -1206,7 +1198,7 @@ cpsw_tick(void *msc)
struct cpsw_softc *sc = msc;
/* Check for TX timeout */
- cpsw_watchdog(sc);
+ cpsw_tx_watchdog(sc);
mii_tick(sc->mii);
@@ -1222,21 +1214,28 @@ cpsw_tick(void *msc)
}
static void
-cpsw_watchdog(struct cpsw_softc *sc)
+cpsw_tx_watchdog(struct cpsw_softc *sc)
{
- struct ifnet *ifp;
+ struct ifnet *ifp = sc->ifp;
- ifp = sc->ifp;
CPSW_GLOBAL_LOCK(sc);
- if (sc->wd_timer == 0 || --sc->wd_timer) {
- CPSW_GLOBAL_UNLOCK(sc);
- return;
+ if (sc->tx_retires > sc->tx_retires_at_last_tick) {
+ sc->tx_wd_timer = 0; /* Stuff got sent. */
+ } else if (sc->tx_queued == 0) {
+ sc->tx_wd_timer = 0; /* Nothing to send. */
+ } else {
+ /* There was something to send but we didn't. */
+ ++sc->tx_wd_timer;
+ if (sc->tx_wd_timer > 3) {
+ sc->tx_wd_timer = 0;
+ ifp->if_oerrors++;
+ if_printf(ifp, "watchdog timeout\n");
+ cpsw_stop_locked(sc);
+ cpsw_init_locked(sc);
+ CPSW_DEBUGF(("watchdog reset completed\n"));
+ }
}
-
- ifp->if_oerrors++;
- if_printf(ifp, "watchdog timeout\n");
- cpsw_stop_locked(sc);
- cpsw_init_locked(sc);
+ sc->tx_retires_at_last_tick = sc->tx_retires;
CPSW_GLOBAL_UNLOCK(sc);
}
@@ -1381,7 +1380,7 @@ cpsw_init_locked(void *arg)
/* Activate network interface */
sc->rx_running = 1;
sc->tx_running = 1;
- sc->wd_timer = 0;
+ sc->tx_wd_timer = 0;
callout_reset(&sc->wd_callout, hz, cpsw_tick, sc);
sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
Modified: head/sys/arm/ti/cpsw/if_cpswvar.h
==============================================================================
--- head/sys/arm/ti/cpsw/if_cpswvar.h Sat Jan 5 17:41:21 2013 (r245063)
+++ head/sys/arm/ti/cpsw/if_cpswvar.h Sat Jan 5 17:59:44 2013 (r245064)
@@ -63,7 +63,7 @@ struct cpsw_softc {
int cpsw_media_status;
struct callout wd_callout;
- int wd_timer;
+ int tx_wd_timer;
bus_dma_tag_t mbuf_dtag;
@@ -82,7 +82,7 @@ struct cpsw_softc {
/* Statistics */
uint32_t tx_enqueues; /* total TX bufs added to queue */
uint32_t tx_retires; /* total TX bufs removed from queue */
- uint32_t tx_retires_at_wd_reset; /* used for watchdog */
+ uint32_t tx_retires_at_last_tick; /* used for watchdog */
/* Note: tx_queued != tx_enqueues - tx_retires
At driver reset, packets can be discarded
from TX queue without being retired. */
More information about the svn-src-head
mailing list