summaryrefslogtreecommitdiffstats
path: root/sys/dev/le
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2006-12-06 02:14:31 +0000
committermarius <marius@FreeBSD.org>2006-12-06 02:14:31 +0000
commita1536822a00c107949772c22d9e2d2d60257f121 (patch)
treea4c29cf5bf2eedf47d912df9f3b10e8f17adf9a9 /sys/dev/le
parentd6685ecfb2ee0ef325499c7ad340360ccfc8a7be (diff)
downloadFreeBSD-src-a1536822a00c107949772c22d9e2d2d60257f121.zip
FreeBSD-src-a1536822a00c107949772c22d9e2d2d60257f121.tar.gz
Use our own callout instead of if_slowtimo() for driving lance_watchdog()
in order to avoid races accessing if_timer.
Diffstat (limited to 'sys/dev/le')
-rw-r--r--sys/dev/le/am7990.c4
-rw-r--r--sys/dev/le/am79900.c4
-rw-r--r--sys/dev/le/lance.c27
-rw-r--r--sys/dev/le/lancevar.h2
4 files changed, 25 insertions, 12 deletions
diff --git a/sys/dev/le/am7990.c b/sys/dev/le/am7990.c
index 0738ed0..10a809d 100644
--- a/sys/dev/le/am7990.c
+++ b/sys/dev/le/am7990.c
@@ -385,7 +385,7 @@ am7990_tint(struct lance_softc *sc)
sc->sc_first_td = bix;
- ifp->if_timer = sc->sc_no_td > 0 ? 5 : 0;
+ sc->sc_wdog_timer = sc->sc_no_td > 0 ? 5 : 0;
}
/*
@@ -575,7 +575,7 @@ am7990_start_locked(struct lance_softc *sc)
sc->sc_last_td = bix;
if (enq > 0)
- ifp->if_timer = 5;
+ sc->sc_wdog_timer = 5;
}
#ifdef LEDEBUG
diff --git a/sys/dev/le/am79900.c b/sys/dev/le/am79900.c
index 7246df3..abaed2d 100644
--- a/sys/dev/le/am79900.c
+++ b/sys/dev/le/am79900.c
@@ -423,7 +423,7 @@ am79900_tint(struct lance_softc *sc)
sc->sc_first_td = bix;
- ifp->if_timer = sc->sc_no_td > 0 ? 5 : 0;
+ sc->sc_wdog_timer = sc->sc_no_td > 0 ? 5 : 0;
}
/*
@@ -614,7 +614,7 @@ am79900_start_locked(struct lance_softc *sc)
sc->sc_last_td = bix;
if (enq > 0)
- ifp->if_timer = 5;
+ sc->sc_wdog_timer = 5;
}
#ifdef LEDEBUG
diff --git a/sys/dev/le/lance.c b/sys/dev/le/lance.c
index 0c22fcc..3257637 100644
--- a/sys/dev/le/lance.c
+++ b/sys/dev/le/lance.c
@@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/endian.h>
#include <sys/lock.h>
+#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/socket.h>
@@ -101,7 +102,7 @@ devclass_t le_devclass;
static void lance_start(struct ifnet *);
static void lance_stop(struct lance_softc *);
static void lance_init(void *);
-static void lance_watchdog(struct ifnet *);
+static void lance_watchdog(void *s);
static int lance_mediachange(struct ifnet *);
static void lance_mediastatus(struct ifnet *, struct ifmediareq *);
static int lance_ioctl(struct ifnet *, u_long, caddr_t);
@@ -119,12 +120,13 @@ lance_config(struct lance_softc *sc, const char* name, int unit)
if (ifp == NULL)
return (ENOSPC);
+ callout_init_mtx(&sc->sc_wdog_ch, &sc->sc_mtx, 0);
+
/* Initialize ifnet structure. */
ifp->if_softc = sc;
if_initname(ifp, name, unit);
ifp->if_start = lance_start;
ifp->if_ioctl = lance_ioctl;
- ifp->if_watchdog = lance_watchdog;
ifp->if_init = lance_init;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
#ifdef LANCE_REVC_BUG
@@ -213,6 +215,7 @@ lance_detach(struct lance_softc *sc)
LE_LOCK(sc);
lance_stop(sc);
LE_UNLOCK(sc);
+ callout_drain(&sc->sc_wdog_ch);
ether_ifdetach(ifp);
if_free(ifp);
}
@@ -257,7 +260,8 @@ lance_stop(struct lance_softc *sc)
* Mark the interface down and cancel the watchdog timer.
*/
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
- ifp->if_timer = 0;
+ callout_stop(&sc->sc_wdog_ch);
+ sc->sc_wdog_timer = 0;
(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
}
@@ -327,7 +331,8 @@ lance_init_locked(struct lance_softc *sc)
(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- ifp->if_timer = 0;
+ sc->sc_wdog_timer = 0;
+ callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
(*sc->sc_start_locked)(sc);
} else
if_printf(ifp, "controller failed to initialize\n");
@@ -434,15 +439,21 @@ lance_get(struct lance_softc *sc, int boff, int totlen)
}
static void
-lance_watchdog(struct ifnet *ifp)
+lance_watchdog(void *xsc)
{
- struct lance_softc *sc = ifp->if_softc;
+ struct lance_softc *sc = (struct lance_softc *)xsc;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ LE_LOCK_ASSERT(sc, MA_OWNED);
+
+ if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) {
+ callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
+ return;
+ }
- LE_LOCK(sc);
if_printf(ifp, "device timeout\n");
++ifp->if_oerrors;
lance_init_locked(sc);
- LE_UNLOCK(sc);
}
static int
diff --git a/sys/dev/le/lancevar.h b/sys/dev/le/lancevar.h
index 1c2142b..b524596 100644
--- a/sys/dev/le/lancevar.h
+++ b/sys/dev/le/lancevar.h
@@ -48,6 +48,8 @@ struct lance_softc {
struct ifnet *sc_ifp;
struct ifmedia sc_media;
struct mtx sc_mtx;
+ struct callout sc_wdog_ch;
+ int sc_wdog_timer;
/*
* Memory functions:
OpenPOWER on IntegriCloud