Skip site navigation (1)Skip section navigation (2)
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>