Update iwm(4) to firmware version 16.242414.0 (API 16).
New firmware has been available in fw_update(1) for several weeks already.

Among many API changes this firmware version introduces a wide command header
for some commands because the old API format has run out command number space.

This firmware has a new scan API (LMAC scan -- "lower mac" scan) which can
scan both 2GHz and 5GHz bands in a single run. This allows us to simplify
the hairy scanning logic in the driver significantly.

A couple of new firmware features (Smart FIFO, BT coex, Location Aware
Regulatory, TX backoff for temperature regulation) are unused, but are
nonetheless initialized by the driver because apparently the firmware
generally expects the driver to initialize firmware state.

Many thanks to Emmanuel Grumbach for providing helpful advice, and to
genua gmbh for funding this effort.

This also paves the way for upcoming 8260 device support in iwm(4).

Index: if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.81
diff -u -p -r1.81 if_iwm.c
--- if_iwm.c    18 May 2016 07:28:01 -0000      1.81
+++ if_iwm.c    18 May 2016 09:42:53 -0000
@@ -1,7 +1,8 @@
 /*     $OpenBSD: if_iwm.c,v 1.81 2016/05/18 07:28:01 stsp Exp $        */
 
 /*
- * Copyright (c) 2014 genua mbh <i...@genua.de>
+ * Copyright (c) 2014, 2016 genua gmbh <i...@genua.de>
+ *   Author: Stefan Sperling <s...@openbsd.org>
  * Copyright (c) 2014 Fixup Software Ltd.
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -21,9 +22,6 @@
  * Based on BSD-licensed source modules in the Linux iwlwifi driver,
  * which were used as the reference documentation for this implementation.
  *
- * Driver version we are currently based off of is
- * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd)
- *
  ***********************************************************************
  *
  * This file is provided under a dual BSD/GPLv2 license.  When using or
@@ -32,6 +30,8 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -58,6 +58,8 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -129,6 +131,7 @@
 #include <net/bpf.h>
 #endif
 #include <net/if.h>
+#include <net/if_dl.h>
 #include <net/if_media.h>
 
 #include <netinet/in.h>
@@ -205,6 +208,11 @@ const int iwm_mcs2ridx[] = {
        IWM_RATE_MCS_7_INDEX,
 };
 
+struct iwm_nvm_section {
+       uint16_t length;
+       uint8_t *data;
+};
+
 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);
@@ -260,7 +268,7 @@ void        iwm_mvm_nic_config(struct iwm_softc
 int    iwm_nic_rx_init(struct iwm_softc *);
 int    iwm_nic_tx_init(struct iwm_softc *);
 int    iwm_nic_init(struct iwm_softc *);
-void   iwm_enable_txq(struct iwm_softc *, int, int);
+int    iwm_enable_txq(struct iwm_softc *, int, int, int);
 int    iwm_post_alive(struct iwm_softc *);
 struct iwm_phy_db_entry *iwm_phy_db_get_section(struct iwm_softc *,
                                        enum iwm_phy_db_section_type, uint16_t);
@@ -287,8 +295,9 @@ void        iwm_mvm_protect_session(struct iwm_
 int    iwm_nvm_read_chunk(struct iwm_softc *, uint16_t, uint16_t, uint16_t,
                                uint8_t *, uint16_t *);
 int    iwm_nvm_read_section(struct iwm_softc *, uint16_t, uint8_t *,
-                               uint16_t *);
-void   iwm_init_channel_map(struct iwm_softc *, const uint16_t * const);
+                               uint16_t *, size_t);
+void   iwm_init_channel_map(struct iwm_softc *, const uint16_t * const,
+                               const uint8_t *nvm_channels, size_t nchan);
 void   iwm_setup_ht_rates(struct iwm_softc *);
 void   iwm_htprot_task(void *);
 void   iwm_update_htprot(struct ieee80211com *, struct ieee80211_node *);
@@ -307,14 +316,16 @@ void      iwm_ampdu_tx_stop(struct ieee80211c
 void   iwm_ba_task(void *);
 
 int    iwm_parse_nvm_data(struct iwm_softc *, const uint16_t *,
-                               const uint16_t *, const uint16_t *, uint8_t,
-                               uint8_t);
-#ifdef notyet
+                               const uint16_t *, const uint16_t *,
+                               const uint16_t *, const uint16_t *,
+                               const uint16_t *);
 int    iwm_parse_nvm_sections(struct iwm_softc *, struct iwm_nvm_section *);
-#endif
 int    iwm_nvm_init(struct iwm_softc *);
+int    iwm_firmware_load_sect(struct iwm_softc *, uint32_t, const uint8_t *,
+                               uint32_t);
 int    iwm_firmware_load_chunk(struct iwm_softc *, uint32_t, const uint8_t *,
                                uint32_t);
+int    iwm_load_firmware_7000(struct iwm_softc *, enum iwm_ucode_type);
 int    iwm_load_firmware(struct iwm_softc *, enum iwm_ucode_type);
 int    iwm_start_fw(struct iwm_softc *, enum iwm_ucode_type);
 int    iwm_send_tx_ant_cfg(struct iwm_softc *, uint8_t);
@@ -378,11 +389,9 @@ void       iwm_mvm_power_build_cmd(struct iwm_
 int    iwm_mvm_power_mac_update_mode(struct iwm_softc *, struct iwm_node *);
 int    iwm_mvm_power_update_device(struct iwm_softc *);
 int    iwm_mvm_enable_beacon_filter(struct iwm_softc *, struct iwm_node *);
-int    iwm_mvm_disable_beacon_filter(struct iwm_softc *, struct iwm_node *);
-void   iwm_mvm_add_sta_cmd_v6_to_v5(struct iwm_mvm_add_sta_cmd_v6 *,
-                                       struct iwm_mvm_add_sta_cmd_v5 *);
+int    iwm_mvm_disable_beacon_filter(struct iwm_softc *);
 int    iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *,
-                                       struct iwm_mvm_add_sta_cmd_v6 *, int *);
+                                       struct iwm_mvm_add_sta_cmd_v7 *, int *);
 int    iwm_mvm_sta_send_to_fw(struct iwm_softc *, struct iwm_node *, int);
 int    iwm_mvm_add_sta(struct iwm_softc *, struct iwm_node *);
 int    iwm_mvm_update_sta(struct iwm_softc *, struct iwm_node *);
@@ -392,15 +401,13 @@ int       iwm_mvm_add_aux_sta(struct iwm_softc
 uint16_t iwm_mvm_scan_rx_chain(struct iwm_softc *);
 uint32_t iwm_mvm_scan_max_out_time(struct iwm_softc *, uint32_t, int);
 uint32_t iwm_mvm_scan_suspend_time(struct iwm_softc *, int);
-uint32_t iwm_mvm_scan_rxon_flags(struct iwm_softc *, int);
 uint32_t iwm_mvm_scan_rate_n_flags(struct iwm_softc *, int, int);
 uint16_t iwm_mvm_get_active_dwell(struct iwm_softc *, int, int);
 uint16_t iwm_mvm_get_passive_dwell(struct iwm_softc *, int);
-int    iwm_mvm_scan_fill_channels(struct iwm_softc *, struct iwm_scan_cmd *,
-                               int, int, int);
-uint16_t iwm_mvm_fill_probe_req(struct iwm_softc *, struct ieee80211_frame *,
-       const uint8_t *, int, const uint8_t *, int, const uint8_t *, int, int);
-int    iwm_mvm_scan_request(struct iwm_softc *, int, int, uint8_t *, int);
+uint8_t        iwm_mvm_lmac_scan_fill_channels(struct iwm_softc *,
+                               struct iwm_scan_channel_cfg_lmac *, int);
+int    iwm_mvm_fill_probe_req(struct iwm_softc *, struct iwm_scan_probe_req *);
+int    iwm_mvm_lmac_scan(struct iwm_softc *);
 void   iwm_mvm_ack_rates(struct iwm_softc *, struct iwm_node *, int *, int *);
 void   iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *, struct iwm_node *,
                                        struct iwm_mac_ctx_cmd *, uint32_t);
@@ -423,6 +430,12 @@ int        iwm_media_change(struct ifnet *);
 void   iwm_newstate_task(void *);
 int    iwm_newstate(struct ieee80211com *, enum ieee80211_state, int);
 void   iwm_endscan_cb(void *);
+void   iwm_mvm_fill_sf_command(struct iwm_softc *, struct iwm_sf_cfg_cmd *,
+           struct ieee80211_node *);
+int    iwm_mvm_sf_config(struct iwm_softc *, enum iwm_sf_state);
+int    iwm_send_bt_init_conf(struct iwm_softc *);
+int    iwm_send_update_mcc_cmd(struct iwm_softc *, const char *);
+void   iwm_mvm_tt_tx_backoff(struct iwm_softc *, uint32_t);
 int    iwm_init_hw(struct iwm_softc *);
 int    iwm_init(struct ifnet *);
 void   iwm_start(struct ifnet *);
@@ -565,6 +578,12 @@ iwm_read_firmware(struct iwm_softc *sc, 
                goto out;
        }
 
+       /* (Re-)Initialize default values. */
+       sc->sc_capaflags = 0;
+       sc->sc_capa_n_scan_channels = IWM_MAX_NUM_SCAN_CHANNELS;
+       memset(sc->sc_enabled_capa, 0, sizeof(sc->sc_enabled_capa));
+       memset(sc->sc_fw_mcc, 0, sizeof(sc->sc_fw_mcc));
+
        /*
         * Parse firmware contents
         */
@@ -578,7 +597,10 @@ iwm_read_firmware(struct iwm_softc *sc, 
                goto out;
        }
 
-       sc->sc_fwver = le32toh(uhdr->ver);
+       snprintf(sc->sc_fwver, sizeof(sc->sc_fwver), "%d.%d (API ver %d)",
+           IWM_UCODE_MAJOR(le32toh(uhdr->ver)),
+           IWM_UCODE_MINOR(le32toh(uhdr->ver)),
+           IWM_UCODE_API(le32toh(uhdr->ver)));
        data = uhdr->data;
        len = fw->fw_rawsize - sizeof(*uhdr);
 
@@ -610,7 +632,8 @@ iwm_read_firmware(struct iwm_softc *sc, 
                        sc->sc_capa_max_probe_len
                            = le32toh(*(uint32_t *)tlv_data);
                        /* limit it to something sensible */
-                       if (sc->sc_capa_max_probe_len > (1<<16)) {
+                       if (sc->sc_capa_max_probe_len >
+                           IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE) {
                                DPRINTF(("%s: IWM_UCODE_TLV_PROBE_MAX_LEN "
                                    "ridiculous\n", DEVNAME(sc)));
                                error = EINVAL;
@@ -690,11 +713,79 @@ iwm_read_firmware(struct iwm_softc *sc, 
                        sc->sc_fw_phy_config = le32toh(*(uint32_t *)tlv_data);
                        break;
 
-               case IWM_UCODE_TLV_API_CHANGES_SET:
-               case IWM_UCODE_TLV_ENABLED_CAPABILITIES:
+               case IWM_UCODE_TLV_API_CHANGES_SET: {
+                       struct iwm_ucode_api *api;
+                       if (tlv_len != sizeof(*api)) {
+                               error = EINVAL;
+                               goto parse_out;
+                       }
+                       api = (struct iwm_ucode_api *)tlv_data;
+                       /* Flags may exceed 32 bits in future firmware. */
+                       if (le32toh(api->api_index) > 0) {
+                               DPRINTF(("%s: unsupported API index %d\n",
+                                   DEVNAME(sc), le32toh(api->api_index)));
+                               goto parse_out;
+                       }
+                       sc->sc_ucode_api = le32toh(api->api_flags);
+                       break;
+               }
+
+               case IWM_UCODE_TLV_ENABLED_CAPABILITIES: {
+                       struct iwm_ucode_capa *capa;
+                       int idx, i;
+                       if (tlv_len != sizeof(*capa)) {
+                               error = EINVAL;
+                               goto parse_out;
+                       }
+                       capa = (struct iwm_ucode_capa *)tlv_data;
+                       idx = le32toh(capa->api_index);
+                       if (idx > howmany(IWM_NUM_UCODE_TLV_CAPA, 32)) {
+                               DPRINTF(("%s: unsupported API index %d\n",
+                                   DEVNAME(sc), idx));
+                               goto parse_out;
+                       }
+                       for (i = 0; i < 32; i++) {
+                               if ((le32toh(capa->api_capa) & (1 << i)) == 0)
+                                       continue;
+                               setbit(sc->sc_enabled_capa, i + (32 * idx));
+                       }
+                       break;
+               }
+
+               case 48: /* undocumented TLV */
+               case IWM_UCODE_TLV_SDIO_ADMA_ADDR:
+               case IWM_UCODE_TLV_FW_GSCAN_CAPA:
                        /* ignore, not used by current driver */
                        break;
 
+               case IWM_UCODE_TLV_SEC_RT_USNIFFER:
+                       if ((error = iwm_firmware_store_section(sc,
+                           IWM_UCODE_TYPE_REGULAR_USNIFFER, tlv_data,
+                           tlv_len)) != 0)
+                               goto parse_out;
+                       break;
+
+               case IWM_UCODE_TLV_N_SCAN_CHANNELS:
+                       if (tlv_len != sizeof(uint32_t)) {
+                               error = EINVAL;
+                               goto parse_out;
+                       }
+                       sc->sc_capa_n_scan_channels =
+                         le32toh(*(uint32_t *)tlv_data);
+                       break;
+
+               case IWM_UCODE_TLV_FW_VERSION:
+                       if (tlv_len != sizeof(uint32_t) * 3) {
+                               error = EINVAL;
+                               goto parse_out;
+                       }
+                       snprintf(sc->sc_fwver, sizeof(sc->sc_fwver),
+                           "%d.%d.%d",
+                           le32toh(((uint32_t *)tlv_data)[0]),
+                           le32toh(((uint32_t *)tlv_data)[1]),
+                           le32toh(((uint32_t *)tlv_data)[2]));
+                       break;
+
                default:
                        DPRINTF(("%s: unknown firmware section %d, abort\n",
                            DEVNAME(sc), tlv_type));
@@ -1291,6 +1382,7 @@ iwm_ict_reset(struct iwm_softc *sc)
        IWM_WRITE(sc, IWM_CSR_DRAM_INT_TBL_REG,
            IWM_CSR_DRAM_INT_TBL_ENABLE
            | IWM_CSR_DRAM_INIT_TBL_WRAP_CHECK
+           | IWM_CSR_DRAM_INIT_TBL_WRITE_POINTER
            | sc->ict_dma.paddr >> IWM_ICT_PADDR_SHIFT);
 
        /* Switch to ICT interrupt mode in driver. */
@@ -1305,13 +1397,20 @@ iwm_ict_reset(struct iwm_softc *sc)
 int
 iwm_set_hw_ready(struct iwm_softc *sc)
 {
+       int ready;
+
        IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
            IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
 
-       return iwm_poll_bit(sc, IWM_CSR_HW_IF_CONFIG_REG,
+       ready = iwm_poll_bit(sc, IWM_CSR_HW_IF_CONFIG_REG,
            IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
            IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
            IWM_HW_READY_TIMEOUT);
+       if (ready)
+               IWM_SETBITS(sc, IWM_CSR_MBOX_SET_REG,
+                   IWM_CSR_MBOX_SET_REG_OS_ALIVE);
+
+       return ready;
 }
 #undef IWM_HW_READY_TIMEOUT
 
@@ -1488,9 +1587,7 @@ iwm_start_hw(struct iwm_softc *sc)
                return error;
 
        /* Reset the entire device */
-       IWM_WRITE(sc, IWM_CSR_RESET,
-           IWM_CSR_RESET_REG_FLAG_SW_RESET |
-           IWM_CSR_RESET_REG_FLAG_NEVO_RESET);
+       IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET);
        DELAY(10);
 
        if ((error = iwm_apm_init(sc)) != 0)
@@ -1563,7 +1660,7 @@ iwm_stop_device(struct iwm_softc *sc)
         */
        iwm_disable_interrupts(sc);
        /* stop and reset the on-board processor */
-       IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_NEVO_RESET);
+       IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET);
 
        /*
         * Even if we stop the HW, we still want the RF kill
@@ -1646,16 +1743,12 @@ iwm_nic_rx_init(struct iwm_softc *sc)
            IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG, sc->rxq.stat_dma.paddr >> 4);
 
        /* Enable RX. */
-       /*
-        * Note: Linux driver also sets this:
-        *  (IWM_RX_RB_TIMEOUT << IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) |
-        *
-        * It causes weird behavior.  YMMV.
-        */
        IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG,
            IWM_FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL            |
            IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY               |  /* HW bug */
            IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL   |
+           IWM_FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK        |
+           (IWM_RX_RB_TIMEOUT << IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) |
            IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K            |
            IWM_RX_QUEUE_SIZE_LOG << IWM_FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS);
 
@@ -1702,6 +1795,9 @@ iwm_nic_tx_init(struct iwm_softc *sc)
                DPRINTF(("loading ring %d descriptors (%p) at %lx\n",
                    qid, txq->desc, txq->desc_dma.paddr >> 8));
        }
+
+       iwm_write_prph(sc, IWM_SCD_GP_CTRL, IWM_SCD_GP_CTRL_AUTO_ACTIVE_MODE);
+
        iwm_nic_unlock(sc);
 
        return 0;
@@ -1739,47 +1835,74 @@ const uint8_t iwm_mvm_ac_to_tx_fifo[] = 
        IWM_MVM_TX_FIFO_BK,
 };
 
-void
-iwm_enable_txq(struct iwm_softc *sc, int qid, int fifo)
+int
+iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo)
 {
        if (!iwm_nic_lock(sc)) {
                DPRINTF(("%s: cannot enable txq %d\n", DEVNAME(sc), qid));
-               return; /* XXX return EBUSY */
+               return EBUSY;
        }
 
-       /* unactivate before configuration */
-       iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
-           (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE)
-           | (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+       IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0);
 
-       if (qid != IWM_MVM_CMD_QUEUE) {
-               iwm_set_bits_prph(sc, IWM_SCD_QUEUECHAIN_SEL, (1 << qid));
-       }
+       if (qid == IWM_MVM_CMD_QUEUE) {
+               /* unactivate before configuration */
+               iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
+                   (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE)
+                   | (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+
+               iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid));
+
+               iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0);
+
+               iwm_write_mem32(sc, sc->sched_base + 
IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0);
+               /* Set scheduler window size and frame limit. */
+               iwm_write_mem32(sc,
+                   sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) +
+                   sizeof(uint32_t),
+                   ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+                   IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                   ((IWM_FRAME_LIMIT << 
IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+                   IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+               iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
+                   (1 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+                   (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) |
+                   (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) |
+                   IWM_SCD_QUEUE_STTS_REG_MSK);
+       } else {
+               struct iwm_scd_txq_cfg_cmd cmd;
+               int error;
 
-       iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid));
+               iwm_nic_unlock(sc);
 
-       IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0);
-       iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0);
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.scd_queue = qid;
+               cmd.enable = 1;
+               cmd.sta_id = sta_id;
+               cmd.tx_fifo = fifo;
+               cmd.aggregate = 0;
+               cmd.window = IWM_FRAME_LIMIT;
 
-       iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 
0);
-       /* Set scheduler window size and frame limit. */
-       iwm_write_mem32(sc,
-           sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) +
-           sizeof(uint32_t),
-           ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-           IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-           ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-           IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-
-       iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
-           (1 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
-           (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) |
-           (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) |
-           IWM_SCD_QUEUE_STTS_REG_MSK);
+               error = iwm_mvm_send_cmd_pdu(sc, IWM_SCD_QUEUE_CFG, 
IWM_CMD_SYNC,
+                   sizeof(cmd), &cmd);
+               if (error) {
+                       DPRINTF(("%s: cannot enable txq %d\n", DEVNAME(sc), 
qid));
+                       return error;
+               }
+
+               if (!iwm_nic_lock(sc))
+                       return EBUSY;
+       }
+
+       iwm_write_prph(sc, IWM_SCD_EN_CTRL,
+           iwm_read_prph(sc, IWM_SCD_EN_CTRL) | qid);
 
        iwm_nic_unlock(sc);
 
        DPRINTF(("enabled txq %d FIFO %d\n", qid, fifo));
+
+       return 0;
 }
 
 int
@@ -1787,15 +1910,15 @@ iwm_post_alive(struct iwm_softc *sc)
 {
        int nwords;
        int error, chnl;
+       uint32_t base;
 
        if (!iwm_nic_lock(sc))
                return EBUSY;
 
-       if (sc->sched_base != iwm_read_prph(sc, IWM_SCD_SRAM_BASE_ADDR)) {
-               DPRINTF(("%s: sched addr mismatch", DEVNAME(sc)));
-               error = EINVAL;
-               goto out;
-       }
+       base = iwm_read_prph(sc, IWM_SCD_SRAM_BASE_ADDR);
+       if (sc->sched_base != base)
+               DPRINTF(("%s: sched addr mismatch: alive: 0x%x prph: 0x%x\n",
+                   DEVNAME(sc), sc->sched_base, base));
 
        iwm_ict_reset(sc);
 
@@ -1814,8 +1937,15 @@ iwm_post_alive(struct iwm_softc *sc)
 
        iwm_write_prph(sc, IWM_SCD_CHAINEXT_EN, 0);
 
+       iwm_nic_unlock(sc);
+
        /* enable command channel */
-       iwm_enable_txq(sc, IWM_MVM_CMD_QUEUE, 7);
+       error = iwm_enable_txq(sc, 0 /* unused */, IWM_MVM_CMD_QUEUE, 7);
+       if (error)
+               return error;
+
+       if (!iwm_nic_lock(sc))
+               return EBUSY;
 
        iwm_write_prph(sc, IWM_SCD_TXFACT, 0xff);
 
@@ -2017,7 +2147,6 @@ iwm_send_phy_db_cmd(struct iwm_softc *sc
        cmd.len[0] = sizeof(struct iwm_phy_db_cmd);
        cmd.data[1] = data;
        cmd.len[1] = length;
-       cmd.dataflags[1] = IWM_HCMD_DFL_NOCOPY;
 
        return iwm_send_cmd(sc, &cmd);
 }
@@ -2047,6 +2176,7 @@ iwm_phy_db_send_all_channel_groups(struc
                        return err;
                }
 
+               DELAY(1000);
                DPRINTFN(10, ("Sent PHY_DB HCMD, type = %d num = %d\n", type, 
i));
        }
 
