svn commit: r346037 - stable/12/sys/dev/iwm

Kyle Evans kevans at FreeBSD.org
Mon Apr 8 18:15:12 UTC 2019


Author: kevans
Date: Mon Apr  8 18:15:10 2019
New Revision: 346037
URL: https://svnweb.freebsd.org/changeset/base/346037

Log:
  MFC r343065, r343373-r343390, r343477
  
  r343065:
  With the sync from Dragonfly BSD in r318216 a bug slipped in (also still present
  upstream it seems).
  
  The tlv variable was changed to a pointer but the advancement of the data pointer
  was left as sizeof(tlv).  While the sizeof the (now) pointer equals the
  sizeof 2 x uint32_t (size of the struct) on 64bit platforms, on 32bit platforms
  the size of the advancement of the data pointer was wrong leading to
  firmware load issues.
  
  Correctly advance the data pointer by the size of the structure and not by
  the size of a pointer.
  
  r343373:
  if_iwm - Update firmware rs table, instead of indexing the table in tx cmds.
  
  * Rather than providing a non-zero index into the firmware RS table,
  we should always use index 0 and update the firmware RS table whenever
  our chosen tx rate for data-frames changes.
  
  * Send IWM_LQ_CMD updates when the tx rate gets updated by the net80211
  rate control (which is after we tell the tx status to the net80211
  rate-control in iwm_mvm_rx_tx_cmd_single()).
  
  * Disregard frames transferred with a different tx rate than the currently
  selected rate for the rate-control calculations. This way we avoid
  counting management frames (which are sent at a slow, and fixed rate),
  as well as frames we added to the tx queue just before a new IWM_LQ_CMD
  update took effect.
  
  r343374:
  if_iwm - The iwm_prepare_card_hw() in iwm_attach() is only needed on 8K hw.
  
  * Doing the iwm_prepare_card_hw() call in iwm_attach() only on Family 8000
  hardware matches the code in Linux iwlwifi.
  
  * While there remove DEFAULT_MAX_TX_POWER definition which is unused, and
  has a value different from IWL_DEFAULT_MAX_TX_POWER in iwlwifi.
  
  r343375:
  if_iwm - Move iwm_read_firmware() call into iwm_attach().
  
  * We should load the firmware exactly once before the driver really
  initializes the hardware the first time, and unload it at detach time.
  There is no need to retrieve the firmware during execution of
  iwm_mvm_load_ucode_wait_alive(), we should make sure we already have the
  firmware data at hand before that.
  
  * The existing sc_preinit_hook code fails to deal with the case where
  if_iwm is loaded by the loader (or is statically linked) and the
  firmware needs to be loaded from disk. So we can just call
  iwm_read_firmware() from iwm_attach() directly.
  
  * A separate solution will have to be added to properly defer the firmware
  loading during bootup, until the necessary filesystem is mounted.
  
  r343376:
  if_iwm - Check sc->sc_attached flag in suspend/resume callbacks.
  
  * There is (almost) nothing to do in suspend/resume if if_iwm has failed
  during initialization (e.g. because of firmware load failure) and was
  already uninitialized by iwm_detach_local().
  
  r343377:
  iwm - Reduce gratuitous differences with Linux iwlwifi in struct naming.
  
  * Rename some structs and struct members for firmware handling.
  
  r343378:
  if_iwm - Update struct iwm_scan_results_notif. Remove old/unused definitions
  
  * Remove outdated notifications IWM_SCAN_ABORT_CMD,
  IWM_SCAN_START_NOTIFICATION and IWM_SCAN_RESULTS_NOTIFICATION.
  
  * Remove unused enum iwm_scan_complete_status.
  
  * Use the updated FW Api version 3 of struct iwm_scan_results_notif.
  
  * No functional change, since struct iwm_scan_results_notif is never
  accessed in iwm at the moment.
  
  Taken-From: Linux iwlwifi commits 1083fd7391e989be52022f0f338e9dadc048b063
  	and 75118fdb63496e4611ab50380499ddd62b9de69f.
  
  r343379:
  if_iwm - Configure the PCIe LTR, fix PCI express capability accesses.
  
  Taken-From: Linux iwlwifi
  
  r343380:
  if_iwm - Add firmware API definitions for TX power commands.
  
  * While there remove unused IWM_UCODE_TLV_CAPA_LMAC_UPLOAD definition,
  which isn't defined in iwlwifi.
  
  Taken-From: Linux iwlwifi
  
  r343381:
  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).
  
  r343382:
  iwm - Avoid Tx watchdog timeout, when dropping a connection.
  
  r343383:
  iwm - Improve firmware Time Event handling.
  
  * This is a mix of the OpenBSD Git 7fd9664469d1b717a307eebd74aeececbd3c41cc
  change, and syncing with the Linux iwlwifi code.
  
  Taken-From: Linux iwlwifi, and OpenBSD
  
  r343384:
  iwm - Clear Time Event active state, when receiving End Notification.
  
  * This hopefully avoids some firmware panics, I was occasionally seeing,
  when iwm disconnects upon losing signal to an access point at some point.
  
  * This is synchronizing the if_iwm_time_event.c file a bit more from the
  corresponding Linux iwlwifi/mvm/time-event.c.
  
  Taken-From:     Linux iwlwifi
  
  r343385:
  iwm - Always clear watchdog timer, when bringing down firmware state.
  
  r343386:
  if_iwm - Stop iwm_watchdog callout when idle.
  
  r343387:
  iwm - Fix race during detach, where a callout is left after driver is gone.
  
  r343388:
  iwm - Update alive response handling, add v4 and remove old versions.
  
  r343389:
  iwm - Remove unused REPLY_MAX
  
  Taken-From: Linux git e4eb275ac5cfe71686612d929a9829345b2a4ada
  
  r343390:
  iwm - Remove unused TX_CMD_NEXT_FRAME_*
  
  Taken-From: Linux git b1e06c65fb69c5e3fddcd91987561e225eaa9bfa
  
  r343477:
  Fix logic errors in iwm_pcie_load_firmware_chunk introduced in r314065.
  
   * There's no reason to have a while() loop here, because:
      - if msleep returns 0, that means we were woken up by the interrupt handler,
        and we are going to exit immediately as sc_fw_chunk_done will now be 1
        (there is nothing else that sleeps on sc_fw.)
      - if msleep doesn't return 0 (i.e. it returned ETIMEDOUT) then we will
        exit immediately because of the if-test.
     So, just use a single msleep() and then check sc_fw_chunk_done as before.
   * The comment said we were sleeping for 5 seconds, but the msleep was only
     for 1. Before r314065, this was 1 second and so was the comment,
     and in that commit the comment was changed and the function call wasn't.
  
  Possibly fixes failures to initialize uCode on certain devices.
  
  PR:		219683

