On Tue, Jul 14, 2015 at 09:56:53PM -0600, Stefan Sperling wrote:
> This implements your suggestion to properly abort async tasks when
> bringing the interface down.
> 
> Fixes the problem for me just as well.

And yet another diff after more discussion.

This diff makes the driver schedule a single 80211 state transition at a time.
The command queue is now used for commands to the device firmware only.

A task scheduled by the scan timeout will now be overwritten when run_stop()
schedules a transition to INIT. So there cannot be a SCAN->SCAN transition
that restarts the timeout while the interface goes down.

If this pattern works out we could move storage and management of this task
up into the net80211 layer eventyally, and make use of it in more drivers.

Index: if_run.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_run.c,v
retrieving revision 1.109
diff -u -p -r1.109 if_run.c
--- if_run.c    12 Jun 2015 15:47:31 -0000      1.109
+++ if_run.c    15 Jul 2015 19:54:40 -0000
@@ -34,6 +34,7 @@
 #include <sys/conf.h>
 #include <sys/device.h>
 #include <sys/endian.h>
+#include <sys/task.h>
 
 #include <machine/intr.h>
 
@@ -361,7 +362,7 @@ void                run_task(void *);
 void           run_do_async(struct run_softc *, void (*)(struct run_softc *,
                    void *), void *, int);
 int            run_newstate(struct ieee80211com *, enum ieee80211_state, int);
-void           run_newstate_cb(struct run_softc *, void *);
+void           run_newstate_task(void *);
 void           run_updateedca(struct ieee80211com *);
 void           run_updateedca_cb(struct run_softc *, void *);
 int            run_set_key(struct ieee80211com *, struct ieee80211_node *,
@@ -568,6 +569,7 @@ run_attach(struct device *parent, struct
        }
 
        usb_init_task(&sc->sc_task, run_task, sc, USB_TASK_TYPE_GENERIC);
+       task_set(&sc->sc_newstate_task, run_newstate_task, sc);
        timeout_set(&sc->scan_to, run_next_scan, sc);
        timeout_set(&sc->calib_to, run_calibrate_to, sc);
 
@@ -685,6 +687,8 @@ run_detach(struct device *self, int flag
 
        s = splusb();
 
+       task_del(systq, &sc->sc_newstate_task);
+
        if (timeout_initialized(&sc->scan_to))
                timeout_del(&sc->scan_to);
        if (timeout_initialized(&sc->calib_to))
@@ -1767,25 +1771,30 @@ int
 run_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
 {
        struct run_softc *sc = ic->ic_softc;
-       struct run_cmd_newstate cmd;
+       struct run_newstate_task_arg *task_arg = &sc->sc_newstate_task_arg;
+
+       /* remove any already scheduled transition */
+       task_del(systq, &sc->sc_newstate_task);
+
+       /* schedule transition in a process context */
+       task_arg->state = nstate;
+       task_arg->arg = arg;
+       task_add(systq, &sc->sc_newstate_task);
 
-       /* do it in a process context */
-       cmd.state = nstate;
-       cmd.arg = arg;
-       run_do_async(sc, run_newstate_cb, &cmd, sizeof cmd);
        return 0;
 }
 
 void
-run_newstate_cb(struct run_softc *sc, void *arg)
+run_newstate_task(void *arg)
 {
-       struct run_cmd_newstate *cmd = arg;
+       struct run_softc *sc = arg;
+       struct run_newstate_task_arg *task_arg = &sc->sc_newstate_task_arg;
        struct ieee80211com *ic = &sc->sc_ic;
        enum ieee80211_state ostate;
        struct ieee80211_node *ni;
        uint32_t tmp, sta[3];
        uint8_t wcid;
-       int s;
+       int s, nstate = task_arg->state;
 
        s = splnet();
        ostate = ic->ic_state;
@@ -1795,7 +1804,7 @@ run_newstate_cb(struct run_softc *sc, vo
                run_set_leds(sc, RT2860_LED_RADIO);
        }
 
-       switch (cmd->state) {
+       switch (nstate) {
        case IEEE80211_S_INIT:
                if (ostate == IEEE80211_S_RUN) {
                        /* abort TSF synchronization */
@@ -1855,7 +1864,7 @@ run_newstate_cb(struct run_softc *sc, vo
                     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
                break;
        }
-       (void)sc->sc_newstate(ic, cmd->state, cmd->arg);
+       (void)sc->sc_newstate(ic, task_arg->state, task_arg->arg);
        splx(s);
 }
 

Reply via email to