@@ -2212,8 +2342,7 @@ iwm_mvm_protect_session(struct iwm_softc
            htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color));
        time_cmd.id = htole32(IWM_TE_BSS_STA_AGGRESSIVE_ASSOC);
 
-       time_cmd.apply_time = htole32(iwm_read_prph(sc,
-           IWM_DEVICE_SYSTEM_TIME_REG));
+       time_cmd.apply_time = htole32(0);
 
        time_cmd.max_frags = IWM_TE_V2_FRAG_NONE;
        time_cmd.max_delay = htole32(max_delay);
@@ -2223,7 +2352,8 @@ iwm_mvm_protect_session(struct iwm_softc
        time_cmd.repeat = 1;
        time_cmd.policy
            = htole32(IWM_TE_V2_NOTIF_HOST_EVENT_START |
-               IWM_TE_V2_NOTIF_HOST_EVENT_END);
+               IWM_TE_V2_NOTIF_HOST_EVENT_END |
+               IWM_T2_V2_START_IMMEDIATELY);
 
        iwm_mvm_time_event_send_add(sc, in, /*te_data*/NULL, &time_cmd);
 }
@@ -2237,17 +2367,22 @@ iwm_mvm_protect_session(struct iwm_softc
 const int nvm_to_read[] = {
        IWM_NVM_SECTION_TYPE_HW,
        IWM_NVM_SECTION_TYPE_SW,
+       IWM_NVM_SECTION_TYPE_REGULATORY,
        IWM_NVM_SECTION_TYPE_CALIBRATION,
        IWM_NVM_SECTION_TYPE_PRODUCTION,
 };
 
 /* Default NVM size to read */
-#define IWM_NVM_DEFAULT_CHUNK_SIZE (2*1024)
-#define IWM_MAX_NVM_SECTION_SIZE 7000
+#define IWM_NVM_DEFAULT_CHUNK_SIZE     (2*1024)
+#define IWM_MAX_NVM_SECTION_SIZE       8192
 
 #define IWM_NVM_WRITE_OPCODE 1
 #define IWM_NVM_READ_OPCODE 0
 
+/* load nvm chunk response */
+#define IWM_READ_NVM_CHUNK_SUCCEED             0
+#define IWM_READ_NVM_CHUNK_INVALID_ADDRESS     1
+
 int
 iwm_nvm_read_chunk(struct iwm_softc *sc, uint16_t section,
        uint16_t offset, uint16_t length, uint8_t *data, uint16_t *len)
@@ -2267,14 +2402,18 @@ iwm_nvm_read_chunk(struct iwm_softc *sc,
                    IWM_CMD_SEND_IN_RFKILL,
                .data = { &nvm_access_cmd, },
        };
-       int ret, bytes_read, offset_read;
+       int ret, offset_read;
+       size_t bytes_read;
        uint8_t *resp_data;
 
        cmd.len[0] = sizeof(struct iwm_nvm_access_cmd);
 
        ret = iwm_send_cmd(sc, &cmd);
-       if (ret)
+       if (ret) {
+               DPRINTF(("%s: Could not send NVM_ACCESS command (error=%d)\n",
+                   DEVNAME(sc), ret));
                return ret;
+       }
 
        pkt = cmd.resp_pkt;
        if (pkt->hdr.flags & IWM_CMD_FAILED_MSK) {
@@ -2305,6 +2444,14 @@ iwm_nvm_read_chunk(struct iwm_softc *sc,
                goto exit;
        }
 
+       if (bytes_read > length) {
+               DPRINTF(("%s: NVM ACCESS response with too much data "
+               "(%d bytes requested, %zd bytes received)\n",
+               DEVNAME(sc), length, bytes_read));
+               ret = EINVAL;
+               goto exit;
+       }
+
        memcpy(data + offset, resp_data, bytes_read);
        *len = bytes_read;
 
@@ -2325,45 +2472,63 @@ iwm_nvm_read_chunk(struct iwm_softc *sc,
  */
 int
 iwm_nvm_read_section(struct iwm_softc *sc,
-       uint16_t section, uint8_t *data, uint16_t *len)
+       uint16_t section, uint8_t *data, uint16_t *len, size_t max_len)
 {
-       uint16_t length, seglen;
-       int error;
+       uint16_t chunklen, seglen;
+       int error = 0;
+
+       DPRINTFN(2, ("%s: reading NVM section %d\n", DEVNAME(sc), section));
 
-       /* Set nvm section read length */
-       length = seglen = IWM_NVM_DEFAULT_CHUNK_SIZE;
+       chunklen = seglen = IWM_NVM_DEFAULT_CHUNK_SIZE;
        *len = 0;
 
-       /* Read the NVM until exhausted (reading less than requested) */
-       while (seglen == length) {
+       /* Read NVM chunks until exhausted (reading less than requested) */
+       while (seglen == chunklen && *len < max_len) {
                error = iwm_nvm_read_chunk(sc,
-                   section, *len, length, data, &seglen);
+                   section, *len, chunklen, data, &seglen);
                if (error) {
-                       printf("%s: Cannot read NVM from section "
-                           "%d offset %d, length %d\n",
-                           DEVNAME(sc), section, *len, length);
+                       DPRINTF(("%s: Cannot read from NVM section "
+                           "%d at offset %d\n", DEVNAME(sc), section, *len));
                        return error;
                }
                *len += seglen;
        }
 
-       DPRINTFN(4, ("NVM section %d read completed\n", section));
-       return 0;
+       DPRINTFN(2, ("%s: NVM section %d read completed (%d bytes, error=%d)\n",
+           DEVNAME(sc), section, *len, error));
+       return error;
 }
 
-/*
- * BEGIN IWM_NVM_PARSE
- */
+uint8_t
+iwm_fw_valid_tx_ant(struct iwm_softc *sc)
+{
+       uint8_t tx_ant;
+
+       tx_ant = ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_TX_CHAIN)
+           >> IWM_FW_PHY_CFG_TX_CHAIN_POS);
+
+       if (sc->sc_nvm.valid_tx_ant)
+               tx_ant &= sc->sc_nvm.valid_tx_ant;
+
+       return tx_ant;
+}
 
-#define IWM_FW_VALID_TX_ANT(sc) \
-    ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_TX_CHAIN) \
-    >> IWM_FW_PHY_CFG_TX_CHAIN_POS)
-#define IWM_FW_VALID_RX_ANT(sc) \
-    ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RX_CHAIN) \
-    >> IWM_FW_PHY_CFG_RX_CHAIN_POS)
+uint8_t
+iwm_fw_valid_rx_ant(struct iwm_softc *sc)
+{
+       uint8_t rx_ant;
+
+       rx_ant = ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RX_CHAIN)
+           >> IWM_FW_PHY_CFG_RX_CHAIN_POS);
+
+       if (sc->sc_nvm.valid_rx_ant)
+               rx_ant &= sc->sc_nvm.valid_rx_ant;
+
+       return rx_ant;
+}
 
 /* NVM offsets (in words) definitions */
