On Sun, Sep 27, 2015 at 08:00:19PM +0200, Stefan Sperling wrote:
> This is yet another attempt at improving the iwm(4) newstate task.

This diff has been working nicely for me, with many suspend/resume cycles.
Never had a problem connecting to several wifis.

Any objections? Any Oks?

> The goal is to simplify things by only queuing one state transition
> at a time. The newstate task now always transitions to the most
> recently requested state, rather than hopping along with every request.
> 
> This allows us get rid of the silly newstate generation counter, and
> allows us to simply cancel any outstanding transition when the interface
> goes down.
> 
> The old code was queuing *additional* work from iwm_stop(). Which meant,
> for example, that every time upon resume, a task ran only to discover that
> it is no longer relevant.
> 
> This probably needs some testing to shake out bugs.
> Test reports are very much appreciated!
> 
> This change might also fix semi-frequent firmware errors during association.
> But not all -- I've found that running with IWM_DEBUG cranked up produces
> sufficient printfs to make firmware commands time out more often.
> It all seems very sensitive to timing which is hard to get completely
> right with tasks involved.
> 
> Index: if_iwm.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
> retrieving revision 1.51
> diff -u -p -r1.51 if_iwm.c
> --- if_iwm.c  27 Sep 2015 16:53:38 -0000      1.51
> +++ if_iwm.c  27 Sep 2015 17:33:58 -0000
> @@ -195,14 +195,6 @@ const struct iwm_rate {
>  #define IWM_RIDX_IS_CCK(_i_) ((_i_) < IWM_RIDX_OFDM)
>  #define IWM_RIDX_IS_OFDM(_i_) ((_i_) >= IWM_RIDX_OFDM)
>  
> -struct iwm_newstate_state {
> -     struct task ns_wk;
> -     struct ieee80211com *ns_ic;
> -     enum ieee80211_state ns_nstate;
> -     int ns_arg;
> -     int ns_generation;
> -};
> -
>  int  iwm_store_cscheme(struct iwm_softc *, uint8_t *, size_t);
>  int  iwm_firmware_store_section(struct iwm_softc *, enum iwm_ucode_type,
>                                       uint8_t *, size_t);
> @@ -406,7 +398,7 @@ struct ieee80211_node *iwm_node_alloc(st
>  void iwm_calib_timeout(void *);
>  void iwm_setrates(struct iwm_node *);
>  int  iwm_media_change(struct ifnet *);
> -void iwm_newstate_cb(void *);
> +void iwm_newstate_task(void *);
>  int  iwm_newstate(struct ieee80211com *, enum ieee80211_state, int);
>  void iwm_endscan_cb(void *);
>  int  iwm_init_hw(struct iwm_softc *);
> @@ -5263,43 +5255,29 @@ iwm_media_change(struct ifnet *ifp)
>  }
>  
>  void
> -iwm_newstate_cb(void *wk)
> +iwm_newstate_task(void *psc)
>  {
> -     struct iwm_newstate_state *iwmns = (void *)wk;
> -     struct ieee80211com *ic = iwmns->ns_ic;
> -     enum ieee80211_state nstate = iwmns->ns_nstate;
> -     int generation = iwmns->ns_generation;
> +     struct iwm_softc *sc = (struct iwm_softc *)psc;
> +     struct ieee80211com *ic = &sc->sc_ic;
> +     enum ieee80211_state nstate = sc->ns_nstate;
> +     enum ieee80211_state ostate = ic->ic_state;
>       struct iwm_node *in;
> -     int arg = iwmns->ns_arg;
> -     struct ifnet *ifp = IC2IFP(ic);
> -     struct iwm_softc *sc = ifp->if_softc;
> +     int arg = sc->ns_arg;
>       int error;
>  
> -     free(iwmns, M_DEVBUF, sizeof(*iwmns));
> -
> -     DPRINTF(("Prepare to switch state %s->%s\n",
> -         ieee80211_state_name[ic->ic_state],
> -         ieee80211_state_name[nstate]));
> -     if (sc->sc_generation != generation) {
> -             DPRINTF(("newstate_cb: someone pulled the plug meanwhile\n"));
> -             if (nstate == IEEE80211_S_INIT) {
> -                     DPRINTF(("newstate_cb: nstate == IEEE80211_S_INIT: 
> calling sc_newstate()\n"));
> -                     sc->sc_newstate(ic, nstate, arg);
> -             }
> -             return;
> -     }
> -
>       DPRINTF(("switching state %s->%s\n",
> -         ieee80211_state_name[ic->ic_state],
> +         ieee80211_state_name[ostate],
>           ieee80211_state_name[nstate]));
>  
> -     if (ic->ic_state == IEEE80211_S_SCAN && nstate != ic->ic_state)
> +     if (ostate == IEEE80211_S_SCAN && nstate != ostate)
>               iwm_led_blink_stop(sc);
>  
>       /* disable beacon filtering if we're hopping out of RUN */
> -     if (ic->ic_state == IEEE80211_S_RUN && nstate != ic->ic_state) {
> +     if (ostate == IEEE80211_S_RUN && nstate != ostate)
>               iwm_mvm_disable_beacon_filter(sc, (void *)ic->ic_bss);
>  
> +     /* Reset the device if moving out of AUTH, ASSOC, or RUN. */
> +     if (ostate > IEEE80211_S_SCAN && nstate < ostate) {
>               if (((in = (void *)ic->ic_bss) != NULL))
>                       in->in_assoc = 0;
>               iwm_release(sc, NULL);
> @@ -5393,25 +5371,15 @@ iwm_newstate_cb(void *wk)
>  int
>  iwm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
>  {
> -     struct iwm_newstate_state *iwmns;
>       struct ifnet *ifp = IC2IFP(ic);
>       struct iwm_softc *sc = ifp->if_softc;
>  
>       timeout_del(&sc->sc_calib_to);
>  
> -     iwmns = malloc(sizeof(*iwmns), M_DEVBUF, M_NOWAIT);
> -     if (!iwmns) {
> -             DPRINTF(("%s: allocating state cb mem failed\n", DEVNAME(sc)));
> -             return ENOMEM;
> -     }
> -
> -     iwmns->ns_ic = ic;
> -     iwmns->ns_nstate = nstate;
> -     iwmns->ns_arg = arg;
> -     iwmns->ns_generation = sc->sc_generation;
> +     sc->ns_nstate = nstate;
> +     sc->ns_arg = arg;
>  
> -     task_set(&iwmns->ns_wk, iwm_newstate_cb, iwmns);
> -     task_add(sc->sc_nswq, &iwmns->ns_wk);
> +     task_add(sc->sc_nswq, &sc->newstate_task);
>  
>       return 0;
>  }
> @@ -5676,8 +5644,10 @@ iwm_stop(struct ifnet *ifp, int disable)
>       ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED;
>       ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
>  
> -     if (ic->ic_state != IEEE80211_S_INIT)
> -             ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
> +     task_del(systq, &sc->init_task);
> +     task_del(sc->sc_nswq, &sc->newstate_task);
> +     task_del(sc->sc_eswq, &sc->sc_eswk);
> +     sc->sc_newstate(ic, IEEE80211_S_INIT, -1);
>  
>       timeout_del(&sc->sc_calib_to);
>       iwm_led_blink_stop(sc);
> @@ -6614,6 +6584,7 @@ iwm_attach(struct device *parent, struct
>       timeout_set(&sc->sc_calib_to, iwm_calib_timeout, sc);
>       timeout_set(&sc->sc_led_blink_to, iwm_led_blink_timeout, sc);
>       task_set(&sc->init_task, iwm_init_task, sc);
> +     task_set(&sc->newstate_task, iwm_newstate_task, sc);
>  
>       /*
>        * We cannot read the MAC address without loading the
> @@ -6687,8 +6658,7 @@ iwm_wakeup(struct iwm_softc *sc)
>       reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
>       pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
>  
> -     iwm_init_task(sc);
> -
> +     task_add(systq, &sc->init_task);
>  }
>  
>  int
> Index: if_iwmvar.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwmvar.h,v
> retrieving revision 1.9
> diff -u -p -r1.9 if_iwmvar.h
> --- if_iwmvar.h       15 Jun 2015 08:06:12 -0000      1.9
> +++ if_iwmvar.h       27 Sep 2015 17:09:03 -0000
> @@ -364,6 +364,9 @@ struct iwm_softc {
>       struct timeout sc_led_blink_to;
>  
>       struct task             init_task;
> +     struct task             newstate_task;
> +     enum ieee80211_state    ns_nstate;
> +     int                     ns_arg;
>  
>       bus_space_tag_t sc_st;
>       bus_space_handle_t sc_sh;

Reply via email to