Modified:
  stable/12/sys/dev/iwm/if_iwm.c
  stable/12/sys/dev/iwm/if_iwm_config.h
  stable/12/sys/dev/iwm/if_iwm_debug.h
  stable/12/sys/dev/iwm/if_iwm_fw.c
  stable/12/sys/dev/iwm/if_iwm_fw.h
  stable/12/sys/dev/iwm/if_iwm_led.c
  stable/12/sys/dev/iwm/if_iwm_mac_ctxt.c
  stable/12/sys/dev/iwm/if_iwm_pcie_trans.c
  stable/12/sys/dev/iwm/if_iwm_phy_db.c
  stable/12/sys/dev/iwm/if_iwm_scan.c
  stable/12/sys/dev/iwm/if_iwm_sta.c
  stable/12/sys/dev/iwm/if_iwm_time_event.c
  stable/12/sys/dev/iwm/if_iwm_time_event.h
  stable/12/sys/dev/iwm/if_iwmreg.h
  stable/12/sys/dev/iwm/if_iwmvar.h
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/dev/iwm/if_iwm.c
==============================================================================
--- stable/12/sys/dev/iwm/if_iwm.c	Mon Apr  8 17:59:42 2019	(r346036)
+++ stable/12/sys/dev/iwm/if_iwm.c	Mon Apr  8 18:15:10 2019	(r346037)
@@ -245,7 +245,7 @@ static int	iwm_firmware_store_section(struct iwm_softc
                                            const uint8_t *, size_t);
 static int	iwm_set_default_calib(struct iwm_softc *, const void *);
 static void	iwm_fw_info_free(struct iwm_fw_info *);
-static int	iwm_read_firmware(struct iwm_softc *, enum iwm_ucode_type);
+static int	iwm_read_firmware(struct iwm_softc *);
 static int	iwm_alloc_fwmem(struct iwm_softc *);
 static int	iwm_alloc_sched(struct iwm_softc *);
 static int	iwm_alloc_kw(struct iwm_softc *);
@@ -305,21 +305,22 @@ static int	iwm_pcie_load_section(struct iwm_softc *, u
 static int	iwm_pcie_load_firmware_chunk(struct iwm_softc *, uint32_t,
 					     bus_addr_t, uint32_t);
 static int	iwm_pcie_load_cpu_sections_8000(struct iwm_softc *sc,
-						const struct iwm_fw_sects *,
+						const struct iwm_fw_img *,
 						int, int *);
 static int	iwm_pcie_load_cpu_sections(struct iwm_softc *,
-					   const struct iwm_fw_sects *,
+					   const struct iwm_fw_img *,
 					   int, int *);
 static int	iwm_pcie_load_given_ucode_8000(struct iwm_softc *,
-					       const struct iwm_fw_sects *);
+					       const struct iwm_fw_img *);
 static int	iwm_pcie_load_given_ucode(struct iwm_softc *,
-					  const struct iwm_fw_sects *);
-static int	iwm_start_fw(struct iwm_softc *, const struct iwm_fw_sects *);
+					  const struct iwm_fw_img *);
+static int	iwm_start_fw(struct iwm_softc *, const struct iwm_fw_img *);
 static int	iwm_send_tx_ant_cfg(struct iwm_softc *, uint8_t);
 static int	iwm_send_phy_cfg_cmd(struct iwm_softc *);
 static int	iwm_mvm_load_ucode_wait_alive(struct iwm_softc *,
                                               enum iwm_ucode_type);
 static int	iwm_run_init_mvm_ucode(struct iwm_softc *, int);
+static int	iwm_mvm_config_ltr(struct iwm_softc *sc);
 static int	iwm_rx_addbuf(struct iwm_softc *, int, int);
 static int	iwm_mvm_get_signal_strength(struct iwm_softc *,
 					    struct iwm_rx_phy_info *);
@@ -349,11 +350,12 @@ 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]);
-static void	iwm_setrates(struct iwm_softc *, struct iwm_node *);
+static uint8_t	iwm_rate_from_ucode_rate(uint32_t);
+static int	iwm_rate2ridx(struct iwm_softc *, uint8_t);
+static void	iwm_setrates(struct iwm_softc *, struct iwm_node *, int);
 static int	iwm_media_change(struct ifnet *);
 static int	iwm_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void	iwm_endscan_cb(void *, int);