-enum wkp_nvm_offsets {
+enum iwm_nvm_offsets {
        /* NVM HW-Section offset (in words) definitions */
        IWM_HW_ADDR = 0x15,
 
@@ -2424,7 +2589,8 @@ enum iwm_nvm_channel_flags {
 };
 
 void
-iwm_init_channel_map(struct iwm_softc *sc, const uint16_t * const nvm_ch_flags)
+iwm_init_channel_map(struct iwm_softc *sc, const uint16_t * const nvm_ch_flags,
+                       const uint8_t *nvm_channels, size_t nchan)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct iwm_nvm_data *data = &sc->sc_nvm;
@@ -2434,7 +2600,7 @@ iwm_init_channel_map(struct iwm_softc *s
        int is_5ghz;
        int flags, hw_value;
 
-       for (ch_idx = 0; ch_idx < nitems(iwm_nvm_channels); ch_idx++) {
+       for (ch_idx = 0; ch_idx < nchan; ch_idx++) {
                ch_flags = le16_to_cpup(nvm_ch_flags + ch_idx);
 
                if (ch_idx >= IWM_NUM_2GHZ_CHANNELS &&
@@ -2443,14 +2609,14 @@ iwm_init_channel_map(struct iwm_softc *s
 
                if (!(ch_flags & IWM_NVM_CHANNEL_VALID)) {
                        DPRINTF(("Ch. %d Flags %x [%sGHz] - No traffic\n",
-                           iwm_nvm_channels[ch_idx],
+                           nvm_channels[ch_idx],
                            ch_flags,
                            (ch_idx >= IWM_NUM_2GHZ_CHANNELS) ?
                            "5.2" : "2.4"));
                        continue;
                }
 
-               hw_value = iwm_nvm_channels[ch_idx];
+               hw_value = nvm_channels[ch_idx];
                channel = &ic->ic_channels[hw_value];
 
                is_5ghz = ch_idx >= IWM_NUM_2GHZ_CHANNELS;
@@ -2490,9 +2656,9 @@ iwm_setup_ht_rates(struct iwm_softc *sc)
        if (sc->sc_nvm.sku_cap_mimo_disable)
                return;
 
-       if (IWM_FW_VALID_RX_ANT(sc) > 1)
+       if (iwm_fw_valid_rx_ant(sc) > 1)
                ic->ic_sup_mcs[1] = 0xff;       /* MCS 8-15 */
-       if (IWM_FW_VALID_RX_ANT(sc) > 2)
+       if (iwm_fw_valid_rx_ant(sc) > 2)
                ic->ic_sup_mcs[2] = 0xff;       /* MCS 16-23 */
 #endif
 }
@@ -2503,7 +2669,7 @@ void
 iwm_mvm_sta_rx_agg(struct iwm_softc *sc, struct ieee80211_node *ni,
     uint8_t tid, uint16_t ssn, int start)
 {
-       struct iwm_mvm_add_sta_cmd_v6 cmd;
+       struct iwm_mvm_add_sta_cmd_v7 cmd;
        struct iwm_node *in = (void *)ni;
        int ret, s;
        uint32_t status;
@@ -2637,11 +2803,13 @@ iwm_ampdu_rx_stop(struct ieee80211com *i
 int
 iwm_parse_nvm_data(struct iwm_softc *sc,
        const uint16_t *nvm_hw, const uint16_t *nvm_sw,
-       const uint16_t *nvm_calib, uint8_t tx_chains, uint8_t rx_chains)
+       const uint16_t *nvm_calib, const uint16_t *mac_override,
+       const uint16_t *phy_sku, const uint16_t *regulatory)
 {
        struct iwm_nvm_data *data = &sc->sc_nvm;
        uint8_t hw_addr[ETHER_ADDR_LEN];
-       uint16_t radio_cfg, sku;
+       uint16_t radio_cfg;
+       uint32_t sku;
 
        data->nvm_version = le16_to_cpup(nvm_sw + IWM_NVM_VERSION);
 
@@ -2668,9 +2836,6 @@ iwm_parse_nvm_data(struct iwm_softc *sc,
 
        data->n_hw_addrs = le16_to_cpup(nvm_sw + IWM_N_HW_ADDRS);
 
-       data->xtal_calib[0] = *(nvm_calib + IWM_XTAL_CALIB);
-       data->xtal_calib[1] = *(nvm_calib + IWM_XTAL_CALIB + 1);
-
        /* The byte order is little endian 16 bit, meaning 214365 */
        memcpy(hw_addr, nvm_hw + IWM_HW_ADDR, ETHER_ADDR_LEN);
        data->hw_addr[0] = hw_addr[1];
@@ -2680,7 +2845,9 @@ iwm_parse_nvm_data(struct iwm_softc *sc,
        data->hw_addr[4] = hw_addr[5];
        data->hw_addr[5] = hw_addr[4];
 
-       iwm_init_channel_map(sc, &nvm_sw[IWM_NVM_CHANNELS]);
+       iwm_init_channel_map(sc, &nvm_sw[IWM_NVM_CHANNELS],
+           iwm_nvm_channels, nitems(iwm_nvm_channels));
+
        data->calib_version = 255;   /* TODO:
                                        this value will prevent some checks from
                                        failing, we need to check if this
@@ -2690,32 +2857,27 @@ iwm_parse_nvm_data(struct iwm_softc *sc,
        return 0;
 }
 
-/*
- * END NVM PARSE
- */
-
-struct iwm_nvm_section {
-       uint16_t length;
-       const uint8_t *data;
-};
-
 int
 iwm_parse_nvm_sections(struct iwm_softc *sc, struct iwm_nvm_section *sections)
 {
-       const uint16_t *hw, *sw, *calib;
+       const uint16_t *hw, *sw, *calib, *mac_override = NULL, *phy_sku = NULL;
+       const uint16_t *regulatory = NULL;
 
        /* Checking for required sections */
        if (!sections[IWM_NVM_SECTION_TYPE_SW].data ||
            !sections[IWM_NVM_SECTION_TYPE_HW].data) {
-               DPRINTF(("%s: Can't parse empty NVM sections\n", DEVNAME(sc)));
+               DPRINTF(("%s: Can't parse empty OTP/NVM sections\n",
+                   DEVNAME(sc)));
                return ENOENT;
        }
 
-       hw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_HW].data;
+       hw = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_HW].data;
        sw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_SW].data;
-       calib = (const uint16_t 
*)sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data;
-       return iwm_parse_nvm_data(sc, hw, sw, calib,
-           IWM_FW_VALID_TX_ANT(sc), IWM_FW_VALID_RX_ANT(sc));
+       calib = (const uint16_t *)
+           sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data;
+
+       return iwm_parse_nvm_data(sc, hw, sw, calib, mac_override,
+           phy_sku, regulatory);
 }
 
 int
@@ -2724,27 +2886,33 @@ iwm_nvm_init(struct iwm_softc *sc)
        struct iwm_nvm_section nvm_sections[IWM_NVM_NUM_OF_SECTIONS];
        int i, section, error;
        uint16_t len;
-       uint8_t *nvm_buffer, *temp;
+       uint8_t *buf;
+       const size_t bufsz = IWM_MAX_NVM_SECTION_SIZE;
 
-       /* Read From FW NVM */
-       DPRINTF(("Read NVM\n"));
+       memset(nvm_sections, 0, sizeof(nvm_sections));
+
+       buf = malloc(bufsz, M_DEVBUF, M_WAIT);
+       if (buf == NULL)
+               return ENOMEM;
 
-       /* TODO: find correct NVM max size for a section */
-       nvm_buffer = malloc(IWM_OTP_LOW_IMAGE_SIZE, M_DEVBUF, M_WAIT);
        for (i = 0; i < nitems(nvm_to_read); i++) {
                section = nvm_to_read[i];
                KASSERT(section <= nitems(nvm_sections));
 
-               error = iwm_nvm_read_section(sc, section, nvm_buffer, &len);
-               if (error)
+               error = iwm_nvm_read_section(sc, section, buf, &len, bufsz);
+               if (error) {
+                       error = 0;
+                       continue;
+               }
+               nvm_sections[section].data = malloc(len, M_DEVBUF, M_WAIT);
+               if (nvm_sections[section].data == NULL) {
+                       error = ENOMEM;
                        break;
-
-               temp = malloc(len, M_DEVBUF, M_WAIT);
-               memcpy(temp, nvm_buffer, len);
-               nvm_sections[section].data = temp;
+               }
+               memcpy(nvm_sections[section].data, buf, len);
                nvm_sections[section].length = len;
        }
-       free(nvm_buffer, M_DEVBUF, IWM_OTP_LOW_IMAGE_SIZE);
+       free(buf, M_DEVBUF, bufsz);
        if (error)
                return error;
 
@@ -2757,22 +2925,52 @@ iwm_nvm_init(struct iwm_softc *sc)
  */
 
 int
-iwm_firmware_load_chunk(struct iwm_softc *sc, uint32_t dst_addr,
+iwm_firmware_load_sect(struct iwm_softc *sc, uint32_t dst_addr,
        const uint8_t *section, uint32_t byte_cnt)
 {
+       int error = EINVAL;
+       uint32_t chunk_sz, offset;
+
+       chunk_sz = MIN(IWM_FH_MEM_TB_MAX_LENGTH, byte_cnt);
+
+       for (offset = 0; offset < byte_cnt; offset += chunk_sz) {
+               uint32_t addr, len;
+               const uint8_t *data;
+
+               addr = dst_addr + offset;
+               len = MIN(chunk_sz, byte_cnt - offset);
+               data = section + offset;
+
+               error = iwm_firmware_load_chunk(sc, addr, data, len);
+               if (error)
+                       break;
+       }
+
+       return error;
+}
+
+int
+iwm_firmware_load_chunk(struct iwm_softc *sc, uint32_t dst_addr,
+       const uint8_t *chunk, uint32_t byte_cnt)
+{
        struct iwm_dma_info *dma = &sc->fw_dma;
        int error;
 
-       /* Copy firmware section into pre-allocated DMA-safe memory. */
-       memcpy(dma->vaddr, section, byte_cnt);
+       /* Copy firmware chunk into pre-allocated DMA-safe memory. */
+       memcpy(dma->vaddr, chunk, byte_cnt);
        bus_dmamap_sync(sc->sc_dmat,
            dma->map, 0, byte_cnt, BUS_DMASYNC_PREWRITE);
 
-       if (!iwm_nic_lock(sc))
-               return EBUSY;
+       if (dst_addr >= IWM_FW_MEM_EXTENDED_START &&
+           dst_addr <= IWM_FW_MEM_EXTENDED_END)
+               iwm_set_bits_prph(sc, IWM_LMPM_CHICK,
+                   IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE);
 
        sc->sc_fw_chunk_done = 0;
 
+       if (!iwm_nic_lock(sc))
+               return EBUSY;
+
        IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(IWM_FH_SRVC_CHNL),
            IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
        IWM_WRITE(sc, IWM_FH_SRVC_CHNL_SRAM_ADDR_REG(IWM_FH_SRVC_CHNL),
@@ -2798,14 +2996,25 @@ iwm_firmware_load_chunk(struct iwm_softc
                if ((error = tsleep(&sc->sc_fw, 0, "iwmfw", hz)) != 0)
                        break;
 
+       if (!sc->sc_fw_chunk_done)
+               DPRINTF(("%s: fw chunk addr 0x%x len %d failed to load\n",
+                   DEVNAME(sc), dst_addr, byte_cnt));
+
+       if (dst_addr >= IWM_FW_MEM_EXTENDED_START &&
+           dst_addr <= IWM_FW_MEM_EXTENDED_END && iwm_nic_lock(sc)) {
+               iwm_clear_bits_prph(sc, IWM_LMPM_CHICK,
+                   IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE);
+               iwm_nic_unlock(sc);
+       }
+
        return error;
 }
 
 int
-iwm_load_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
+iwm_load_firmware_7000(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
 {
        struct iwm_fw_sects *fws;
-       int error, i, w;
+       int error, i;
        void *data;
        uint32_t dlen;
        uint32_t offset;
@@ -2817,21 +3026,47 @@ iwm_load_firmware(struct iwm_softc *sc, 
                data = fws->fw_sect[i].fws_data;
                dlen = fws->fw_sect[i].fws_len;
                offset = fws->fw_sect[i].fws_devoff;
-               DPRINTF(("LOAD FIRMWARE type %d offset %u len %d\n",
+               DPRINTFN(4, ("LOAD FIRMWARE type %d offset %u len %d\n",
                    ucode_type, offset, dlen));
-               error = iwm_firmware_load_chunk(sc, offset, data, dlen);
+               if (dlen > sc->sc_fwdmasegsz) {
+                       DPRINTF(("chunk %d too large (%d bytes)\n", i, dlen));
+                       error = EFBIG;
+               } else
+                       error = iwm_firmware_load_sect(sc, offset, data, dlen);
                if (error) {
-                       DPRINTF(("iwm_firmware_load_chunk() chunk %u of %u 
returned error %02d\n", i, fws->fw_count, error));
+                       printf("%s: could not load firmware chunk %u of %u\n",
+                           DEVNAME(sc), i, fws->fw_count);
                        return error;
                }
        }
 
-       /* wait for the firmware to load */
        IWM_WRITE(sc, IWM_CSR_RESET, 0);
 
+       return 0;
+}
+
+int
+iwm_load_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
+{
+       int error, w;
+
+       error = iwm_load_firmware_7000(sc, ucode_type);
+       if (error)
+               return error;
+
+       /* wait for the firmware to load */
        for (w = 0; !sc->sc_uc.uc_intr && w < 10; w++) {
                error = tsleep(&sc->sc_uc, 0, "iwmuc", hz/10);
        }
+       if (error || !sc->sc_uc.uc_ok) {
+               printf("%s: could not load firmware\n", DEVNAME(sc));
+       }
+
+       /*
+        * Give the firmware some time to initialize.
+        * Accessing it too early causes errors.
+        */
+       tsleep(&w, PCATCH, "iwmfwinit", hz);
 
        return error;
 }
@@ -2948,23 +3183,31 @@ iwm_run_init_mvm_ucode(struct iwm_softc 
                        IEEE80211_ADDR_COPY(sc->sc_ic.ic_myaddr,
                            sc->sc_nvm.hw_addr);
 
-               sc->sc_scan_cmd_len = sizeof(struct iwm_scan_cmd)
-                   + sc->sc_capa_max_probe_len
-                   + IWM_MAX_NUM_SCAN_CHANNELS
-                   * sizeof(struct iwm_scan_channel);
-               sc->sc_scan_cmd = malloc(sc->sc_scan_cmd_len, M_DEVBUF, M_WAIT);
-
                return 0;
        }
 
+       if ((error = iwm_send_bt_init_conf(sc)) != 0) {
+               DPRINTF(("%s: failed to send bt coex configuration: %d\n",
+                   DEVNAME(sc), error));
+               return error;
+       }
+
+       /* Init Smart FIFO. */
+       error = iwm_mvm_sf_config(sc, IWM_SF_INIT_OFF);
+       if (error != 0)
+               return error;
+
        /* Send TX valid antennas before triggering calibrations */
-       if ((error = iwm_send_tx_ant_cfg(sc, IWM_FW_VALID_TX_ANT(sc))) != 0)
+       if ((error = iwm_send_tx_ant_cfg(sc, iwm_fw_valid_tx_ant(sc))) != 0) {
+               DPRINTF(("%s: failed to send antennas before calibration: %d\n",
+                   DEVNAME(sc), error));
                return error;
+       }
 
        /*
-       * Send phy configurations command to init uCode
-       * to start the 16.0 uCode init image internal calibrations.
-       */
+        * Send phy configurations command to init uCode
+        * to start the 16.0 uCode init image internal calibrations.
+        */
        if ((error = iwm_send_phy_cfg_cmd(sc)) != 0 ) {
                DPRINTF(("%s: failed to run internal calibration: %d\n",
                    DEVNAME(sc), error));
@@ -2980,6 +3223,9 @@ iwm_run_init_mvm_ucode(struct iwm_softc 
                    0, "iwminit", 2*hz)) != 0)
                        break;
 
+       DPRINTF(("%s: init %scomplete\n", DEVNAME(sc),
+           sc->sc_init_complete ? "" : "not "));
+
        return error;
 }
 
@@ -3192,10 +3438,8 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc,
        if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0)
                return;
 
-       if (sc->sc_scanband == IEEE80211_CHAN_5GHZ) {
-               if (le32toh(phy_info->channel) < nitems(ic->ic_channels))
-                       c = &ic->ic_channels[le32toh(phy_info->channel)];
-       }
+       if (le32toh(phy_info->channel) < nitems(ic->ic_channels))
+               c = &ic->ic_channels[le32toh(phy_info->channel)];
 
        memset(&rxi, 0, sizeof(rxi));
        rxi.rxi_rssi = rssi;
@@ -3429,13 +3673,13 @@ iwm_mvm_phy_ctxt_cmd_data(struct iwm_sof
        idle_cnt = chains_static;
        active_cnt = chains_dynamic;
 
-       cmd->rxchain_info = htole32(IWM_FW_VALID_RX_ANT(sc) <<
+       cmd->rxchain_info = htole32(iwm_fw_valid_rx_ant(sc) <<
                                        IWM_PHY_RX_CHAIN_VALID_POS);
        cmd->rxchain_info |= htole32(idle_cnt << IWM_PHY_RX_CHAIN_CNT_POS);
        cmd->rxchain_info |= htole32(active_cnt <<
            IWM_PHY_RX_CHAIN_MIMO_CNT_POS);
 
-       cmd->txchain_info = htole32(IWM_FW_VALID_TX_ANT(sc));
+       cmd->txchain_info = htole32(iwm_fw_valid_tx_ant(sc));
 }
 
 /*
@@ -3512,7 +3756,7 @@ iwm_send_cmd(struct iwm_softc *sc, struc
 {
        struct iwm_tx_ring *ring = &sc->txq[IWM_MVM_CMD_QUEUE];
        struct iwm_tfd *desc;
-       struct iwm_tx_data *data;
+       struct iwm_tx_data *txdata;
        struct iwm_device_cmd *cmd;
        struct mbuf *m;
        bus_addr_t paddr;
@@ -3520,6 +3764,9 @@ iwm_send_cmd(struct iwm_softc *sc, struc
        int error = 0, i, paylen, off, s;
        int code;
        int async, wantresp;
+       int group_id;
+       size_t hdrlen, datasz;
+       uint8_t *data;
 
        code = hcmd->id;
        async = hcmd->flags & IWM_CMD_ASYNC;
@@ -3548,11 +3795,20 @@ iwm_send_cmd(struct iwm_softc *sc, struc
        }
 
        desc = &ring->desc[ring->cur];
-       data = &ring->data[ring->cur];
+       txdata = &ring->data[ring->cur];
 
-       if (paylen > sizeof(cmd->data)) {
+       group_id = iwm_cmd_groupid(code);
+       if (group_id != 0) {
+               hdrlen = sizeof(cmd->hdr_wide);
+               datasz = sizeof(cmd->data_wide);
+       } else {
+               hdrlen = sizeof(cmd->hdr);
+               datasz = sizeof(cmd->data);
+       }
+
+       if (paylen > datasz) {
                /* Command is too large to fit in pre-allocated space. */
-               size_t totlen = sizeof(cmd->hdr) + paylen;
+               size_t totlen = hdrlen + paylen;
                if (paylen > IWM_MAX_CMD_PAYLOAD_SIZE) {
                        printf("%s: firmware command too long (%zd bytes)\n",
                            DEVNAME(sc), totlen);
@@ -3567,7 +3823,7 @@ iwm_send_cmd(struct iwm_softc *sc, struc
                        goto out;
                }
                cmd = mtod(m, struct iwm_device_cmd *);
-               error = bus_dmamap_load(sc->sc_dmat, data->map, cmd,
+               error = bus_dmamap_load(sc->sc_dmat, txdata->map, cmd,
                    totlen, NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
                if (error != 0) {
                        printf("%s: could not load fw cmd mbuf (%zd bytes)\n",
@@ -3575,22 +3831,33 @@ iwm_send_cmd(struct iwm_softc *sc, struc
                        m_freem(m);
                        goto out;
                }
-               data->m = m; /* mbuf will be freed in iwm_cmd_done() */
-               paddr = data->map->dm_segs[0].ds_addr;
+               txdata->m = m; /* mbuf will be freed in iwm_cmd_done() */
+               paddr = txdata->map->dm_segs[0].ds_addr;
        } else {
                cmd = &ring->cmd[ring->cur];
-               paddr = data->cmd_paddr;
+               paddr = txdata->cmd_paddr;
        }
 
-       cmd->hdr.code = code;
-       cmd->hdr.flags = 0;
-       cmd->hdr.qid = ring->qid;
-       cmd->hdr.idx = ring->cur;
+       if (group_id != 0) {
+               cmd->hdr_wide.opcode = iwm_cmd_opcode(code);
+               cmd->hdr_wide.group_id = group_id;
+               cmd->hdr_wide.qid = ring->qid;
+               cmd->hdr_wide.idx = ring->cur;
+               cmd->hdr_wide.length = htole16(paylen);
+               cmd->hdr_wide.version = iwm_cmd_version(code);
+               data = cmd->data_wide;
+       } else {
+               cmd->hdr.code = code;
+               cmd->hdr.flags = 0;
+               cmd->hdr.qid = ring->qid;
+               cmd->hdr.idx = ring->cur;
+               data = cmd->data;
+       }
 
        for (i = 0, off = 0; i < nitems(hcmd->data); i++) {
                if (hcmd->len[i] == 0)
                        continue;
-               memcpy(cmd->data + off, hcmd->data[i], hcmd->len[i]);
+               memcpy(data + off, hcmd->data[i], hcmd->len[i]);
                off += hcmd->len[i];
        }
        KASSERT(off == paylen);
@@ -3599,21 +3866,15 @@ iwm_send_cmd(struct iwm_softc *sc, struc
        addr_lo = htole32((uint32_t)paddr);
        memcpy(&desc->tbs[0].lo, &addr_lo, sizeof(uint32_t));
        desc->tbs[0].hi_n_len  = htole16(iwm_get_dma_hi_addr(paddr)
-           | ((sizeof(cmd->hdr) + paylen) << 4));
+           | ((hdrlen + paylen) << 4));
        desc->num_tbs = 1;
 
        DPRINTFN(8, ("iwm_send_cmd 0x%x size=%lu %s\n",
-           code, hcmd->len[0] + hcmd->len[1] + sizeof(cmd->hdr),
+           code, hcmd->len[0] + hcmd->len[1] + hdrlen,
            async ? " (async)" : ""));
 
-       if (paylen > sizeof(cmd->data)) {
-               bus_dmamap_sync(sc->sc_dmat, data->map, 0,
-                   sizeof(cmd->hdr) + paylen, BUS_DMASYNC_PREWRITE);
-       } else {
-               bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map,
-                   (char *)(void *)cmd - (char *)(void *)ring->cmd_dma.vaddr,
-                   sizeof(cmd->hdr) + hcmd->len[0], BUS_DMASYNC_PREWRITE);
-       }
+       bus_dmamap_sync(sc->sc_dmat, txdata->map, 0,
+           hdrlen + paylen, BUS_DMASYNC_PREWRITE);
        bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
            (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr,
            sizeof (*desc), BUS_DMASYNC_PREWRITE);
@@ -4314,7 +4575,7 @@ iwm_mvm_enable_beacon_filter(struct iwm_
 }
 
 int
-iwm_mvm_disable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in)
+iwm_mvm_disable_beacon_filter(struct iwm_softc *sc)
 {
        struct iwm_beacon_filter_cmd cmd;
        int ret;
@@ -4330,63 +4591,19 @@ iwm_mvm_disable_beacon_filter(struct iwm
        return ret;
 }
 
-#if 0
-int
-iwm_mvm_update_beacon_filter(struct iwm_softc *sc, struct iwm_node *in)
-{
-       if (!sc->sc_bf.bf_enabled)
-               return 0;
-
-       return iwm_mvm_enable_beacon_filter(sc, in);
-}
-#endif
-
-void
-iwm_mvm_add_sta_cmd_v6_to_v5(struct iwm_mvm_add_sta_cmd_v6 *cmd_v6,
-       struct iwm_mvm_add_sta_cmd_v5 *cmd_v5)
-{
-       memset(cmd_v5, 0, sizeof(*cmd_v5));
-
-       cmd_v5->add_modify = cmd_v6->add_modify;
-       cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx;
-       cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color;
-       memcpy(cmd_v5->addr, cmd_v6->addr, ETHER_ADDR_LEN);
-       cmd_v5->sta_id = cmd_v6->sta_id;
-       cmd_v5->modify_mask = cmd_v6->modify_mask;
-       cmd_v5->station_flags = cmd_v6->station_flags;
-       cmd_v5->station_flags_msk = cmd_v6->station_flags_msk;
-       cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid;
-       cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid;
-       cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn;
-       cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count;
-       cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags;
-       cmd_v5->assoc_id = cmd_v6->assoc_id;
-       cmd_v5->beamform_flags = cmd_v6->beamform_flags;
-       cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk;
-}
-
 int
 iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *sc,
-       struct iwm_mvm_add_sta_cmd_v6 *cmd, int *status)
+       struct iwm_mvm_add_sta_cmd_v7 *cmd, int *status)
 {
-       struct iwm_mvm_add_sta_cmd_v5 cmd_v5;
-
-       if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_STA_KEY_CMD) {
-               return iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA,
-                   sizeof(*cmd), cmd, status);
-       }
-
-       iwm_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5);
-
-       return iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, sizeof(cmd_v5),
-           &cmd_v5, status);
+       return iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, sizeof(*cmd),
+           cmd, status);
 }
 
 /* send station add/update command to firmware */
 int
 iwm_mvm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in, int update)
 {
-       struct iwm_mvm_add_sta_cmd_v6 add_sta_cmd;
+       struct iwm_mvm_add_sta_cmd_v7 add_sta_cmd;
        int ret;
        uint32_t status;
        struct ieee80211com *ic = &sc->sc_ic;
@@ -4397,12 +4614,19 @@ iwm_mvm_sta_send_to_fw(struct iwm_softc 
        add_sta_cmd.mac_id_n_color
            = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color));
        if (!update) {
-               add_sta_cmd.tfd_queue_msk = htole32(0xf);
+               int ac;
+               for (ac = 0; ac < EDCA_NUM_AC; ac++) {
+                       add_sta_cmd.tfd_queue_msk |=
+                           htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]);
+               }
                IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid);
        }
        add_sta_cmd.add_modify = update ? 1 : 0;
        add_sta_cmd.station_flags_msk
            |= htole32(IWM_STA_FLG_FAT_EN_MSK | IWM_STA_FLG_MIMO_EN_MSK);
+       add_sta_cmd.tid_disable_tx = htole16(0xffff);
+       if (update)
+               add_sta_cmd.modify_mask |= (IWM_STA_MODIFY_TID_DISABLE_TX);
 
        if (in->in_ni.ni_flags & IEEE80211_NODE_HT) {
                add_sta_cmd.station_flags_msk
@@ -4466,7 +4690,7 @@ int
 iwm_mvm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta,
        const uint8_t *addr, uint16_t mac_id, uint16_t color)
 {
-       struct iwm_mvm_add_sta_cmd_v6 cmd;
+       struct iwm_mvm_add_sta_cmd_v7 cmd;
        int ret;
        uint32_t status;
 
@@ -4475,6 +4699,7 @@ iwm_mvm_add_int_sta_common(struct iwm_so
        cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(mac_id, color));
 
        cmd.tfd_queue_msk = htole32(sta->tfd_queue_msk);
+       cmd.tid_disable_tx = htole16(0xffff);
 
        if (addr)
                memcpy(cmd.addr, addr, ETHER_ADDR_LEN);
@@ -4501,8 +4726,12 @@ iwm_mvm_add_aux_sta(struct iwm_softc *sc
 {
        int ret;
 
-       sc->sc_aux_sta.sta_id = 3;
-       sc->sc_aux_sta.tfd_queue_msk = 0;
+       sc->sc_aux_sta.sta_id = IWM_AUX_STA_ID;
+       sc->sc_aux_sta.tfd_queue_msk = (1 << IWM_MVM_AUX_QUEUE);
+
+       ret = iwm_enable_txq(sc, 0, IWM_MVM_AUX_QUEUE, IWM_MVM_TX_FIFO_MCAST);
+       if (ret)
+               return ret;
 
        ret = iwm_mvm_add_int_sta_common(sc,
            &sc->sc_aux_sta, NULL, IWM_MAC_INDEX_AUX, 0);
@@ -4524,7 +4753,7 @@ iwm_mvm_scan_rx_chain(struct iwm_softc *
        uint16_t rx_chain;
        uint8_t rx_ant;
 
-       rx_ant = IWM_FW_VALID_RX_ANT(sc);
+       rx_ant = iwm_fw_valid_rx_ant(sc);
        rx_chain = rx_ant << IWM_PHY_RX_CHAIN_VALID_POS;
        rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
        rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_SEL_POS;
@@ -4553,15 +4782,6 @@ iwm_mvm_scan_suspend_time(struct iwm_sof
 }
 
 uint32_t
-iwm_mvm_scan_rxon_flags(struct iwm_softc *sc, int flags)
-{
-       if (flags & IEEE80211_CHAN_2GHZ)
-               return htole32(IWM_PHY_BAND_24);
-       else
-               return htole32(IWM_PHY_BAND_5);
-}
-
-uint32_t
 iwm_mvm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck)
 {
        uint32_t tx_ant;
@@ -4570,7 +4790,7 @@ iwm_mvm_scan_rate_n_flags(struct iwm_sof
        for (i = 0, ind = sc->sc_scan_last_antenna;
            i < IWM_RATE_MCS_ANT_NUM; i++) {
                ind = (ind + 1) % IWM_RATE_MCS_ANT_NUM;
-               if (IWM_FW_VALID_TX_ANT(sc) & (1 << ind)) {
+               if (iwm_fw_valid_tx_ant(sc) & (1 << ind)) {
                        sc->sc_scan_last_antenna = ind;
                        break;
                }
@@ -4608,192 +4828,236 @@ iwm_mvm_get_passive_dwell(struct iwm_sof
        return (flags & IEEE80211_CHAN_2GHZ) ? 100 + 20 : 100 + 10;
 }
 
-int
-iwm_mvm_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_cmd *cmd,
-       int flags, int n_ssids, int basic_ssid)
+uint8_t
+iwm_mvm_lmac_scan_fill_channels(struct iwm_softc *sc,
+       struct iwm_scan_channel_cfg_lmac *chan, int n_ssids)
 {
        struct ieee80211com *ic = &sc->sc_ic;
-       uint16_t passive_dwell = iwm_mvm_get_passive_dwell(sc, flags);
-       uint16_t active_dwell = iwm_mvm_get_active_dwell(sc, flags, n_ssids);
-       struct iwm_scan_channel *chan = (struct iwm_scan_channel *)
-               (cmd->data + le16toh(cmd->tx_cmd.len));
-       int type = (1 << n_ssids) - 1;
        struct ieee80211_channel *c;
-       int nchan;
-
-       if (!basic_ssid)
-               type |= (1 << n_ssids);
+       uint8_t nchan;
 
        for (nchan = 0, c = &ic->ic_channels[1];
-           c <= &ic->ic_channels[IEEE80211_CHAN_MAX];
+           c <= &ic->ic_channels[IEEE80211_CHAN_MAX] &&
+           nchan < sc->sc_capa_n_scan_channels;
            c++) {
-               if ((c->ic_flags & flags) != flags)
+               if (c->ic_flags == 0)
                        continue;
 
-               chan->channel = htole16(ieee80211_mhz2ieee(c->ic_freq, flags));
-               chan->type = htole32(type);
-               if (c->ic_flags & IEEE80211_CHAN_PASSIVE)
-                       chan->type &= htole32(~IWM_SCAN_CHANNEL_TYPE_ACTIVE);
-               chan->active_dwell = htole16(active_dwell);
-               chan->passive_dwell = htole16(passive_dwell);
-               chan->iteration_count = htole16(1);
+               chan->channel_num = htole16(ieee80211_mhz2ieee(c->ic_freq, 0));
+               chan->iter_count = htole16(1);
+               chan->iter_interval = 0;
+               chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL);
+#if 0 /* makes scanning while associated less useful */
+               if (n_ssids != 0)
+                       chan->flags |= htole32(1 << 1); /* select SSID 0 */
+#endif
                chan++;
                nchan++;
        }
-       if (nchan == 0)
-               DPRINTF(("%s: NO CHANNEL!\n", DEVNAME(sc)));
+
        return nchan;
 }
 
-/*
- * Fill in probe request with the following parameters:
- * TA is our vif HW address, which mac80211 ensures we have.
- * Packet is broadcasted, so this is both SA and DA.
- * The probe request IE is made out of two: first comes the most prioritized
- * SSID if a directed scan is requested. Second comes whatever extra
- * information was given to us as the scan request IE.
- */
-uint16_t
-iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct ieee80211_frame *frame,
-       const uint8_t *ta, int n_ssids, const uint8_t *ssid, int ssid_len,
-       const uint8_t *ie, int ie_len, int left)
-{
-       int len = 0;
-       uint8_t *pos = NULL;
-
-       /* Make sure there is enough space for the probe request,
-        * two mandatory IEs and the data */
-       left -= sizeof(*frame);
-       if (left < 0)
-               return 0;
+int
+iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req *preq)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = IC2IFP(ic);
+       struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf;
+       struct ieee80211_rateset *rs;
+       size_t remain = sizeof(preq->buf);
+       uint8_t *frm, *pos;
+
+       memset(preq, 0, sizeof(*preq));
 
-       frame->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
+       /* Ensure enough space for header and SSID IE. */
+       if (remain < sizeof(*wh) + 2 + ic->ic_des_esslen)
+               return ENOBUFS;
+
+       /*
+        * Build a probe request frame.  Most of the following code is a
+        * copy & paste of what is done in net80211.
+        */
+       wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
            IEEE80211_FC0_SUBTYPE_PROBE_REQ;
-       frame->i_fc[1] = IEEE80211_FC1_DIR_NODS;
-       IEEE80211_ADDR_COPY(frame->i_addr1, etherbroadcastaddr);
-       memcpy(frame->i_addr2, ta, ETHER_ADDR_LEN);
-       IEEE80211_ADDR_COPY(frame->i_addr3, etherbroadcastaddr);
-
-       len += sizeof(*frame);
-       CTASSERT(sizeof(*frame) == 24);
-
-       /* for passive scans, no need to fill anything */
-       if (n_ssids == 0)
-               return (uint16_t)len;
-
-       /* points to the payload of the request */
-       pos = (uint8_t *)frame + sizeof(*frame);
-
-       /* fill in our SSID IE */
-       left -= ssid_len + 2;
-       if (left < 0)
-               return 0;
-       *pos++ = IEEE80211_ELEMID_SSID;
-       *pos++ = ssid_len;
-       if (ssid && ssid_len) { /* ssid_len may be == 0 even if ssid is valid */
-               memcpy(pos, ssid, ssid_len);
-               pos += ssid_len;
+       wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
+       IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
+       IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
+       IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
+       IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr);
+       *(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */
+       *(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */
+
+       frm = (uint8_t *)(wh + 1);
+       frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
+
+       /* Tell the firmware where the MAC header is. */
+       preq->mac_header.offset = 0;
+       preq->mac_header.len = htole16(frm - (uint8_t *)wh);
+       remain -= frm - (uint8_t *)wh;
+
+       /* Fill in 2GHz IEs and tell firmware where they are. */
+       rs = &ic->ic_sup_rates[IEEE80211_MODE_11G];
+       if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
+               if (remain < 4 + rs->rs_nrates)
+                       return ENOBUFS;
+       } else if (remain < 2 + rs->rs_nrates)
+               return ENOBUFS;
+       preq->band_data[0].offset = htole16(frm - (uint8_t *)wh);
+       pos = frm;
+       frm = ieee80211_add_rates(frm, rs);
+       if (rs->rs_nrates > IEEE80211_RATE_SIZE)
+               frm = ieee80211_add_xrates(frm, rs);
+       preq->band_data[0].len = htole16(frm - pos);
+       remain -= frm - pos;
+
+       if (isset(sc->sc_enabled_capa, 
+           IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)) {
+               if (remain < 3)
+                       return ENOBUFS;
+               *frm++ = IEEE80211_ELEMID_DSPARMS;
+               *frm++ = 1;
+               *frm++ = 0;
+               remain -= 3;
        }
 
-       len += ssid_len + 2;
-
-       if (left < ie_len)
-               return len;
+       if (sc->sc_nvm.sku_cap_band_52GHz_enable) {
+               /* Fill in 5GHz IEs. */
+               rs = &ic->ic_sup_rates[IEEE80211_MODE_11A];
+               if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
+                       if (remain < 4 + rs->rs_nrates)
+                               return ENOBUFS;
+               } else if (remain < 2 + rs->rs_nrates)
+                       return ENOBUFS;
+               preq->band_data[1].offset = htole16(frm - (uint8_t *)wh);
+               pos = frm;
+               frm = ieee80211_add_rates(frm, rs);
+               if (rs->rs_nrates > IEEE80211_RATE_SIZE)
+                       frm = ieee80211_add_xrates(frm, rs);
+               preq->band_data[1].len = htole16(frm - pos);
+               remain -= frm - pos;
+       }
 
-       if (ie && ie_len) {
-               memcpy(pos, ie, ie_len);
-               len += ie_len;
+       /* Send 11n IEs on both 2GHz and 5GHz bands. */
+       preq->common_data.offset = htole16(frm - (uint8_t *)wh);
+       pos = frm;
+       if (ic->ic_flags & IEEE80211_F_HTON) {
+               if (remain < 28)
+                       return ENOBUFS;
+               frm = ieee80211_add_htcaps(frm, ic);
+               /* XXX add WME info? */
        }
+       preq->common_data.len = htole16(frm - pos);
 
-       return (uint16_t)len;
+       return 0;
 }
 
 int
-iwm_mvm_scan_request(struct iwm_softc *sc, int flags,
-       int n_ssids, uint8_t *ssid, int ssid_len)
+iwm_mvm_lmac_scan(struct iwm_softc *sc)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct iwm_host_cmd hcmd = {
-               .id = IWM_SCAN_REQUEST_CMD,
+               .id = IWM_SCAN_OFFLOAD_REQUEST_CMD,
                .len = { 0, },
-               .data = { sc->sc_scan_cmd, },
+               .data = { NULL, },
                .flags = IWM_CMD_SYNC,
-               .dataflags = { IWM_HCMD_DFL_NOCOPY, },
        };
-       struct iwm_scan_cmd *cmd = sc->sc_scan_cmd;
-       int is_assoc = 0;
+       struct iwm_scan_req_lmac *req;
+       size_t req_len;
        int ret;
-       uint32_t status;
-       int basic_ssid = !(sc->sc_capaflags & 
IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID);
 
-       //lockdep_assert_held(&mvm->mutex);
+       req_len = sizeof(struct iwm_scan_req_lmac) +
+           (sizeof(struct iwm_scan_channel_cfg_lmac) *
+           sc->sc_capa_n_scan_channels) + sizeof(struct iwm_scan_probe_req);
+       if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
+               return ENOMEM;
+       req = malloc(req_len, M_DEVBUF, M_WAIT | M_CANFAIL | M_ZERO);
+       if (req == NULL)
+               return ENOMEM;
 
-       sc->sc_scanband = flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ);
+       hcmd.len[0] = (uint16_t)req_len;
+       hcmd.data[0] = (void *)req;
 
        DPRINTF(("Handling ieee80211 scan request\n"));
-       memset(cmd, 0, sc->sc_scan_cmd_len);
 
-       cmd->quiet_time = htole16(IWM_ACTIVE_QUIET_TIME);
-       cmd->quiet_plcp_th = htole16(IWM_PLCP_QUIET_THRESH);
-       cmd->rxchain_sel_flags = iwm_mvm_scan_rx_chain(sc);
-       cmd->max_out_time = iwm_mvm_scan_max_out_time(sc, 0, is_assoc);
-       cmd->suspend_time = iwm_mvm_scan_suspend_time(sc, is_assoc);
-       cmd->rxon_flags = iwm_mvm_scan_rxon_flags(sc, flags);
-       cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP |
-           IWM_MAC_FILTER_IN_BEACON);
+       /* These timings correspond to iwlwifi's UNASSOC scan. */
+       req->active_dwell = 10;
+       req->passive_dwell = 110;
+       req->fragmented_dwell = 44;
+       req->extended_dwell = 90;
+       req->max_out_time = 0;
+       req->suspend_time = 0;
+
+       req->scan_prio = htole32(IWM_SCAN_PRIORITY_HIGH);
+       req->rx_chain_select = iwm_mvm_scan_rx_chain(sc);
+       req->iter_num = htole32(1);
+       req->delay = 0;
+
+       req->scan_flags = htole32(IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL |
+           IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE |
+           IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL);
+       if (ic->ic_des_esslen == 0)
+               req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAG_PASSIVE);
+       else
+               req->scan_flags |=
+                   htole32(IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION);
+       if (isset(sc->sc_enabled_capa, 
+           IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
+               req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
+
+       req->flags = htole32(IWM_PHY_BAND_24);
+       if (sc->sc_nvm.sku_cap_band_52GHz_enable)
+               req->flags |= htole32(IWM_PHY_BAND_5);
+       req->filter_flags =
+           htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON);
 
-       cmd->type = htole32(IWM_SCAN_TYPE_FORCED);
-       cmd->repeats = htole32(1);
+       /* Tx flags 2 GHz. */
+       req->tx_cmd[0].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
+           IWM_TX_CMD_FLG_BT_DIS);
+       req->tx_cmd[0].rate_n_flags =
+           iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_2GHZ, 1/*XXX*/);
+       req->tx_cmd[0].sta_id = sc->sc_aux_sta.sta_id;
 
-       /*
-        * If the user asked for passive scan, don't change to active scan if
-        * you see any activity on the channel - remain passive.
-        */
-       if (n_ssids > 0) {
-               cmd->passive2active = htole16(1);
-               cmd->scan_flags |= IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
-#if 0
-               if (basic_ssid) {
-                       ssid = req->ssids[0].ssid;
-                       ssid_len = req->ssids[0].ssid_len;
-               }
-#endif
-       } else {
-               cmd->passive2active = 0;
-               cmd->scan_flags &= ~IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
+       /* Tx flags 5 GHz. */
+       req->tx_cmd[1].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
+           IWM_TX_CMD_FLG_BT_DIS);
+       req->tx_cmd[1].rate_n_flags =
+           iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_5GHZ, 1/*XXX*/);
+       req->tx_cmd[1].sta_id = sc->sc_aux_sta.sta_id;
+
+       /* Check if we're doing an active directed scan. */
+       if (ic->ic_des_esslen != 0) {
+               req->direct_scan[0].id = IEEE80211_ELEMID_SSID;
+               req->direct_scan[0].len = ic->ic_des_esslen;
+               memcpy(req->direct_scan[0].ssid, ic->ic_des_essid,
+                   ic->ic_des_esslen);
+       }
+
+       req->n_channels = iwm_mvm_lmac_scan_fill_channels(sc,
+           (struct iwm_scan_channel_cfg_lmac *)req->data,
+           ic->ic_des_esslen != 0);
+
+       ret = iwm_mvm_fill_probe_req(sc,
+                           (struct iwm_scan_probe_req *)(req->data +
+                           (sizeof(struct iwm_scan_channel_cfg_lmac) *
+                           sc->sc_capa_n_scan_channels)));
+       if (ret) {
+               free(req, M_DEVBUF, req_len);
+               return ret;
        }
 
-       cmd->tx_cmd.tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
-           IWM_TX_CMD_FLG_BT_DIS);
-       cmd->tx_cmd.sta_id = sc->sc_aux_sta.sta_id;
-       cmd->tx_cmd.life_time = htole32(IWM_TX_CMD_LIFE_TIME_INFINITE);
-       cmd->tx_cmd.rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, flags, 
1/*XXX*/);
-
-       cmd->tx_cmd.len = htole16(iwm_mvm_fill_probe_req(sc,
-                           (struct ieee80211_frame *)cmd->data,
-                           ic->ic_myaddr, n_ssids, ssid, ssid_len,
-                           NULL, 0, sc->sc_capa_max_probe_len));
-
-       cmd->channel_count
-           = iwm_mvm_scan_fill_channels(sc, cmd, flags, n_ssids, basic_ssid);
-
-       cmd->len = htole16(sizeof(struct iwm_scan_cmd) +
-               le16toh(cmd->tx_cmd.len) +
-               (cmd->channel_count * sizeof(struct iwm_scan_channel)));
-       hcmd.len[0] = le16toh(cmd->len);
-
-       status = IWM_SCAN_RESPONSE_OK;
-       ret = iwm_mvm_send_cmd_status(sc, &hcmd, &status);
-       if (!ret && status == IWM_SCAN_RESPONSE_OK) {
+       /* Specify the scan plan: We'll do one iteration. */
+       req->schedule[0].iterations = 1;
+       req->schedule[0].full_scan_mul = 1;
+
+       /* Disable EBS. */
+       req->channel_opt[0].non_ebs_ratio = 1;
+       req->channel_opt[1].non_ebs_ratio = 1;
+
+       ret = iwm_send_cmd(sc, &hcmd);
+       if (!ret)
                DPRINTF(("Scan request was sent successfully\n"));
-       } else {
-               /*
-                * If the scan failed, it usually means that the FW was unable
-                * to allocate the time events. Warn on it, but maybe we
-                * should try to send the command again with different params.
-                */
-               ret = EIO;
-       }
+       free(req, M_DEVBUF, req_len);
        return ret;
 }
 
@@ -5190,6 +5454,10 @@ iwm_auth(struct iwm_softc *sc)
 
        in->in_assoc = 0;
 
+       error = iwm_mvm_sf_config(sc, IWM_SF_FULL_ON);
+       if (error != 0)
+               return error;
+
        error = iwm_allow_mcast(sc);
        if (error)
                return error;
@@ -5266,7 +5534,7 @@ iwm_release(struct iwm_softc *sc, struct
         * back to nothing anyway, we'll just do a complete device reset.
         * Up your's, device!
         */
-       //iwm_mvm_flush_tx_path(sc, 0xf, 1);
+       /* iwm_mvm_flush_tx_path(sc, 0xf, 1); */
        iwm_stop_device(sc);
        iwm_init_hw(sc);
        if (in)
@@ -5486,7 +5754,7 @@ iwm_newstate_task(void *psc)
 
        /* disable beacon filtering if we're hopping out of RUN */
        if (ostate == IEEE80211_S_RUN && nstate != ostate)
-               iwm_mvm_disable_beacon_filter(sc, (void *)ic->ic_bss);
+               iwm_mvm_disable_beacon_filter(sc);
 
        /* Reset the device if moving out of AUTH, ASSOC, or RUN. */
        if (ostate > IEEE80211_S_SCAN && nstate < ostate) {
@@ -5509,7 +5777,8 @@ iwm_newstate_task(void *psc)
                    nstate == IEEE80211_S_AUTH ||
                    nstate == IEEE80211_S_ASSOC) {
                        DPRINTF(("Force transition to INIT; MGT=%d\n", arg));
-                       sc->sc_newstate(ic, IEEE80211_S_INIT, arg);
+                       /* Always pass arg as -1 since we can't Tx right now. */
+                       sc->sc_newstate(ic, IEEE80211_S_INIT, -1);
                        DPRINTF(("Going INIT->SCAN\n"));
                        nstate = IEEE80211_S_SCAN;
                }
@@ -5517,19 +5786,14 @@ iwm_newstate_task(void *psc)
 
        switch (nstate) {
        case IEEE80211_S_INIT:
-               sc->sc_scanband = 0;
                break;
 
        case IEEE80211_S_SCAN:
-               if (sc->sc_scanband)
-                       break;
-
-               if ((error = iwm_mvm_scan_request(sc, IEEE80211_CHAN_2GHZ,
-                   ic->ic_des_esslen != 0,
-                   ic->ic_des_essid, ic->ic_des_esslen)) != 0) {
-                       printf("%s: could not initiate 2 GHz scan\n",
-                           DEVNAME(sc));
-                       sc->sc_scanband = 0;
+               if (ic->ic_state == nstate)
+                       return;
+               error = iwm_mvm_lmac_scan(sc);
+               if (error != 0) {
+                       printf("%s: could not initiate scan\n", DEVNAME(sc));
                        return;
                }
                ic->ic_state = nstate;
@@ -5599,29 +5863,234 @@ iwm_endscan_cb(void *arg)
 {
        struct iwm_softc *sc = arg;
        struct ieee80211com *ic = &sc->sc_ic;
-       int done;
 
        DPRINTF(("scan ended\n"));
 
-       if (sc->sc_scanband == IEEE80211_CHAN_2GHZ &&
-           sc->sc_nvm.sku_cap_band_52GHz_enable) {
-               int error;
-               done = 0;
-               if ((error = iwm_mvm_scan_request(sc,
-                   IEEE80211_CHAN_5GHZ, ic->ic_des_esslen != 0,
-                   ic->ic_des_essid, ic->ic_des_esslen)) != 0) {
-                       printf("%s: could not initiate 5 GHz scan\n",
-                           DEVNAME(sc));
-                       done = 1;
+       ieee80211_end_scan(&ic->ic_if);
+}
+
+/*
+ * Aging and idle timeouts for the different possible scenarios
+ * in default configuration
+ */
+static const uint32_t
+iwm_sf_full_timeout_def[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = {
+       {
+               htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER_DEF),
+               htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER_DEF)
+       },
+       {
+               htole32(IWM_SF_AGG_UNICAST_AGING_TIMER_DEF),
+               htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER_DEF)
+       },
+       {
+               htole32(IWM_SF_MCAST_AGING_TIMER_DEF),
+               htole32(IWM_SF_MCAST_IDLE_TIMER_DEF)
+       },
+       {
+               htole32(IWM_SF_BA_AGING_TIMER_DEF),
+               htole32(IWM_SF_BA_IDLE_TIMER_DEF)
+       },
+       {
+               htole32(IWM_SF_TX_RE_AGING_TIMER_DEF),
+               htole32(IWM_SF_TX_RE_IDLE_TIMER_DEF)
+       },
+};
+
+/*
+ * Aging and idle timeouts for the different possible scenarios
+ * in single BSS MAC configuration.
+ */
+static const uint32_t
+iwm_sf_full_timeout[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = {
+       {
+               htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER),
+               htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER)
+       },
+       {
+               htole32(IWM_SF_AGG_UNICAST_AGING_TIMER),
+               htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER)
+       },
+       {
+               htole32(IWM_SF_MCAST_AGING_TIMER),
+               htole32(IWM_SF_MCAST_IDLE_TIMER)
+       },
+       {
+               htole32(IWM_SF_BA_AGING_TIMER),
+               htole32(IWM_SF_BA_IDLE_TIMER)
+       },
+       {
+               htole32(IWM_SF_TX_RE_AGING_TIMER),
+               htole32(IWM_SF_TX_RE_IDLE_TIMER)
+       },
+};
+
+void
+iwm_mvm_fill_sf_command(struct iwm_softc *sc, struct iwm_sf_cfg_cmd *sf_cmd,
+    struct ieee80211_node *ni)
+{
+       int i, j, watermark;
+
+       sf_cmd->watermark[IWM_SF_LONG_DELAY_ON] = htole32(IWM_SF_W_MARK_SCAN);
+
+       /*
+        * If we are in association flow - check antenna configuration
+        * capabilities of the AP station, and choose the watermark accordingly.
+        */
+       if (ni) {
+               if (ni->ni_flags & IEEE80211_NODE_HT) {
+#ifdef notyet
+                       if (ni->ni_rxmcs[2] != 0)
+                               watermark = IWM_SF_W_MARK_MIMO3;
+                       else if (ni->ni_rxmcs[1] != 0)
+                               watermark = IWM_SF_W_MARK_MIMO2;
+                       else
+#endif
+                               watermark = IWM_SF_W_MARK_SISO;
+               } else {
+                       watermark = IWM_SF_W_MARK_LEGACY;
                }
+       /* default watermark value for unassociated mode. */
        } else {
-               done = 1;
+               watermark = IWM_SF_W_MARK_MIMO2;
+       }
+       sf_cmd->watermark[IWM_SF_FULL_ON] = htole32(watermark);
+
+       for (i = 0; i < IWM_SF_NUM_SCENARIO; i++) {
+               for (j = 0; j < IWM_SF_NUM_TIMEOUT_TYPES; j++) {
+                       sf_cmd->long_delay_timeouts[i][j] =
+                                       htole32(IWM_SF_LONG_DELAY_AGING_TIMER);
+               }
+       }
+
+       if (ni) {
+               memcpy(sf_cmd->full_on_timeouts, iwm_sf_full_timeout,
+                      sizeof(iwm_sf_full_timeout));
+       } else {
+               memcpy(sf_cmd->full_on_timeouts, iwm_sf_full_timeout_def,
+                      sizeof(iwm_sf_full_timeout_def));
+       }
+
+}
+
+int
+iwm_mvm_sf_config(struct iwm_softc *sc, enum iwm_sf_state new_state)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct iwm_sf_cfg_cmd sf_cmd = {
+               .state = htole32(IWM_SF_FULL_ON),
+       };
+       int ret = 0;
+
+       switch (new_state) {
+       case IWM_SF_UNINIT:
+       case IWM_SF_INIT_OFF:
+               iwm_mvm_fill_sf_command(sc, &sf_cmd, NULL);
+               break;
+       case IWM_SF_FULL_ON:
+               iwm_mvm_fill_sf_command(sc, &sf_cmd, ic->ic_bss);
+               break;
+       default:
+               DPRINTF(("Invalid state: %d. not sending Smart Fifo cmd\n",
+                         new_state));
+               return EINVAL;
        }
 
-       if (done) {
-               ieee80211_end_scan(&ic->ic_if);
-               sc->sc_scanband = 0;
+       ret = iwm_mvm_send_cmd_pdu(sc, IWM_REPLY_SF_CFG_CMD, IWM_CMD_ASYNC,
+                                  sizeof(sf_cmd), &sf_cmd);
+       return ret;
+}
+
+int
+iwm_send_bt_init_conf(struct iwm_softc *sc)
+{
+       struct iwm_bt_coex_cmd bt_cmd;
+
+       bt_cmd.mode = htole32(IWM_BT_COEX_WIFI);
+       bt_cmd.enabled_modules = htole32(IWM_BT_COEX_HIGH_BAND_RET);
+
+       return iwm_mvm_send_cmd_pdu(sc, IWM_BT_CONFIG, 0, sizeof(bt_cmd),
+           &bt_cmd);
+}
+
+int
+iwm_send_update_mcc_cmd(struct iwm_softc *sc, const char *alpha2)
+{
+       struct iwm_mcc_update_cmd mcc_cmd;
+       struct iwm_host_cmd hcmd = {
+               .id = IWM_MCC_UPDATE_CMD,
+               .flags = (IWM_CMD_SYNC | IWM_CMD_WANT_SKB),
+               .data = { &mcc_cmd },
+       };
+       int ret;
+#ifdef IWM_DEBUG
+       struct iwm_rx_packet *pkt;
+       struct iwm_mcc_update_resp_v1 *mcc_resp_v1 = NULL;
+       struct iwm_mcc_update_resp *mcc_resp;
+       int n_channels;
+       uint16_t mcc;
+#endif
+       int resp_v2 = isset(sc->sc_enabled_capa,
+           IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2);
+
+       memset(&mcc_cmd, 0, sizeof(mcc_cmd));
+       mcc_cmd.mcc = htole16(alpha2[0] << 8 | alpha2[1]);
+       if ((sc->sc_ucode_api & IWM_UCODE_TLV_API_WIFI_MCC_UPDATE) ||
+           isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC))
+               mcc_cmd.source_id = IWM_MCC_SOURCE_GET_CURRENT;
+       else
+               mcc_cmd.source_id = IWM_MCC_SOURCE_OLD_FW;
+
+       if (resp_v2)
+               hcmd.len[0] = sizeof(struct iwm_mcc_update_cmd);
+       else
+               hcmd.len[0] = sizeof(struct iwm_mcc_update_cmd_v1);
+
+       DPRINTF(("send MCC update to FW with '%c%c' src = %d\n",
+           alpha2[0], alpha2[1], mcc_cmd.source_id));
+
+       ret = iwm_send_cmd(sc, &hcmd);
+       if (ret)
+               return ret;
+
+#ifdef IWM_DEBUG
+       pkt = hcmd.resp_pkt;
+
+       /* Extract MCC response */
+       if (resp_v2) {
+               mcc_resp = (void *)pkt->data;
+               mcc = mcc_resp->mcc;
+               n_channels =  le32toh(mcc_resp->n_channels);
+       } else {
+               mcc_resp_v1 = (void *)pkt->data;
+               mcc = mcc_resp_v1->mcc;
+               n_channels =  le32toh(mcc_resp_v1->n_channels);
        }
+
+       /* W/A for a FW/NVM issue - returns 0x00 for the world domain */
+       if (mcc == 0)
+               mcc = 0x3030;  /* "00" - world */
+
+       DPRINTF(("%s: regulatory domain '%c%c' (%d channels available)\n",
+           DEVNAME(sc), mcc >> 8, mcc & 0xff, n_channels));
+#endif
+       iwm_free_resp(sc, &hcmd);
+
+       return 0;
+}
+
+void
+iwm_mvm_tt_tx_backoff(struct iwm_softc *sc, uint32_t backoff)
+{
+       struct iwm_host_cmd cmd = {
+               .id = IWM_REPLY_THERMAL_MNG_BACKOFF,
+               .len = { sizeof(uint32_t), },
+               .data = { &backoff, },
+       };
+
+       if (iwm_send_cmd(sc, &cmd) != 0)
+               DPRINTF(("%s: failed to change thermal tx backoff\n",
+                   DEVNAME(sc)));
 }
 
 int
@@ -5629,7 +6098,7 @@ iwm_init_hw(struct iwm_softc *sc)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct iwm_node *in = (struct iwm_node *)ic->ic_bss;
-       int error, i, qid;
+       int error, i, ac;
 
        if ((error = iwm_preinit(sc)) != 0)
                return error;
@@ -5658,7 +6127,10 @@ iwm_init_hw(struct iwm_softc *sc)
                goto error;
        }
 
