diff options
author | jhb <jhb@FreeBSD.org> | 2009-11-19 22:06:40 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2009-11-19 22:06:40 +0000 |
commit | affabaa85e18565f9c0a68b33c5b0f2e0587f05a (patch) | |
tree | 8407585eec2a1c0c6cadd011a7eb682949649bde /sys/dev/sn/if_sn.c | |
parent | d49024b6f48c6368a3af0f695133bdc2a695e281 (diff) | |
download | FreeBSD-src-affabaa85e18565f9c0a68b33c5b0f2e0587f05a.zip FreeBSD-src-affabaa85e18565f9c0a68b33c5b0f2e0587f05a.tar.gz |
- Add a private timer to drive the transmit watchdog instead of using
if_watchdog and if_timer.
- Fix some issues in detach for sn(4), ste(4), and ti(4). Primarily this
means calling ether_ifdetach() before anything else.
Diffstat (limited to 'sys/dev/sn/if_sn.c')
-rw-r--r-- | sys/dev/sn/if_sn.c | 57 |
1 files changed, 37 insertions, 20 deletions
diff --git a/sys/dev/sn/if_sn.c b/sys/dev/sn/if_sn.c index 751071a..217d811 100644 --- a/sys/dev/sn/if_sn.c +++ b/sys/dev/sn/if_sn.c @@ -82,6 +82,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/errno.h> +#include <sys/kernel.h> #include <sys/sockio.h> #include <sys/mbuf.h> #include <sys/socket.h> @@ -121,6 +122,7 @@ static int snioctl(struct ifnet * ifp, u_long, caddr_t); static void snresume(struct ifnet *); +static void snintr_locked(struct sn_softc *); static void sninit_locked(void *); static void snstart_locked(struct ifnet *); @@ -128,7 +130,7 @@ static void sninit(void *); static void snread(struct ifnet *); static void snstart(struct ifnet *); static void snstop(struct sn_softc *); -static void snwatchdog(struct ifnet *); +static void snwatchdog(void *); static void sn_setmcast(struct sn_softc *); static int sn_getmcf(struct ifnet *ifp, u_char *mcf); @@ -170,6 +172,7 @@ sn_attach(device_t dev) } SN_LOCK_INIT(sc); + callout_init_mtx(&sc->watchdog, &sc->sc_mtx, 0); snstop(sc); sc->pages_wanted = -1; @@ -202,13 +205,11 @@ sn_attach(device_t dev) ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_start = snstart; ifp->if_ioctl = snioctl; - ifp->if_watchdog = snwatchdog; ifp->if_init = sninit; ifp->if_baudrate = 10000000; IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; IFQ_SET_READY(&ifp->if_snd); - ifp->if_timer = 0; ether_ifattach(ifp, eaddr); @@ -233,9 +234,11 @@ sn_detach(device_t dev) struct sn_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->ifp; - snstop(sc); - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ether_ifdetach(ifp); + SN_LOCK(sc); + snstop(sc); + SN_UNLOCK(sc); + callout_drain(&sc->watchdog); sn_deactivate(dev); if_free(ifp); SN_LOCK_DESTROY(sc); @@ -342,6 +345,7 @@ sninit_locked(void *xsc) */ ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + callout_reset(&sc->watchdog, hz, snwatchdog, sc); /* * Attempt to push out any waiting packets. @@ -463,7 +467,7 @@ startagain: CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); sc->intr_mask = mask; - ifp->if_timer = 1; + sc->timer = 1; ifp->if_drv_flags |= IFF_DRV_OACTIVE; sc->pages_wanted = numPages; return; @@ -548,7 +552,7 @@ startagain: CSR_WRITE_2(sc, MMU_CMD_REG_W, MMUCR_ENQUEUE); ifp->if_drv_flags |= IFF_DRV_OACTIVE; - ifp->if_timer = 1; + sc->timer = 1; BPF_MTAP(ifp, top); @@ -657,7 +661,7 @@ snresume(struct ifnet *ifp) packet_no = CSR_READ_1(sc, ALLOC_RESULT_REG_B); if (packet_no & ARR_FAILED) { if_printf(ifp, "Memory allocation failed. Weird.\n"); - ifp->if_timer = 1; + sc->timer = 1; goto try_start; } /* @@ -755,24 +759,32 @@ try_start: * Now pass control to snstart() to queue any additional packets */ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - snstart(ifp); + snstart_locked(ifp); /* * We've sent something, so we're active. Set a watchdog in case the * TX_EMPTY interrupt is lost. */ ifp->if_drv_flags |= IFF_DRV_OACTIVE; - ifp->if_timer = 1; + sc->timer = 1; return; } - void sn_intr(void *arg) { - int status, interrupts; struct sn_softc *sc = (struct sn_softc *) arg; + + SN_LOCK(sc); + snintr_locked(sc); + SN_UNLOCK(sc); +} + +static void +snintr_locked(struct sn_softc *sc) +{ + int status, interrupts; struct ifnet *ifp = sc->ifp; /* @@ -783,12 +795,10 @@ sn_intr(void *arg) uint16_t tx_status; uint16_t card_stats; - SN_LOCK(sc); - /* * Clear the watchdog. */ - ifp->if_timer = 0; + sc->timer = 0; SMC_SELECT_BANK(sc, 2); @@ -981,7 +991,6 @@ out: mask |= CSR_READ_1(sc, INTR_MASK_REG_B); CSR_WRITE_1(sc, INTR_MASK_REG_B, mask); sc->intr_mask = mask; - SN_UNLOCK(sc); } static void @@ -1136,7 +1145,6 @@ snioctl(struct ifnet *ifp, u_long cmd, caddr_t data) SN_LOCK(sc); if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) { - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; snstop(sc); } else { /* reinitialize card on any parameter change */ @@ -1161,9 +1169,16 @@ snioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } static void -snwatchdog(struct ifnet *ifp) +snwatchdog(void *arg) { - sn_intr(ifp->if_softc); + struct sn_softc *sc; + + sc = arg; + SN_ASSERT_LOCKED(sc); + callout_reset(&sc->watchdog, hz, snwatchdog, sc); + if (sc->timer == 0 || --sc->timer > 0) + return; + snintr_locked(sc); } @@ -1193,7 +1208,9 @@ snstop(struct sn_softc *sc) /* * Cancel watchdog. */ - ifp->if_timer = 0; + sc->timer = 0; + callout_stop(&sc->watchdog); + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); } |