@@ -424,7 +426,7 @@ static int
 iwm_firmware_store_section(struct iwm_softc *sc,
     enum iwm_ucode_type type, const uint8_t *data, size_t dlen)
 {
-	struct iwm_fw_sects *fws;
+	struct iwm_fw_img *fws;
 	struct iwm_fw_desc *fwone;
 
 	if (type >= IWM_UCODE_TYPE_MAX)
@@ -432,11 +434,11 @@ iwm_firmware_store_section(struct iwm_softc *sc,
 	if (dlen < sizeof(uint32_t))
 		return EINVAL;
 
-	fws = &sc->sc_fw.fw_sects[type];
+	fws = &sc->sc_fw.img[type];
 	if (fws->fw_count >= IWM_UCODE_SECTION_MAX)
 		return EINVAL;
 
-	fwone = &fws->fw_sect[fws->fw_count];
+	fwone = &fws->sec[fws->fw_count];
 
 	/* first 32bit are device load offset */
 	memcpy(&fwone->offset, data, sizeof(uint32_t));
@@ -534,17 +536,16 @@ iwm_fw_info_free(struct iwm_fw_info *fw)
 {
 	firmware_put(fw->fw_fp, FIRMWARE_UNLOAD);
 	fw->fw_fp = NULL;
-	/* don't touch fw->fw_status */
-	memset(fw->fw_sects, 0, sizeof(fw->fw_sects));
+	memset(fw->img, 0, sizeof(fw->img));
 }
 
 static int
-iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
+iwm_read_firmware(struct iwm_softc *sc)
 {
 	struct iwm_fw_info *fw = &sc->sc_fw;
 	const struct iwm_tlv_ucode_header *uhdr;
 	const struct iwm_ucode_tlv *tlv;
-	struct iwm_ucode_capabilities *capa = &sc->ucode_capa;
+	struct iwm_ucode_capabilities *capa = &sc->sc_fw.ucode_capa;
 	enum iwm_ucode_tlv_type tlv_type;
 	const struct firmware *fwp;
 	const uint8_t *data;
@@ -556,24 +557,11 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 	int error = 0;
 	size_t len;
 
-	if (fw->fw_status == IWM_FW_STATUS_DONE &&
-	    ucode_type != IWM_UCODE_INIT)
-		return 0;
-
-	while (fw->fw_status == IWM_FW_STATUS_INPROGRESS)
-		msleep(&sc->sc_fw, &sc->sc_mtx, 0, "iwmfwp", 0);
-	fw->fw_status = IWM_FW_STATUS_INPROGRESS;
-
-	if (fw->fw_fp != NULL)
-		iwm_fw_info_free(fw);
-
 	/*
 	 * Load firmware into driver memory.
 	 * fw_fp will be set.
 	 */
-	IWM_UNLOCK(sc);
 	fwp = firmware_get(sc->cfg->fw_name);
-	IWM_LOCK(sc);
 	if (fwp == NULL) {
 		device_printf(sc->sc_dev,
 		    "could not read firmware %s (error %d)\n",
@@ -626,15 +614,14 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 			goto parse_out;
 		}
 		len -= roundup2(tlv_len, 4);
-		data += sizeof(tlv) + roundup2(tlv_len, 4);
+		data += sizeof(*tlv) + roundup2(tlv_len, 4);
 
 		switch ((int)tlv_type) {
 		case IWM_UCODE_TLV_PROBE_MAX_LEN:
 			if (tlv_len != sizeof(uint32_t)) {
 				device_printf(sc->sc_dev,
-				    "%s: PROBE_MAX_LEN (%d) != sizeof(uint32_t)\n",
-				    __func__,
-				    (int) tlv_len);
+				    "%s: PROBE_MAX_LEN (%u) != sizeof(uint32_t)\n",
+				    __func__, tlv_len);
 				error = EINVAL;
 				goto parse_out;
 			}
@@ -653,9 +640,8 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 		case IWM_UCODE_TLV_PAN:
 			if (tlv_len) {
 				device_printf(sc->sc_dev,
-				    "%s: IWM_UCODE_TLV_PAN: tlv_len (%d) > 0\n",
-				    __func__,
-				    (int) tlv_len);
+				    "%s: IWM_UCODE_TLV_PAN: tlv_len (%u) > 0\n",
+				    __func__, tlv_len);
 				error = EINVAL;
 				goto parse_out;
 			}
@@ -664,17 +650,15 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 		case IWM_UCODE_TLV_FLAGS:
 			if (tlv_len < sizeof(uint32_t)) {
 				device_printf(sc->sc_dev,
-				    "%s: IWM_UCODE_TLV_FLAGS: tlv_len (%d) < sizeof(uint32_t)\n",
-				    __func__,
-				    (int) tlv_len);
+				    "%s: IWM_UCODE_TLV_FLAGS: tlv_len (%u) < sizeof(uint32_t)\n",
+				    __func__, tlv_len);
 				error = EINVAL;
 				goto parse_out;
 			}
 			if (tlv_len % sizeof(uint32_t)) {
 				device_printf(sc->sc_dev,
-				    "%s: IWM_UCODE_TLV_FLAGS: tlv_len (%d) %% sizeof(uint32_t)\n",
-				    __func__,
-				    (int) tlv_len);
+				    "%s: IWM_UCODE_TLV_FLAGS: tlv_len (%u) %% sizeof(uint32_t)\n",
+				    __func__, tlv_len);
 				error = EINVAL;
 				goto parse_out;
 			}
@@ -696,27 +680,25 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 			    tlv_data, tlv_len)) != 0) {
 				device_printf(sc->sc_dev,
 				    "%s: iwm_store_cscheme(): returned %d\n",
-				    __func__,
-				    error);
+				    __func__, error);
 				goto parse_out;
 			}
 			break;
 		case IWM_UCODE_TLV_NUM_OF_CPU:
 			if (tlv_len != sizeof(uint32_t)) {
 				device_printf(sc->sc_dev,
-				    "%s: IWM_UCODE_TLV_NUM_OF_CPU: tlv_len (%d) != sizeof(uint32_t)\n",
-				    __func__,
-				    (int) tlv_len);
+				    "%s: IWM_UCODE_TLV_NUM_OF_CPU: tlv_len (%u) != sizeof(uint32_t)\n",
+				    __func__, tlv_len);
 				error = EINVAL;
 				goto parse_out;
 			}
 			num_of_cpus = le32_to_cpup((const uint32_t *)tlv_data);
 			if (num_of_cpus == 2) {
-				fw->fw_sects[IWM_UCODE_REGULAR].is_dual_cpus =
+				fw->img[IWM_UCODE_REGULAR].is_dual_cpus =
 					TRUE;
-				fw->fw_sects[IWM_UCODE_INIT].is_dual_cpus =
+				fw->img[IWM_UCODE_INIT].is_dual_cpus =
 					TRUE;
-				fw->fw_sects[IWM_UCODE_WOWLAN].is_dual_cpus =
+				fw->img[IWM_UCODE_WOWLAN].is_dual_cpus =
 					TRUE;
 			} else if ((num_of_cpus > 2) || (num_of_cpus < 1)) {
 				device_printf(sc->sc_dev,
@@ -731,8 +713,7 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 			    IWM_UCODE_REGULAR, tlv_data, tlv_len)) != 0) {
 				device_printf(sc->sc_dev,
 				    "%s: IWM_UCODE_REGULAR: iwm_firmware_store_section() failed; %d\n",
-				    __func__,
-				    error);
+				    __func__, error);
 				goto parse_out;
 			}
 			break;