-       if ((error = iwm_send_tx_ant_cfg(sc, IWM_FW_VALID_TX_ANT(sc))) != 0)
+       if ((error = iwm_send_bt_init_conf(sc)) != 0)
+               goto error;
+
+       if ((error = iwm_send_tx_ant_cfg(sc, iwm_fw_valid_tx_ant(sc))) != 0)
                goto error;
 
        /* Send phy db control command and then phy db calibration*/
@@ -5683,13 +6155,24 @@ iwm_init_hw(struct iwm_softc *sc)
                        goto error;
        }
 
+       /* Initialize tx backoffs to the minimum. */
+       iwm_mvm_tt_tx_backoff(sc, 0);
+
        error = iwm_mvm_power_update_device(sc);
        if (error)
                goto error;
 
-       /* Mark TX rings as active. */
-       for (qid = 0; qid < 4; qid++) {
-               iwm_enable_txq(sc, qid, qid);
+       if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_SUPPORT)) {
+               if ((error = iwm_send_update_mcc_cmd(sc, "ZZ")) != 0)
+                       goto error;
+       }
+
+       /* Enable Tx queues. */
+       for (ac = 0; ac < EDCA_NUM_AC; ac++) {
+               error = iwm_enable_txq(sc, IWM_STATION_ID, ac,
+                   iwm_mvm_ac_to_tx_fifo[ac]);
+               if (error)
+                       goto error;
        }
 
        /* Add the MAC context. */
