The "link quality" (LQ) command for iwm firmware is used to tell the firmware about our Tx rate selection decisions, among other things.
The driver currently avoids sending this command directly from interrupt context. Instead it schedules a task which will send the command. The driver usually defers to a task when it needs to wait for a response to the command from the firmware, and runs in a context where sleeping (i.e. waiting) isn't allowed. The LQ command requires no actual response handling, and works just fine when sent asynchrounously. So get rid of the task and just send the LQ command directly from interrupt context. This simplifies the driver a bit and means we have less potential delay between our decision to use a new Tx rate and getting the firmware's rate retry table updated for our new Tx rate. ok? diff 960b1fc5c6485d1b9e9fe9d73b34986dd0a3a942 50417a34cf53a2cdd32a025c586789525bfa9d00 blob - c6963275801e8f8b962721bcd81fd3b1a541b46f (mode 644) blob + cb582fd301f6a85569c578a83e49daeffa087724 (mode 600) --- sys/dev/pci/if_iwm.c +++ sys/dev/pci/if_iwm.c @@ -453,8 +453,7 @@ int iwm_run(struct iwm_softc *); int iwm_run_stop(struct iwm_softc *); struct ieee80211_node *iwm_node_alloc(struct ieee80211com *); void iwm_calib_timeout(void *); -void iwm_setrates_task(void *); -void iwm_setrates(struct iwm_node *); +void iwm_setrates(struct iwm_node *, int); int iwm_media_change(struct ifnet *); void iwm_newstate_task(void *); int iwm_newstate(struct ieee80211com *, enum ieee80211_state, int); @@ -4206,7 +4205,7 @@ iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_ best_mcs = ieee80211_mira_get_best_mcs(&in->in_mn); if (best_mcs != in->chosen_txmcs) { in->chosen_txmcs = best_mcs; - iwm_add_task(sc, systq, &sc->setrates_task); + iwm_setrates(in, 1); } /* Fall back to CCK rates if MCS 0 is failing. */ @@ -6736,7 +6735,7 @@ iwm_run(struct iwm_softc *sc) in->in_ni.ni_txmcs = 0; in->chosen_txrate = 0; in->chosen_txmcs = 0; - iwm_setrates(in); + iwm_setrates(in, 0); timeout_add_msec(&sc->sc_calib_to, 500); iwm_led_enable(sc); @@ -6817,7 +6816,7 @@ iwm_calib_timeout(void *arg) */ if (ni->ni_txrate != in->chosen_txrate) { in->chosen_txrate = ni->ni_txrate; - iwm_add_task(sc, systq, &sc->setrates_task); + iwm_setrates(in, 1); } if (in->ht_force_cck) { struct ieee80211_rateset *rs = &ni->ni_rates; @@ -6834,28 +6833,8 @@ iwm_calib_timeout(void *arg) } void -iwm_setrates_task(void *arg) +iwm_setrates(struct iwm_node *in, int async) { - struct iwm_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; - struct iwm_node *in = (struct iwm_node *)ic->ic_bss; - int s = splnet(); - - if (sc->sc_flags & IWM_FLAG_SHUTDOWN) { - refcnt_rele_wake(&sc->task_refs); - splx(s); - return; - } - - /* Update rates table based on new TX rate determined by AMRR. */ - iwm_setrates(in); - refcnt_rele_wake(&sc->task_refs); - splx(s); -} - -void -iwm_setrates(struct iwm_node *in) -{ struct ieee80211_node *ni = &in->in_ni; struct ieee80211com *ic = ni->ni_ic; struct iwm_softc *sc = IC2IFP(ic)->if_softc; @@ -6867,6 +6846,8 @@ iwm_setrates(struct iwm_node *in) .len = { sizeof(lqcmd), }, }; + cmd.flags = async ? IWM_CMD_ASYNC : 0; + memset(&lqcmd, 0, sizeof(lqcmd)); lqcmd.sta_id = IWM_STATION_ID; @@ -7111,7 +7092,6 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_s ieee80211_mira_cancel_timeouts(&in->in_mn); iwm_del_task(sc, systq, &sc->ba_task); iwm_del_task(sc, systq, &sc->htprot_task); - iwm_del_task(sc, systq, &sc->setrates_task); } sc->ns_nstate = nstate; @@ -7885,7 +7865,6 @@ iwm_stop(struct ifnet *ifp) /* Cancel scheduled tasks and let any stale tasks finish up. */ task_del(systq, &sc->init_task); iwm_del_task(sc, sc->sc_nswq, &sc->newstate_task); - iwm_del_task(sc, systq, &sc->setrates_task); iwm_del_task(sc, systq, &sc->ba_task); iwm_del_task(sc, systq, &sc->htprot_task); KASSERT(sc->task_refs.refs >= 1); @@ -9313,7 +9292,6 @@ iwm_attach(struct device *parent, struct device *self, 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); - task_set(&sc->setrates_task, iwm_setrates_task, sc); task_set(&sc->ba_task, iwm_ba_task, sc); task_set(&sc->htprot_task, iwm_htprot_task, sc); blob - ec579e3f75095d6c28ea14293bd75d257971c66f blob + 5034497e1d10a9124f4f254105f251955e9cd534 --- sys/dev/pci/if_iwmvar.h +++ sys/dev/pci/if_iwmvar.h @@ -375,7 +375,6 @@ struct iwm_softc { struct task init_task; /* NB: not reference-counted */ struct refcnt task_refs; struct task newstate_task; - struct task setrates_task; enum ieee80211_state ns_nstate; int ns_arg;