@@ -741,8 +722,7 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 			    IWM_UCODE_INIT, tlv_data, tlv_len)) != 0) {
 				device_printf(sc->sc_dev,
 				    "%s: IWM_UCODE_INIT: iwm_firmware_store_section() failed; %d\n",
-				    __func__,
-				    error);
+				    __func__, error);
 				goto parse_out;
 			}
 			break;
@@ -751,26 +731,23 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 			    IWM_UCODE_WOWLAN, tlv_data, tlv_len)) != 0) {
 				device_printf(sc->sc_dev,
 				    "%s: IWM_UCODE_WOWLAN: iwm_firmware_store_section() failed; %d\n",
-				    __func__,
-				    error);
+				    __func__, error);
 				goto parse_out;
 			}
 			break;
 		case IWM_UCODE_TLV_DEF_CALIB:
 			if (tlv_len != sizeof(struct iwm_tlv_calib_data)) {
 				device_printf(sc->sc_dev,
-				    "%s: IWM_UCODE_TLV_DEV_CALIB: tlv_len (%d) < sizeof(iwm_tlv_calib_data) (%d)\n",
-				    __func__,
-				    (int) tlv_len,
-				    (int) sizeof(struct iwm_tlv_calib_data));
+				    "%s: IWM_UCODE_TLV_DEV_CALIB: tlv_len (%u) < sizeof(iwm_tlv_calib_data) (%zu)\n",
+				    __func__, tlv_len,
+				    sizeof(struct iwm_tlv_calib_data));
 				error = EINVAL;
 				goto parse_out;
 			}
 			if ((error = iwm_set_default_calib(sc, tlv_data)) != 0) {
 				device_printf(sc->sc_dev,
 				    "%s: iwm_set_default_calib() failed: %d\n",
-				    __func__,
-				    error);
+				    __func__, error);
 				goto parse_out;
 			}
 			break;
@@ -778,9 +755,8 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 			if (tlv_len != sizeof(uint32_t)) {
 				error = EINVAL;
 				device_printf(sc->sc_dev,
-				    "%s: IWM_UCODE_TLV_PHY_SKU: tlv_len (%d) < sizeof(uint32_t)\n",
-				    __func__,
-				    (int) tlv_len);
+				    "%s: IWM_UCODE_TLV_PHY_SKU: tlv_len (%u) < sizeof(uint32_t)\n",
+				    __func__, tlv_len);
 				goto parse_out;
 			}
 			sc->sc_fw.phy_config =
@@ -855,10 +831,10 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 				goto out;
 			}
 
-			sc->sc_fw.fw_sects[IWM_UCODE_REGULAR].paging_mem_size =
+			sc->sc_fw.img[IWM_UCODE_REGULAR].paging_mem_size =
 			    paging_mem_size;
 			usniffer_img = IWM_UCODE_REGULAR_USNIFFER;
-			sc->sc_fw.fw_sects[usniffer_img].paging_mem_size =
+			sc->sc_fw.img[usniffer_img].paging_mem_size =
 			    paging_mem_size;
 			break;
 
@@ -905,12 +881,9 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode
 
  out:
 	if (error) {
-		fw->fw_status = IWM_FW_STATUS_NONE;
 		if (fw->fw_fp != NULL)
 			iwm_fw_info_free(fw);
-	} else
-		fw->fw_status = IWM_FW_STATUS_DONE;
-	wakeup(&sc->sc_fw);
+	}
 
 	return error;
 }
@@ -1289,6 +1262,8 @@ iwm_stop_device(struct iwm_softc *sc)
 		iv->phy_ctxt = NULL;
 		iv->is_uploaded = 0;
 	}
+	sc->sc_firmware_state = 0;
+	sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE;
 
 	/* device going down, Stop using ICT table */
 	sc->sc_flags &= ~IWM_FLAG_USE_ICT;