@@ -5698,6 +6181,11 @@ iwm_init_hw(struct iwm_softc *sc)
                goto error;
        }
 
+       if ((error = iwm_mvm_disable_beacon_filter(sc)) != 0) {
+               printf("%s: failed to disable beacon filter\n", DEVNAME(sc));
+               goto error;
+       }
+
        return 0;
 
  error:
@@ -5845,7 +6333,6 @@ iwm_stop(struct ifnet *ifp, int disable)
        sc->sc_flags &= ~IWM_FLAG_HW_INITED;
        sc->sc_flags |= IWM_FLAG_STOPPED;
        sc->sc_generation++;
-       sc->sc_scanband = 0;
        ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED;
        ifp->if_flags &= ~IFF_RUNNING;
        ifq_clr_oactive(&ifp->if_snd);
@@ -5968,8 +6455,8 @@ iwm_ioctl(struct ifnet *ifp, u_long cmd,
 struct iwm_error_event_table {
        uint32_t valid;         /* (nonzero) valid, (0) log is empty */
        uint32_t error_id;              /* type of error */
-       uint32_t pc;                    /* program counter */
-       uint32_t blink1;                /* branch link */
+       uint32_t trm_hw_status0;        /* TRM HW status */
+       uint32_t trm_hw_status1;        /* TRM HW status */
        uint32_t blink2;                /* branch link */
        uint32_t ilink1;                /* interrupt link */
        uint32_t ilink2;                /* interrupt link */
@@ -5981,8 +6468,9 @@ struct iwm_error_event_table {
        uint32_t tsf_hi;                /* network timestamp function timer */
        uint32_t gp1;           /* GP1 timer register */
        uint32_t gp2;           /* GP2 timer register */
-       uint32_t gp3;           /* GP3 timer register */
-       uint32_t ucode_ver;             /* uCode version */
+       uint32_t fw_rev_type;   /* firmware revision type */
+       uint32_t major;         /* uCode version major */
+       uint32_t minor;         /* uCode version minor */
        uint32_t hw_ver;                /* HW Silicon version */
        uint32_t brd_ver;               /* HW board version */
        uint32_t log_pc;                /* log program counter */
@@ -5999,7 +6487,7 @@ struct iwm_error_event_table {
                                 * time_flag */
        uint32_t isr4;          /* isr status register LMPM_NIC_ISR4:
                                 * wico interrupt */
-       uint32_t isr_pref;              /* isr status register 
LMPM_NIC_PREF_STAT */
+       uint32_t last_cmd_id;   /* last HCMD id handled by the firmware */
        uint32_t wait_event;            /* wait event() caller address */
        uint32_t l2p_control;   /* L2pControlField */
        uint32_t l2p_duration;  /* L2pDurationField */
@@ -6065,13 +6553,13 @@ iwm_nic_error(struct iwm_softc *sc)
 
        printf("%s: dumping device error log\n", DEVNAME(sc));
        base = sc->sc_uc.uc_error_event_table;
-       if (base < 0x800000 || base >= 0x80C000) {
-               printf("%s: Not valid error log pointer 0x%08x\n",
+       if (base < 0x800000) {
+               printf("%s: Invalid error log pointer 0x%08x\n",
                    DEVNAME(sc), base);
                return;
        }
 
-       if (iwm_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t)) != 
0) {
+       if (iwm_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t))) {
                printf("%s: reading errlog failed\n", DEVNAME(sc));
                return;
        }
@@ -6082,15 +6570,17 @@ iwm_nic_error(struct iwm_softc *sc)
        }
 
        if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
-               printf("%s: Start IWL Error Log Dump:\n", DEVNAME(sc));
+               printf("%s: Start Error Log Dump:\n", DEVNAME(sc));
                printf("%s: Status: 0x%x, count: %d\n", DEVNAME(sc),
                    sc->sc_flags, table.valid);
        }
 
        printf("%s: 0x%08X | %-28s\n", DEVNAME(sc), table.error_id,
-               iwm_desc_lookup(table.error_id));
-       printf("%s: %08X | uPc\n", DEVNAME(sc), table.pc);
-       printf("%s: %08X | branchlink1\n", DEVNAME(sc), table.blink1);
+           iwm_desc_lookup(table.error_id));
+       printf("%s: %08X | trm_hw_status0\n", DEVNAME(sc),
+           table.trm_hw_status0);
+       printf("%s: %08X | trm_hw_status1\n", DEVNAME(sc),
+           table.trm_hw_status1);
        printf("%s: %08X | branchlink2\n", DEVNAME(sc), table.blink2);
        printf("%s: %08X | interruptlink1\n", DEVNAME(sc), table.ilink1);
        printf("%s: %08X | interruptlink2\n", DEVNAME(sc), table.ilink2);
@@ -6102,8 +6592,12 @@ iwm_nic_error(struct iwm_softc *sc)
        printf("%s: %08X | tsf hi\n", DEVNAME(sc), table.tsf_hi);
        printf("%s: %08X | time gp1\n", DEVNAME(sc), table.gp1);
        printf("%s: %08X | time gp2\n", DEVNAME(sc), table.gp2);
-       printf("%s: %08X | time gp3\n", DEVNAME(sc), table.gp3);
-       printf("%s: %08X | uCode version\n", DEVNAME(sc), table.ucode_ver);
+       printf("%s: %08X | uCode revision type\n", DEVNAME(sc),
+           table.fw_rev_type);
+       printf("%s: %08X | uCode version major\n", DEVNAME(sc),
+           table.major);
+       printf("%s: %08X | uCode version minor\n", DEVNAME(sc),
+           table.minor);
        printf("%s: %08X | hw version\n", DEVNAME(sc), table.hw_ver);
        printf("%s: %08X | board version\n", DEVNAME(sc), table.brd_ver);
        printf("%s: %08X | hcmd\n", DEVNAME(sc), table.hcmd);
@@ -6112,7 +6606,7 @@ iwm_nic_error(struct iwm_softc *sc)
        printf("%s: %08X | isr2\n", DEVNAME(sc), table.isr2);
        printf("%s: %08X | isr3\n", DEVNAME(sc), table.isr3);
        printf("%s: %08X | isr4\n", DEVNAME(sc), table.isr4);
-       printf("%s: %08X | isr_pref\n", DEVNAME(sc), table.isr_pref);
+       printf("%s: %08X | last cmd Id\n", DEVNAME(sc), table.last_cmd_id);
        printf("%s: %08X | wait_event\n", DEVNAME(sc), table.wait_event);
        printf("%s: %08X | l2p_control\n", DEVNAME(sc), table.l2p_control);
        printf("%s: %08X | l2p_duration\n", DEVNAME(sc), table.l2p_duration);
@@ -6157,7 +6651,7 @@ iwm_notif_intr(struct iwm_softc *sc)
                struct iwm_rx_data *data = &sc->rxq.data[sc->rxq.cur];
                struct iwm_rx_packet *pkt;
                struct iwm_cmd_response *cresp;
-               int qid, idx;
+               int qid, idx, code;
 
                bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof(*pkt),
                    BUS_DMASYNC_POSTREAD);
@@ -6166,9 +6660,9 @@ iwm_notif_intr(struct iwm_softc *sc)
                qid = pkt->hdr.qid & ~0x80;
                idx = pkt->hdr.idx;
 
-               DPRINTFN(12, ("rx packet qid=%d idx=%d flags=%x type=%x %d 
%d\n",
-                   pkt->hdr.qid & ~0x80, pkt->hdr.idx, pkt->hdr.flags,
-                   pkt->hdr.code, sc->rxq.cur, hw));
+               code = IWM_WIDE_ID(pkt->hdr.flags, pkt->hdr.code);
+               DPRINTFN(12, ("rx packet qid=%d idx=%d type=%x %d %d\n",
+                   pkt->hdr.qid & ~0x80, pkt->hdr.idx, code, sc->rxq.cur, hw));
 
                /*
                 * randomly get these from the firmware, no idea why.
@@ -6180,7 +6674,7 @@ iwm_notif_intr(struct iwm_softc *sc)
                        continue;
                }
 
-               switch (pkt->hdr.code) {
+               switch (code) {
                case IWM_REPLY_RX_PHY_CMD:
                        iwm_mvm_rx_rx_phy_cmd(sc, pkt, data);
                        break;
@@ -6197,16 +6691,52 @@ iwm_notif_intr(struct iwm_softc *sc)
                        /* OpenBSD does not provide ieee80211_beacon_miss() */
                        break;
 
+               case IWM_MFUART_LOAD_NOTIFICATION:
+                       break;
+
                case IWM_MVM_ALIVE: {
-                       struct iwm_mvm_alive_resp *resp;
-                       SYNC_RESP_STRUCT(resp, pkt);
+                       struct iwm_mvm_alive_resp_v1 *resp1;
+                       struct iwm_mvm_alive_resp_v2 *resp2;
+                       struct iwm_mvm_alive_resp_v3 *resp3;
+
+                       if (iwm_rx_packet_payload_len(pkt) == sizeof(*resp1)) {
+                               SYNC_RESP_STRUCT(resp1, pkt);
+                               sc->sc_uc.uc_error_event_table
+                                   = le32toh(resp1->error_event_table_ptr);
+                               sc->sc_uc.uc_log_event_table
+                                   = le32toh(resp1->log_event_table_ptr);
+                               sc->sched_base = le32toh(resp1->scd_base_ptr);
+                               if (resp1->status == IWM_ALIVE_STATUS_OK)
+                                       sc->sc_uc.uc_ok = 1;
+                               else
+                                       sc->sc_uc.uc_ok = 0;
+                       }
+
+                       if (iwm_rx_packet_payload_len(pkt) == sizeof(*resp2)) {
+                               SYNC_RESP_STRUCT(resp2, pkt);
+                               sc->sc_uc.uc_error_event_table
+                                   = le32toh(resp2->error_event_table_ptr);
+                               sc->sc_uc.uc_log_event_table
+                                   = le32toh(resp2->log_event_table_ptr);
+                               sc->sched_base = le32toh(resp2->scd_base_ptr);
+                               if (resp2->status == IWM_ALIVE_STATUS_OK)
+                                       sc->sc_uc.uc_ok = 1;
+                               else
+                                       sc->sc_uc.uc_ok = 0;
+                       }
 
-                       sc->sc_uc.uc_error_event_table
-                           = le32toh(resp->error_event_table_ptr);
-                       sc->sc_uc.uc_log_event_table
-                           = le32toh(resp->log_event_table_ptr);
-                       sc->sched_base = le32toh(resp->scd_base_ptr);
-                       sc->sc_uc.uc_ok = resp->status == IWM_ALIVE_STATUS_OK;
+                       if (iwm_rx_packet_payload_len(pkt) == sizeof(*resp3)) {
+                               SYNC_RESP_STRUCT(resp3, pkt);
+                               sc->sc_uc.uc_error_event_table
+                                   = le32toh(resp3->error_event_table_ptr);
+                               sc->sc_uc.uc_log_event_table
+                                   = le32toh(resp3->log_event_table_ptr);
+                               sc->sched_base = le32toh(resp3->scd_base_ptr);
+                               if (resp3->status == IWM_ALIVE_STATUS_OK)
+                                       sc->sc_uc.uc_ok = 1;
+                               else
+                                       sc->sc_uc.uc_ok = 0;
+                       }
 
                        sc->sc_uc.uc_intr = 1;
                        wakeup(&sc->sc_uc);
@@ -6228,6 +6758,7 @@ iwm_notif_intr(struct iwm_softc *sc)
                        break; }
 
                case IWM_NVM_ACCESS_CMD:
