diff options
author | alfred <alfred@FreeBSD.org> | 2006-11-29 19:19:44 +0000 |
---|---|---|
committer | alfred <alfred@FreeBSD.org> | 2006-11-29 19:19:44 +0000 |
commit | f9848aa039f704531519cf2fed3a6c9fe42d957e (patch) | |
tree | e86bf412cb760b7f3eb40e8b56d7124cd5c747ee /sys/dev/usb | |
parent | ac243d503ea38d3ff52ffd1c89eadde7cd48a56f (diff) | |
download | FreeBSD-src-f9848aa039f704531519cf2fed3a6c9fe42d957e.zip FreeBSD-src-f9848aa039f704531519cf2fed3a6c9fe42d957e.tar.gz |
Stop INVARIANTS panics in if_aue with a stopgap.
aue_tick calls several synchronous usb functions from a timeout(9),
this is very broken since a timeout(9) is run as an interrupt
and the usb functions tsleep.
A stopgap fix is to schedule a taskqueue task from the timeout
and defer work to that taskqueue task.
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/if_aue.c | 38 | ||||
-rw-r--r-- | sys/dev/usb/if_auereg.h | 1 |
2 files changed, 32 insertions, 7 deletions
diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c index 3395944..f3c3c2c 100644 --- a/sys/dev/usb/if_aue.c +++ b/sys/dev/usb/if_aue.c @@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/module.h> #include <sys/socket.h> +#include <sys/taskqueue.h> #include <net/if.h> #include <net/if_arp.h> @@ -189,6 +190,8 @@ static void aue_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); #endif static void aue_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status); static void aue_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status); +static void aue_task_tick(void *xsc, int pending); +static void aue_task_tick_locked(struct aue_softc *sc); static void aue_tick(void *); static void aue_rxstart(struct ifnet *); static void aue_start(struct ifnet *); @@ -789,6 +792,7 @@ aue_detach(device_t dev) sc->aue_dying = 1; untimeout(aue_tick, sc, sc->aue_stat_ch); + taskqueue_drain(taskqueue_thread, &sc->aue_stat_task); #if __FreeBSD_version >= 500000 ether_ifdetach(ifp); if_free(ifp); @@ -1015,18 +1019,40 @@ static void aue_tick(void *xsc) { struct aue_softc *sc = xsc; - struct ifnet *ifp; - struct mii_data *mii; if (sc == NULL) return; + taskqueue_enqueue(taskqueue_thread, &sc->aue_stat_task); + timeout(aue_tick, sc, hz); +} + + +static void +aue_task_tick(void *xsc, int pending) +{ + struct aue_softc *sc = xsc; + + if (sc == NULL) + return; + + mtx_lock(&Giant); AUE_LOCK(sc); + aue_task_tick_locked(sc); + AUE_UNLOCK(sc); + mtx_unlock(&Giant); +} + + +static void +aue_task_tick_locked(struct aue_softc *sc) +{ + struct ifnet *ifp; + struct mii_data *mii; ifp = sc->aue_ifp; mii = GET_MII(sc); if (mii == NULL) { - AUE_UNLOCK(sc); return; } @@ -1038,10 +1064,6 @@ aue_tick(void *xsc) aue_start(ifp); } - sc->aue_stat_ch = timeout(aue_tick, sc, hz); - - AUE_UNLOCK(sc); - return; } @@ -1241,6 +1263,7 @@ aue_init(void *xsc) ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + TASK_INIT(&sc->aue_stat_task, 0, aue_task_tick, sc); sc->aue_stat_ch = timeout(aue_tick, sc, hz); AUE_UNLOCK(sc); @@ -1374,6 +1397,7 @@ aue_stop(struct aue_softc *sc) aue_csr_write_1(sc, AUE_CTL1, 0); aue_reset(sc); untimeout(aue_tick, sc, sc->aue_stat_ch); + taskqueue_drain(taskqueue_thread, &sc->aue_stat_task); /* Stop transfers. */ if (sc->aue_ep[AUE_ENDPT_RX] != NULL) { diff --git a/sys/dev/usb/if_auereg.h b/sys/dev/usb/if_auereg.h index d161acd..37dd8e6 100644 --- a/sys/dev/usb/if_auereg.h +++ b/sys/dev/usb/if_auereg.h @@ -220,6 +220,7 @@ struct aue_softc { int aue_if_flags; struct ue_cdata aue_cdata; struct callout_handle aue_stat_ch; + struct task aue_stat_task; #if __FreeBSD_version >= 500000 struct mtx aue_mtx; #endif |