From a1536822a00c107949772c22d9e2d2d60257f121 Mon Sep 17 00:00:00 2001 From: marius Date: Wed, 6 Dec 2006 02:14:31 +0000 Subject: Use our own callout instead of if_slowtimo() for driving lance_watchdog() in order to avoid races accessing if_timer. --- sys/dev/le/am7990.c | 4 ++-- sys/dev/le/am79900.c | 4 ++-- sys/dev/le/lance.c | 27 +++++++++++++++++++-------- sys/dev/le/lancevar.h | 2 ++ 4 files changed, 25 insertions(+), 12 deletions(-) (limited to 'sys') 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 #include #include +#include #include #include #include @@ -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: -- cgit v1.1