+               case IWM_MCC_UPDATE_CMD:
                        if (sc->sc_wantresp == ((qid << 16) | idx)) {
                                bus_dmamap_sync(sc->sc_dmat, data->map, 0,
                                    sizeof(sc->sc_cmd_resp),
@@ -6237,6 +6768,20 @@ iwm_notif_intr(struct iwm_softc *sc)
                        }
                        break;
 
+               case IWM_MCC_CHUB_UPDATE_CMD: {
+                       struct iwm_mcc_chub_notif *notif;
+                       SYNC_RESP_STRUCT(notif, pkt);
+
+                       sc->sc_fw_mcc[0] = (notif->mcc & 0xff00) >> 8;
+                       sc->sc_fw_mcc[1] = notif->mcc & 0xff;
+                       sc->sc_fw_mcc[2] = '\0';
+                       DPRINTF(("%s: fw source %d sent CC '%s'\n",
+                           DEVNAME(sc), notif->source_id, sc->sc_fw_mcc));
+               }
+
+               case IWM_DTS_MEASUREMENT_NOTIFICATION:
+                       break;
+
                case IWM_PHY_CONFIGURATION_CMD:
                case IWM_TX_ANT_CONFIGURATION_CMD:
                case IWM_ADD_STA:
@@ -6247,12 +6792,14 @@ iwm_notif_intr(struct iwm_softc *sc)
                case IWM_BINDING_CONTEXT_CMD:
                case IWM_TIME_EVENT_CMD:
                case IWM_SCAN_REQUEST_CMD:
+               case IWM_SCAN_OFFLOAD_REQUEST_CMD:
                case IWM_REPLY_BEACON_FILTERING_CMD:
                case IWM_MAC_PM_POWER_TABLE:
                case IWM_TIME_QUOTA_CMD:
                case IWM_REMOVE_STA:
                case IWM_TXPATH_FLUSH:
                case IWM_LQ_CMD:
+               case IWM_BT_CONFIG:
                        SYNC_RESP_STRUCT(cresp, pkt);
                        if (sc->sc_wantresp == ((qid << 16) | idx)) {
                                memcpy(sc->sc_cmd_resp,
@@ -6269,8 +6816,14 @@ iwm_notif_intr(struct iwm_softc *sc)
                        wakeup(&sc->sc_init_complete);
                        break;
 
-               case IWM_SCAN_COMPLETE_NOTIFICATION: {
-                       struct iwm_scan_complete_notif *notif;
+               case IWM_SCAN_OFFLOAD_COMPLETE: {
+                       struct iwm_periodic_scan_complete *notif;
+                       SYNC_RESP_STRUCT(notif, pkt);
+
+                       break; }
+
+               case IWM_SCAN_ITERATION_COMPLETE: {
+                       struct iwm_lmac_scan_complete_notif *notif;
                        SYNC_RESP_STRUCT(notif, pkt);
 
                        task_add(sc->sc_eswq, &sc->sc_eswk);
@@ -6296,6 +6849,17 @@ iwm_notif_intr(struct iwm_softc *sc)
                case IWM_MCAST_FILTER_CMD:
                        break;
 
+               case IWM_SCD_QUEUE_CFG: {
+                       struct iwm_scd_txq_cfg_rsp *rsp;
+                       SYNC_RESP_STRUCT(rsp, pkt);
+                       
+                       DPRINTF(("%s: queue cfg token=0x%x sta_id=%d "
+                           "tid=%d scd_queue=%d\n",
+                           DEVNAME(sc), rsp->token, rsp->sta_id, rsp->tid,
+                           rsp->scd_queue));
+                       break;
+               }
+
                default:
                        printf("%s: unhandled firmware response 0x%x/0x%x "
                            "rx ring %d[%d]\n",
@@ -6535,12 +7099,9 @@ iwm_preinit(struct iwm_softc *sc)
 
        /* Print version info and MAC address on first successful fw load. */
        attached = 1;
-       printf("%s: hw rev 0x%x, fw ver %d.%d (API ver %d), address %s\n",
+       printf("%s: hw rev 0x%x, fw ver %s, address %s\n",
            DEVNAME(sc), sc->sc_hw_rev & IWM_CSR_HW_REV_TYPE_MSK,
-           IWM_UCODE_MAJOR(sc->sc_fwver),
-           IWM_UCODE_MINOR(sc->sc_fwver),
-           IWM_UCODE_API(sc->sc_fwver),
-           ether_sprintf(sc->sc_nvm.hw_addr));
+           sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr));
 
        if (sc->sc_nvm.sku_cap_11n_enable)
                iwm_setup_ht_rates(sc);
@@ -6651,17 +7212,17 @@ iwm_attach(struct device *parent, struct
        switch (PCI_PRODUCT(pa->pa_id)) {
        case PCI_PRODUCT_INTEL_WL_3160_1:
        case PCI_PRODUCT_INTEL_WL_3160_2:
-               sc->sc_fwname = "iwm-3160-9";
+               sc->sc_fwname = "iwm-3160-16";
                sc->host_interrupt_operation_mode = 1;
                break;
        case PCI_PRODUCT_INTEL_WL_7260_1:
        case PCI_PRODUCT_INTEL_WL_7260_2:
-               sc->sc_fwname = "iwm-7260-9";
+               sc->sc_fwname = "iwm-7260-16";
                sc->host_interrupt_operation_mode = 1;
                break;
        case PCI_PRODUCT_INTEL_WL_7265_1:
        case PCI_PRODUCT_INTEL_WL_7265_2:
-               sc->sc_fwname = "iwm-7265-9";
+               sc->sc_fwname = "iwm-7265-16";
                sc->host_interrupt_operation_mode = 0;
                break;
        default:
Index: if_iwmreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwmreg.h,v
retrieving revision 1.11
diff -u -p -r1.11 if_iwmreg.h
--- if_iwmreg.h 18 May 2016 07:28:01 -0000      1.11
+++ if_iwmreg.h 18 May 2016 09:07:12 -0000
@@ -126,6 +126,9 @@
 #define IWM_CSR_UCODE_DRV_GP1_CLR   (0x05c)
 #define IWM_CSR_UCODE_DRV_GP2       (0x060)
 
+#define IWM_CSR_MBOX_SET_REG           (0x088)
+#define IWM_CSR_MBOX_SET_REG_OS_ALIVE  0x20
+
 #define IWM_CSR_LED_REG                        (0x094)
 #define IWM_CSR_DRAM_INT_TBL_REG       (0x0A0)
 #define IWM_CSR_MAC_SHADOW_REG_CTRL    (0x0A8) /* 6000 and up */
@@ -172,6 +175,8 @@
 #define IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */
 #define IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
 #define IWM_CSR_HW_IF_CONFIG_REG_PREPARE       (0x08000000) /* WAKE_ME */
+#define IWM_CSR_HW_IF_CONFIG_REG_ENABLE_PME    (0x10000000)
+#define IWM_CSR_HW_IF_CONFIG_REG_PERSIST_MODE  (0x40000000) /* PERSISTENCE */
 
 #define IWM_CSR_INT_PERIODIC_DIS               (0x00) /* disable periodic int*/
 #define IWM_CSR_INT_PERIODIC_ENA               (0xFF) /* 255*32 usec ~ 8 msec*/
@@ -298,6 +303,7 @@
 #define IWM_CSR_HW_REV_TYPE_2x00       (0x0000100)
 #define IWM_CSR_HW_REV_TYPE_105                (0x0000110)
 #define IWM_CSR_HW_REV_TYPE_135                (0x0000120)
+#define IWM_CSR_HW_REV_TYPE_7265D      (0x0000210)
 #define IWM_CSR_HW_REV_TYPE_NONE       (0x00001F0)
 
 /* EEPROM REG */
@@ -392,6 +398,7 @@
 
 /* DRAM INT TABLE */
 #define IWM_CSR_DRAM_INT_TBL_ENABLE            (1 << 31)
+#define IWM_CSR_DRAM_INIT_TBL_WRITE_POINTER    (1 << 28)
 #define IWM_CSR_DRAM_INIT_TBL_WRAP_CHECK       (1 << 27)
 
 /* SECURE boot registers */
@@ -411,19 +418,37 @@ enum iwm_secure_boot_status_reg {
        IWM_CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL   = 0x00000010,
 };
 
-#define IWM_CSR_UCODE_LOAD_STATUS_ADDR (0x100)
+#define IWM_FH_UCODE_LOAD_STATUS       0x1af0
+#define IWM_CSR_UCODE_LOAD_STATUS_ADDR 0x1e70
 enum iwm_secure_load_status_reg {
-       IWM_CSR_CPU_STATUS_LOADING_STARTED                      = 0x00000001,
-       IWM_CSR_CPU_STATUS_LOADING_COMPLETED            = 0x00000002,
-       IWM_CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED                = 0x000000F8,
-       IWM_CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK             = 0x0000FF00,
-};
-
-#define IWM_CSR_SECURE_INSPECTOR_CODE_ADDR     (0x100)
-#define IWM_CSR_SECURE_INSPECTOR_DATA_ADDR     (0x100)
+       IWM_LMPM_CPU_UCODE_LOADING_STARTED              = 0x00000001,
+       IWM_LMPM_CPU_HDRS_LOADING_COMPLETED             = 0x00000003,
+       IWM_LMPM_CPU_UCODE_LOADING_COMPLETED            = 0x00000007,
+       IWM_LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED       = 0x000000F8,
+       IWM_LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK    = 0x0000FF00,
+};
+#define IWM_FH_MEM_TB_MAX_LENGTH       0x20000
+
+#define IWM_LMPM_SECURE_INSPECTOR_CODE_ADDR            0x1e38
+#define IWM_LMPM_SECURE_INSPECTOR_DATA_ADDR            0x1e3c
+#define IWM_LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR       0x1e78
+#define IWM_LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR       0x1e7c
+
+#define IWM_LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE       0x400000
+#define IWM_LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE       0x402000
+#define IWM_LMPM_SECURE_CPU1_HDR_MEM_SPACE             0x420000
+#define IWM_LMPM_SECURE_CPU2_HDR_MEM_SPACE             0x420400
 
 #define IWM_CSR_SECURE_TIME_OUT        (100)
 
+/* extended range in FW SRAM */
+#define IWM_FW_MEM_EXTENDED_START       0x40000
+#define IWM_FW_MEM_EXTENDED_END         0x57FFF
+
+/* FW chicken bits */
+#define IWM_LMPM_CHICK                         0xa01ff8
+#define IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE     0x01
+
 #define IWM_FH_TCSR_0_REG0 (0x1D00)
 
 /*
@@ -474,6 +499,32 @@ enum iwm_secure_load_status_reg {
 #define IWM_HBUS_TARG_PRPH_WDAT     (IWM_HBUS_BASE+0x04c)
 #define IWM_HBUS_TARG_PRPH_RDAT     (IWM_HBUS_BASE+0x050)
 
+/* enable the ID buf for read */
+#define IWM_WFPM_PS_CTL_CLR                    0xa0300c
+#define IWM_WFMP_MAC_ADDR_0                    0xa03080
+#define IWM_WFMP_MAC_ADDR_1                    0xa03084
+#define IWM_LMPM_PMG_EN                                0xa01cec
+#define IWM_RADIO_REG_SYS_MANUAL_DFT_0         0xad4078
+#define IWM_RFIC_REG_RD                                0xad0470
+#define IWM_WFPM_CTRL_REG                      0xa03030
+#define IWM_WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK  0x08000000
+#define IWM_ENABLE_WFPM                                0x80000000
+
+#define IWM_AUX_MISC_REG                       0xa200b0
+#define IWM_HW_STEP_LOCATION_BITS              24
+
+#define IWM_AUX_MISC_MASTER1_EN                        0xa20818
+#define IWM_AUX_MISC_MASTER1_EN_SBE_MSK                0x1
+#define IWM_AUX_MISC_MASTER1_SMPHR_STATUS      0xa20800
+#define IWM_RSA_ENABLE                         0xa24b08
+#define IWM_PREG_AUX_BUS_WPROT_0               0xa04cc0
+#define IWM_SB_CFG_OVERRIDE_ADDR               0xa26c78
+#define IWM_SB_CFG_OVERRIDE_ENABLE             0x8000
+#define IWM_SB_CFG_BASE_OVERRIDE               0xa20000
+#define IWM_SB_MODIFY_CFG_FLAG                 0xa03088
+#define IWM_SB_CPU_1_STATUS                    0xa01e30
+#define IWM_SB_CPU_2_STATUS                    0Xa01e34
+
 /* Used to enable DBGM */
 #define IWM_HBUS_TARG_TEST_REG (IWM_HBUS_BASE+0x05c)
 
@@ -549,7 +600,12 @@ enum iwm_dtd_diode_reg {
  *     containing CAM (Continuous Active Mode) indication.
  * @IWM_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
  *     single bound interface).
+ * @IWM_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD
+ * @IWM_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS.
  * @IWM_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
+ * @IWM_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
+ * @IWM_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
+ *
  */
 enum iwm_ucode_tlv_flag {
        IWM_UCODE_TLV_FLAGS_PAN                 = (1 << 0),
@@ -572,8 +628,146 @@ enum iwm_ucode_tlv_flag {
        IWM_UCODE_TLV_FLAGS_STA_KEY_CMD         = (1 << 19),
        IWM_UCODE_TLV_FLAGS_DEVICE_PS_CMD       = (1 << 20),
        IWM_UCODE_TLV_FLAGS_P2P_PS              = (1 << 21),
+       IWM_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM      = (1 << 22),
+       IWM_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM      = (1 << 23),
        IWM_UCODE_TLV_FLAGS_UAPSD_SUPPORT       = (1 << 24),
+       IWM_UCODE_TLV_FLAGS_EBS_SUPPORT         = (1 << 25),
        IWM_UCODE_TLV_FLAGS_P2P_PS_UAPSD        = (1 << 26),
+       IWM_UCODE_TLV_FLAGS_BCAST_FILTERING     = (1 << 29),
+       IWM_UCODE_TLV_FLAGS_GO_UAPSD            = (1 << 30),
+       IWM_UCODE_TLV_FLAGS_LTE_COEX            = (1 << 31),
+};
+#define IWM_UCODE_TLV_FLAG_BITS \
+       
"\020\1PAN\2NEWSCAN\3MFP\4P2P\5DW_BC_TABLE\6NEWBT_COEX\7PM_CMD\10SHORT_BL\11RX_ENERGY\12TIME_EVENT_V2\13D3_6_IPV6\14BF_UPDATED\15NO_BASIC_SSID\17D3_CONTINUITY\20NEW_NSOFFL_S\21NEW_NSOFFL_L\22SCHED_SCAN\24STA_KEY_CMD\25DEVICE_PS_CMD\26P2P_PS\27P2P_PS_DCM\30P2P_PS_SCM\31UAPSD_SUPPORT\32EBS\33P2P_PS_UAPSD\36BCAST_FILTERING\37GO_UAPSD\40LTE_COEX"
+
+/**
+ * enum iwm_ucode_tlv_api - ucode api
+ * @IWM_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
+ *     longer than the passive one, which is essential for fragmented scan.
+ * @IWM_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source.
+ * @IWM_UCODE_TLV_API_WIDE_CMD_HDR: ucode supports wide command header
+ * @IWM_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params
+ * @IWM_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority
+ *     instead of 3.
+ * @IWM_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size
+ *     (command version 3) that supports per-chain limits
+ *
+ * @IWM_NUM_UCODE_TLV_API: number of bits used
+ */
+enum iwm_ucode_tlv_api {
+       IWM_UCODE_TLV_API_FRAGMENTED_SCAN       = (1 << 8),
+       IWM_UCODE_TLV_API_WIFI_MCC_UPDATE       = (1 << 9),
+       IWM_UCODE_TLV_API_WIDE_CMD_HDR          = (1 << 14),
+       IWM_UCODE_TLV_API_LQ_SS_PARAMS          = (1 << 18),
+       IWM_UCODE_TLV_API_EXT_SCAN_PRIORITY     = (1 << 24),
+       IWM_UCODE_TLV_API_TX_POWER_CHAIN        = (1 << 27),
+
+       IWM_NUM_UCODE_TLV_API = 32
+};
+
+#define IWM_UCODE_TLV_API_BITS \
+       
"\020\10FRAGMENTED_SCAN\11WIFI_MCC_UPDATE\16WIDE_CMD_HDR\22LQ_SS_PARAMS\30EXT_SCAN_PRIO\33TX_POWER_CHAIN"
+
+/**
+ * enum iwm_ucode_tlv_capa - ucode capabilities
+ * @IWM_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3
+ * @IWM_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory
+ * @IWM_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan.
+ * @IWM_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer
+ * @IWM_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM)
+ * @IWM_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality
+ * @IWM_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current
+ *     tx power value into TPC Report action frame and Link Measurement Report
+ *     action frame
+ * @IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports updating current
+ *     channel in DS parameter set element in probe requests.
+ * @IWM_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in
+ *     probe requests.
+ * @IWM_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests
+ * @IWM_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA),
+ *     which also implies support for the scheduler configuration command
+ * @IWM_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching
+ * @IWM_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG: Consolidated D3-D0 image
+ * @IWM_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
+ * @IWM_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command
+ * @IWM_UCODE_TLV_CAPA_2G_COEX_SUPPORT: supports 2G coex Command
+ * @IWM_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload
+ * @IWM_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
+ * @IWM_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD
+ * @IWM_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running
+ * @IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different
+ *     sources for the MCC. This TLV bit is a future replacement to
+ *     IWM_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR
+ *     is supported.
+ * @IWM_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC
+ * @IWM_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan
+ * @IWM_UCODE_TLV_CAPA_NAN_SUPPORT: supports NAN
+ * @IWM_UCODE_TLV_CAPA_UMAC_UPLOAD: supports upload mode in umac (1=supported,
+ *     0=no support)
+ * @IWM_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
+ * @IWM_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
+ * @IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
+ * @IWM_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what
+ *     antenna the beacon should be transmitted
+ * @IWM_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon
+ *     from AP and will send it upon d0i3 exit.
+ * @IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2
+ * @IWM_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill
+ * @IWM_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature
+ *     thresholds reporting
+ * @IWM_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command
+ * @IWM_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in
+ *     regular image.
+ * @IWM_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared
+ *     memory addresses from the firmware.
+ * @IWM_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement
+ * @IWM_UCODE_TLV_CAPA_LMAC_UPLOAD: supports upload mode in lmac (1=supported,
+ *     0=no support)
+ *
+ * @IWM_NUM_UCODE_TLV_CAPA: number of bits used
+ */
+enum iwm_ucode_tlv_capa {
+       IWM_UCODE_TLV_CAPA_D0I3_SUPPORT                 = 0,
+       IWM_UCODE_TLV_CAPA_LAR_SUPPORT                  = 1,
+       IWM_UCODE_TLV_CAPA_UMAC_SCAN                    = 2,
+       IWM_UCODE_TLV_CAPA_BEAMFORMER                   = 3,
+       IWM_UCODE_TLV_CAPA_TOF_SUPPORT                  = 5,
+       IWM_UCODE_TLV_CAPA_TDLS_SUPPORT                 = 6,
+       IWM_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT    = 8,
+       IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT      = 9,
+       IWM_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT       = 10,
+       IWM_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT         = 11,
+       IWM_UCODE_TLV_CAPA_DQA_SUPPORT                  = 12,
+       IWM_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH          = 13,
+       IWM_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG            = 17,
+       IWM_UCODE_TLV_CAPA_HOTSPOT_SUPPORT              = 18,
+       IWM_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT         = 19,
+       IWM_UCODE_TLV_CAPA_2G_COEX_SUPPORT              = 20,
+       IWM_UCODE_TLV_CAPA_CSUM_SUPPORT                 = 21,
+       IWM_UCODE_TLV_CAPA_RADIO_BEACON_STATS           = 22,
+       IWM_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD         = 26,
+       IWM_UCODE_TLV_CAPA_BT_COEX_PLCR                 = 28,
+       IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC                = 29,
+       IWM_UCODE_TLV_CAPA_BT_COEX_RRC                  = 30,
+       IWM_UCODE_TLV_CAPA_GSCAN_SUPPORT                = 31,
+       IWM_UCODE_TLV_CAPA_NAN_SUPPORT                  = 34,
+       IWM_UCODE_TLV_CAPA_UMAC_UPLOAD                  = 35,
+       IWM_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE         = 64,
+       IWM_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS            = 65,
+       IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT             = 67,
+       IWM_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT       = 68,
+       IWM_UCODE_TLV_CAPA_BEACON_ANT_SELECTION         = 71,
+       IWM_UCODE_TLV_CAPA_BEACON_STORING               = 72,
+       IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2               = 73,
+       IWM_UCODE_TLV_CAPA_CT_KILL_BY_FW                = 74,
+       IWM_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT      = 75,
+       IWM_UCODE_TLV_CAPA_CTDP_SUPPORT                 = 76,
+       IWM_UCODE_TLV_CAPA_USNIFFER_UNIFIED             = 77,
+       IWM_UCODE_TLV_CAPA_LMAC_UPLOAD                  = 79,
+       IWM_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG        = 80,
+       IWM_UCODE_TLV_CAPA_LQM_SUPPORT                  = 81,
+
+       IWM_NUM_UCODE_TLV_CAPA = 128
 };
 
 /* The default calibrate table size if not specified by firmware file */
@@ -599,8 +793,8 @@ enum iwm_ucode_sec {
  * For 16.0 uCode and above, there is no differentiation between sections,
  * just an offset to the HW address.
  */
-#define IWM_UCODE_SECTION_MAX 6
-#define IWM_UCODE_FIRST_SECTION_OF_SECOND_CPU  (IWM_UCODE_SECTION_MAX/2)
+#define IWM_CPU1_CPU2_SEPARATOR_SECTION                0xFFFFCCCC
+#define IWM_PAGING_SEPARATOR_SECTION           0xAAAABBBB
 
 /* uCode version contains 4 values: Major/Minor/API/Serial */
 #define IWM_UCODE_MAJOR(ver)   (((ver) & 0xFF000000) >> 24)
@@ -739,7 +933,17 @@ enum iwm_ucode_tlv_type {
         * handling ucode version 9.
         */
        IWM_UCODE_TLV_API_CHANGES_SET   = 29,
-       IWM_UCODE_TLV_ENABLED_CAPABILITIES = 30
+       IWM_UCODE_TLV_ENABLED_CAPABILITIES = 30,
+
+       IWM_UCODE_TLV_N_SCAN_CHANNELS   = 31,
+       IWM_UCODE_TLV_PAGING            = 32,
+       IWM_UCODE_TLV_SEC_RT_USNIFFER   = 34,
+       IWM_UCODE_TLV_SDIO_ADMA_ADDR    = 35,
+       IWM_UCODE_TLV_FW_VERSION        = 36,
+       IWM_UCODE_TLV_FW_DBG_DEST       = 38,
+       IWM_UCODE_TLV_FW_DBG_CONF       = 39,
+       IWM_UCODE_TLV_FW_DBG_TRIGGER    = 40,
+       IWM_UCODE_TLV_FW_GSCAN_CAPA     = 50,
 };
 
 struct iwm_ucode_tlv {
@@ -748,6 +952,16 @@ struct iwm_ucode_tlv {
        uint8_t data[0];
 };
 
+struct iwm_ucode_api {
+       uint32_t api_index;
+       uint32_t api_flags;
+} __packed;
+
+struct iwm_ucode_capa {
+       uint32_t api_index;
+       uint32_t api_capa;
+} __packed;
+
 #define IWM_TLV_UCODE_MAGIC    0x0a4c5749
 
 struct iwm_tlv_ucode_header {
@@ -812,7 +1026,9 @@ struct iwm_tlv_ucode_header {
 #define IWM_DEVICE_SYSTEM_TIME_REG 0xA0206C
 
 /* Device NMI register */
-#define IWM_DEVICE_SET_NMI_REG 0x00a01c30
+#define IWM_DEVICE_SET_NMI_REG         0x00a01c30
+#define IWM_DEVICE_SET_NMI_VAL_HW      0x01
+#define IWM_DEVICE_SET_NMI_VAL_DRV     0x80
 
 /*****************************************************************************
  *                        7000/3000 series SHR DTS addresses                 *
@@ -926,6 +1142,8 @@ struct iwm_tlv_ucode_header {
 #define IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK    (0x0000007F)
 #define IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
 #define IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
+#define IWM_SCD_GP_CTRL_ENABLE_31_QUEUES       (1 << 0)
+#define IWM_SCD_GP_CTRL_AUTO_ACTIVE_MODE       (1 << 18)
 
 /* Context Data */
 #define IWM_SCD_CONTEXT_MEM_LOWER_BOUND        (IWM_SCD_MEM_LOWER_BOUND + 
0x600)
@@ -959,6 +1177,8 @@ struct iwm_tlv_ucode_header {
 #define IWM_SCD_CHAINEXT_EN    (IWM_SCD_BASE + 0x244)
 #define IWM_SCD_AGGR_SEL       (IWM_SCD_BASE + 0x248)
 #define IWM_SCD_INTERRUPT_MASK (IWM_SCD_BASE + 0x108)
+#define IWM_SCD_GP_CTRL                (IWM_SCD_BASE + 0x1a8)
+#define IWM_SCD_EN_CTRL                (IWM_SCD_BASE + 0x254)
 
 static inline unsigned int IWM_SCD_QUEUE_WRPTR(unsigned int chnl)
 {
@@ -1460,13 +1680,14 @@ struct iwm_agn_scd_bc_tbl {
        uint16_t tfd_offset[IWM_TFD_QUEUE_BC_SIZE];
 } __packed;
 
-/* maximal number of Tx queues in any platform */
-#define IWM_MVM_MAX_QUEUES     20
+/* Maximum number of Tx queues. */
+#define IWM_MVM_MAX_QUEUES     31
 
 /* Tx queue numbers */
 enum {
        IWM_MVM_OFFCHANNEL_QUEUE = 8,
        IWM_MVM_CMD_QUEUE = 9,
+       IWM_MVM_AUX_QUEUE = 15,
 };
 
 enum iwm_mvm_tx_fifo {
@@ -1501,6 +1722,9 @@ enum {
        IWM_TXPATH_FLUSH = 0x1e,
        IWM_MGMT_MCAST_KEY = 0x1f,
 
+       /* scheduler config */
+       IWM_SCD_QUEUE_CFG = 0x1d,
+
        /* global key */
        IWM_WEP_KEY = 0x20,
 
@@ -1524,10 +1748,12 @@ enum {
        /* Scan offload */
        IWM_SCAN_OFFLOAD_REQUEST_CMD = 0x51,
        IWM_SCAN_OFFLOAD_ABORT_CMD = 0x52,
-       IWM_SCAN_OFFLOAD_COMPLETE = 0x6D,
-       IWM_SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
+       IWM_HOT_SPOT_CMD = 0x53,
+       IWM_SCAN_OFFLOAD_COMPLETE = 0x6d,
+       IWM_SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6e,
        IWM_SCAN_OFFLOAD_CONFIG_CMD = 0x6f,
        IWM_MATCH_FOUND_NOTIFICATION = 0xd9,
+       IWM_SCAN_ITERATION_COMPLETE = 0xe7,
 
        /* Phy */
        IWM_PHY_CONFIGURATION_CMD = 0x6a,
@@ -1566,6 +1792,8 @@ enum {
 
        IWM_MISSED_BEACONS_NOTIFICATION = 0xa2,
 
+       IWM_MFUART_LOAD_NOTIFICATION = 0xb1,
+
        /* Power - new power table command */
        IWM_MAC_PM_POWER_TABLE = 0xa9,
 
@@ -1573,6 +1801,10 @@ enum {
        IWM_REPLY_RX_MPDU_CMD = 0xc1,
        IWM_BA_NOTIF = 0xc5,
 
+       /* Location Aware Regulatory */
+       IWM_MCC_UPDATE_CMD = 0xc8,
+       IWM_MCC_CHUB_UPDATE_CMD = 0xc9,
+
        /* BT Coex */
        IWM_BT_COEX_PRIO_TABLE = 0xcc,
        IWM_BT_COEX_PROT_ENV = 0xcd,
@@ -1582,6 +1814,10 @@ enum {
        IWM_REPLY_SF_CFG_CMD = 0xd1,
        IWM_REPLY_BEACON_FILTERING_CMD = 0xd2,
 
+       /* DTS measurements */
+       IWM_CMD_DTS_MEASUREMENT_TRIGGER = 0xdc,
+       IWM_DTS_MEASUREMENT_NOTIFICATION = 0xdd,
+
        IWM_REPLY_DEBUG_CMD = 0xf0,
        IWM_DEBUG_LOG_MSG = 0xf7,
 
@@ -1750,7 +1986,7 @@ enum {
        IWM_NVM_SECTION_TYPE_HW = 0,
        IWM_NVM_SECTION_TYPE_SW,
        IWM_NVM_SECTION_TYPE_PAPD,
-       IWM_NVM_SECTION_TYPE_BT,
+       IWM_NVM_SECTION_TYPE_REGULATORY,
        IWM_NVM_SECTION_TYPE_CALIBRATION,
        IWM_NVM_SECTION_TYPE_PRODUCTION,
        IWM_NVM_SECTION_TYPE_POST_FCS_CALIB,
@@ -1824,7 +2060,7 @@ enum {
 
 #define IWM_ALIVE_FLG_RFKILL   (1 << 0)
 
-struct iwm_mvm_alive_resp {
+struct iwm_mvm_alive_resp_v1 {
        uint16_t status;
        uint16_t flags;
        uint8_t ucode_minor;
@@ -1846,6 +2082,59 @@ struct iwm_mvm_alive_resp {
        uint32_t scd_base_ptr;          /* SRAM address for SCD */
 } __packed; /* IWM_ALIVE_RES_API_S_VER_1 */
 
+struct iwm_mvm_alive_resp_v2 {
+       uint16_t status;
+       uint16_t flags;
+       uint8_t ucode_minor;
+       uint8_t ucode_major;
+       uint16_t id;
+       uint8_t api_minor;
+       uint8_t api_major;
+       uint8_t ver_subtype;
+       uint8_t ver_type;
+       uint8_t mac;
+       uint8_t opt;
+       uint16_t reserved2;
+       uint32_t timestamp;
+       uint32_t error_event_table_ptr; /* SRAM address for error log */
+       uint32_t log_event_table_ptr;   /* SRAM address for LMAC event log */
+       uint32_t cpu_register_ptr;
+       uint32_t dbgm_config_ptr;
+       uint32_t alive_counter_ptr;
+       uint32_t scd_base_ptr;          /* SRAM address for SCD */
+       uint32_t st_fwrd_addr;          /* pointer to Store and forward */
+       uint32_t st_fwrd_size;
+       uint8_t umac_minor;                     /* UMAC version: minor */
+       uint8_t umac_major;                     /* UMAC version: major */
+       uint16_t umac_id;                       /* UMAC version: id */
+       uint32_t error_info_addr;               /* SRAM address for UMAC error 
log */
+       uint32_t dbg_print_buff_addr;
+} __packed; /* ALIVE_RES_API_S_VER_2 */
+
+struct iwm_mvm_alive_resp_v3 {
+       uint16_t status;
+       uint16_t flags;
+       uint32_t ucode_minor;
+       uint32_t ucode_major;
+       uint8_t ver_subtype;
+       uint8_t ver_type;
+       uint8_t mac;
+       uint8_t opt;
+       uint32_t timestamp;
+       uint32_t error_event_table_ptr; /* SRAM address for error log */
+       uint32_t log_event_table_ptr;   /* SRAM address for LMAC event log */
+       uint32_t cpu_register_ptr;
+       uint32_t dbgm_config_ptr;
+       uint32_t alive_counter_ptr;
+       uint32_t scd_base_ptr;          /* SRAM address for SCD */
+       uint32_t st_fwrd_addr;          /* pointer to Store and forward */
+       uint32_t st_fwrd_size;
+       uint32_t umac_minor;            /* UMAC version: minor */
+       uint32_t umac_major;            /* UMAC version: major */
+       uint32_t error_info_addr;               /* SRAM address for UMAC error 
log */
+       uint32_t dbg_print_buff_addr;
+} __packed; /* ALIVE_RES_API_S_VER_3 */
+
 /* Error response/notification */
 enum {
        IWM_FW_ERR_UNKNOWN_CMD = 0x0,
@@ -2153,6 +2442,7 @@ enum {
        IWM_TE_V2_NOTIF_HOST_FRAG_END = (1 << 5),
        IWM_TE_V2_NOTIF_INTERNAL_FRAG_START = (1 << 6),
        IWM_TE_V2_NOTIF_INTERNAL_FRAG_END = (1 << 7),
+       IWM_T2_V2_START_IMMEDIATELY = (1 << 11),
 
        IWM_TE_V2_NOTIF_MSK = 0xff,
 
@@ -2593,6 +2883,21 @@ struct iwm_missed_beacons_notif {
 } __packed; /* IWM_MISSED_BEACON_NTFY_API_S_VER_3 */
 
 /**
+ * struct iwm_mfuart_load_notif - mfuart image version & status
+ * ( IWM_MFUART_LOAD_NOTIFICATION = 0xb1 )
+ * @installed_ver: installed image version
+ * @external_ver: external image version
+ * @status: MFUART loading status
+ * @duration: MFUART loading time
+*/
+struct iwm_mfuart_load_notif {
+       uint32_t installed_ver;
+       uint32_t external_ver;
+       uint32_t status;
+       uint32_t duration;
+} __packed; /*MFU_LOADER_NTFY_API_S_VER_1*/
+
+/**
  * struct iwm_set_calib_default_cmd - set default value for calibration.
  * ( IWM_SET_CALIB_DEFAULT_CMD = 0x8e )
  * @calib_index: the calibration to set value for
@@ -2869,6 +3174,18 @@ enum iwm_sf_scenario {
 #define IWM_SF_W_MARK_LEGACY 4096
 #define IWM_SF_W_MARK_SCAN 4096
 
+/* SF Scenarios timers for default configuration (aligned to 32 uSec) */
+#define IWM_SF_SINGLE_UNICAST_IDLE_TIMER_DEF 160       /* 150 uSec  */
+#define IWM_SF_SINGLE_UNICAST_AGING_TIMER_DEF 400      /* 0.4 mSec */
+#define IWM_SF_AGG_UNICAST_IDLE_TIMER_DEF 160          /* 150 uSec */
+#define IWM_SF_AGG_UNICAST_AGING_TIMER_DEF 400         /* 0.4 mSec */
+#define IWM_SF_MCAST_IDLE_TIMER_DEF 160                        /* 150 mSec */
+#define IWM_SF_MCAST_AGING_TIMER_DEF 400               /* 0.4 mSec */
+#define IWM_SF_BA_IDLE_TIMER_DEF 160                   /* 150 uSec */
+#define IWM_SF_BA_AGING_TIMER_DEF 400                  /* 0.4 mSec */
+#define IWM_SF_TX_RE_IDLE_TIMER_DEF 160                        /* 150 uSec */
+#define IWM_SF_TX_RE_AGING_TIMER_DEF 400               /* 0.4 mSec */
+
 /* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */
 #define IWM_SF_SINGLE_UNICAST_IDLE_TIMER 320   /* 300 uSec  */
 #define IWM_SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */
@@ -2883,6 +3200,8 @@ enum iwm_sf_scenario {
 
 #define IWM_SF_LONG_DELAY_AGING_TIMER 1000000  /* 1 Sec */
 
+#define IWM_SF_CFG_DUMMY_NOTIF_OFF     (1 << 16)
+
 /**
  * Smart Fifo configuration command.
  * @state: smart fifo state, types listed in iwm_sf_sate.
@@ -4366,6 +4685,46 @@ static inline uint32_t iwm_mvm_get_scd_s
                            tx_resp->frame_count) & 0xfff;
 }
 
+/**
+ * struct iwm_scd_txq_cfg_cmd - New txq hw scheduler config command
+ * @token:
+ * @sta_id: station id
+ * @tid:
+ * @scd_queue: scheduler queue to confiug
+ * @enable: 1 queue enable, 0 queue disable
+ * @aggregate: 1 aggregated queue, 0 otherwise
+ * @tx_fifo: %enum iwm_mvm_tx_fifo
+ * @window: BA window size
+ * @ssn: SSN for the BA agreement
+ */
+struct iwm_scd_txq_cfg_cmd {
+       uint8_t token;
+       uint8_t sta_id;
+       uint8_t tid;
+       uint8_t scd_queue;
+       uint8_t enable;
+       uint8_t aggregate;
+       uint8_t tx_fifo;
+       uint8_t window;
+       uint16_t ssn;
+       uint16_t reserved;
+} __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */
+
+/**
+ * struct iwm_scd_txq_cfg_rsp
+ * @token: taken from the command
+ * @sta_id: station id from the command
+ * @tid: tid from the command
+ * @scd_queue: scd_queue from the command
+ */
+struct iwm_scd_txq_cfg_rsp {
+       uint8_t token;
+       uint8_t sta_id;
+       uint8_t tid;
+       uint8_t scd_queue;
+} __packed; /* SCD_QUEUE_CFG_RSP_API_S_VER_1 */
+
+
 /* Scan Commands, Responses, Notifications */
 
 /* Masks for iwm_scan_channel.type flags */
@@ -4430,6 +4789,23 @@ struct iwm_ssid_ie {
        uint8_t ssid[IEEE80211_NWID_LEN];
 } __packed; /* IWM_SCAN_DIRECT_SSID_IE_API_S_VER_1 */
 
+/* scan offload */
+#define IWM_MAX_SCAN_CHANNELS          40
+#define IWM_SCAN_MAX_BLACKLIST_LEN     64
+#define IWM_SCAN_SHORT_BLACKLIST_LEN   16
+#define IWM_SCAN_MAX_PROFILES          11
+#define IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE        512
+
+/* Default watchdog (in MS) for scheduled scan iteration */
+#define IWM_SCHED_SCAN_WATCHDOG cpu_to_le16(15000)
+
+#define IWM_GOOD_CRC_TH_DEFAULT cpu_to_le16(1)
+#define IWM_CAN_ABORT_STATUS 1
+
+#define IWM_FULL_SCAN_MULTIPLIER 5
+#define IWM_FAST_SCHED_SCAN_ITERATIONS 3
+#define IWM_MAX_SCHED_SCAN_PLANS 2
+
 /**
  * iwm_scan_flags - masks for scan command flags
  *@IWM_SCAN_FLAGS_PERIODIC_SCAN:
@@ -4473,64 +4849,194 @@ enum iwm_scan_type {
 #define IWM_MAX_NUM_SCAN_CHANNELS 0x24
 
 /**
- * struct iwm_scan_cmd - scan request command
- * ( IWM_SCAN_REQUEST_CMD = 0x80 )
- * @len: command length in bytes
- * @scan_flags: scan flags from IWM_SCAN_FLAGS_*
- * @channel_count: num of channels in channel list (1 - 
IWM_MAX_NUM_SCAN_CHANNELS)
- * @quiet_time: in msecs, dwell this time for active scan on quiet channels
- * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than
- *     this number of packets were received (typically 1)
- * @passive2active: is auto switching from passive to active during scan 
allowed
- * @rxchain_sel_flags: RXON_RX_CHAIN_*
- * @max_out_time: in usecs, max out of serving channel time
- * @suspend_time: how long to pause scan when returning to service channel:
- *     bits 0-19: beacon interal in usecs (suspend before executing)
- *     bits 20-23: reserved
- *     bits 24-31: number of beacons (suspend between channels)
- * @rxon_flags: RXON_FLG_*
- * @filter_flags: RXON_FILTER_*
- * @tx_cmd: for active scans (zero for passive), w/o payload,
- *     no RS so specify TX rate
- * @direct_scan: direct scan SSIDs
- * @type: one of IWM_SCAN_TYPE_*
- * @repeats: how many time to repeat the scan
+ * iwm_scan_schedule_lmac - schedule of scan offload
+ * @delay:             delay between iterations, in seconds.
+ * @iterations:                num of scan iterations
+ * @full_scan_mul:     number of partial scans before each full scan
+ */
+struct iwm_scan_schedule_lmac {
+       uint16_t delay;
+       uint8_t iterations;
+       uint8_t full_scan_mul;
+} __packed; /* SCAN_SCHEDULE_API_S */
+
+/**
+ * iwm_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S
+ * @tx_flags: combination of TX_CMD_FLG_*
+ * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is
+ *     cleared. Combination of RATE_MCS_*
+ * @sta_id: index of destination station in FW station table
+ * @reserved: for alignment and future use
+ */
+struct iwm_scan_req_tx_cmd {
+       uint32_t tx_flags;
+       uint32_t rate_n_flags;
+       uint8_t sta_id;
+       uint8_t reserved[3];
+} __packed;
+
+enum iwm_scan_channel_flags_lmac {
+       IWM_UNIFIED_SCAN_CHANNEL_FULL           = (1 << 27),
+       IWM_UNIFIED_SCAN_CHANNEL_PARTIAL        = (1 << 28),
+};
+
+/**
+ * iwm_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2
+ * @flags:             bits 1-20: directed scan to i'th ssid
+ *                     other bits &enum iwm_scan_channel_flags_lmac
+ * @channel_number:    channel number 1-13 etc
+ * @iter_count:                scan iteration on this channel
+ * @iter_interval:     interval in seconds between iterations on one channel
+ */
+struct iwm_scan_channel_cfg_lmac {
+       uint32_t flags;
+       uint16_t channel_num;
+       uint16_t iter_count;
+       uint32_t iter_interval;
+} __packed;
+
+/*
+ * iwm_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1
+ * @offset: offset in the data block
+ * @len: length of the segment
  */
-struct iwm_scan_cmd {
+struct iwm_scan_probe_segment {
+       uint16_t offset;
        uint16_t len;
-       uint8_t scan_flags;
-       uint8_t channel_count;
-       uint16_t quiet_time;
-       uint16_t quiet_plcp_th;
-       uint16_t passive2active;
-       uint16_t rxchain_sel_flags;
+} __packed;
+
+/* iwm_scan_probe_req - PROBE_REQUEST_FRAME_API_S_VER_2
+ * @mac_header: first (and common) part of the probe
+ * @band_data: band specific data
+ * @common_data: last (and common) part of the probe
+ * @buf: raw data block
+ */
+struct iwm_scan_probe_req {
+       struct iwm_scan_probe_segment mac_header;
+       struct iwm_scan_probe_segment band_data[2];
+       struct iwm_scan_probe_segment common_data;
+       uint8_t buf[IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE];
+} __packed;
+
+enum iwm_scan_channel_flags {
+       IWM_SCAN_CHANNEL_FLAG_EBS               = (1 << 0),
+       IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE      = (1 << 1),
+       IWM_SCAN_CHANNEL_FLAG_CACHE_ADD         = (1 << 2),
+};
+
+/* iwm_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S
+ * @flags: enum iwm_scan_channel_flags
+ * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is
+ *     involved.
+ *     1 - EBS is disabled.
+ *     2 - every second scan will be full scan(and so on).
+ */
+struct iwm_scan_channel_opt {
+       uint16_t flags;
+       uint16_t non_ebs_ratio;
+} __packed;
+
+/**
+ * iwm_mvm_lmac_scan_flags
+ * @IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL: pass all beacons and probe responses
+ *      without filtering.
+ * @IWM_MVM_LMAC_SCAN_FLAG_PASSIVE: force passive scan on all channels
+ * @IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION: single channel scan
+ * @IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification
+ * @IWM_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching
+ * @IWM_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented
+ * @IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report
+ *      and DS parameter set IEs into probe requests.
+ * @IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL: use extended dwell time on channels
+ *      1, 6 and 11.
+ * @IWM_MVM_LMAC_SCAN_FLAG_MATCH: Send match found notification on matches
+ */
+enum iwm_mvm_lmac_scan_flags {
+       IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL         = (1 << 0),
+       IWM_MVM_LMAC_SCAN_FLAG_PASSIVE          = (1 << 1),
+       IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION   = (1 << 2),
+       IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE    = (1 << 3),
+       IWM_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS   = (1 << 4),
+       IWM_MVM_LMAC_SCAN_FLAG_FRAGMENTED       = (1 << 5),
+       IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED     = (1 << 6),
+       IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL   = (1 << 7),
+       IWM_MVM_LMAC_SCAN_FLAG_MATCH            = (1 << 9),
+};
+
+enum iwm_scan_priority {
+       IWM_SCAN_PRIORITY_LOW,
+       IWM_SCAN_PRIORITY_MEDIUM,
+       IWM_SCAN_PRIORITY_HIGH,
+};
+
+/**
+ * iwm_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1
+ * @reserved1: for alignment and future use
+ * @channel_num: num of channels to scan
+ * @active-dwell: dwell time for active channels
+ * @passive-dwell: dwell time for passive channels
+ * @fragmented-dwell: dwell time for fragmented passive scan
+ * @extended_dwell: dwell time for channels 1, 6 and 11 (in certain cases)
+ * @reserved2: for alignment and future use
+ * @rx_chain_selct: PHY_RX_CHAIN_* flags
+ * @scan_flags: &enum iwm_mvm_lmac_scan_flags
+ * @max_out_time: max time (in TU) to be out of associated channel
+ * @suspend_time: pause scan this long (TUs) when returning to service channel
+ * @flags: RXON flags
+ * @filter_flags: RXON filter
+ * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz
+ * @direct_scan: list of SSIDs for directed active scan
+ * @scan_prio: enum iwm_scan_priority
+ * @iter_num: number of scan iterations
+ * @delay: delay in seconds before first iteration
+ * @schedule: two scheduling plans. The first one is finite, the second one can
+ *     be infinite.
+ * @channel_opt: channel optimization options, for full and partial scan
+ * @data: channel configuration and probe request packet.
+ */
+struct iwm_scan_req_lmac {
+       /* SCAN_REQUEST_FIXED_PART_API_S_VER_7 */
+       uint32_t reserved1;
+       uint8_t n_channels;
+       uint8_t active_dwell;
+       uint8_t passive_dwell;
+       uint8_t fragmented_dwell;
+       uint8_t extended_dwell;
+       uint8_t reserved2;
+       uint16_t rx_chain_select;
+       uint32_t scan_flags;
        uint32_t max_out_time;
        uint32_t suspend_time;
-       /* IWM_RX_ON_FLAGS_API_S_VER_1 */
-       uint32_t rxon_flags;
+       /* RX_ON_FLAGS_API_S_VER_1 */
+       uint32_t flags;
        uint32_t filter_flags;
-       struct iwm_tx_cmd tx_cmd;
+       struct iwm_scan_req_tx_cmd tx_cmd[2];
        struct iwm_ssid_ie direct_scan[IWM_PROBE_OPTION_MAX];
-       uint32_t type;
-       uint32_t repeats;
+       uint32_t scan_prio;
+       /* SCAN_REQ_PERIODIC_PARAMS_API_S */
+       uint32_t iter_num;
+       uint32_t delay;
+       struct iwm_scan_schedule_lmac schedule[IWM_MAX_SCHED_SCAN_PLANS];
+       struct iwm_scan_channel_opt channel_opt[2];
+       uint8_t data[];
+} __packed;
 
-       /*
-        * Probe request frame, followed by channel list.
-        *
-        * Size of probe request frame is specified by byte count in tx_cmd.
-        * Channel list follows immediately after probe request frame.
-        * Number of channels in list is specified by channel_count.
-        * Each channel in list is of type:
-        *
-        * struct iwm_scan_channel channels[0];
-        *
-        * NOTE:  Only one band of channels can be scanned per pass.  You
-        * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
-        * for one scan to complete (i.e. receive 
IWM_SCAN_COMPLETE_NOTIFICATION)
-        * before requesting another scan.
-        */
-       uint8_t data[0];
-} __packed; /* IWM_SCAN_REQUEST_FIXED_PART_API_S_VER_5 */
+/**
+ * iwm_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2
+ * @last_schedule_line: last schedule line executed (fast or regular)
+ * @last_schedule_iteration: last scan iteration executed before scan abort
+ * @status: enum iwm_scan_offload_complete_status
+ * @ebs_status: EBS success status &enum iwm_scan_ebs_status
+ * @time_after_last_iter; time in seconds elapsed after last iteration
+ */
+struct iwm_periodic_scan_complete {
+       uint8_t last_schedule_line;
+       uint8_t last_schedule_iteration;
+       uint8_t status;
+       uint8_t ebs_status;
+       uint32_t time_after_last_iter;
+       uint32_t reserved;
+} __packed;
 
 /* Response to scan request contains only status with one of these values */
 #define IWM_SCAN_RESPONSE_OK   0x1
@@ -4653,22 +5159,6 @@ struct iwm_scan_complete_notif {
        struct iwm_scan_results_notif results[IWM_MAX_NUM_SCAN_CHANNELS];
 } __packed; /* IWM_SCAN_COMPLETE_NTF_API_S_VER_2 */
 
-/* scan offload */
-#define IWM_MAX_SCAN_CHANNELS          40
-#define IWM_SCAN_MAX_BLACKLIST_LEN     64
-#define IWM_SCAN_SHORT_BLACKLIST_LEN   16
-#define IWM_SCAN_MAX_PROFILES          11
-#define IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE        512
-
-/* Default watchdog (in MS) for scheduled scan iteration */
-#define IWM_SCHED_SCAN_WATCHDOG cpu_to_le16(15000)
-
-#define IWM_GOOD_CRC_TH_DEFAULT cpu_to_le16(1)
-#define IWM_CAN_ABORT_STATUS 1
-
-#define IWM_FULL_SCAN_MULTIPLIER 5
-#define IWM_FAST_SCHED_SCAN_ITERATIONS 3
-
 enum iwm_scan_framework_client {
        IWM_SCAN_CLIENT_SCHED_SCAN      = (1 << 0),
        IWM_SCAN_CLIENT_NETDETECT       = (1 << 1),
@@ -4864,6 +5354,28 @@ enum iwm_scan_offload_compleate_status {
 };
 
 /**
+ * struct iwm_lmac_scan_complete_notif - notifies end of scanning (all 
channels)
+ *     SCAN_COMPLETE_NTF_API_S_VER_3
+ * @scanned_channels: number of channels scanned (and number of valid results)
+ * @status: one of SCAN_COMP_STATUS_*
+ * @bt_status: BT on/off status
+ * @last_channel: last channel that was scanned
+ * @tsf_low: TSF timer (lower half) in usecs
+ * @tsf_high: TSF timer (higher half) in usecs
+ * @results: an array of scan results, only "scanned_channels" of them are 
valid
+ */
+struct iwm_lmac_scan_complete_notif {
+       uint8_t scanned_channels;
+       uint8_t status;
+       uint8_t bt_status;
+       uint8_t last_channel;
+       uint32_t tsf_low;
+       uint32_t tsf_high;
+       struct iwm_scan_results_notif results[];
+} __packed;
+
+
+/**
  * iwm_scan_offload_complete - IWM_SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1
  * @last_schedule_line:                last schedule line executed (fast or 
regular)
  * @last_schedule_iteration:   last scan iteration executed before scan abort
@@ -4887,11 +5399,13 @@ struct iwm_sched_scan_results {
        uint8_t reserved;
 };
 
+/* STA API */
+
 /**
  * enum iwm_sta_flags - flags for the ADD_STA host command
  * @IWM_STA_FLG_REDUCED_TX_PWR_CTRL:
  * @IWM_STA_FLG_REDUCED_TX_PWR_DATA:
- * @IWM_STA_FLG_FLG_ANT_MSK: Antenna selection
+ * @IWM_STA_FLG_DISABLE_TX: set if TX should be disabled
  * @IWM_STA_FLG_PS: set if STA is in Power Save
  * @IWM_STA_FLG_INVALID: set if STA is invalid
  * @IWM_STA_FLG_DLP_EN: Direct Link Protocol is enabled
@@ -4915,10 +5429,7 @@ enum iwm_sta_flags {
        IWM_STA_FLG_REDUCED_TX_PWR_CTRL = (1 << 3),
        IWM_STA_FLG_REDUCED_TX_PWR_DATA = (1 << 6),
 
-       IWM_STA_FLG_FLG_ANT_A           = (1 << 4),
-       IWM_STA_FLG_FLG_ANT_B           = (2 << 4),
-       IWM_STA_FLG_FLG_ANT_MSK         = (IWM_STA_FLG_FLG_ANT_A |
-                                          IWM_STA_FLG_FLG_ANT_B),
+       IWM_STA_FLG_DISABLE_TX          = (1 << 4),
 
        IWM_STA_FLG_PS                  = (1 << 8),
        IWM_STA_FLG_DRAIN_FLOW          = (1 << 12),
@@ -4996,7 +5507,7 @@ enum iwm_sta_key_flag {
 
 /**
  * enum iwm_sta_modify_flag - indicate to the fw what flag are being changed
- * @IWM_STA_MODIFY_KEY: this command modifies %key
+ * @IWM_STA_MODIFY_QUEUE_REMOVAL: this command removes a queue
  * @IWM_STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx
  * @IWM_STA_MODIFY_TX_RATE: unused
  * @IWM_STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid
@@ -5006,7 +5517,7 @@ enum iwm_sta_key_flag {
  * @IWM_STA_MODIFY_QUEUES: modify the queues used by this station
  */
 enum iwm_sta_modify_flag {
-       IWM_STA_MODIFY_KEY                      = (1 << 0),
+       IWM_STA_MODIFY_QUEUE_REMOVAL            = (1 << 0),
        IWM_STA_MODIFY_TID_DISABLE_TX           = (1 << 1),
        IWM_STA_MODIFY_TX_RATE                  = (1 << 2),
        IWM_STA_MODIFY_ADD_BA_TID               = (1 << 3),
@@ -5023,11 +5534,14 @@ enum iwm_sta_modify_flag {
  * @IWM_STA_SLEEP_STATE_AWAKE:
  * @IWM_STA_SLEEP_STATE_PS_POLL:
  * @IWM_STA_SLEEP_STATE_UAPSD:
+ * @IWM_STA_SLEEP_STATE_MOREDATA: set more-data bit on
+ *     (last) released frame
  */
 enum iwm_sta_sleep_flag {
        IWM_STA_SLEEP_STATE_AWAKE       = 0,
        IWM_STA_SLEEP_STATE_PS_POLL     = (1 << 0),
        IWM_STA_SLEEP_STATE_UAPSD       = (1 << 1),
+       IWM_STA_SLEEP_STATE_MOREDATA    = (1 << 2),
 };
 
 /* STA ID and color bits definitions */
@@ -5075,23 +5589,25 @@ struct iwm_mvm_keyinfo {
        uint64_t hw_tkip_mic_tx_key;
 } __packed;
 
+#define IWM_ADD_STA_STATUS_MASK                0xFF
+#define IWM_ADD_STA_BAID_VALID_MASK    0x8000
+#define IWM_ADD_STA_BAID_MASK          0x7F00
+#define IWM_ADD_STA_BAID_SHIFT         8
+
 /**
- * struct iwm_mvm_add_sta_cmd_v5 - Add/modify a station in the fw's sta table.
- * ( IWM_REPLY_ADD_STA = 0x18 )
+ * struct iwm_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table.
+ * ( REPLY_ADD_STA = 0x18 )
  * @add_modify: 1: modify existing, 0: add new station
- * @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent
- * @multicast_tx_key_id: multicast tx key id. Relevant only when multicast key
- *     sent
+ * @awake_acs:
+ * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
+ *     AMPDU for tid x. Set %IWM_STA_MODIFY_TID_DISABLE_TX to change this 
field.
  * @mac_id_n_color: the Mac context this station belongs to
  * @addr[ETHER_ADDR_LEN]: station's MAC address
  * @sta_id: index of station in uCode's station table
  * @modify_mask: IWM_STA_MODIFY_*, selects which parameters to modify vs. leave
  *     alone. 1 - modify, 0 - don't change.
- * @key: look at %iwm_mvm_keyinfo
  * @station_flags: look at %iwm_sta_flags
  * @station_flags_msk: what of %station_flags have changed
- * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
- *     AMPDU for tid x. Set %IWM_STA_MODIFY_TID_DISABLE_TX to change this 
field.
  * @add_immediate_ba_tid: tid for which to add block-ack support (Rx)
  *     Set %IWM_STA_MODIFY_ADD_BA_TID to use this field, and also set
  *     add_immediate_ba_ssn.
@@ -5115,40 +5631,9 @@ struct iwm_mvm_keyinfo {
  * ADD_STA sets up the table entry for one station, either creating a new
  * entry, or modifying a pre-existing one.
  */
-struct iwm_mvm_add_sta_cmd_v5 {
-       uint8_t add_modify;
-       uint8_t unicast_tx_key_id;
-       uint8_t multicast_tx_key_id;
-       uint8_t reserved1;
-       uint32_t mac_id_n_color;
-       uint8_t addr[ETHER_ADDR_LEN];
-       uint16_t reserved2;
-       uint8_t sta_id;
-       uint8_t modify_mask;
-       uint16_t reserved3;
-       struct iwm_mvm_keyinfo key;
-       uint32_t station_flags;
-       uint32_t station_flags_msk;
-       uint16_t tid_disable_tx;
-       uint16_t reserved4;
-       uint8_t add_immediate_ba_tid;
-       uint8_t remove_immediate_ba_tid;
-       uint16_t add_immediate_ba_ssn;
-       uint16_t sleep_tx_count;
-       uint16_t sleep_state_flags;
-       uint16_t assoc_id;
-       uint16_t beamform_flags;
-       uint32_t tfd_queue_msk;
-} __packed; /* IWM_ADD_STA_CMD_API_S_VER_5 */
-
-/**
- * struct iwm_mvm_add_sta_cmd_v6 - Add / modify a station
- * VER_6 of this command is quite similar to VER_5 except
- * exclusion of all fields related to the security key installation.
- */
-struct iwm_mvm_add_sta_cmd_v6 {
+struct iwm_mvm_add_sta_cmd_v7 {
        uint8_t add_modify;
-       uint8_t reserved1;
+       uint8_t awake_acs;
        uint16_t tid_disable_tx;
        uint32_t mac_id_n_color;
        uint8_t addr[ETHER_ADDR_LEN];   /* _STA_ID_MODIFY_INFO_API_S_VER_1 */
@@ -5166,7 +5651,7 @@ struct iwm_mvm_add_sta_cmd_v6 {
        uint16_t assoc_id;
        uint16_t beamform_flags;
        uint32_t tfd_queue_msk;
-} __packed; /* IWM_ADD_STA_CMD_API_S_VER_6 */
+} __packed; /* ADD_STA_CMD_API_S_VER_7 */
 
 /**
  * struct iwm_mvm_add_sta_key_cmd - add/modify sta key
@@ -5256,6 +5741,175 @@ struct iwm_mvm_wep_key_cmd {
        struct iwm_mvm_wep_key wep_key[0];
 } __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */
 
+/* 
+ * BT coex
+ */
+
+enum iwm_bt_coex_mode {
+       IWM_BT_COEX_DISABLE             = 0x0,
+       IWM_BT_COEX_NW                  = 0x1,
+       IWM_BT_COEX_BT                  = 0x2,
+       IWM_BT_COEX_WIFI                = 0x3,
+}; /* BT_COEX_MODES_E */
+
+enum iwm_bt_coex_enabled_modules {
+       IWM_BT_COEX_MPLUT_ENABLED       = (1 << 0),
+       IWM_BT_COEX_MPLUT_BOOST_ENABLED = (1 << 1),
+       IWM_BT_COEX_SYNC2SCO_ENABLED    = (1 << 2),
+       IWM_BT_COEX_CORUN_ENABLED       = (1 << 3),
+       IWM_BT_COEX_HIGH_BAND_RET       = (1 << 4),
+}; /* BT_COEX_MODULES_ENABLE_E_VER_1 */
+
+/**
+ * struct iwm_bt_coex_cmd - bt coex configuration command
+ * @mode: enum %iwm_bt_coex_mode
+ * @enabled_modules: enum %iwm_bt_coex_enabled_modules
+ *
+ * The structure is used for the BT_COEX command.
+ */
+struct iwm_bt_coex_cmd {
+       uint32_t mode;
+       uint32_t enabled_modules;
+} __packed; /* BT_COEX_CMD_API_S_VER_6 */
+
+
+/*
+ * Location Aware Regulatory (LAR) API - MCC updates
+ */
+
+/**
+ * struct iwm_mcc_update_cmd_v1 - Request the device to update geographic
+ * regulatory profile according to the given MCC (Mobile Country Code).
+ * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
+ * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
+ * MCC in the cmd response will be the relevant MCC in the NVM.
+ * @mcc: given mobile country code
+ * @source_id: the source from where we got the MCC, see iwm_mcc_source
+ * @reserved: reserved for alignment
+ */
+struct iwm_mcc_update_cmd_v1 {
+       uint16_t mcc;
+       uint8_t source_id;
+       uint8_t reserved;
+} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */
+
+/**
+ * struct iwm_mcc_update_cmd - Request the device to update geographic
+ * regulatory profile according to the given MCC (Mobile Country Code).
+ * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
+ * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
+ * MCC in the cmd response will be the relevant MCC in the NVM.
+ * @mcc: given mobile country code
+ * @source_id: the source from where we got the MCC, see iwm_mcc_source
+ * @reserved: reserved for alignment
+ * @key: integrity key for MCC API OEM testing
+ * @reserved2: reserved
+ */
+struct iwm_mcc_update_cmd {
+       uint16_t mcc;
+       uint8_t source_id;
+       uint8_t reserved;
+       uint32_t key;
+       uint32_t reserved2[5];
+} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */
+
+/**
+ * iwm_mcc_update_resp_v1  - response to MCC_UPDATE_CMD.
+ * Contains the new channel control profile map, if changed, and the new MCC
+ * (mobile country code).
+ * The new MCC may be different than what was requested in MCC_UPDATE_CMD.
+ * @status: see &enum iwm_mcc_update_status
+ * @mcc: the new applied MCC
+ * @cap: capabilities for all channels which matches the MCC
+ * @source_id: the MCC source, see iwm_mcc_source
+ * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
+ *             channels, depending on platform)
+ * @channels: channel control data map, DWORD for each channel. Only the first
+ *     16bits are used.
+ */
+struct iwm_mcc_update_resp_v1  {
+       uint32_t status;
+       uint16_t mcc;
+       uint8_t cap;
+       uint8_t source_id;
+       uint32_t n_channels;
+       uint32_t channels[0];
+} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */
+
+/**
+ * iwm_mcc_update_resp - response to MCC_UPDATE_CMD.
+ * Contains the new channel control profile map, if changed, and the new MCC
+ * (mobile country code).
+ * The new MCC may be different than what was requested in MCC_UPDATE_CMD.
+ * @status: see &enum iwm_mcc_update_status
+ * @mcc: the new applied MCC
+ * @cap: capabilities for all channels which matches the MCC
+ * @source_id: the MCC source, see iwm_mcc_source
+ * @time: time elapsed from the MCC test start (in 30 seconds TU)
+ * @reserved: reserved.
+ * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
+ *             channels, depending on platform)
+ * @channels: channel control data map, DWORD for each channel. Only the first
+ *     16bits are used.
+ */
+struct iwm_mcc_update_resp {
+       uint32_t status;
+       uint16_t mcc;
+       uint8_t cap;
+       uint8_t source_id;
+       uint16_t time;
+       uint16_t reserved;
+       uint32_t n_channels;
+       uint32_t channels[0];
+} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */
+
+/**
+ * struct iwm_mcc_chub_notif - chub notifies of mcc change
+ * (MCC_CHUB_UPDATE_CMD = 0xc9)
+ * The Chub (Communication Hub, CommsHUB) is a HW component that connects to
+ * the cellular and connectivity cores that gets updates of the mcc, and
+ * notifies the ucode directly of any mcc change.
+ * The ucode requests the driver to request the device to update geographic
+ * regulatory  profile according to the given MCC (Mobile Country Code).
+ * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
+ * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
+ * MCC in the cmd response will be the relevant MCC in the NVM.
+ * @mcc: given mobile country code
+ * @source_id: identity of the change originator, see iwm_mcc_source
+ * @reserved1: reserved for alignment
+ */
+struct iwm_mcc_chub_notif {
+       uint16_t mcc;
+       uint8_t source_id;
+       uint8_t reserved1;
+} __packed; /* LAR_MCC_NOTIFY_S */
+
+enum iwm_mcc_update_status {
+       IWM_MCC_RESP_NEW_CHAN_PROFILE,
+       IWM_MCC_RESP_SAME_CHAN_PROFILE,
+       IWM_MCC_RESP_INVALID,
+       IWM_MCC_RESP_NVM_DISABLED,
+       IWM_MCC_RESP_ILLEGAL,
+       IWM_MCC_RESP_LOW_PRIORITY,
+       IWM_MCC_RESP_TEST_MODE_ACTIVE,
+       IWM_MCC_RESP_TEST_MODE_NOT_ACTIVE,
+       IWM_MCC_RESP_TEST_MODE_DENIAL_OF_SERVICE,
+};
+
+enum iwm_mcc_source {
+       IWM_MCC_SOURCE_OLD_FW = 0,
+       IWM_MCC_SOURCE_ME = 1,
+       IWM_MCC_SOURCE_BIOS = 2,
+       IWM_MCC_SOURCE_3G_LTE_HOST = 3,
+       IWM_MCC_SOURCE_3G_LTE_DEVICE = 4,
+       IWM_MCC_SOURCE_WIFI = 5,
+       IWM_MCC_SOURCE_RESERVED = 6,
+       IWM_MCC_SOURCE_DEFAULT = 7,
+       IWM_MCC_SOURCE_UNINITIALIZED = 8,
+       IWM_MCC_SOURCE_MCC_API = 9,
+       IWM_MCC_SOURCE_GET_CURRENT = 0x10,
+       IWM_MCC_SOURCE_GETTING_MCC_TEST_MODE = 0x11,
+};
 
 /*
  * Some cherry-picked definitions
@@ -5263,6 +5917,48 @@ struct iwm_mvm_wep_key_cmd {
 
 #define IWM_FRAME_LIMIT        64
 
+/*
+ * From Linux commit ab02165ccec4c78162501acedeef1a768acdb811:
+ *   As the firmware is slowly running out of command IDs and grouping of
+ *   commands is desirable anyway, the firmware is extending the command
+ *   header from 4 bytes to 8 bytes to introduce a group (in place of the
+ *   former flags field, since that's always 0 on commands and thus can
+ *   be easily used to distinguish between the two).
+ *
+ * These functions retrieve specific information from the id field in
+ * the iwm_host_cmd struct which contains the command id, the group id,
+ * and the version of the command.
+*/
+static inline uint8_t
+iwm_cmd_opcode(uint32_t cmdid)
+{
+       return cmdid & 0xff;
+}
+
+static inline uint8_t
+iwm_cmd_groupid(uint32_t cmdid)
+{
+       return ((cmdid & 0Xff00) >> 8);
+}
+
+static inline uint8_t
+iwm_cmd_version(uint32_t cmdid)
+{
+       return ((cmdid & 0xff0000) >> 16);
+}
+
+static inline uint32_t
+iwm_cmd_id(uint8_t opcode, uint8_t groupid, uint8_t version)
+{
+       return opcode + (groupid << 8) + (version << 16);
+}
+
+/* make uint16_t wide id out of uint8_t group and opcode */
+#define IWM_WIDE_ID(grp, opcode) ((grp << 8) | opcode)
+
+/* due to the conversion, this group is special */
+#define IWM_ALWAYS_LONG_GROUP  1
+
 struct iwm_cmd_header {
        uint8_t code;
        uint8_t flags;
@@ -5270,6 +5966,16 @@ struct iwm_cmd_header {
        uint8_t qid;
 } __packed;
 
+struct iwm_cmd_header_wide {
+       uint8_t opcode;
+       uint8_t group_id;
+       uint8_t idx;
+       uint8_t qid;
+       uint16_t length;
+       uint8_t reserved;
+       uint8_t version;
+} __packed;
+
 enum iwm_power_scheme {
        IWM_POWER_SCHEME_CAM = 1,
        IWM_POWER_SCHEME_BPS,
@@ -5280,10 +5986,26 @@ enum iwm_power_scheme {
 #define IWM_MAX_CMD_PAYLOAD_SIZE ((4096 - 4) - sizeof(struct iwm_cmd_header))
 #define IWM_CMD_FAILED_MSK 0x40
 
+/**
+ * struct iwm_device_cmd
+ *
+ * For allocation of the command and tx queues, this establishes the overall
+ * size of the largest command we send to uCode, except for commands that
+ * aren't fully copied and use other TFD space.
+ */
 struct iwm_device_cmd {
-       struct iwm_cmd_header hdr;
-
-       uint8_t data[IWM_DEF_CMD_PAYLOAD_SIZE];
+       union {
+               struct {
+                       struct iwm_cmd_header hdr;
+                       uint8_t data[IWM_DEF_CMD_PAYLOAD_SIZE];
+               };
+               struct {
+                       struct iwm_cmd_header_wide hdr_wide;
+                       uint8_t data_wide[IWM_DEF_CMD_PAYLOAD_SIZE -
+                                       sizeof(struct iwm_cmd_header_wide) +
+                                       sizeof(struct iwm_cmd_header)];
+               };
+       };
 } __packed;
 
 struct iwm_rx_packet {
Index: if_iwmvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwmvar.h,v
retrieving revision 1.16
diff -u -p -r1.16 if_iwmvar.h
--- if_iwmvar.h 25 Jan 2016 11:27:11 -0000      1.16
+++ if_iwmvar.h 18 May 2016 08:55:13 -0000
@@ -137,7 +137,7 @@ struct iwm_tx_radiotap_header {
         (1 << IEEE80211_RADIOTAP_CHANNEL) |                            \
         (1 << IEEE80211_RADIOTAP_HWQUEUE))
 
-#define IWM_UCODE_SECT_MAX 6
+#define IWM_UCODE_SECT_MAX 16
 #define IWM_FWDMASEGSZ (192*1024)
 /* sanity check value */
 #define IWM_FWMAXSIZE (2*1024*1024)
@@ -152,9 +152,10 @@ struct iwm_tx_radiotap_header {
 #define IWM_FW_STATUS_DONE             2
 
 enum iwm_ucode_type {
-       IWM_UCODE_TYPE_INIT,
        IWM_UCODE_TYPE_REGULAR,
+       IWM_UCODE_TYPE_INIT,
        IWM_UCODE_TYPE_WOW,
+       IWM_UCODE_TYPE_REGULAR_USNIFFER,
        IWM_UCODE_TYPE_MAX
 };
 
@@ -217,7 +218,7 @@ struct iwm_host_cmd {
        uint32_t flags;
        uint16_t len[IWM_MAX_CMD_TBS_PER_TFD];
        uint8_t dataflags[IWM_MAX_CMD_TBS_PER_TFD];
-       uint8_t id;
+       uint32_t id;
 };
 
 /*
@@ -304,7 +305,8 @@ struct iwm_ucode_status {
 
 #define IWM_CMD_RESP_MAX PAGE_SIZE
 
-#define IWM_OTP_LOW_IMAGE_SIZE 2048
+/* lower blocks contain EEPROM image and calibration data */
+#define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_7000     16384
 
 #define IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 1000
 #define IWM_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400
@@ -320,7 +322,7 @@ enum iwm_hcmd_dataflag {
        IWM_HCMD_DFL_DUP        = (1 << 1),
 };
 
-#define IWM_NUM_PAPD_CH_GROUPS 4
+#define IWM_NUM_PAPD_CH_GROUPS 9
 #define IWM_NUM_TXP_CH_GROUPS  9
 
 struct iwm_phy_db_entry {
@@ -413,10 +415,14 @@ struct iwm_softc {
 
        struct iwm_ucode_status sc_uc;
        enum iwm_ucode_type sc_uc_current;
-       int sc_fwver;
+       char sc_fwver[32];
 
        int sc_capaflags;
        int sc_capa_max_probe_len;
+       int sc_capa_n_scan_channels;
+       uint32_t sc_ucode_api;
+       uint8_t sc_enabled_capa[howmany(IWM_NUM_UCODE_TLV_CAPA, NBBY)];
+       char sc_fw_mcc[3];
 
        int sc_intmask;
        int sc_flags;
@@ -448,10 +454,7 @@ struct iwm_softc {
        int sc_tx_timer;
        int sc_rx_ba_sessions;
 
-       struct iwm_scan_cmd *sc_scan_cmd;
-       size_t sc_scan_cmd_len;
        int sc_scan_last_antenna;
-       int sc_scanband;
 
        int sc_fixed_ridx;
 
@@ -511,6 +514,7 @@ struct iwm_node {
        struct ieee80211_amrr_node in_amn;
 };
 #define IWM_STATION_ID 0
+#define IWM_AUX_STA_ID 1
 
 #define IWM_ICT_SIZE           4096
 #define IWM_ICT_COUNT          (IWM_ICT_SIZE / sizeof (uint32_t))

Reply via email to