Date: Sat, 5 Jan 2013 17:59:44 +0000 (UTC) From: Tim Kientzle <kientzle@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r245064 - head/sys/arm/ti/cpsw Message-ID: <201301051759.r05HxiOX006608@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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. */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201301051759.r05HxiOX006608>