svn commit: r343381 - head/sys/dev/iwm
Kyle Evans
kevans at FreeBSD.org
Thu Jan 24 03:45:57 UTC 2019
Author: kevans
Date: Thu Jan 24 03:45:55 2019
New Revision: 343381
URL: https://svnweb.freebsd.org/changeset/base/343381
Log:
iwm - Track firmware state better, and improve handling in iwm_newstate().
* This avoids firmware resets in all the cases in iwm_newstate(). Instead
iwm_bring_down_firmware() is called, which tears down all the STA
connection state, according to the sc->sc_firmware_state value.
* Improve the behaviour of the LED blinking a bit, so it only blinks when
there really is a wireless scan going on.
* Print the newstate arg in debug output of iwm_newstate(), to help in
debugging.
This is inspired by the firmware state maintaining change in OpenBSD's iwm,
by stsp at openbsd.org (OpenBSD Git 0ddb056fb7370664b1d4b84392697cb17d1a414a).
Submitted by: Augustin Cavalier <waddlesplash at gmail.com> (Haiku)
Obtained from: DragonFlyBSD (8a41b10ac639d0609878696808387a6799d39b57)
Modified:
head/sys/dev/iwm/if_iwm.c
head/sys/dev/iwm/if_iwm_mac_ctxt.c
head/sys/dev/iwm/if_iwm_sta.c
head/sys/dev/iwm/if_iwmvar.h
Modified: head/sys/dev/iwm/if_iwm.c
==============================================================================
--- head/sys/dev/iwm/if_iwm.c Thu Jan 24 03:45:24 2019 (r343380)
+++ head/sys/dev/iwm/if_iwm.c Thu Jan 24 03:45:55 2019 (r343381)
@@ -350,7 +350,6 @@ static int iwm_raw_xmit(struct ieee80211_node *, struc
const struct ieee80211_bpf_params *);
static int iwm_mvm_update_quotas(struct iwm_softc *, struct iwm_vap *);
static int iwm_auth(struct ieee80211vap *, struct iwm_softc *);
-static int iwm_release(struct iwm_softc *, struct iwm_node *);
static struct ieee80211_node *
iwm_node_alloc(struct ieee80211vap *,
const uint8_t[IEEE80211_ADDR_LEN]);
@@ -1263,6 +1262,7 @@ iwm_stop_device(struct iwm_softc *sc)
iv->phy_ctxt = NULL;
iv->is_uploaded = 0;
}
+ sc->sc_firmware_state = 0;
/* device going down, Stop using ICT table */
sc->sc_flags &= ~IWM_FLAG_USE_ICT;
@@ -3951,8 +3951,11 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *s
__func__,
vap,
ni);
+ IWM_DPRINTF(sc, IWM_DEBUG_STATE, "%s: Current node bssid: %s\n",
+ __func__, ether_sprintf(ni->ni_bssid));
in->in_assoc = 0;
+ iv->iv_auth = 1;
/*
* Firmware bug - it'll crash if the beacon interval is less
@@ -4004,6 +4007,7 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *s
goto out;
}
}
+ sc->sc_firmware_state = 1;
if ((error = iwm_mvm_phy_ctxt_changed(sc, &sc->sc_phyctxt[0],
in->in_ni.ni_chan, 1, 1)) != 0) {
@@ -4018,6 +4022,7 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *s
"%s: binding update cmd\n", __func__);
goto out;
}
+ sc->sc_firmware_state = 2;
/*
* Authentication becomes unreliable when powersaving is left enabled
* here. Powersaving will be activated again when association has
@@ -4037,6 +4042,7 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *s
"%s: failed to add sta\n", __func__);
goto out;
}
+ sc->sc_firmware_state = 3;
/*
* Prevent the FW from wandering off channel during association
@@ -4049,81 +4055,12 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *s
error = 0;
out:
+ if (error != 0)
+ iv->iv_auth = 0;
ieee80211_free_node(ni);
return (error);
}
-static int
-iwm_release(struct iwm_softc *sc, struct iwm_node *in)
-{
- uint32_t tfd_msk;
-
- /*
- * Ok, so *technically* the proper set of calls for going
- * from RUN back to SCAN is:
- *
- * iwm_mvm_power_mac_disable(sc, in);
- * iwm_mvm_mac_ctxt_changed(sc, vap);
- * iwm_mvm_rm_sta(sc, in);
- * iwm_mvm_update_quotas(sc, NULL);
- * iwm_mvm_mac_ctxt_changed(sc, in);
- * iwm_mvm_binding_remove_vif(sc, IWM_VAP(in->in_ni.ni_vap));
- * iwm_mvm_mac_ctxt_remove(sc, in);
- *
- * However, that freezes the device not matter which permutations
- * and modifications are attempted. Obviously, this driver is missing
- * something since it works in the Linux driver, but figuring out what
- * is missing is a little more complicated. Now, since we're going
- * back to nothing anyway, we'll just do a complete device reset.
- * Up your's, device!
- */
- /*
- * Just using 0xf for the queues mask is fine as long as we only
- * get here from RUN state.
- */
- tfd_msk = 0xf;
- iwm_xmit_queue_drain(sc);
- iwm_mvm_flush_tx_path(sc, tfd_msk, IWM_CMD_SYNC);
- /*
- * We seem to get away with just synchronously sending the
- * IWM_TXPATH_FLUSH command.
- */
-// iwm_trans_wait_tx_queue_empty(sc, tfd_msk);
- iwm_stop_device(sc);
- iwm_init_hw(sc);
- if (in)
- in->in_assoc = 0;
- return 0;
-
-#if 0
- int error;
-
- iwm_mvm_power_mac_disable(sc, in);
-
- if ((error = iwm_mvm_mac_ctxt_changed(sc, vap)) != 0) {
- device_printf(sc->sc_dev, "mac ctxt change fail 1 %d\n", error);
- return error;
- }
-
- if ((error = iwm_mvm_rm_sta(sc, in)) != 0) {
- device_printf(sc->sc_dev, "sta remove fail %d\n", error);
- return error;
- }
- error = iwm_mvm_rm_sta(sc, in);
- in->in_assoc = 0;
- iwm_mvm_update_quotas(sc, NULL);
- if ((error = iwm_mvm_mac_ctxt_changed(sc, vap)) != 0) {
- device_printf(sc->sc_dev, "mac ctxt change fail 2 %d\n", error);
- return error;
- }
- iwm_mvm_binding_remove_vif(sc, IWM_VAP(in->in_ni.ni_vap));
-
- iwm_mvm_mac_ctxt_remove(sc, in);
-
- return error;
-#endif
-}
-
static struct ieee80211_node *
iwm_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
{
@@ -4282,7 +4219,98 @@ iwm_media_change(struct ifnet *ifp)
return error;
}
+static void
+iwm_bring_down_firmware(struct iwm_softc *sc, struct ieee80211vap *vap)
+{
+ struct iwm_vap *ivp = IWM_VAP(vap);
+ int error;
+ ivp->iv_auth = 0;
+ if (sc->sc_firmware_state == 3) {
+ iwm_xmit_queue_drain(sc);
+// iwm_mvm_flush_tx_path(sc, 0xf, IWM_CMD_SYNC);
+ error = iwm_mvm_rm_sta(sc, vap, TRUE);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "%s: Failed to remove station: %d\n",
+ __func__, error);
+ }
+ }
+ if (sc->sc_firmware_state == 3) {
+ error = iwm_mvm_mac_ctxt_changed(sc, vap);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "%s: Failed to change mac context: %d\n",
+ __func__, error);
+ }
+ }
+ if (sc->sc_firmware_state == 3) {
+ error = iwm_mvm_sf_update(sc, vap, FALSE);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "%s: Failed to update smart FIFO: %d\n",
+ __func__, error);
+ }
+ }
+ if (sc->sc_firmware_state == 3) {
+ error = iwm_mvm_rm_sta_id(sc, vap);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "%s: Failed to remove station id: %d\n",
+ __func__, error);
+ }
+ }
+ if (sc->sc_firmware_state == 3) {
+ error = iwm_mvm_update_quotas(sc, NULL);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "%s: Failed to update PHY quota: %d\n",
+ __func__, error);
+ }
+ }
+ if (sc->sc_firmware_state == 3) {
+ /* XXX Might need to specify bssid correctly. */
+ error = iwm_mvm_mac_ctxt_changed(sc, vap);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "%s: Failed to change mac context: %d\n",
+ __func__, error);
+ }
+ }
+ if (sc->sc_firmware_state == 3) {
+ sc->sc_firmware_state = 2;
+ }
+ if (sc->sc_firmware_state > 1) {
+ error = iwm_mvm_binding_remove_vif(sc, ivp);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "%s: Failed to remove channel ctx: %d\n",
+ __func__, error);
+ }
+ }
+ if (sc->sc_firmware_state > 1) {
+ sc->sc_firmware_state = 1;
+ }
+ ivp->phy_ctxt = NULL;
+ if (sc->sc_firmware_state > 0) {
+ error = iwm_mvm_mac_ctxt_changed(sc, vap);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "%s: Failed to change mac context: %d\n",
+ __func__, error);
+ }
+ }
+ if (sc->sc_firmware_state > 0) {
+ error = iwm_mvm_power_update_mac(sc);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: failed to update power management\n",
+ __func__);
+ }
+ }
+ sc->sc_firmware_state = 0;
+}
+
static int
iwm_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
@@ -4293,115 +4321,64 @@ iwm_newstate(struct ieee80211vap *vap, enum ieee80211_
int error;
IWM_DPRINTF(sc, IWM_DEBUG_STATE,
- "switching state %s -> %s\n",
+ "switching state %s -> %s arg=0x%x\n",
ieee80211_state_name[vap->iv_state],
- ieee80211_state_name[nstate]);
+ ieee80211_state_name[nstate],
+ arg);
+
IEEE80211_UNLOCK(ic);
IWM_LOCK(sc);
- if (vap->iv_state == IEEE80211_S_SCAN && nstate != vap->iv_state)
+ if ((sc->sc_flags & IWM_FLAG_SCAN_RUNNING) &&
+ (nstate == IEEE80211_S_AUTH ||
+ nstate == IEEE80211_S_ASSOC ||
+ nstate == IEEE80211_S_RUN)) {
+ /* Stop blinking for a scan, when authenticating. */
iwm_led_blink_stop(sc);
+ }
- /* disable beacon filtering if we're hopping out of RUN */
- if (vap->iv_state == IEEE80211_S_RUN && nstate != vap->iv_state) {
+ if (vap->iv_state == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
+ iwm_mvm_led_disable(sc);
+ /* disable beacon filtering if we're hopping out of RUN */
iwm_mvm_disable_beacon_filter(sc);
-
if (((in = IWM_NODE(vap->iv_bss)) != NULL))
in->in_assoc = 0;
+ }
- if (nstate == IEEE80211_S_INIT) {
- IWM_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- error = ivp->iv_newstate(vap, nstate, arg);
- IEEE80211_UNLOCK(ic);
- IWM_LOCK(sc);
- iwm_release(sc, NULL);
- IWM_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- return error;
- }
-
+ if ((vap->iv_state == IEEE80211_S_RUN ||
+ vap->iv_state == IEEE80211_S_ASSOC) &&
+ nstate == IEEE80211_S_INIT) {
/*
- * It's impossible to directly go RUN->SCAN. If we iwm_release()
- * above then the card will be completely reinitialized,
- * so the driver must do everything necessary to bring the card
- * from INIT to SCAN.
- *
- * Additionally, upon receiving deauth frame from AP,
- * OpenBSD 802.11 stack puts the driver in IEEE80211_S_AUTH
- * state. This will also fail with this driver, so bring the FSM
- * from IEEE80211_S_RUN to IEEE80211_S_SCAN in this case as well.
- *
- * XXX TODO: fix this for FreeBSD!
+ * In this case, iv_newstate() wants to send an 80211 frame on
+ * the network that we are leaving. So we need to call it,
+ * before tearing down all the firmware state.
*/
- if (nstate == IEEE80211_S_SCAN ||
- nstate == IEEE80211_S_AUTH ||
- nstate == IEEE80211_S_ASSOC) {
- IWM_DPRINTF(sc, IWM_DEBUG_STATE,
- "Force transition to INIT; MGT=%d\n", arg);
- IWM_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- /* Always pass arg as -1 since we can't Tx right now. */
- /*
- * XXX arg is just ignored anyway when transitioning
- * to IEEE80211_S_INIT.
- */
- vap->iv_newstate(vap, IEEE80211_S_INIT, -1);
- IWM_DPRINTF(sc, IWM_DEBUG_STATE,
- "Going INIT->SCAN\n");
- nstate = IEEE80211_S_SCAN;
- IEEE80211_UNLOCK(ic);
- IWM_LOCK(sc);
- }
+ IWM_UNLOCK(sc);
+ IEEE80211_LOCK(ic);
+ ivp->iv_newstate(vap, nstate, arg);
+ IEEE80211_UNLOCK(ic);
+ IWM_LOCK(sc);
+ iwm_bring_down_firmware(sc, vap);
+ IWM_UNLOCK(sc);
+ IEEE80211_LOCK(ic);
+ return 0;
}
switch (nstate) {
case IEEE80211_S_INIT:
case IEEE80211_S_SCAN:
- if (vap->iv_state == IEEE80211_S_AUTH ||
- vap->iv_state == IEEE80211_S_ASSOC) {
- int myerr;
- IWM_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- myerr = ivp->iv_newstate(vap, nstate, arg);
- IEEE80211_UNLOCK(ic);
- IWM_LOCK(sc);
- error = iwm_mvm_rm_sta(sc, vap, FALSE);
- if (error) {
- device_printf(sc->sc_dev,
- "%s: Failed to remove station: %d\n",
- __func__, error);
- }
- error = iwm_mvm_mac_ctxt_changed(sc, vap);
- if (error) {
- device_printf(sc->sc_dev,
- "%s: Failed to change mac context: %d\n",
- __func__, error);
- }
- error = iwm_mvm_binding_remove_vif(sc, ivp);
- if (error) {
- device_printf(sc->sc_dev,
- "%s: Failed to remove channel ctx: %d\n",
- __func__, error);
- }
- ivp->phy_ctxt = NULL;
- error = iwm_mvm_power_update_mac(sc);
- if (error != 0) {
- device_printf(sc->sc_dev,
- "%s: failed to update power management\n",
- __func__);
- }
- IWM_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- return myerr;
- }
break;
case IEEE80211_S_AUTH:
+ iwm_bring_down_firmware(sc, vap);
if ((error = iwm_auth(vap, sc)) != 0) {
device_printf(sc->sc_dev,
"%s: could not move to auth state: %d\n",
__func__, error);
+ iwm_bring_down_firmware(sc, vap);
+ IWM_UNLOCK(sc);
+ IEEE80211_LOCK(ic);
+ return 1;
}
break;
@@ -5566,6 +5543,8 @@ iwm_intr(void *arg)
device_printf(sc->sc_dev,
" 802.11 state %d\n", (vap == NULL) ? -1 : vap->iv_state);
+ /* Reset our firmware state tracking. */
+ sc->sc_firmware_state = 0;
/* Don't stop the device; just do a VAP restart */
IWM_UNLOCK(sc);
Modified: head/sys/dev/iwm/if_iwm_mac_ctxt.c
==============================================================================
--- head/sys/dev/iwm/if_iwm_mac_ctxt.c Thu Jan 24 03:45:24 2019 (r343380)
+++ head/sys/dev/iwm/if_iwm_mac_ctxt.c Thu Jan 24 03:45:55 2019 (r343381)
@@ -309,7 +309,12 @@ iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *sc, stru
* iwm_mvm_mac_ctxt_changed() when already authenticating or
* associating, ni->ni_bssid should always make sense here.
*/
- IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
+ if (ivp->iv_auth) {
+ IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
+ } else {
+ /* XXX Or maybe all zeroes address? */
+ IEEE80211_ADDR_COPY(cmd->bssid_addr, ieee80211broadcastaddr);
+ }
#endif
/*
Modified: head/sys/dev/iwm/if_iwm_sta.c
==============================================================================
--- head/sys/dev/iwm/if_iwm_sta.c Thu Jan 24 03:45:24 2019 (r343380)
+++ head/sys/dev/iwm/if_iwm_sta.c Thu Jan 24 03:45:55 2019 (r343381)
@@ -286,7 +286,7 @@ iwm_mvm_rm_sta(struct iwm_softc *sc, struct ieee80211v
for (ac = 0; ac < WME_NUM_AC; ac++) {
tfd_queue_msk |= htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]);
}
- ret = iwm_mvm_flush_tx_path(sc, tfd_queue_msk, 0);
+ ret = iwm_mvm_flush_tx_path(sc, tfd_queue_msk, IWM_CMD_SYNC);
if (ret)
return ret;
#ifdef notyet /* function not yet implemented */
Modified: head/sys/dev/iwm/if_iwmvar.h
==============================================================================
--- head/sys/dev/iwm/if_iwmvar.h Thu Jan 24 03:45:24 2019 (r343380)
+++ head/sys/dev/iwm/if_iwmvar.h Thu Jan 24 03:45:55 2019 (r343381)
@@ -365,6 +365,7 @@ struct iwm_bf_data {
struct iwm_vap {
struct ieee80211vap iv_vap;
int is_uploaded;
+ int iv_auth;
int (*iv_newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
@@ -558,6 +559,9 @@ struct iwm_softc {
boolean_t sc_ps_disabled;
int sc_ltr_enabled;
+
+ /* Track firmware state for STA association. */
+ int sc_firmware_state;
};
#define IWM_LOCK_INIT(_sc) \
More information about the svn-src-head
mailing list