On Thu, Dec 16, 2010 at 12:28:56AM +0000, Jacob Meuser wrote: > the following diff tries to make sure that no other processes/threads > are or will be using the drivers software context when the driver is > detached.
same treatment for otus(4), rsu(4) and urtwn(4) ok? -- jake...@sdf.lonestar.org SDF Public Access UNIX System - http://sdf.lonestar.org Index: if_otus.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_otus.c,v retrieving revision 1.25 diff -u -p -r1.25 if_otus.c --- if_otus.c 27 Dec 2010 03:03:50 -0000 1.25 +++ if_otus.c 30 Dec 2010 05:57:42 -0000 @@ -246,17 +246,32 @@ otus_detach(struct device *self, int fla struct ifnet *ifp = &sc->sc_ic.ic_if; int s; - s = splnet(); - - /* Wait for all queued asynchronous commands to complete. */ - while (sc->cmdq.queued > 0) - tsleep(&sc->cmdq, 0, "cmdq", 0); + s = splusb(); if (timeout_initialized(&sc->scan_to)) timeout_del(&sc->scan_to); if (timeout_initialized(&sc->calib_to)) timeout_del(&sc->calib_to); + /* Wait for all queued asynchronous commands to complete. */ +#if 0 + while (sc->cmdq.queued > 0) + tsleep(&sc->cmdq, 0, "cmdq", 0); +#endif + /* the async commands are run in a task */ + usb_rem_wait_task(sc->sc_udev, &sc->sc_task); + + /* but the task might not have run if it did not start before + * usbd_deactivate() was called, so wakeup now. we're + * detaching, no need to try to run more commands. + */ + if (sc->cmdq.queued > 0) { + sc->cmdq.queued = 0; + wakeup(&sc->cmdq); + } + + usbd_ref_wait(sc->sc_udev); + if (ifp->if_softc != NULL) { ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); ieee80211_ifdetach(ifp); @@ -732,8 +747,15 @@ otus_next_scan(void *arg) { struct otus_softc *sc = arg; + if (usbd_is_dying(sc->sc_udev)) + return; + + usbd_ref_incr(sc->sc_udev); + if (sc->sc_ic.ic_state == IEEE80211_S_SCAN) ieee80211_next_scan(&sc->sc_ic.ic_if); + + usbd_ref_decr(sc->sc_udev); } void @@ -809,7 +831,8 @@ otus_newstate_cb(struct otus_softc *sc, case IEEE80211_S_SCAN: (void)otus_set_chan(sc, ic->ic_bss->ni_chan, 0); - timeout_add_msec(&sc->scan_to, 200); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_msec(&sc->scan_to, 200); break; case IEEE80211_S_AUTH: @@ -830,7 +853,8 @@ otus_newstate_cb(struct otus_softc *sc, otus_newassoc(ic, ni, 1); /* Start calibration timer. */ - timeout_add_sec(&sc->calib_to, 1); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_sec(&sc->calib_to, 1); } break; } @@ -1499,6 +1523,11 @@ otus_ioctl(struct ifnet *ifp, u_long cmd struct ifreq *ifr; int s, error = 0; + if (usbd_is_dying(sc->sc_udev)) + return ENXIO; + + usbd_ref_incr(sc->sc_udev); + s = splnet(); switch (cmd) { @@ -1555,6 +1584,9 @@ otus_ioctl(struct ifnet *ifp, u_long cmd } splx(s); + + usbd_ref_decr(sc->sc_udev); + return error; } @@ -2176,12 +2208,20 @@ otus_calibrate_to(void *arg) struct ieee80211_node *ni; int s; + if (usbd_is_dying(sc->sc_udev)) + return; + + usbd_ref_incr(sc->sc_udev); + s = splnet(); ni = ic->ic_bss; ieee80211_amrr_choose(&sc->amrr, ni, &((struct otus_node *)ni)->amn); splx(s); - timeout_add_sec(&sc->calib_to, 1); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_sec(&sc->calib_to, 1); + + usbd_ref_decr(sc->sc_udev); } int Index: if_rsu.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_rsu.c,v retrieving revision 1.8 diff -u -p -r1.8 if_rsu.c --- if_rsu.c 27 Dec 2010 03:03:50 -0000 1.8 +++ if_rsu.c 30 Dec 2010 05:57:42 -0000 @@ -343,12 +343,29 @@ rsu_detach(struct device *self, int flag struct ifnet *ifp = &sc->sc_ic.ic_if; int s; - s = splnet(); - /* Wait for all async commands to complete. */ - rsu_wait_async(sc); + s = splusb(); if (timeout_initialized(&sc->calib_to)) timeout_del(&sc->calib_to); + + /* Wait for all async commands to complete. */ +#if 0 + rsu_wait_async(sc); +#endif + /* the async commands are run in a task */ + usb_rem_wait_task(sc->sc_udev, &sc->sc_task); + + /* but the task might not have run if it did not start before + * usbd_deactivate() was called, so wakeup now. we're + * detaching, no need to try to run more commands. + */ + if (sc->cmdq.queued > 0) { + sc->cmdq.queued = 0; + wakeup(&sc->cmdq); + } + + usbd_ref_wait(sc->sc_udev); + if (ifp->if_softc != NULL) { ieee80211_ifdetach(ifp); if_detach(ifp); @@ -807,8 +824,15 @@ rsu_calib_to(void *arg) { struct rsu_softc *sc = arg; + if (usbd_is_dying(sc->sc_udev)) + return; + + usbd_ref_incr(sc->sc_udev); + /* Do it in a process context. */ rsu_do_async(sc, rsu_calib_cb, NULL, 0); + + usbd_ref_decr(sc->sc_udev); } /* ARGSUSED */ @@ -833,7 +857,8 @@ rsu_calib_cb(struct rsu_softc *sc, void DPRINTFN(8, ("RSSI=%d%%\n", reg >> 4)); } - timeout_add_sec(&sc->calib_to, 2); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_sec(&sc->calib_to, 2); } int @@ -900,7 +925,8 @@ rsu_newstate_cb(struct rsu_softc *sc, vo ic->ic_bss->ni_txrate = ic->ic_bss->ni_rates.rs_nrates - 1; /* Start periodic calibration. */ - timeout_add_sec(&sc->calib_to, 2); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_sec(&sc->calib_to, 2); break; } (void)sc->sc_newstate(ic, cmd->state, cmd->arg); @@ -1704,6 +1730,11 @@ rsu_ioctl(struct ifnet *ifp, u_long cmd, struct ifreq *ifr; int s, error = 0; + if (usbd_is_dying(sc->sc_udev)) + return ENXIO; + + usbd_ref_incr(sc->sc_udev); + s = splnet(); switch (cmd) { @@ -1746,6 +1777,9 @@ rsu_ioctl(struct ifnet *ifp, u_long cmd, error = 0; } splx(s); + + usbd_ref_decr(sc->sc_udev); + return (error); } Index: if_urtwn.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_urtwn.c,v retrieving revision 1.11 diff -u -p -r1.11 if_urtwn.c --- if_urtwn.c 27 Dec 2010 03:03:50 -0000 1.11 +++ if_urtwn.c 30 Dec 2010 05:57:45 -0000 @@ -371,14 +371,31 @@ urtwn_detach(struct device *self, int fl struct ifnet *ifp = &sc->sc_ic.ic_if; int s; - s = splnet(); - /* Wait for all async commands to complete. */ - urtwn_wait_async(sc); + s = splusb(); if (timeout_initialized(&sc->scan_to)) timeout_del(&sc->scan_to); if (timeout_initialized(&sc->calib_to)) timeout_del(&sc->calib_to); + + /* Wait for all async commands to complete. */ +#if 0 + urtwn_wait_async(sc); +#endif + /* the async commands are run in a task */ + usb_rem_wait_task(sc->sc_udev, &sc->sc_task); + + /* but the task might not have run if it did not start before + * usbd_deactivate() was called, so wakeup now. we're + * detaching, no need to try to run more commands. + */ + if (sc->cmdq.queued > 0) { + sc->cmdq.queued = 0; + wakeup(&sc->cmdq); + } + + usbd_ref_wait(sc->sc_udev); + if (ifp->if_softc != NULL) { ieee80211_ifdetach(ifp); if_detach(ifp); @@ -1066,8 +1083,15 @@ urtwn_calib_to(void *arg) { struct urtwn_softc *sc = arg; + if (usbd_is_dying(sc->sc_udev)) + return; + + usbd_ref_incr(sc->sc_udev); + /* Do it in a process context. */ urtwn_do_async(sc, urtwn_calib_cb, NULL, 0); + + usbd_ref_decr(sc->sc_udev); } /* ARGSUSED */ @@ -1088,7 +1112,8 @@ urtwn_calib_cb(struct urtwn_softc *sc, v /* Do temperature compensation. */ urtwn_temp_calib(sc); - timeout_add_sec(&sc->calib_to, 2); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_sec(&sc->calib_to, 2); } void @@ -1098,10 +1123,17 @@ urtwn_next_scan(void *arg) struct ieee80211com *ic = &sc->sc_ic; int s; + if (usbd_is_dying(sc->sc_udev)) + return; + + usbd_ref_incr(sc->sc_udev); + s = splnet(); if (ic->ic_state == IEEE80211_S_SCAN) ieee80211_next_scan(&ic->ic_if); splx(s); + + usbd_ref_decr(sc->sc_udev); } int @@ -1190,7 +1222,8 @@ urtwn_newstate_cb(struct urtwn_softc *sc urtwn_read_1(sc, R92C_TXPAUSE) | 0x0f); urtwn_set_chan(sc, ic->ic_bss->ni_chan, NULL); - timeout_add_msec(&sc->scan_to, 200); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_msec(&sc->scan_to, 200); break; case IEEE80211_S_AUTH: @@ -1268,7 +1301,8 @@ urtwn_newstate_cb(struct urtwn_softc *sc sc->thcal_state = 0; sc->thcal_lctemp = 0; /* Start periodic calibration. */ - timeout_add_sec(&sc->calib_to, 2); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_sec(&sc->calib_to, 2); break; } (void)sc->sc_newstate(ic, cmd->state, cmd->arg); @@ -1931,6 +1965,11 @@ urtwn_ioctl(struct ifnet *ifp, u_long cm struct ifreq *ifr; int s, error = 0; + if (usbd_is_dying(sc->sc_udev)) + return ENXIO; + + usbd_ref_incr(sc->sc_udev); + s = splnet(); switch (cmd) { @@ -1983,6 +2022,9 @@ urtwn_ioctl(struct ifnet *ifp, u_long cm error = 0; } splx(s); + + usbd_ref_decr(sc->sc_udev); + return (error); }