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);
 }

Reply via email to