@@ -1910,8 +1885,6 @@ enum nvm_sku_bits {
 #define IWM_NVM_RF_CFG_TX_ANT_MSK_8000(x)	((x >> 24) & 0xF)
 #define IWM_NVM_RF_CFG_RX_ANT_MSK_8000(x)	((x >> 28) & 0xF)
 
-#define DEFAULT_MAX_TX_POWER 16
-
 /**
  * enum iwm_nvm_channel_flags - channel flags in NVM
  * @IWM_NVM_CHANNEL_VALID: channel is usable for this SKU/geo
@@ -2426,8 +2399,6 @@ static int
 iwm_pcie_load_firmware_chunk(struct iwm_softc *sc, uint32_t dst_addr,
 			     bus_addr_t phy_addr, uint32_t byte_cnt)
 {
-	int ret;
-
 	sc->sc_fw_chunk_done = 0;
 
 	if (!iwm_nic_lock(sc))
@@ -2459,14 +2430,9 @@ iwm_pcie_load_firmware_chunk(struct iwm_softc *sc, uin
 	iwm_nic_unlock(sc);
 
 	/* wait up to 5s for this segment to load */
-	ret = 0;
-	while (!sc->sc_fw_chunk_done) {
-		ret = msleep(&sc->sc_fw, &sc->sc_mtx, 0, "iwmfw", hz);
-		if (ret)
-			break;
-	}
+	msleep(&sc->sc_fw, &sc->sc_mtx, 0, "iwmfw", hz * 5);
 
-	if (ret != 0) {
+	if (!sc->sc_fw_chunk_done) {
 		device_printf(sc->sc_dev,
 		    "fw chunk addr 0x%x len %d failed to load\n",
 		    dst_addr, byte_cnt);
@@ -2478,7 +2444,7 @@ iwm_pcie_load_firmware_chunk(struct iwm_softc *sc, uin
 
 static int
 iwm_pcie_load_cpu_sections_8000(struct iwm_softc *sc,
-	const struct iwm_fw_sects *image, int cpu, int *first_ucode_section)
+	const struct iwm_fw_img *image, int cpu, int *first_ucode_section)
 {
 	int shift_param;
 	int i, ret = 0, sec_num = 0x1;
@@ -2501,15 +2467,15 @@ iwm_pcie_load_cpu_sections_8000(struct iwm_softc *sc,
 		 * PAGING_SEPARATOR_SECTION delimiter - separate between
 		 * CPU2 non paged to CPU2 paging sec.
 		 */
-		if (!image->fw_sect[i].data ||
-		    image->fw_sect[i].offset == IWM_CPU1_CPU2_SEPARATOR_SECTION ||
-		    image->fw_sect[i].offset == IWM_PAGING_SEPARATOR_SECTION) {
+		if (!image->sec[i].data ||
+		    image->sec[i].offset == IWM_CPU1_CPU2_SEPARATOR_SECTION ||
+		    image->sec[i].offset == IWM_PAGING_SEPARATOR_SECTION) {
 			IWM_DPRINTF(sc, IWM_DEBUG_RESET,
 				    "Break since Data not valid or Empty section, sec = %d\n",
 				    i);
 			break;
 		}
-		ret = iwm_pcie_load_section(sc, i, &image->fw_sect[i]);
+		ret = iwm_pcie_load_section(sc, i, &image->sec[i]);
 		if (ret)
 			return ret;
 
@@ -2540,7 +2506,7 @@ iwm_pcie_load_cpu_sections_8000(struct iwm_softc *sc,
 
 static int
 iwm_pcie_load_cpu_sections(struct iwm_softc *sc,
-	const struct iwm_fw_sects *image, int cpu, int *first_ucode_section)
+	const struct iwm_fw_img *image, int cpu, int *first_ucode_section)
 {
 	int shift_param;
 	int i, ret = 0;
@@ -2563,16 +2529,16 @@ iwm_pcie_load_cpu_sections(struct iwm_softc *sc,
 		 * PAGING_SEPARATOR_SECTION delimiter - separate between
 		 * CPU2 non paged to CPU2 paging sec.
 		 */
-		if (!image->fw_sect[i].data ||
-		    image->fw_sect[i].offset == IWM_CPU1_CPU2_SEPARATOR_SECTION ||
-		    image->fw_sect[i].offset == IWM_PAGING_SEPARATOR_SECTION) {
+		if (!image->sec[i].data ||
+		    image->sec[i].offset == IWM_CPU1_CPU2_SEPARATOR_SECTION ||
+		    image->sec[i].offset == IWM_PAGING_SEPARATOR_SECTION) {
 			IWM_DPRINTF(sc, IWM_DEBUG_RESET,
 				    "Break since Data not valid or Empty section, sec = %d\n",
 				     i);
 			break;
 		}
 
-		ret = iwm_pcie_load_section(sc, i, &image->fw_sect[i]);
+		ret = iwm_pcie_load_section(sc, i, &image->sec[i]);
 		if (ret)
 			return ret;
 	}
@@ -2584,8 +2550,7 @@ iwm_pcie_load_cpu_sections(struct iwm_softc *sc,
 }
 
 static int
-iwm_pcie_load_given_ucode(struct iwm_softc *sc,
-	const struct iwm_fw_sects *image)
+iwm_pcie_load_given_ucode(struct iwm_softc *sc, const struct iwm_fw_img *image)
 {
 	int ret = 0;
 	int first_ucode_section;
@@ -2624,7 +2589,7 @@ iwm_pcie_load_given_ucode(struct iwm_softc *sc,
 
 int
 iwm_pcie_load_given_ucode_8000(struct iwm_softc *sc,
-	const struct iwm_fw_sects *image)
+	const struct iwm_fw_img *image)
 {
 	int ret = 0;
 	int first_ucode_section;
@@ -2662,8 +2627,7 @@ iwm_enable_fw_load_int(struct iwm_softc *sc)
 
 /* XXX Add proper rfkill support code */
 static int
-iwm_start_fw(struct iwm_softc *sc,
-	const struct iwm_fw_sects *fw)
+iwm_start_fw(struct iwm_softc *sc, const struct iwm_fw_img *fw)
 {
 	int ret;
 
@@ -2754,75 +2718,48 @@ static int
 iwm_alive_fn(struct iwm_softc *sc, struct iwm_rx_packet *pkt, void *data)
 {
 	struct iwm_mvm_alive_data *alive_data = data;
-	struct iwm_mvm_alive_resp_ver1 *palive1;
-	struct iwm_mvm_alive_resp_ver2 *palive2;
+	struct iwm_mvm_alive_resp_v3 *palive3;
 	struct iwm_mvm_alive_resp *palive;
+	struct iwm_umac_alive *umac;
+	struct iwm_lmac_alive *lmac1;
+	struct iwm_lmac_alive *lmac2 = NULL;
+	uint16_t status;
 
-	if (iwm_rx_packet_payload_len(pkt) == sizeof(*palive1)) {
-		palive1 = (void *)pkt->data;
-
-		sc->support_umac_log = FALSE;
-                sc->error_event_table =
-                        le32toh(palive1->error_event_table_ptr);
-                sc->log_event_table =
-                        le32toh(palive1->log_event_table_ptr);
-                alive_data->scd_base_addr = le32toh(palive1->scd_base_ptr);
-
-                alive_data->valid = le16toh(palive1->status) ==
-                                    IWM_ALIVE_STATUS_OK;
-                IWM_DPRINTF(sc, IWM_DEBUG_RESET,
-			    "Alive VER1 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
-			     le16toh(palive1->status), palive1->ver_type,
-                             palive1->ver_subtype, palive1->flags);
-	} else if (iwm_rx_packet_payload_len(pkt) == sizeof(*palive2)) {
-		palive2 = (void *)pkt->data;
-		sc->error_event_table =
-			le32toh(palive2->error_event_table_ptr);
-		sc->log_event_table =
-			le32toh(palive2->log_event_table_ptr);
-		alive_data->scd_base_addr = le32toh(palive2->scd_base_ptr);
-		sc->umac_error_event_table =
-                        le32toh(palive2->error_info_addr);
-
-		alive_data->valid = le16toh(palive2->status) ==
-				    IWM_ALIVE_STATUS_OK;
-		if (sc->umac_error_event_table)
-			sc->support_umac_log = TRUE;
-
-		IWM_DPRINTF(sc, IWM_DEBUG_RESET,
-			    "Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
-			    le16toh(palive2->status), palive2->ver_type,
-			    palive2->ver_subtype, palive2->flags);
-
-		IWM_DPRINTF(sc, IWM_DEBUG_RESET,
-			    "UMAC version: Major - 0x%x, Minor - 0x%x\n",
-			    palive2->umac_major, palive2->umac_minor);
-	} else if (iwm_rx_packet_payload_len(pkt) == sizeof(*palive)) {
+	if (iwm_rx_packet_payload_len(pkt) == sizeof(*palive)) {
 		palive = (void *)pkt->data;
+		umac = &palive->umac_data;
+		lmac1 = &palive->lmac_data[0];
+		lmac2 = &palive->lmac_data[1];
+		status = le16toh(palive->status);
+	} else {
+		palive3 = (void *)pkt->data;
+		umac = &palive3->umac_data;
+		lmac1 = &palive3->lmac_data;
+		status = le16toh(palive3->status);
+	}
 
-		sc->error_event_table =
-			le32toh(palive->error_event_table_ptr);
-		sc->log_event_table =
-			le32toh(palive->log_event_table_ptr);
-		alive_data->scd_base_addr = le32toh(palive->scd_base_ptr);
-		sc->umac_error_event_table =
-			le32toh(palive->error_info_addr);
+	sc->error_event_table[0] = le32toh(lmac1->error_event_table_ptr);
+	if (lmac2)
+		sc->error_event_table[1] =
+			le32toh(lmac2->error_event_table_ptr);
+	sc->log_event_table = le32toh(lmac1->log_event_table_ptr);
+	sc->umac_error_event_table = le32toh(umac->error_info_addr);
+	alive_data->scd_base_addr = le32toh(lmac1->scd_base_ptr);
+	alive_data->valid = status == IWM_ALIVE_STATUS_OK;
+	if (sc->umac_error_event_table)
+		sc->support_umac_log = TRUE;
 
-		alive_data->valid = le16toh(palive->status) ==
-				    IWM_ALIVE_STATUS_OK;
-		if (sc->umac_error_event_table)
-			sc->support_umac_log = TRUE;
+	IWM_DPRINTF(sc, IWM_DEBUG_FW,
+		    "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n",
+		    status, lmac1->ver_type, lmac1->ver_subtype);
 
-		IWM_DPRINTF(sc, IWM_DEBUG_RESET,
-			    "Alive VER3 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
-			    le16toh(palive->status), palive->ver_type,
-			    palive->ver_subtype, palive->flags);
+	if (lmac2)
+		IWM_DPRINTF(sc, IWM_DEBUG_FW, "Alive ucode CDB\n");
 
-		IWM_DPRINTF(sc, IWM_DEBUG_RESET,
-			    "UMAC version: Major - 0x%x, Minor - 0x%x\n",
-			    le32toh(palive->umac_major),
-			    le32toh(palive->umac_minor));
-	}
+	IWM_DPRINTF(sc, IWM_DEBUG_FW,
+		    "UMAC version: Major - 0x%x, Minor - 0x%x\n",
+		    le32toh(umac->umac_major),
+		    le32toh(umac->umac_minor));
 
 	return TRUE;
 }
@@ -2855,17 +2792,12 @@ iwm_mvm_load_ucode_wait_alive(struct iwm_softc *sc,
 {
 	struct iwm_notification_wait alive_wait;
 	struct iwm_mvm_alive_data alive_data;
-	const struct iwm_fw_sects *fw;
+	const struct iwm_fw_img *fw;
 	enum iwm_ucode_type old_type = sc->cur_ucode;
 	int error;
 	static const uint16_t alive_cmd[] = { IWM_MVM_ALIVE };
 
-	if ((error = iwm_read_firmware(sc, ucode_type)) != 0) {
-		device_printf(sc->sc_dev, "iwm_read_firmware: failed %d\n",
-			error);
-		return error;
-	}
-	fw = &sc->sc_fw.fw_sects[ucode_type];
+	fw = &sc->sc_fw.img[ucode_type];
 	sc->cur_ucode = ucode_type;
 	sc->ucode_loaded = FALSE;
 
@@ -3038,6 +2970,19 @@ out:
 	return ret;
 }
 
+static int
+iwm_mvm_config_ltr(struct iwm_softc *sc)
+{
+	struct iwm_ltr_config_cmd cmd = {
+		.flags = htole32(IWM_LTR_CFG_FLAG_FEATURE_ENABLE),
+	};
+
+	if (!sc->sc_ltr_enabled)
+		return 0;
+
+	return iwm_mvm_send_cmd_pdu(sc, IWM_LTR_CONFIG, 0, sizeof(cmd), &cmd);
+}
+
 /*
  * receive side
  */
@@ -3319,7 +3264,11 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct 
 	struct iwm_mvm_tx_resp *tx_resp = (void *)pkt->data;
 	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct ieee80211_node *ni = &in->in_ni;
+	struct ieee80211vap *vap = ni->ni_vap;
 	int status = le16toh(tx_resp->status.status) & IWM_TX_STATUS_MSK;
+	int new_rate, cur_rate = vap->iv_bss->ni_txrate;
+	boolean_t rate_matched;
+	uint8_t tx_resp_rate;
 
 	KASSERT(tx_resp->frame_count == 1, ("too many frames"));
 
@@ -3335,6 +3284,17 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct 
 	    le32toh(tx_resp->initial_rate),
 	    (int) le16toh(tx_resp->wireless_media_time));
 
+	tx_resp_rate = iwm_rate_from_ucode_rate(le32toh(tx_resp->initial_rate));
+
+	/* For rate control, ignore frames sent at different initial rate */
+	rate_matched = (tx_resp_rate != 0 && tx_resp_rate == cur_rate);
+
+	if (tx_resp_rate != 0 && cur_rate != 0 && !rate_matched) {
+		IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
+		    "tx_resp_rate doesn't match ni_txrate (tx_resp_rate=%u "
+		    "ni_txrate=%d)\n", tx_resp_rate, cur_rate);
+	}
+
 	txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY |
 		     IEEE80211_RATECTL_STATUS_LONG_RETRY;
 	txs->short_retries = tx_resp->failure_rts;
@@ -3358,8 +3318,19 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct 
 	} else {
 		txs->status = IEEE80211_RATECTL_TX_SUCCESS;
 	}
-	ieee80211_ratectl_tx_complete(ni, txs);
 
+	if (rate_matched) {
+		ieee80211_ratectl_tx_complete(ni, txs);
+
+		int rix = ieee80211_ratectl_rate(vap->iv_bss, NULL, 0);
+		new_rate = vap->iv_bss->ni_txrate;
+		if (new_rate != 0 && new_rate != cur_rate) {
+			struct iwm_node *in = IWM_NODE(vap->iv_bss);
+			iwm_setrates(sc, in, rix);
+			iwm_mvm_send_lq_cmd(sc, &in->in_lq, FALSE);
+		}
+ 	}
+
 	return (txs->status != IEEE80211_RATECTL_TX_SUCCESS);
 }
 
@@ -3484,38 +3455,7 @@ iwm_update_sched(struct iwm_softc *sc, int qid, int id
 }
 #endif
 
-/*
- * Take an 802.11 (non-n) rate, find the relevant rate
- * table entry.  return the index into in_ridx[].
- *
- * The caller then uses that index back into in_ridx
- * to figure out the rate index programmed /into/
- * the firmware for this given node.
- */
 static int
-iwm_tx_rateidx_lookup(struct iwm_softc *sc, struct iwm_node *in,
-    uint8_t rate)
-{
-	int i;
-	uint8_t r;
-
-	for (i = 0; i < nitems(in->in_ridx); i++) {
-		r = iwm_rates[in->in_ridx[i]].rate;
-		if (rate == r)
-			return (i);
-	}
-
-	IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE,
-	    "%s: couldn't find an entry for rate=%d\n",
-	    __func__,
-	    rate);
-
-	/* XXX Return the first */
-	/* XXX TODO: have it return the /lowest/ */
-	return (0);
-}
-
-static int
 iwm_tx_rateidx_global_lookup(struct iwm_softc *sc, uint8_t rate)
 {
 	int i;
@@ -3567,22 +3507,15 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node 
 		IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
 		    "%s: FIXED_RATE (%d)\n", __func__, tp->ucastrate);
 	} else {
-		int i;
-
 		/* for data frames, use RS table */
 		IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: DATA\n", __func__);
-		/* XXX pass pktlen */
-		(void) ieee80211_ratectl_rate(ni, NULL, 0);
-		i = iwm_tx_rateidx_lookup(sc, in, ni->ni_txrate);
-		ridx = in->in_ridx[i];
+		ridx = iwm_rate2ridx(sc, ni->ni_txrate);
+		if (ridx == -1)
+			ridx = 0;
 
 		/* This is the index into the programmed table */
-		tx->initial_rate_index = i;
+		tx->initial_rate_index = 0;
 		tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE);
-
-		IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE,
-		    "%s: start with i=%d, txrate %d\n",
-		    __func__, i, iwm_rates[ridx].rate);
 	}
 
 	IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE,
@@ -3849,6 +3782,8 @@ iwm_raw_xmit(struct ieee80211_node *ni, struct mbuf *m
 	} else {
 		error = iwm_tx(sc, m, ni, 0);
 	}
+	if (sc->sc_tx_timer == 0)
+		callout_reset(&sc->sc_watchdog_to, hz, iwm_watchdog, sc);
 	sc->sc_tx_timer = 5;
 	IWM_UNLOCK(sc);
 
@@ -3987,8 +3922,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
@@ -4040,6 +3978,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) {
@@ -4054,6 +3993,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
@@ -4073,6 +4013,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
@@ -4080,86 +4021,16 @@ iwm_auth(struct ieee80211vap *vap, struct iwm_softc *s
 	 */
 	/* XXX duration is in units of TU, not MS */
 	duration = IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
-	iwm_mvm_protect_session(sc, iv, duration, 500 /* XXX magic number */);
-	DELAY(100);
+	iwm_mvm_protect_session(sc, iv, duration, 500 /* XXX magic number */, TRUE);
 
 	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])
 {
@@ -4167,6 +4038,19 @@ iwm_node_alloc(struct ieee80211vap *vap, const uint8_t
 	    M_NOWAIT | M_ZERO);
 }
 
+static uint8_t
+iwm_rate_from_ucode_rate(uint32_t rate_n_flags)
+{
+	uint8_t plcp = rate_n_flags & 0xff;
+	int i;
+
+	for (i = 0; i <= IWM_RIDX_MAX; i++) {
+		if (iwm_rates[i].plcp == plcp)
+			return iwm_rates[i].rate;
+	}
+	return 0;
+}
+
 uint8_t
 iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx)
 {
@@ -4182,15 +4066,36 @@ iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx)
 	return 0;
 }
 
+static int
+iwm_rate2ridx(struct iwm_softc *sc, uint8_t rate)
+{
+	int i;
+
+	for (i = 0; i <= IWM_RIDX_MAX; i++) {
+		if (iwm_rates[i].rate == rate)
+			return i;
+	}
+
+	device_printf(sc->sc_dev,
+	    "%s: WARNING: device rate for %u not found!\n",
+	    __func__, rate);
+
+	return -1;
+}
+
+
 static void
-iwm_setrates(struct iwm_softc *sc, struct iwm_node *in)
+iwm_setrates(struct iwm_softc *sc, struct iwm_node *in, int rix)
 {
 	struct ieee80211_node *ni = &in->in_ni;
 	struct iwm_lq_cmd *lq = &in->in_lq;
-	int nrates = ni->ni_rates.rs_nrates;
+	struct ieee80211_rateset *rs = &ni->ni_rates;
+	int nrates = rs->rs_nrates;
 	int i, ridx, tab = 0;
 //	int txant = 0;
 
+	KASSERT(rix >= 0 && rix < nrates, ("invalid rix"));
+
 	if (nrates > nitems(lq->rs_table)) {
 		device_printf(sc->sc_dev,
 		    "%s: node supports %d rates, driver handles "
@@ -4202,45 +4107,11 @@ iwm_setrates(struct iwm_softc *sc, struct iwm_node *in
 		    "%s: node supports 0 rates, odd!\n", __func__);
 		return;
 	}
+	nrates = imin(rix + 1, nrates);
 
-	/*
-	 * XXX .. and most of iwm_node is not initialised explicitly;
-	 * it's all just 0x0 passed to the firmware.
-	 */
-
-	/* first figure out which rates we should support */
-	/* XXX TODO: this isn't 11n aware /at all/ */
-	memset(&in->in_ridx, -1, sizeof(in->in_ridx));
 	IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
 	    "%s: nrates=%d\n", __func__, nrates);
 
-	/*
-	 * Loop over nrates and populate in_ridx from the highest
-	 * rate to the lowest rate.  Remember, in_ridx[] has
-	 * IEEE80211_RATE_MAXSIZE entries!
-	 */
-	for (i = 0; i < min(nrates, IEEE80211_RATE_MAXSIZE); i++) {
-		int rate = ni->ni_rates.rs_rates[(nrates - 1) - i] & IEEE80211_RATE_VAL;
-
-		/* Map 802.11 rate to HW rate index. */
-		for (ridx = 0; ridx <= IWM_RIDX_MAX; ridx++)
-			if (iwm_rates[ridx].rate == rate)
-				break;
-		if (ridx > IWM_RIDX_MAX) {
-			device_printf(sc->sc_dev,
-			    "%s: WARNING: device rate for %d not found!\n",
-			    __func__, rate);
-		} else {
-			IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
-			    "%s: rate: i: %d, rate=%d, ridx=%d\n",
-			    __func__,
-			    i,
-			    rate,
-			    ridx);
-			in->in_ridx[i] = ridx;
-		}
-	}
-
 	/* then construct a lq_cmd based on those */
 	memset(lq, 0, sizeof(*lq));
 	lq->sta_id = IWM_STATION_ID;
@@ -4264,13 +4135,15 @@ iwm_setrates(struct iwm_softc *sc, struct iwm_node *in
 	 * Note that we add the rates in the highest rate first
 	 * (opposite of ni_rates).
 	 */
-	/*
-	 * XXX TODO: this should be looping over the min of nrates
-	 * and LQ_MAX_RETRY_NUM.  Sigh.
-	 */
 	for (i = 0; i < nrates; i++) {
+		int rate = rs->rs_rates[rix - i] & IEEE80211_RATE_VAL;
 		int nextant;
 
+		/* Map 802.11 rate to HW rate index. */
+		ridx = iwm_rate2ridx(sc, rate);
+		if (ridx == -1)
+			continue;
+
 #if 0
 		if (txant == 0)
 			txant = iwm_mvm_get_valid_tx_ant(sc);
@@ -4279,12 +4152,6 @@ iwm_setrates(struct iwm_softc *sc, struct iwm_node *in
 #else
 		nextant = iwm_mvm_get_valid_tx_ant(sc);
 #endif
-		/*
-		 * Map the rate id into a rate index into
-		 * our hardware table containing the
-		 * configuration to use for this rate.
-		 */
-		ridx = in->in_ridx[i];
 		tab = iwm_rates[ridx].plcp;
 		tab |= nextant << IWM_RATE_MCS_ANT_POS;
 		if (IWM_RIDX_IS_CCK(ridx))
@@ -4322,7 +4189,101 @@ 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;
 
+	/* Avoid Tx watchdog triggering, when transfers get dropped here. */
+	sc->sc_tx_timer = 0;
+
+	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) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-stable mailing list