On Wed, Feb 22, 2023 at 03:31:28PM +0100, Stefan Sperling wrote:
> Below is my work-in-progress diff to update iwx(4) to latest firmware.
> Every system tracking -current should already have the new -77 firmware 
> images.
> 
> The new images contain security fixes of (to me) unknown severity.
> Unfortunately there have been quite a number of firmware API changes since
> our last upgrade and it took me quite some time to get all the required new
> bits in place and arrive at an operational state.
> 
> While testing please enable additional debug output with:
>   ifconfig iwx0 debug
> To activate it at boot time: echo debug >> /etc/hostname.iwx0
> 
> There are some known issue with occasional firmware errors.
> My devices eventually manage to connect and work regardless. If you see a
> firmware error in dmesg please include the extra information shown in dmesg
> after enabling the debugging mode as above. This information is hidden by
> default and the driver will only print "fatal firmware error" to dmesg
> without more context, but the extra context is needed for debugging.
> 
> If you hit an error which looks like this:
> 
>    iwx0: firmware parse error 22, section type 19
>    iwx0: failed to load init firmware
> 
> Then you will need to increase this constant in if_iwxvar.h until you
> get past the error:
> 
> #define IWX_UCODE_SECT_MAX 56

This new version of the patch fixes two issues:

IWX_UCODE_SECT_MAX was bumped to 57 to accommodate some AX211 devices.

Fixed iwx0: 0x2000011A | ADVANCED_SYSASSERT
with helpful hints from Johannes Berg at Linux/Intel.
This was an annoying issue since it made connecting to an access point
fail quite often. Root cause were changes in the mac context command,
where the firmware now expects beacon-related info to be initialized
early, already before we attempt to associate.

The only remaining known issue is:
iwx0: 0x20002806 | ADVANCED_SYSASSERT, as seen by jmc@
This seems related to background scans. I could not yet reproduce the error,
roaming seems to work as expected for me, but this might depend on the RF
environment. Since roaming is evidently not completely broken by this I will
not treat this as a blocker for moving development into the tree.

Patch test reports are still welcome but please be fast if there is an issue
you are seeing that I am not aware of. I will start splitting/committing this
soon.

diff refs/heads/master refs/heads/iwxfw
commit - 50b5a752f56b56e236653f0da2264f2ec83f9fde
commit + 0e6ef712fc262423d483ba4cdeab9f957d41e71e
blob - a91a0d85b3877e13d7798e7f90f21fd601eac1e5
blob + b4f90c6d74e76f1b5a4658cde4af19f2fe76a42a
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -235,7 +235,6 @@ int iwx_is_mimo_mcs(int);
 uint8_t        iwx_lookup_cmd_ver(struct iwx_softc *, uint8_t, uint8_t);
 uint8_t        iwx_lookup_notif_ver(struct iwx_softc *, uint8_t, uint8_t);
 int    iwx_is_mimo_ht_plcp(uint8_t);
-int    iwx_is_mimo_mcs(int);
 int    iwx_store_cscheme(struct iwx_softc *, uint8_t *, size_t);
 int    iwx_alloc_fw_monitor_block(struct iwx_softc *, uint8_t, uint8_t);
 int    iwx_alloc_fw_monitor(struct iwx_softc *, uint8_t);
@@ -380,10 +379,10 @@ int       iwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *, 
struct
            struct iwx_rx_data *);
 int    iwx_binding_cmd(struct iwx_softc *, struct iwx_node *, uint32_t);
 uint8_t        iwx_get_vht_ctrl_pos(struct ieee80211com *, struct 
ieee80211_channel *);
-int    iwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *, struct iwx_phy_ctxt *, 
uint8_t,
-           uint8_t, uint32_t, uint8_t, uint8_t);
-int    iwx_phy_ctxt_cmd_v3(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
-           uint8_t, uint32_t, uint8_t, uint8_t);
+int    iwx_phy_ctxt_cmd_uhb_v3_v4(struct iwx_softc *, struct iwx_phy_ctxt *,
+           uint8_t, uint8_t, uint32_t, uint8_t, uint8_t, int);
+int    iwx_phy_ctxt_cmd_v3_v4(struct iwx_softc *, struct iwx_phy_ctxt *,
+           uint8_t, uint8_t, uint32_t, uint8_t, uint8_t, int);
 int    iwx_phy_ctxt_cmd(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
            uint8_t, uint32_t, uint32_t, uint8_t, uint8_t);
 int    iwx_send_cmd(struct iwx_softc *, struct iwx_host_cmd *);
@@ -395,6 +394,8 @@ const struct iwx_rate *iwx_tx_fill_cmd(struct iwx_soft
            const void *, uint32_t *);
 void   iwx_free_resp(struct iwx_softc *, struct iwx_host_cmd *);
 void   iwx_cmd_done(struct iwx_softc *, int, int, int);
+uint32_t iwx_fw_rateidx_ofdm(uint8_t);
+uint32_t iwx_fw_rateidx_cck(uint8_t);
 const struct iwx_rate *iwx_tx_fill_cmd(struct iwx_softc *, struct iwx_node *,
            struct ieee80211_frame *, uint16_t *, uint32_t *);
 void   iwx_tx_update_byte_tbl(struct iwx_softc *, struct iwx_tx_ring *, int,
@@ -446,11 +447,16 @@ int       iwx_rs_rval2idx(uint8_t);
 int    iwx_umac_scan_abort(struct iwx_softc *);
 int    iwx_scan_abort(struct iwx_softc *);
 int    iwx_enable_mgmt_queue(struct iwx_softc *);
+int    iwx_disable_mgmt_queue(struct iwx_softc *);
 int    iwx_rs_rval2idx(uint8_t);
 uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ieee80211_node *, int);
 uint16_t iwx_rs_vht_rates(struct iwx_softc *, struct ieee80211_node *, int);
+int    iwx_rs_init_v3(struct iwx_softc *, struct iwx_node *);
+int    iwx_rs_init_v4(struct iwx_softc *, struct iwx_node *);
 int    iwx_rs_init(struct iwx_softc *, struct iwx_node *);
 int    iwx_enable_data_tx_queues(struct iwx_softc *);
+int    iwx_phy_send_rlc(struct iwx_softc *, struct iwx_phy_ctxt *,
+           uint8_t, uint8_t);
 int    iwx_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *,
            struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t,
            uint8_t);
@@ -551,16 +557,21 @@ iwx_is_mimo_ht_plcp(uint8_t ht_plcp)
 int
 iwx_is_mimo_ht_plcp(uint8_t ht_plcp)
 {
-       return (ht_plcp != IWX_RATE_HT_SISO_MCS_INV_PLCP &&
-           (ht_plcp & IWX_RATE_HT_MCS_NSS_MSK));
-}
+       switch (ht_plcp) {
+       case IWX_RATE_HT_MIMO2_MCS_8_PLCP:
+       case IWX_RATE_HT_MIMO2_MCS_9_PLCP:
+       case IWX_RATE_HT_MIMO2_MCS_10_PLCP:
+       case IWX_RATE_HT_MIMO2_MCS_11_PLCP:
+       case IWX_RATE_HT_MIMO2_MCS_12_PLCP:
+       case IWX_RATE_HT_MIMO2_MCS_13_PLCP:
+       case IWX_RATE_HT_MIMO2_MCS_14_PLCP:
+       case IWX_RATE_HT_MIMO2_MCS_15_PLCP:
+               return 1;
+       default:
+               break;
+       }
 
-int
-iwx_is_mimo_mcs(int mcs)
-{
-       int ridx = iwx_mcs2ridx[mcs];
-       return iwx_is_mimo_ht_plcp(iwx_rates[ridx].ht_plcp);
-       
+       return 0;
 }
 
 int
@@ -1537,6 +1548,7 @@ iwx_read_firmware(struct iwx_softc *sc)
                case IWX_UCODE_TLV_FW_FSEQ_VERSION:
                case IWX_UCODE_TLV_PHY_INTEGRATION_VERSION:
                case IWX_UCODE_TLV_FW_NUM_STATIONS:
+               case IWX_UCODE_TLV_FW_NUM_BEACONS:
                        break;
 
                /* undocumented TLVs found in iwx-cc-a0-46 image */
@@ -1556,12 +1568,23 @@ iwx_read_firmware(struct iwx_softc *sc)
                case IWX_UCODE_TLV_TYPE_REGIONS:
                case IWX_UCODE_TLV_TYPE_TRIGGERS:
                case IWX_UCODE_TLV_TYPE_CONF_SET:
+               case IWX_UCODE_TLV_SEC_TABLE_ADDR:
+               case IWX_UCODE_TLV_D3_KEK_KCK_ADDR:
+               case IWX_UCODE_TLV_CURRENT_PC:
                        break;
 
                /* undocumented TLV found in iwx-cc-a0-67 image */
                case 0x100000b:
                        break;
 
+               /* undocumented TLV found in iwx-ty-a0-gf-a0-73 image */
+               case 0x101:
+                       break;
+
+               /* undocumented TLV found in iwx-ty-a0-gf-a0-77 image */
+               case 0x100000c:
+                       break;
+
                default:
                        err = EINVAL;
                        goto parse_out;
@@ -2793,46 +2816,65 @@ iwx_enable_txq(struct iwx_softc *sc, int sta_id, int q
 iwx_enable_txq(struct iwx_softc *sc, int sta_id, int qid, int tid,
     int num_slots)
 {
-       struct iwx_tx_queue_cfg_cmd cmd;
        struct iwx_rx_packet *pkt;
        struct iwx_tx_queue_cfg_rsp *resp;
+       struct iwx_tx_queue_cfg_cmd cmd_v0;
+       struct iwx_scd_queue_cfg_cmd cmd_v3;
        struct iwx_host_cmd hcmd = {
-               .id = IWX_SCD_QUEUE_CFG,
                .flags = IWX_CMD_WANT_RESP,
                .resp_pkt_len = sizeof(*pkt) + sizeof(*resp),
        };
        struct iwx_tx_ring *ring = &sc->txq[qid];
-       int err, fwqid;
+       int err, fwqid, cmd_ver;
        uint32_t wr_idx;
        size_t resp_len;
 
        iwx_reset_tx_ring(sc, ring);
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.sta_id = sta_id;
-       cmd.tid = tid;
-       cmd.flags = htole16(IWX_TX_QUEUE_CFG_ENABLE_QUEUE);
-       cmd.cb_size = htole32(IWX_TFD_QUEUE_CB_SIZE(num_slots));
-       cmd.byte_cnt_addr = htole64(ring->bc_tbl.paddr);
-       cmd.tfdq_addr = htole64(ring->desc_dma.paddr);
+       cmd_ver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+           IWX_SCD_QUEUE_CONFIG_CMD);
+       if (cmd_ver == 0 || cmd_ver == IWX_FW_CMD_VER_UNKNOWN) {
+               memset(&cmd_v0, 0, sizeof(cmd_v0));
+               cmd_v0.sta_id = sta_id;
+               cmd_v0.tid = tid;
+               cmd_v0.flags = htole16(IWX_TX_QUEUE_CFG_ENABLE_QUEUE);
+               cmd_v0.cb_size = htole32(IWX_TFD_QUEUE_CB_SIZE(num_slots));
+               cmd_v0.byte_cnt_addr = htole64(ring->bc_tbl.paddr);
+               cmd_v0.tfdq_addr = htole64(ring->desc_dma.paddr);
+               hcmd.id = IWX_SCD_QUEUE_CFG;
+               hcmd.data[0] = &cmd_v0;
+               hcmd.len[0] = sizeof(cmd_v0);
+       } else if (cmd_ver == 3) {
+               memset(&cmd_v3, 0, sizeof(cmd_v3));
+               cmd_v3.operation = htole32(IWX_SCD_QUEUE_ADD);
+               cmd_v3.u.add.tfdq_dram_addr = htole64(ring->desc_dma.paddr);
+               cmd_v3.u.add.bc_dram_addr = htole64(ring->bc_tbl.paddr);
+               cmd_v3.u.add.cb_size = 
htole32(IWX_TFD_QUEUE_CB_SIZE(num_slots));
+               cmd_v3.u.add.flags = htole32(0);
+               cmd_v3.u.add.sta_mask = htole32(1 << sta_id);
+               cmd_v3.u.add.tid = tid;
+               hcmd.id = IWX_WIDE_ID(IWX_DATA_PATH_GROUP,
+                   IWX_SCD_QUEUE_CONFIG_CMD);
+               hcmd.data[0] = &cmd_v3;
+               hcmd.len[0] = sizeof(cmd_v3);
+       } else {
+               printf("%s: unsupported SCD_QUEUE_CFG command version %d\n",
+                   DEVNAME(sc), cmd_ver);
+               return ENOTSUP;
+       }
 
-       hcmd.data[0] = &cmd;
-       hcmd.len[0] = sizeof(cmd);
-
        err = iwx_send_cmd(sc, &hcmd);
        if (err)
                return err;
 
        pkt = hcmd.resp_pkt;
        if (!pkt || (pkt->hdr.flags & IWX_CMD_FAILED_MSK)) {
-               DPRINTF(("SCD_QUEUE_CFG command failed\n"));
                err = EIO;
                goto out;
        }
 
        resp_len = iwx_rx_packet_payload_len(pkt);
        if (resp_len != sizeof(*resp)) {
-               DPRINTF(("SCD_QUEUE_CFG returned %zu bytes, expected %zu 
bytes\n", resp_len, sizeof(*resp)));
                err = EIO;
                goto out;
        }
@@ -2843,14 +2885,11 @@ iwx_enable_txq(struct iwx_softc *sc, int sta_id, int q
 
        /* Unlike iwlwifi, we do not support dynamic queue ID assignment. */
        if (fwqid != qid) {
-               DPRINTF(("requested qid %d but %d was assigned\n", qid, fwqid));
                err = EIO;
                goto out;
        }
 
        if (wr_idx != ring->cur_hw) {
-               DPRINTF(("fw write index is %d but ring is %d\n",
-                   wr_idx, ring->cur_hw));
                err = EIO;
                goto out;
        }
@@ -2865,35 +2904,51 @@ iwx_disable_txq(struct iwx_softc *sc, int sta_id, int 
 int
 iwx_disable_txq(struct iwx_softc *sc, int sta_id, int qid, uint8_t tid)
 {
-       struct iwx_tx_queue_cfg_cmd cmd;
        struct iwx_rx_packet *pkt;
        struct iwx_tx_queue_cfg_rsp *resp;
+       struct iwx_tx_queue_cfg_cmd cmd_v0;
+       struct iwx_scd_queue_cfg_cmd cmd_v3;
        struct iwx_host_cmd hcmd = {
-               .id = IWX_SCD_QUEUE_CFG,
                .flags = IWX_CMD_WANT_RESP,
                .resp_pkt_len = sizeof(*pkt) + sizeof(*resp),
        };
        struct iwx_tx_ring *ring = &sc->txq[qid];
-       int err;
+       int err, cmd_ver;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.sta_id = sta_id;
-       cmd.tid = tid;
-       cmd.flags = htole16(0); /* clear "queue enabled" flag */
-       cmd.cb_size = htole32(0);
-       cmd.byte_cnt_addr = htole64(0);
-       cmd.tfdq_addr = htole64(0);
+       cmd_ver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+           IWX_SCD_QUEUE_CONFIG_CMD);
+       if (cmd_ver == 0 || cmd_ver == IWX_FW_CMD_VER_UNKNOWN) {
+               memset(&cmd_v0, 0, sizeof(cmd_v0));
+               cmd_v0.sta_id = sta_id;
+               cmd_v0.tid = tid;
+               cmd_v0.flags = htole16(0); /* clear "queue enabled" flag */
+               cmd_v0.cb_size = htole32(0);
+               cmd_v0.byte_cnt_addr = htole64(0);
+               cmd_v0.tfdq_addr = htole64(0);
+               hcmd.id = IWX_SCD_QUEUE_CFG,
+               hcmd.data[0] = &cmd_v0;
+               hcmd.len[0] = sizeof(cmd_v0);
+       } else if (cmd_ver == 3) {
+               memset(&cmd_v3, 0, sizeof(cmd_v3));
+               cmd_v3.operation = htole32(IWX_SCD_QUEUE_REMOVE);
+               cmd_v3.u.remove.sta_mask = htole32(1 << sta_id);
+               cmd_v3.u.remove.tid = tid;
+               hcmd.id = IWX_WIDE_ID(IWX_DATA_PATH_GROUP,
+                   IWX_SCD_QUEUE_CONFIG_CMD);
+               hcmd.data[0] = &cmd_v3;
+               hcmd.len[0] = sizeof(cmd_v3);
+       } else {
+               printf("%s: unsupported SCD_QUEUE_CFG command version %d\n",
+                   DEVNAME(sc), cmd_ver);
+               return ENOTSUP;
+       }
 
-       hcmd.data[0] = &cmd;
-       hcmd.len[0] = sizeof(cmd);
-
        err = iwx_send_cmd(sc, &hcmd);
        if (err)
                return err;
 
        pkt = hcmd.resp_pkt;
        if (!pkt || (pkt->hdr.flags & IWX_CMD_FAILED_MSK)) {
-               DPRINTF(("SCD_QUEUE_CFG command failed\n"));
                err = EIO;
                goto out;
        }
@@ -2908,19 +2963,29 @@ iwx_post_alive(struct iwx_softc *sc)
 void
 iwx_post_alive(struct iwx_softc *sc)
 {
+       int txcmd_ver;
+
        iwx_ict_reset(sc);
+
+       txcmd_ver = iwx_lookup_notif_ver(sc, IWX_LONG_GROUP, IWX_TX_CMD) ;
+       if (txcmd_ver != IWX_FW_CMD_VER_UNKNOWN && txcmd_ver > 6)
+               sc->sc_rate_n_flags_version = 2;
+       else
+               sc->sc_rate_n_flags_version = 1;
+
+       txcmd_ver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_TX_CMD);
 }
 
 int
 iwx_schedule_session_protection(struct iwx_softc *sc, struct iwx_node *in,
-    uint32_t duration)
+    uint32_t duration_tu)
 {
        struct iwx_session_prot_cmd cmd = {
                .id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id,
                    in->in_color)),
                .action = htole32(IWX_FW_CTXT_ACTION_ADD),
                .conf_id = htole32(IWX_SESSION_PROTECT_CONF_ASSOC),
-               .duration_tu = htole32(duration * IEEE80211_DUR_TU),
+               .duration_tu = htole32(duration_tu),
        };
        uint32_t cmd_id;
        int err;
@@ -3285,25 +3350,84 @@ void
 
 #define IWX_MAX_RX_BA_SESSIONS 16
 
-void
-iwx_sta_rx_agg(struct iwx_softc *sc, struct ieee80211_node *ni, uint8_t tid,
-    uint16_t ssn, uint16_t winsize, int timeout_val, int start)
+struct iwx_rxba_data *
+iwx_find_rxba_data(struct iwx_softc *sc, uint8_t tid)
 {
-       struct ieee80211com *ic = &sc->sc_ic;
+       int i;
+
+       for (i = 0; i < nitems(sc->sc_rxba_data); i++) {
+               if (sc->sc_rxba_data[i].baid ==
+                   IWX_RX_REORDER_DATA_INVALID_BAID)
+                       continue;
+               if (sc->sc_rxba_data[i].tid == tid)
+                       return &sc->sc_rxba_data[i];
+       }
+
+       return NULL;
+}
+
+int
+iwx_sta_rx_agg_baid_cfg_cmd(struct iwx_softc *sc, struct ieee80211_node *ni,
+    uint8_t tid, uint16_t ssn, uint16_t winsize, int timeout_val, int start,
+    uint8_t *baid)
+{
+       struct iwx_rx_baid_cfg_cmd cmd;
+       uint32_t new_baid = 0;
+       int err;
+
+       splassert(IPL_NET);
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       if (start) {
+               cmd.action = IWX_RX_BAID_ACTION_ADD;
+               cmd.alloc.sta_id_mask = htole32(1 << IWX_STATION_ID);
+               cmd.alloc.tid = tid;
+               cmd.alloc.ssn = htole16(ssn);
+               cmd.alloc.win_size = htole16(winsize);
+       } else {
+               struct iwx_rxba_data *rxba;
+
+               rxba = iwx_find_rxba_data(sc, tid);
+               if (rxba == NULL)
+                       return ENOENT;
+               *baid = rxba->baid;
+
+               cmd.action = IWX_RX_BAID_ACTION_REMOVE;
+               if (iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+                   IWX_RX_BAID_ALLOCATION_CONFIG_CMD) == 1) {
+                       cmd.remove_v1.baid = rxba->baid;
+               } else {
+                       cmd.remove.sta_id_mask = htole32(1 << IWX_STATION_ID);
+                       cmd.remove.tid = tid;
+               }
+       }
+
+       err = iwx_send_cmd_pdu_status(sc, IWX_WIDE_ID(IWX_DATA_PATH_GROUP,
+           IWX_RX_BAID_ALLOCATION_CONFIG_CMD), sizeof(cmd), &cmd, &new_baid);
+       if (err)
+               return err;
+
+       if (start) {
+               if (new_baid >= nitems(sc->sc_rxba_data))
+                       return ERANGE;
+               *baid = new_baid;
+       }
+
+       return 0;
+}
+
+int
+iwx_sta_rx_agg_sta_cmd(struct iwx_softc *sc, struct ieee80211_node *ni,
+    uint8_t tid, uint16_t ssn, uint16_t winsize, int timeout_val, int start,
+    uint8_t *baid)
+{
        struct iwx_add_sta_cmd cmd;
        struct iwx_node *in = (void *)ni;
-       int err, s;
+       int err;
        uint32_t status;
-       struct iwx_rxba_data *rxba = NULL;
-       uint8_t baid = 0;
- 
-       s = splnet();
 
-       if (start && sc->sc_rx_ba_sessions >= IWX_MAX_RX_BA_SESSIONS) {
-               ieee80211_addba_req_refuse(ic, ni, tid);
-               splx(s);
-               return;
-       }
+       splassert(IPL_NET);
 
        memset(&cmd, 0, sizeof(cmd));
 
@@ -3317,6 +3441,13 @@ iwx_sta_rx_agg(struct iwx_softc *sc, struct ieee80211_
                cmd.add_immediate_ba_ssn = htole16(ssn);
                cmd.rx_ba_window = htole16(winsize);
        } else {
+               struct iwx_rxba_data *rxba;
+
+               rxba = iwx_find_rxba_data(sc, tid);
+               if (rxba == NULL)
+                       return ENOENT;
+               *baid = rxba->baid;
+
                cmd.remove_immediate_ba_tid = (uint8_t)tid;
        }
        cmd.modify_mask = start ? IWX_STA_MODIFY_ADD_BA_TID :
@@ -3325,30 +3456,60 @@ iwx_sta_rx_agg(struct iwx_softc *sc, struct ieee80211_
        status = IWX_ADD_STA_SUCCESS;
        err = iwx_send_cmd_pdu_status(sc, IWX_ADD_STA, sizeof(cmd), &cmd,
            &status);
+       if (err)
+               return err;
 
-       if (err || (status & IWX_ADD_STA_STATUS_MASK) != IWX_ADD_STA_SUCCESS) {
-               if (start)
-                       ieee80211_addba_req_refuse(ic, ni, tid);
-               splx(s);
-               return;
-       }
+       if ((status & IWX_ADD_STA_STATUS_MASK) != IWX_ADD_STA_SUCCESS)
+               return EIO;
 
-       /* Deaggregation is done in hardware. */
+       if (!(status & IWX_ADD_STA_BAID_VALID_MASK))
+               return EINVAL;
+
        if (start) {
-               if (!(status & IWX_ADD_STA_BAID_VALID_MASK)) {
-                       ieee80211_addba_req_refuse(ic, ni, tid);
-                       splx(s);
-                       return;
-               }
-               baid = (status & IWX_ADD_STA_BAID_MASK) >>
+               *baid = (status & IWX_ADD_STA_BAID_MASK) >>
                    IWX_ADD_STA_BAID_SHIFT;
-               if (baid == IWX_RX_REORDER_DATA_INVALID_BAID ||
-                   baid >= nitems(sc->sc_rxba_data)) {
-                       ieee80211_addba_req_refuse(ic, ni, tid);
-                       splx(s);
-                       return;
-               }
-               rxba = &sc->sc_rxba_data[baid];
+               if (*baid == IWX_RX_REORDER_DATA_INVALID_BAID ||
+                   *baid >= nitems(sc->sc_rxba_data))
+                       return ERANGE;
+       }
+
+       return 0;
+}
+
+void
+iwx_sta_rx_agg(struct iwx_softc *sc, struct ieee80211_node *ni, uint8_t tid,
+    uint16_t ssn, uint16_t winsize, int timeout_val, int start)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       int err, s;
+       struct iwx_rxba_data *rxba = NULL;
+       uint8_t baid = 0;
+
+       s = splnet();
+
+       if (start && sc->sc_rx_ba_sessions >= IWX_MAX_RX_BA_SESSIONS) {
+               ieee80211_addba_req_refuse(ic, ni, tid);
+               splx(s);
+               return;
+       }
+
+       if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_BAID_ML_SUPPORT)) {
+               err = iwx_sta_rx_agg_baid_cfg_cmd(sc, ni, tid, ssn, winsize,
+                   timeout_val, start, &baid);
+       } else {
+               err = iwx_sta_rx_agg_sta_cmd(sc, ni, tid, ssn, winsize,
+                   timeout_val, start, &baid);
+       }
+       if (err) {
+               ieee80211_addba_req_refuse(ic, ni, tid);
+               splx(s);
+               return;
+       }
+
+       rxba = &sc->sc_rxba_data[baid];
+
+       /* Deaggregation is done in hardware. */
+       if (start) {
                if (rxba->baid != IWX_RX_REORDER_DATA_INVALID_BAID) {
                        ieee80211_addba_req_refuse(ic, ni, tid);
                        splx(s);
@@ -3369,19 +3530,8 @@ iwx_sta_rx_agg(struct iwx_softc *sc, struct ieee80211_
                        ba = &ni->ni_rx_ba[tid];
                        ba->ba_timeout_val = 0;
                }
-       } else {
-               int i;
-               for (i = 0; i < nitems(sc->sc_rxba_data); i++) {
-                       rxba = &sc->sc_rxba_data[i];
-                       if (rxba->baid ==
-                           IWX_RX_REORDER_DATA_INVALID_BAID)
-                               continue;
-                       if (rxba->tid != tid)
-                               continue;
-                       iwx_clear_reorder_buffer(sc, rxba);
-                       break;
-               }
-       }
+       } else
+               iwx_clear_reorder_buffer(sc, rxba);
 
        if (start) {
                sc->sc_rx_ba_sessions++;
@@ -4524,6 +4674,8 @@ iwx_rx_frame(struct iwx_softc *sc, struct mbuf *m, int
        if (sc->sc_drvbpf != NULL) {
                struct iwx_rx_radiotap_header *tap = &sc->sc_rxtap;
                uint16_t chan_flags;
+               int have_legacy_rate = 1;
+               uint8_t mcs, rate;
 
                tap->wr_flags = 0;
                if (is_shortpre)
@@ -4542,14 +4694,36 @@ iwx_rx_frame(struct iwx_softc *sc, struct mbuf *m, int
                tap->wr_dbm_antsignal = (int8_t)rxi->rxi_rssi;
                tap->wr_dbm_antnoise = (int8_t)sc->sc_noise;
                tap->wr_tsft = device_timestamp;
-               if (rate_n_flags & IWX_RATE_MCS_HT_MSK) {
-                       uint8_t mcs = (rate_n_flags &
-                           (IWX_RATE_HT_MCS_RATE_CODE_MSK |
-                           IWX_RATE_HT_MCS_NSS_MSK));
+               if (sc->sc_rate_n_flags_version >= 2) {
+                       uint32_t mod_type = (rate_n_flags &
+                           IWX_RATE_MCS_MOD_TYPE_MSK);
+                       const struct ieee80211_rateset *rs = NULL;
+                       uint32_t ridx;
+                       have_legacy_rate = (mod_type == IWX_RATE_MCS_CCK_MSK ||
+                           mod_type == IWX_RATE_MCS_LEGACY_OFDM_MSK);
+                       mcs = (rate_n_flags & IWX_RATE_HT_MCS_CODE_MSK);
+                       ridx = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK);
+                       if (mod_type == IWX_RATE_MCS_CCK_MSK)
+                               rs = &ieee80211_std_rateset_11b;
+                       else if (mod_type == IWX_RATE_MCS_LEGACY_OFDM_MSK)
+                               rs = &ieee80211_std_rateset_11a;
+                       if (rs && ridx < rs->rs_nrates) {
+                               rate = (rs->rs_rates[ridx] &
+                                   IEEE80211_RATE_VAL);
+                       } else
+                               rate = 0;
+               } else {
+                       have_legacy_rate = ((rate_n_flags &
+                           (IWX_RATE_MCS_HT_MSK_V1 |
+                           IWX_RATE_MCS_VHT_MSK_V1)) == 0);
+                       mcs = (rate_n_flags &
+                           (IWX_RATE_HT_MCS_RATE_CODE_MSK_V1 |
+                           IWX_RATE_HT_MCS_NSS_MSK_V1));
+                       rate = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK_V1);
+               }
+               if (!have_legacy_rate) {
                        tap->wr_rate = (0x80 | mcs);
                } else {
-                       uint8_t rate = (rate_n_flags &
-                           IWX_RATE_LEGACY_RATE_MSK);
                        switch (rate) {
                        /* CCK rates. */
                        case  10: tap->wr_rate =   2; break;
@@ -5378,7 +5552,7 @@ iwx_get_vht_ctrl_pos(struct ieee80211com *ic, struct i
 iwx_get_vht_ctrl_pos(struct ieee80211com *ic, struct ieee80211_channel *chan)
 {
        int center_idx = ic->ic_bss->ni_vht_chan_center_freq_idx0;
-       int primary_idx = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
+       int primary_idx = ic->ic_bss->ni_primary_chan;
        /*
         * The FW is expected to check the control channel position only
         * when in HT/VHT and the channel width is not 20MHz. Return
@@ -5407,9 +5581,9 @@ iwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *sc, struct i
 }
 
 int
-iwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt,
+iwx_phy_ctxt_cmd_uhb_v3_v4(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt,
     uint8_t chains_static, uint8_t chains_dynamic, uint32_t action, uint8_t 
sco,
-    uint8_t vht_chan_width)
+    uint8_t vht_chan_width, int cmdver)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct iwx_phy_context_cmd_uhb cmd;
@@ -5451,21 +5625,25 @@ iwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *sc, struct i
                cmd.ci.ctrl_pos = IWX_PHY_VHT_CTRL_POS_1_BELOW;
        }
 
-       idle_cnt = chains_static;
-       active_cnt = chains_dynamic;
-       cmd.rxchain_info = htole32(iwx_fw_valid_rx_ant(sc) <<
-           IWX_PHY_RX_CHAIN_VALID_POS);
-       cmd.rxchain_info |= htole32(idle_cnt << IWX_PHY_RX_CHAIN_CNT_POS);
-       cmd.rxchain_info |= htole32(active_cnt <<
-           IWX_PHY_RX_CHAIN_MIMO_CNT_POS);
+       if (cmdver < 4 && iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+           IWX_RLC_CONFIG_CMD) != 2) {
+               idle_cnt = chains_static;
+               active_cnt = chains_dynamic;
+               cmd.rxchain_info = htole32(iwx_fw_valid_rx_ant(sc) <<
+                   IWX_PHY_RX_CHAIN_VALID_POS);
+               cmd.rxchain_info |= htole32(idle_cnt <<
+                   IWX_PHY_RX_CHAIN_CNT_POS);
+               cmd.rxchain_info |= htole32(active_cnt <<
+                   IWX_PHY_RX_CHAIN_MIMO_CNT_POS);
+       }
 
        return iwx_send_cmd_pdu(sc, IWX_PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd);
 }
 
 int
-iwx_phy_ctxt_cmd_v3(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt,
+iwx_phy_ctxt_cmd_v3_v4(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt,
     uint8_t chains_static, uint8_t chains_dynamic, uint32_t action, uint8_t 
sco,
-    uint8_t vht_chan_width)
+    uint8_t vht_chan_width, int cmdver)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct iwx_phy_context_cmd cmd;
@@ -5507,13 +5685,17 @@ iwx_phy_ctxt_cmd_v3(struct iwx_softc *sc, struct iwx_p
                cmd.ci.ctrl_pos = IWX_PHY_VHT_CTRL_POS_1_BELOW;
        }
 
-       idle_cnt = chains_static;
-       active_cnt = chains_dynamic;
-       cmd.rxchain_info = htole32(iwx_fw_valid_rx_ant(sc) <<
-           IWX_PHY_RX_CHAIN_VALID_POS);
-       cmd.rxchain_info |= htole32(idle_cnt << IWX_PHY_RX_CHAIN_CNT_POS);
-       cmd.rxchain_info |= htole32(active_cnt <<
-           IWX_PHY_RX_CHAIN_MIMO_CNT_POS);
+       if (cmdver < 4 && iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+           IWX_RLC_CONFIG_CMD) != 2) {
+               idle_cnt = chains_static;
+               active_cnt = chains_dynamic;
+               cmd.rxchain_info = htole32(iwx_fw_valid_rx_ant(sc) <<
+                   IWX_PHY_RX_CHAIN_VALID_POS);
+               cmd.rxchain_info |= htole32(idle_cnt <<
+                   IWX_PHY_RX_CHAIN_CNT_POS);
+               cmd.rxchain_info |= htole32(active_cnt <<
+                   IWX_PHY_RX_CHAIN_MIMO_CNT_POS);
+       }
 
        return iwx_send_cmd_pdu(sc, IWX_PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd);
 }
@@ -5526,8 +5708,8 @@ iwx_phy_ctxt_cmd(struct iwx_softc *sc, struct iwx_phy_
        int cmdver;
 
        cmdver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_PHY_CONTEXT_CMD);
-       if (cmdver != 3) {
-               printf("%s: firmware does not support phy-context-cmd v3\n",
+       if (cmdver != 3 && cmdver != 4) {
+               printf("%s: firmware does not support phy-context-cmd v3/v4\n",
                    DEVNAME(sc));
                return ENOTSUP;
        }
@@ -5540,12 +5722,12 @@ iwx_phy_ctxt_cmd(struct iwx_softc *sc, struct iwx_phy_
         * variant of the phy context command.
         */
        if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS)) {
-               return iwx_phy_ctxt_cmd_uhb_v3(sc, ctxt, chains_static,
-                   chains_dynamic, action, sco, vht_chan_width);
+               return iwx_phy_ctxt_cmd_uhb_v3_v4(sc, ctxt, chains_static,
+                   chains_dynamic, action, sco, vht_chan_width, cmdver);
        }
 
-       return iwx_phy_ctxt_cmd_v3(sc, ctxt, chains_static, chains_dynamic,
-           action, sco, vht_chan_width);
+       return iwx_phy_ctxt_cmd_v3_v4(sc, ctxt, chains_static, chains_dynamic,
+           action, sco, vht_chan_width, cmdver);
 }
 
 int
@@ -5813,6 +5995,36 @@ iwx_cmd_done(struct iwx_softc *sc, int qid, int idx, i
                ring->queued--;
 }
 
+uint32_t
+iwx_fw_rateidx_ofdm(uint8_t rval)
+{
+       /* Firmware expects indices which match our 11a rate set. */
+       const struct ieee80211_rateset *rs = &ieee80211_std_rateset_11a;
+       int i;
+
+       for (i = 0; i < rs->rs_nrates; i++) {
+               if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rval)
+                       return i;
+       }
+
+       return 0;
+}
+
+uint32_t
+iwx_fw_rateidx_cck(uint8_t rval)
+{
+       /* Firmware expects indices which match our 11b rate set. */
+       const struct ieee80211_rateset *rs = &ieee80211_std_rateset_11b;
+       int i;
+
+       for (i = 0; i < rs->rs_nrates; i++) {
+               if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rval)
+                       return i;
+       }
+
+       return 0;
+}
+
 /*
  * Determine the Tx command flags and Tx rate+flags to use.
  * Return the selected Tx rate.
@@ -5828,6 +6040,7 @@ iwx_tx_fill_cmd(struct iwx_softc *sc, struct iwx_node 
        int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
        int min_ridx = iwx_rval2ridx(ieee80211_min_basic_rate(ic));
        int ridx, rate_flags;
+       uint8_t rval;
 
        *flags = 0;
 
@@ -5836,16 +6049,9 @@ iwx_tx_fill_cmd(struct iwx_softc *sc, struct iwx_node 
                /* for non-data, use the lowest supported rate */
                ridx = min_ridx;
                *flags |= IWX_TX_FLAGS_CMD_RATE;
-       } else if (ic->ic_fixed_mcs != -1) {
-               ridx = sc->sc_fixed_ridx;
-               *flags |= IWX_TX_FLAGS_CMD_RATE;
-       } else if (ic->ic_fixed_rate != -1) {
-               ridx = sc->sc_fixed_ridx;
-               *flags |= IWX_TX_FLAGS_CMD_RATE;
        } else if (ni->ni_flags & IEEE80211_NODE_HT) {
                ridx = iwx_mcs2ridx[ni->ni_txmcs];
        } else {
-               uint8_t rval;
                rval = (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL);
                ridx = iwx_rval2ridx(rval);
                if (ridx < min_ridx)
@@ -5857,46 +6063,43 @@ iwx_tx_fill_cmd(struct iwx_softc *sc, struct iwx_node 
                *flags |= IWX_TX_FLAGS_HIGH_PRI;
 
        rinfo = &iwx_rates[ridx];
-       if (iwx_is_mimo_ht_plcp(rinfo->ht_plcp))
-               rate_flags = IWX_RATE_MCS_ANT_AB_MSK;
-       else
-               rate_flags = IWX_RATE_MCS_ANT_A_MSK;
-       if (IWX_RIDX_IS_CCK(ridx))
-               rate_flags |= IWX_RATE_MCS_CCK_MSK;
-       if ((ni->ni_flags & IEEE80211_NODE_HT) &&
-           type == IEEE80211_FC0_TYPE_DATA &&
-           rinfo->ht_plcp != IWX_RATE_HT_SISO_MCS_INV_PLCP) {
-               uint8_t sco = IEEE80211_HTOP0_SCO_SCN;
-               uint8_t vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_HT;
-               if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
-                   IEEE80211_CHAN_80MHZ_ALLOWED(ni->ni_chan) &&
-                   ieee80211_node_supports_vht_chan80(ni))
-                       vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_80;
-               else if (IEEE80211_CHAN_40MHZ_ALLOWED(ni->ni_chan) &&
-                   ieee80211_node_supports_ht_chan40(ni))
-                       sco = (ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK);
-               if (ni->ni_flags & IEEE80211_NODE_VHT)
-                       rate_flags |= IWX_RATE_MCS_VHT_MSK; 
+
+       /*
+        * Do not fill rate_n_flags if firmware controls the Tx rate.
+        * For data frames we rely on Tx rate scaling in firmware by default.
+        */
+       if ((*flags & IWX_TX_FLAGS_CMD_RATE) == 0) {
+               *rate_n_flags = 0;
+               return rinfo;
+       }
+
+       /*
+        * Forcing a CCK/OFDM legacy rate is important for management frames.
+        * Association will only succeed if we do this correctly.
+        */
+       rate_flags = IWX_RATE_MCS_ANT_A_MSK;
+       if (IWX_RIDX_IS_CCK(ridx)) {
+               if (sc->sc_rate_n_flags_version >= 2)
+                       rate_flags |= IWX_RATE_MCS_CCK_MSK;
                else
-                       rate_flags |= IWX_RATE_MCS_HT_MSK; 
-               if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80 &&
-                   in->in_phyctxt != NULL &&
-                   in->in_phyctxt->vht_chan_width == vht_chan_width) {
-                       rate_flags |= IWX_RATE_MCS_CHAN_WIDTH_80;
-                       if (ieee80211_node_supports_vht_sgi80(ni))
-                               rate_flags |= IWX_RATE_MCS_SGI_MSK;
-               } else if ((sco == IEEE80211_HTOP0_SCO_SCA || 
-                   sco == IEEE80211_HTOP0_SCO_SCB) &&
-                   in->in_phyctxt != NULL && in->in_phyctxt->sco == sco) {
-                       rate_flags |= IWX_RATE_MCS_CHAN_WIDTH_40;
-                       if (ieee80211_node_supports_ht_sgi40(ni))
-                               rate_flags |= IWX_RATE_MCS_SGI_MSK;
-               } else if (ieee80211_node_supports_ht_sgi20(ni))
-                       rate_flags |= IWX_RATE_MCS_SGI_MSK;
-               *rate_n_flags = rate_flags | rinfo->ht_plcp;
+                       rate_flags |= IWX_RATE_MCS_CCK_MSK_V1;
+       } else if (sc->sc_rate_n_flags_version >= 2)
+               rate_flags |= IWX_RATE_MCS_LEGACY_OFDM_MSK;
+
+       rval = (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL);
+       if (sc->sc_rate_n_flags_version >= 2) {
+               if (rate_flags & IWX_RATE_MCS_LEGACY_OFDM_MSK) {
+                       rate_flags |= (iwx_fw_rateidx_ofdm(rval) &
+                           IWX_RATE_LEGACY_RATE_MSK);
+               } else {
+                       rate_flags |= (iwx_fw_rateidx_cck(rval) &
+                           IWX_RATE_LEGACY_RATE_MSK);
+               }
        } else
-               *rate_n_flags = rate_flags | rinfo->plcp;
+               rate_flags |= rinfo->plcp;
 
+       *rate_n_flags = rate_flags;
+
        return rinfo;
 }
 
@@ -6587,7 +6790,7 @@ iwx_rm_sta(struct iwx_softc *sc, struct iwx_node *in)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ieee80211_node *ni = &in->in_ni;
-       int err, i;
+       int err, i, cmd_ver;
 
        err = iwx_flush_sta(sc, in);
        if (err) {
@@ -6595,6 +6798,33 @@ iwx_rm_sta(struct iwx_softc *sc, struct iwx_node *in)
                    DEVNAME(sc), err);
                return err;
        }
+
+       /*
+        * New SCD_QUEUE_CONFIG API requires explicit queue removal
+        * before a station gets removed.
+        */
+       cmd_ver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+           IWX_SCD_QUEUE_CONFIG_CMD);
+       if (cmd_ver != 0 && cmd_ver != IWX_FW_CMD_VER_UNKNOWN) {
+               err = iwx_disable_mgmt_queue(sc);
+               if (err)
+                       return err;
+               for (i = IWX_FIRST_AGG_TX_QUEUE;
+                   i < IWX_LAST_AGG_TX_QUEUE; i++) {
+                       struct iwx_tx_ring *ring = &sc->txq[i];
+                       if ((sc->qenablemsk & (1 << i)) == 0)
+                               continue;
+                       err = iwx_disable_txq(sc, IWX_STATION_ID,
+                           ring->qid, ring->tid);
+                       if (err) {
+                               printf("%s: could not disable Tx queue %d "
+                                   "(error %d)\n", DEVNAME(sc), ring->qid,
+                                   err);
+                               return err;
+                       }
+               }
+       }
+
        err = iwx_rm_sta_cmd(sc, in);
        if (err) {
                printf("%s: could not remove STA (error %d)\n",
@@ -7206,15 +7436,16 @@ iwx_mac_ctxt_cmd_fill_sta(struct iwx_softc *sc, struct
        tsf = letoh64(tsf);
 
        sta->is_assoc = htole32(assoc);
-       sta->dtim_time = htole32(ni->ni_rstamp + dtim_off);
-       sta->dtim_tsf = htole64(tsf + dtim_off);
+       if (assoc) {
+               sta->dtim_time = htole32(ni->ni_rstamp + dtim_off);
+               sta->dtim_tsf = htole64(tsf + dtim_off);
+               sta->assoc_beacon_arrive_time = htole32(ni->ni_rstamp);
+       }
        sta->bi = htole32(ni->ni_intval);
-       sta->bi_reciprocal = htole32(iwx_reciprocal(ni->ni_intval));
        sta->dtim_interval = htole32(ni->ni_intval * ni->ni_dtimperiod);
-       sta->dtim_reciprocal = htole32(iwx_reciprocal(sta->dtim_interval));
+       sta->data_policy = htole32(0);
        sta->listen_interval = htole32(10);
        sta->assoc_id = htole32(ni->ni_associd);
-       sta->assoc_beacon_arrive_time = htole32(ni->ni_rstamp);
 }
 
 int
@@ -7247,15 +7478,14 @@ iwx_mac_ctxt_cmd(struct iwx_softc *sc, struct iwx_node
                    IWX_MAC_FILTER_IN_BEACON |
                    IWX_MAC_FILTER_IN_PROBE_REQUEST |
                    IWX_MAC_FILTER_IN_CRC32);
-       } else if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod)
+       } else if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod) {
                /* 
                 * Allow beacons to pass through as long as we are not
                 * associated or we do not have dtim period information.
                 */
                cmd.filter_flags |= htole32(IWX_MAC_FILTER_IN_BEACON);
-       else
-               iwx_mac_ctxt_cmd_fill_sta(sc, in, &cmd.sta, assoc);
-
+       }
+       iwx_mac_ctxt_cmd_fill_sta(sc, in, &cmd.sta, assoc);
        return iwx_send_cmd_pdu(sc, IWX_MAC_CONTEXT_CMD, 0, sizeof(cmd), &cmd);
 }
 
@@ -7484,6 +7714,30 @@ iwx_rs_rval2idx(uint8_t rval)
 }
 
 int
+iwx_disable_mgmt_queue(struct iwx_softc *sc)
+{
+       int err, cmd_ver;
+
+       /* Explicit removal is only required with old SCD_QUEUE_CFG command. */
+       cmd_ver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+           IWX_SCD_QUEUE_CONFIG_CMD);
+       if (cmd_ver == 0 || cmd_ver == IWX_FW_CMD_VER_UNKNOWN)
+               return 0;
+
+       sc->first_data_qid = IWX_DQA_CMD_QUEUE + 1;
+
+       err = iwx_disable_txq(sc, IWX_STATION_ID, sc->first_data_qid,
+           IWX_MGMT_TID);
+       if (err) {
+               printf("%s: could not disable Tx queue %d (error %d)\n",
+                   DEVNAME(sc), sc->first_data_qid, err);
+               return err;
+       }
+
+       return 0;
+}
+
+int
 iwx_rs_rval2idx(uint8_t rval)
 {
        /* Firmware expects indices which match our 11g rate set. */
@@ -7550,71 +7804,151 @@ iwx_rs_init(struct iwx_softc *sc, struct iwx_node *in)
 }
 
 int
+iwx_rs_init_v3(struct iwx_softc *sc, struct iwx_node *in)
+{
+       struct ieee80211_node *ni = &in->in_ni;
+       struct ieee80211_rateset *rs = &ni->ni_rates;
+       struct iwx_tlc_config_cmd_v3 cfg_cmd;
+       uint32_t cmd_id;
+       int i;
+       size_t cmd_size = sizeof(cfg_cmd);
+
+       memset(&cfg_cmd, 0, sizeof(cfg_cmd));
+
+       for (i = 0; i < rs->rs_nrates; i++) {
+               uint8_t rval = rs->rs_rates[i] & IEEE80211_RATE_VAL;
+               int idx = iwx_rs_rval2idx(rval);
+               if (idx == -1)
+                       return EINVAL;
+               cfg_cmd.non_ht_rates |= (1 << idx);
+       }
+
+       if (ni->ni_flags & IEEE80211_NODE_VHT) {
+               cfg_cmd.mode = IWX_TLC_MNG_MODE_VHT;
+               cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
+                   htole16(iwx_rs_vht_rates(sc, ni, 1));
+               cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
+                   htole16(iwx_rs_vht_rates(sc, ni, 2));
+       } else if (ni->ni_flags & IEEE80211_NODE_HT) {
+               cfg_cmd.mode = IWX_TLC_MNG_MODE_HT;
+               cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
+                   htole16(iwx_rs_ht_rates(sc, ni,
+                   IEEE80211_HT_RATESET_SISO));
+               cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
+                   htole16(iwx_rs_ht_rates(sc, ni,
+                   IEEE80211_HT_RATESET_MIMO2));
+       } else
+               cfg_cmd.mode = IWX_TLC_MNG_MODE_NON_HT;
+
+       cfg_cmd.sta_id = IWX_STATION_ID;
+       if (in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80)
+               cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_80MHZ;
+       else if (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA ||
+           in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB)
+               cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_40MHZ;
+       else
+               cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_20MHZ;
+       cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK | IWX_TLC_MNG_CHAIN_B_MSK;
+       if (ni->ni_flags & IEEE80211_NODE_VHT)
+               cfg_cmd.max_mpdu_len = htole16(3895);
+       else
+               cfg_cmd.max_mpdu_len = htole16(3839);
+       if (ni->ni_flags & IEEE80211_NODE_HT) {
+               if (ieee80211_node_supports_ht_sgi20(ni)) {
+                       cfg_cmd.sgi_ch_width_supp |= (1 <<
+                           IWX_TLC_MNG_CH_WIDTH_20MHZ);
+               }
+               if (ieee80211_node_supports_ht_sgi40(ni)) {
+                       cfg_cmd.sgi_ch_width_supp |= (1 <<
+                           IWX_TLC_MNG_CH_WIDTH_40MHZ);
+               }
+       }
+       if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
+           ieee80211_node_supports_vht_sgi80(ni))
+               cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_80MHZ);
+
+       cmd_id = iwx_cmd_id(IWX_TLC_MNG_CONFIG_CMD, IWX_DATA_PATH_GROUP, 0);
+       return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd);
+}
+
+int
+iwx_rs_init_v4(struct iwx_softc *sc, struct iwx_node *in)
+{
+       struct ieee80211_node *ni = &in->in_ni;
+       struct ieee80211_rateset *rs = &ni->ni_rates;
+       struct iwx_tlc_config_cmd_v4 cfg_cmd;
+       uint32_t cmd_id;
+       int i;
+       size_t cmd_size = sizeof(cfg_cmd);
+
+       memset(&cfg_cmd, 0, sizeof(cfg_cmd));
+
+       for (i = 0; i < rs->rs_nrates; i++) {
+               uint8_t rval = rs->rs_rates[i] & IEEE80211_RATE_VAL;
+               int idx = iwx_rs_rval2idx(rval);
+               if (idx == -1)
+                       return EINVAL;
+               cfg_cmd.non_ht_rates |= (1 << idx);
+       }
+
+       if (ni->ni_flags & IEEE80211_NODE_VHT) {
+               cfg_cmd.mode = IWX_TLC_MNG_MODE_VHT;
+               cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
+                   htole16(iwx_rs_vht_rates(sc, ni, 1));
+               cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
+                   htole16(iwx_rs_vht_rates(sc, ni, 2));
+       } else if (ni->ni_flags & IEEE80211_NODE_HT) {
+               cfg_cmd.mode = IWX_TLC_MNG_MODE_HT;
+               cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
+                   htole16(iwx_rs_ht_rates(sc, ni,
+                   IEEE80211_HT_RATESET_SISO));
+               cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
+                   htole16(iwx_rs_ht_rates(sc, ni,
+                   IEEE80211_HT_RATESET_MIMO2));
+       } else
+               cfg_cmd.mode = IWX_TLC_MNG_MODE_NON_HT;
+
+       cfg_cmd.sta_id = IWX_STATION_ID;
+       if (in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80)
+               cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_80MHZ;
+       else if (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA ||
+           in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB)
+               cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_40MHZ;
+       else
+               cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_20MHZ;
+       cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK | IWX_TLC_MNG_CHAIN_B_MSK;
+       if (ni->ni_flags & IEEE80211_NODE_VHT)
+               cfg_cmd.max_mpdu_len = htole16(3895);
+       else
+               cfg_cmd.max_mpdu_len = htole16(3839);
+       if (ni->ni_flags & IEEE80211_NODE_HT) {
+               if (ieee80211_node_supports_ht_sgi20(ni)) {
+                       cfg_cmd.sgi_ch_width_supp |= (1 <<
+                           IWX_TLC_MNG_CH_WIDTH_20MHZ);
+               }
+               if (ieee80211_node_supports_ht_sgi40(ni)) {
+                       cfg_cmd.sgi_ch_width_supp |= (1 <<
+                           IWX_TLC_MNG_CH_WIDTH_40MHZ);
+               }
+       }
+       if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
+           ieee80211_node_supports_vht_sgi80(ni))
+               cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_80MHZ);
+
+       cmd_id = iwx_cmd_id(IWX_TLC_MNG_CONFIG_CMD, IWX_DATA_PATH_GROUP, 0);
+       return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd);
+}
+
+int
 iwx_rs_init(struct iwx_softc *sc, struct iwx_node *in)
 {
-       struct ieee80211_node *ni = &in->in_ni;
-       struct ieee80211_rateset *rs = &ni->ni_rates;
-       struct iwx_tlc_config_cmd cfg_cmd;
-       uint32_t cmd_id;
-       int i;
-       size_t cmd_size = sizeof(cfg_cmd);
+       int cmd_ver;
 
-       memset(&cfg_cmd, 0, sizeof(cfg_cmd));
-
-       for (i = 0; i < rs->rs_nrates; i++) {
-               uint8_t rval = rs->rs_rates[i] & IEEE80211_RATE_VAL;
-               int idx = iwx_rs_rval2idx(rval);
-               if (idx == -1)
-                       return EINVAL;
-               cfg_cmd.non_ht_rates |= (1 << idx);
-       }
-
-       if (ni->ni_flags & IEEE80211_NODE_VHT) {
-               cfg_cmd.mode = IWX_TLC_MNG_MODE_VHT;
-               cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_HT_BW_NONE_160] =
-                   htole16(iwx_rs_vht_rates(sc, ni, 1));
-               cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_HT_BW_NONE_160] =
-                   htole16(iwx_rs_vht_rates(sc, ni, 2));
-       } else if (ni->ni_flags & IEEE80211_NODE_HT) {
-               cfg_cmd.mode = IWX_TLC_MNG_MODE_HT;
-               cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_HT_BW_NONE_160] =
-                   htole16(iwx_rs_ht_rates(sc, ni,
-                   IEEE80211_HT_RATESET_SISO));
-               cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_HT_BW_NONE_160] =
-                   htole16(iwx_rs_ht_rates(sc, ni,
-                   IEEE80211_HT_RATESET_MIMO2));
-       } else
-               cfg_cmd.mode = IWX_TLC_MNG_MODE_NON_HT;
-
-       cfg_cmd.sta_id = IWX_STATION_ID;
-       if (in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80)
-               cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_80MHZ;
-       else if (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA ||
-           in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB)
-               cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_40MHZ;
-       else
-               cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_20MHZ;
-       cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK | IWX_TLC_MNG_CHAIN_B_MSK;
-       if (ni->ni_flags & IEEE80211_NODE_VHT)
-               cfg_cmd.max_mpdu_len = htole16(3895);
-       else
-               cfg_cmd.max_mpdu_len = htole16(3839);
-       if (ni->ni_flags & IEEE80211_NODE_HT) {
-               if (ieee80211_node_supports_ht_sgi20(ni)) {
-                       cfg_cmd.sgi_ch_width_supp |= (1 <<
-                           IWX_TLC_MNG_CH_WIDTH_20MHZ);
-               }
-               if (ieee80211_node_supports_ht_sgi40(ni)) {
-                       cfg_cmd.sgi_ch_width_supp |= (1 <<
-                           IWX_TLC_MNG_CH_WIDTH_40MHZ);
-               }
-       }
-       if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
-           ieee80211_node_supports_vht_sgi80(ni))
-               cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_80MHZ);
-
-       cmd_id = iwx_cmd_id(IWX_TLC_MNG_CONFIG_CMD, IWX_DATA_PATH_GROUP, 0);
-       return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd);
+       cmd_ver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+           IWX_TLC_MNG_CONFIG_CMD);
+       if (cmd_ver == 4)
+               return iwx_rs_init_v4(sc, in);
+       return iwx_rs_init_v3(sc, in);
 }
 
 void
@@ -7624,44 +7958,108 @@ iwx_rs_update(struct iwx_softc *sc, struct iwx_tlc_upd
        struct ieee80211_node *ni = ic->ic_bss;
        struct ieee80211_rateset *rs = &ni->ni_rates;
        uint32_t rate_n_flags;
-       int i;
+       uint8_t plcp, rval;
+       int i, cmd_ver, rate_n_flags_ver2 = 0;
 
        if (notif->sta_id != IWX_STATION_ID ||
            (le32toh(notif->flags) & IWX_TLC_NOTIF_FLAG_RATE) == 0)
                return;
 
        rate_n_flags = le32toh(notif->rate);
-       if (rate_n_flags & IWX_RATE_MCS_VHT_MSK) {
-               ni->ni_txmcs = (rate_n_flags & IWX_RATE_VHT_MCS_RATE_CODE_MSK);
-               ni->ni_vht_ss = ((rate_n_flags & IWX_RATE_VHT_MCS_NSS_MSK) >>
-                   IWX_RATE_VHT_MCS_NSS_POS) + 1;
-       } else if (rate_n_flags & IWX_RATE_MCS_HT_MSK) {
-               ni->ni_txmcs = (rate_n_flags &
-                   (IWX_RATE_HT_MCS_RATE_CODE_MSK |
-                   IWX_RATE_HT_MCS_NSS_MSK));
+
+       cmd_ver = iwx_lookup_notif_ver(sc, IWX_DATA_PATH_GROUP,
+           IWX_TLC_MNG_UPDATE_NOTIF);
+       if (cmd_ver != IWX_FW_CMD_VER_UNKNOWN && cmd_ver >= 3)
+               rate_n_flags_ver2 = 1;
+       if (rate_n_flags_ver2) {
+               uint32_t mod_type = (rate_n_flags & IWX_RATE_MCS_MOD_TYPE_MSK);
+               if (mod_type == IWX_RATE_MCS_VHT_MSK) {
+                       ni->ni_txmcs = (rate_n_flags &
+                           IWX_RATE_HT_MCS_CODE_MSK);
+                       ni->ni_vht_ss = ((rate_n_flags &
+                           IWX_RATE_MCS_NSS_MSK) >>
+                           IWX_RATE_MCS_NSS_POS) + 1;
+                       return;
+               } else if (mod_type == IWX_RATE_MCS_HT_MSK) {
+                       ni->ni_txmcs = IWX_RATE_HT_MCS_INDEX(rate_n_flags);
+                       return;
+               }
        } else {
-               uint8_t plcp = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK);
-               uint8_t rval = 0;
+               if (rate_n_flags & IWX_RATE_MCS_VHT_MSK_V1) {
+                       ni->ni_txmcs = (rate_n_flags &
+                           IWX_RATE_VHT_MCS_RATE_CODE_MSK);
+                       ni->ni_vht_ss = ((rate_n_flags &
+                           IWX_RATE_VHT_MCS_NSS_MSK) >>
+                           IWX_RATE_VHT_MCS_NSS_POS) + 1;
+                       return;
+               } else if (rate_n_flags & IWX_RATE_MCS_HT_MSK_V1) {
+                       ni->ni_txmcs = (rate_n_flags &
+                           (IWX_RATE_HT_MCS_RATE_CODE_MSK_V1 |
+                           IWX_RATE_HT_MCS_NSS_MSK_V1));
+                       return;
+               }
+       }
+
+       if (rate_n_flags_ver2) {
+               const struct ieee80211_rateset *rs;
+               uint32_t ridx = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK);
+               if (rate_n_flags & IWX_RATE_MCS_LEGACY_OFDM_MSK)
+                       rs = &ieee80211_std_rateset_11a;
+               else
+                       rs = &ieee80211_std_rateset_11b;
+               if (ridx < rs->rs_nrates)
+                       rval = (rs->rs_rates[ridx] & IEEE80211_RATE_VAL);
+               else
+                       rval = 0;
+       } else {
+               plcp = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK_V1);
+
+               rval = 0;
                for (i = IWX_RATE_1M_INDEX; i < nitems(iwx_rates); i++) {
                        if (iwx_rates[i].plcp == plcp) {
                                rval = iwx_rates[i].rate;
                                break;
                        }
                }
-               if (rval) {
-                       uint8_t rv;
-                       for (i = 0; i < rs->rs_nrates; i++) {
-                               rv = rs->rs_rates[i] & IEEE80211_RATE_VAL;
-                               if (rv == rval) {
-                                       ni->ni_txrate = i;
-                                       break;
-                               }
+       }
+
+       if (rval) {
+               uint8_t rv;
+               for (i = 0; i < rs->rs_nrates; i++) {
+                       rv = rs->rs_rates[i] & IEEE80211_RATE_VAL;
+                       if (rv == rval) {
+                               ni->ni_txrate = i;
+                               break;
                        }
                }
        }
 }
 
 int
+iwx_phy_send_rlc(struct iwx_softc *sc, struct iwx_phy_ctxt *phyctxt,
+    uint8_t chains_static, uint8_t chains_dynamic)
+{
+       struct iwx_rlc_config_cmd cmd;
+       uint32_t cmd_id;
+       uint8_t active_cnt, idle_cnt;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       idle_cnt = chains_static;
+       active_cnt = chains_dynamic;
+
+       cmd.phy_id = htole32(phyctxt->id),
+       cmd.rlc.rx_chain_info = htole32(iwx_fw_valid_rx_ant(sc) <<
+           IWX_PHY_RX_CHAIN_VALID_POS);
+       cmd.rlc.rx_chain_info |= htole32(idle_cnt << IWX_PHY_RX_CHAIN_CNT_POS);
+       cmd.rlc.rx_chain_info |= htole32(active_cnt <<
+           IWX_PHY_RX_CHAIN_MIMO_CNT_POS);
+
+       cmd_id = iwx_cmd_id(IWX_RLC_CONFIG_CMD, IWX_DATA_PATH_GROUP, 2);
+       return iwx_send_cmd_pdu(sc, cmd_id, 0, sizeof(cmd), &cmd);
+}
+
+int
 iwx_phy_ctxt_update(struct iwx_softc *sc, struct iwx_phy_ctxt *phyctxt,
     struct ieee80211_channel *chan, uint8_t chains_static,
     uint8_t chains_dynamic, uint32_t apply_time, uint8_t sco,
@@ -7705,6 +8103,12 @@ iwx_phy_ctxt_update(struct iwx_softc *sc, struct iwx_p
 
        phyctxt->sco = sco;
        phyctxt->vht_chan_width = vht_chan_width;
+
+       if (iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+           IWX_RLC_CONFIG_CMD) == 2)
+               return iwx_phy_send_rlc(sc, phyctxt,
+                   chains_static, chains_dynamic);
+
        return 0;
 }
 
@@ -7773,17 +8177,20 @@ iwx_auth(struct iwx_softc *sc)
 
        err = iwx_clear_statistics(sc);
        if (err)
-               goto rm_sta;
+               goto rm_mgmt_queue;
 
        /*
         * Prevent the FW from wandering off channel during association
         * by "protecting" the session with a time event.
         */
        if (in->in_ni.ni_intval)
-               duration = in->in_ni.ni_intval * 2;
+               duration = in->in_ni.ni_intval * 9;
        else
-               duration = IEEE80211_DUR_TU; 
+               duration = 900; 
        return iwx_schedule_session_protection(sc, in, duration);
+rm_mgmt_queue:
+       if (generation == sc->sc_generation)
+               iwx_disable_mgmt_queue(sc);
 rm_sta:
        if (generation == sc->sc_generation) {
                iwx_rm_sta_cmd(sc, in);
@@ -7821,6 +8228,7 @@ iwx_deauth(struct iwx_softc *sc)
        }
 
        if (sc->sc_flags & IWX_FLAG_BINDING_ACTIVE) {
+               /* TODO: stop session protection to avoid fatal FW error here. 
*/
                err = iwx_binding_cmd(sc, in, IWX_FW_CTXT_ACTION_REMOVE);
                if (err) {
                        printf("%s: could not remove binding (error %d)\n",
@@ -8170,6 +8578,9 @@ iwx_delete_key(struct ieee80211com *ic, struct ieee802
        struct iwx_softc *sc = ic->ic_softc;
        struct iwx_add_sta_key_cmd cmd;
 
+       if ((sc->sc_flags & IWX_FLAG_STA_ACTIVE) == 0)
+               return;
+
        if (k->k_cipher != IEEE80211_CIPHER_CCMP) {
                /* Fallback to software crypto for other ciphers. */
                 ieee80211_delete_key(ic, ni, k);
@@ -8195,27 +8606,12 @@ iwx_media_change(struct ifnet *ifp)
 int
 iwx_media_change(struct ifnet *ifp)
 {
-       struct iwx_softc *sc = ifp->if_softc;
-       struct ieee80211com *ic = &sc->sc_ic;
-       uint8_t rate, ridx;
        int err;
 
        err = ieee80211_media_change(ifp);
        if (err != ENETRESET)
                return err;
 
-       if (ic->ic_fixed_mcs != -1)
-               sc->sc_fixed_ridx = iwx_mcs2ridx[ic->ic_fixed_mcs];
-       else if (ic->ic_fixed_rate != -1) {
-               rate = ic->ic_sup_rates[ic->ic_curmode].
-                   rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
-               /* Map 802.11 rate to HW rate index. */
-               for (ridx = 0; ridx <= IWX_RIDX_MAX; ridx++)
-                       if (iwx_rates[ridx].rate == rate)
-                               break;
-               sc->sc_fixed_ridx = ridx;
-       }
-
        if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
            (IFF_UP | IFF_RUNNING)) {
                iwx_stop(ifp);
@@ -8685,6 +9081,15 @@ iwx_init_hw(struct iwx_softc *sc)
                            DEVNAME(sc), i, err);
                        goto err;
                }
+               if (iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+                   IWX_RLC_CONFIG_CMD) == 2) {
+                       err = iwx_phy_send_rlc(sc, &sc->sc_phyctxt[i], 1, 1);
+                       if (err) {
+                               printf("%s: could not configure RLC for PHY "
+                                   "%d (error %d)\n", DEVNAME(sc), i, err);
+                               goto err;
+                       }
+               }
        }
 
        err = iwx_config_ltr(sc);
@@ -9462,6 +9867,7 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *d
                case IWX_ALIVE: {
                        struct iwx_alive_resp_v4 *resp4;
                        struct iwx_alive_resp_v5 *resp5;
+                       struct iwx_alive_resp_v6 *resp6;
 
                        DPRINTF(("%s: firmware alive\n", __func__));
                        sc->sc_uc.uc_ok = 0;
@@ -9471,6 +9877,31 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *d
                         * versions we need to check the size.
                         */
                         if (iwx_lookup_notif_ver(sc, IWX_LEGACY_GROUP,
+                           IWX_ALIVE) == 6) {
+                               SYNC_RESP_STRUCT(resp6, pkt);
+                               if (iwx_rx_packet_payload_len(pkt) !=
+                                   sizeof(*resp6)) {
+                                       sc->sc_uc.uc_intr = 1;
+                                       wakeup(&sc->sc_uc);
+                                       break;
+                               }
+                               sc->sc_uc.uc_lmac_error_event_table[0] = 
le32toh(
+                                   
resp6->lmac_data[0].dbg_ptrs.error_event_table_ptr);
+                               sc->sc_uc.uc_lmac_error_event_table[1] = 
le32toh(
+                                   
resp6->lmac_data[1].dbg_ptrs.error_event_table_ptr);
+                               sc->sc_uc.uc_log_event_table = le32toh(
+                                   
resp6->lmac_data[0].dbg_ptrs.log_event_table_ptr);
+                               sc->sc_uc.uc_umac_error_event_table = le32toh(
+                                   resp6->umac_data.dbg_ptrs.error_info_addr);
+                               sc->sc_sku_id[0] =
+                                   le32toh(resp6->sku_id.data[0]);
+                               sc->sc_sku_id[1] =
+                                   le32toh(resp6->sku_id.data[1]);
+                               sc->sc_sku_id[2] =
+                                   le32toh(resp6->sku_id.data[2]);
+                               if (resp6->status == IWX_ALIVE_STATUS_OK)
+                                       sc->sc_uc.uc_ok = 1;
+                        } else if (iwx_lookup_notif_ver(sc, IWX_LEGACY_GROUP,
                            IWX_ALIVE) == 5) {
                                SYNC_RESP_STRUCT(resp5, pkt);
                                if (iwx_rx_packet_payload_len(pkt) !=
@@ -9541,6 +9972,10 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *d
                        break;
                }
 
+               case IWX_WIDE_ID(IWX_DATA_PATH_GROUP,
+                   IWX_SCD_QUEUE_CONFIG_CMD):
+               case IWX_WIDE_ID(IWX_DATA_PATH_GROUP,
+                   IWX_RX_BAID_ALLOCATION_CONFIG_CMD):
                case IWX_WIDE_ID(IWX_MAC_CONF_GROUP,
                    IWX_SESSION_PROTECTION_CMD):
                case IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP,
@@ -9701,6 +10136,13 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *d
                        break;
                }
 
+               case IWX_WIDE_ID(IWX_DATA_PATH_GROUP, IWX_RLC_CONFIG_CMD):
+                       break;
+
+               /* undocumented notification from iwx-ty-a0-gf-a0-77 image */
+               case IWX_WIDE_ID(IWX_DATA_PATH_GROUP, 0xf8):
+                       break;
+
                case IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP,
                    IWX_PNVM_INIT_COMPLETE):
                        sc->sc_init_complete |= IWX_PNVM_COMPLETE;
blob - 3b9cbde8fc577052a23a428e0be998f375adc146
blob + 519cdeff7cc20637e8dcf80a18353b52f754ef10
--- sys/dev/pci/if_iwxreg.h
+++ sys/dev/pci/if_iwxreg.h
@@ -1387,6 +1387,7 @@ enum msix_ivar_for_cause {
 #define IWX_UCODE_TLV_CAPA_PROTECTED_TWT               56
 #define IWX_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE          57
 #define IWX_UCODE_TLV_CAPA_PASSIVE_6GHZ_SCAN           58
+#define IWX_UCODE_TLV_CAPA_BAID_ML_SUPPORT             63
 #define IWX_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE                64
 #define IWX_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS           65
 #define IWX_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT            67
@@ -1574,8 +1575,13 @@ struct iwx_ucode_header {
 #define IWX_UCODE_TLV_PNVM_VERSION             62
 #define IWX_UCODE_TLV_PNVM_SKU                 64
 
+#define IWX_UCODE_TLV_SEC_TABLE_ADDR           66
+#define IWX_UCODE_TLV_D3_KEK_KCK_ADDR          67
+#define IWX_UCODE_TLV_CURRENT_PC               68
+
 #define IWX_UCODE_TLV_CONST_BASE               0x100
 #define IWX_UCODE_TLV_FW_NUM_STATIONS          (IWX_UCODE_TLV_CONST_BASE + 0)
+#define IWX_UCODE_TLV_FW_NUM_BEACONS           (IWX_UCODE_TLV_CONST_BASE + 2)
 
 #define IWX_UCODE_TLV_DEBUG_BASE       0x1000005
 #define IWX_UCODE_TLV_TYPE_DEBUG_INFO          (IWX_UCODE_TLV_DEBUG_BASE + 0)
@@ -1999,7 +2005,10 @@ struct iwx_tx_queue_cfg_rsp {
 
 /* DATA_PATH group subcommand IDs */
 #define IWX_DQA_ENABLE_CMD     0x00
+#define IWX_RLC_CONFIG_CMD     0x08
 #define IWX_TLC_MNG_CONFIG_CMD 0x0f
+#define IWX_RX_BAID_ALLOCATION_CONFIG_CMD      0x16
+#define IWX_SCD_QUEUE_CONFIG_CMD       0x17
 #define IWX_RX_NO_DATA_NOTIF   0xf5
 #define IWX_TLC_MNG_UPDATE_NOTIF 0xf7
 
@@ -2328,7 +2337,22 @@ struct iwx_alive_resp_v5 {
        struct iwx_sku_id sku_id;
 } __packed; /* UCODE_ALIVE_NTFY_API_S_VER_5 */
 
+struct iwx_imr_alive_info {
+       uint64_t base_addr;
+       uint32_t size;
+       uint32_t enabled;
+} __packed; /* IMR_ALIVE_INFO_API_S_VER_1 */
 
+struct iwx_alive_resp_v6 {
+       uint16_t status;
+       uint16_t flags;
+       struct iwx_lmac_alive lmac_data[2];
+       struct iwx_umac_alive umac_data;
+       struct iwx_sku_id sku_id;
+       struct iwx_imr_alive_info imr;
+} __packed; /* UCODE_ALIVE_NTFY_API_S_VER_6 */
+
+
 #define IWX_SOC_CONFIG_CMD_FLAGS_DISCRETE      (1 << 0)
 #define IWX_SOC_CONFIG_CMD_FLAGS_LOW_LATENCY   (1 << 1)
 
@@ -3374,13 +3398,13 @@ struct iwx_phy_context_cmd {
        /* COMMON_INDEX_HDR_API_S_VER_1 */
        uint32_t id_and_color;
        uint32_t action;
-       /* PHY_CONTEXT_DATA_API_S_VER_3 */
+       /* PHY_CONTEXT_DATA_API_S_VER_3, PHY_CONTEXT_DATA_API_S_VER_4 */
        struct iwx_fw_channel_info_v1 ci;
        uint32_t lmac_id;
-       uint32_t rxchain_info;
+       uint32_t rxchain_info; /* reserved in _VER_4 */
        uint32_t dsp_cfg_flags;
        uint32_t reserved;
-} __packed; /* PHY_CONTEXT_CMD_API_VER_3 */
+} __packed; /* PHY_CONTEXT_CMD_API_VER_3, PHY_CONTEXT_CMD_API_VER_4 */
 
 /* TODO: complete missing documentation */
 /**
@@ -4284,14 +4308,32 @@ struct iwx_mac_data_ibss {
 } __packed; /* IBSS_MAC_DATA_API_S_VER_1 */
 
 /**
+ * enum iwx_mac_data_policy - policy of the data path for this MAC
+ * @TWT_SUPPORTED: twt is supported
+ * @MORE_DATA_ACK_SUPPORTED: AP supports More Data Ack according to
+ *     paragraph 9.4.1.17 in P802.11ax_D4 specification. Used for TWT
+ *     early termination detection.
+ * @FLEXIBLE_TWT_SUPPORTED: AP supports flexible TWT schedule
+ * @PROTECTED_TWT_SUPPORTED: AP supports protected TWT frames (with 11w)
+ * @BROADCAST_TWT_SUPPORTED: AP and STA support broadcast TWT
+ * @COEX_HIGH_PRIORITY_ENABLE: high priority mode for BT coex, to be used
+ *     during 802.1X negotiation (and allowed during 4-way-HS)
+ */
+#define IWX_TWT_SUPPORTED BIT          (1 << 0)
+#define IWX_MORE_DATA_ACK_SUPPORTED    (1 << 1)
+#define        IWX_FLEXIBLE_TWT_SUPPORTED      (1 << 2)
+#define IWX_PROTECTED_TWT_SUPPORTED    (1 << 3)
+#define IWX_BROADCAST_TWT_SUPPORTED    (1 << 4)
+#define IWX_COEX_HIGH_PRIORITY_ENABLE  (1 << 5)
+
+/**
  * struct iwx_mac_data_sta - configuration data for station MAC context
  * @is_assoc: 1 for associated state, 0 otherwise
  * @dtim_time: DTIM arrival time in system time
  * @dtim_tsf: DTIM arrival time in TSF
  * @bi: beacon interval in TU, applicable only when associated
- * @bi_reciprocal: 2^32 / bi , applicable only when associated
+ * @data_policy: see &enum iwl_mac_data_policy
  * @dtim_interval: DTIM interval in TU, applicable only when associated
- * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated
  * @listen_interval: in beacon intervals, applicable only when associated
  * @assoc_id: unique ID assigned by the AP during association
  */
@@ -4300,13 +4342,13 @@ struct iwx_mac_data_sta {
        uint32_t dtim_time;
        uint64_t dtim_tsf;
        uint32_t bi;
-       uint32_t bi_reciprocal;
+       uint32_t reserved1;
        uint32_t dtim_interval;
-       uint32_t dtim_reciprocal;
+       uint32_t data_policy;
        uint32_t listen_interval;
        uint32_t assoc_id;
        uint32_t assoc_beacon_arrive_time;
-} __packed; /* IWX_STA_MAC_DATA_API_S_VER_1 */
+} __packed; /* IWX_STA_MAC_DATA_API_S_VER_2 */
 
 /**
  * struct iwx_mac_data_go - configuration data for P2P GO MAC context
@@ -4882,7 +4924,7 @@ enum {
 #define IWX_RATE_INVM_PLCP     0xff
 
 /*
- * rate_n_flags bit fields
+ * rate_n_flags bit fields version 1
  *
  * The 32-bit value has different layouts in the low 8 bites depending on the
  * format. There are three formats, HT, VHT and legacy (11abg, with subformats
@@ -4900,15 +4942,15 @@ enum {
 
 /* Bit 8: (1) HT format, (0) legacy or VHT format */
 #define IWX_RATE_MCS_HT_POS 8
-#define IWX_RATE_MCS_HT_MSK (1 << IWX_RATE_MCS_HT_POS)
+#define IWX_RATE_MCS_HT_MSK_V1 (1 << IWX_RATE_MCS_HT_POS)
 
 /* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid 
*/
-#define IWX_RATE_MCS_CCK_POS 9
-#define IWX_RATE_MCS_CCK_MSK (1 << IWX_RATE_MCS_CCK_POS)
+#define IWX_RATE_MCS_CCK_POS_V1 9
+#define IWX_RATE_MCS_CCK_MSK_V1 (1 << IWX_RATE_MCS_CCK_POS_V1)
 
 /* Bit 26: (1) VHT format, (0) legacy format in bits 8:0 */
-#define IWX_RATE_MCS_VHT_POS 26
-#define IWX_RATE_MCS_VHT_MSK (1 << IWX_RATE_MCS_VHT_POS)
+#define IWX_RATE_MCS_VHT_POS_V1 26
+#define IWX_RATE_MCS_VHT_MSK_V1 (1 << IWX_RATE_MCS_VHT_POS_V1)
 
 
 /*
@@ -4934,15 +4976,16 @@ enum {
  * streams and 16-23 have three streams. We could also support MCS 32
  * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.)
  */
-#define IWX_RATE_HT_MCS_RATE_CODE_MSK  0x7
-#define IWX_RATE_HT_MCS_NSS_POS             3
-#define IWX_RATE_HT_MCS_NSS_MSK             (3 << IWX_RATE_HT_MCS_NSS_POS)
+#define IWX_RATE_HT_MCS_RATE_CODE_MSK_V1       0x7
+#define IWX_RATE_HT_MCS_NSS_POS_V1             3
+#define IWX_RATE_HT_MCS_NSS_MSK_V1             (3 << 
IWX_RATE_HT_MCS_NSS_POS_V1)
+#define IWX_RATE_HT_MCS_MIMO2_MSK_V1           (1 << 
IWX_RATE_HT_MCS_NSS_POS_V1)
 
 /* Bit 10: (1) Use Green Field preamble */
 #define IWX_RATE_HT_MCS_GF_POS         10
 #define IWX_RATE_HT_MCS_GF_MSK         (1 << IWX_RATE_HT_MCS_GF_POS)
 
-#define IWX_RATE_HT_MCS_INDEX_MSK              0x3f
+#define IWX_RATE_HT_MCS_INDEX_MSK_V1           0x3f
 
 /*
  * Very High-throughput (VHT) rate format for bits 7:0
@@ -4958,6 +5001,7 @@ enum {
 #define IWX_RATE_VHT_MCS_RATE_CODE_MSK 0xf
 #define IWX_RATE_VHT_MCS_NSS_POS               4
 #define IWX_RATE_VHT_MCS_NSS_MSK               (3 << IWX_RATE_VHT_MCS_NSS_POS)
+#define IWX_RATE_VHT_MCS_MIMO2_MSK             (1 << IWX_RATE_VHT_MCS_NSS_POS)
 
 /*
  * Legacy OFDM rate format for bits 7:0
@@ -4981,57 +5025,244 @@ enum {
  *        110)  11 Mbps
  * (bit 7 is 0)
  */
-#define IWX_RATE_LEGACY_RATE_MSK 0xff
+#define IWX_RATE_LEGACY_RATE_MSK_V1 0xff
 
+/* Bit 10 - OFDM HE */
+#define IWX_RATE_MCS_HE_POS_V1 10
+#define IWX_RATE_MCS_HE_MSK_V1 (1 << RATE_MCS_HE_POS_V1)
 
 /*
  * Bit 11-12: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz
  * 0 and 1 are valid for HT and VHT, 2 and 3 only for VHT
  */
 #define IWX_RATE_MCS_CHAN_WIDTH_POS            11
-#define IWX_RATE_MCS_CHAN_WIDTH_MSK            (3 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
-#define IWX_RATE_MCS_CHAN_WIDTH_20             (0 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
-#define IWX_RATE_MCS_CHAN_WIDTH_40             (1 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
-#define IWX_RATE_MCS_CHAN_WIDTH_80             (2 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
-#define IWX_RATE_MCS_CHAN_WIDTH_160            (3 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_MSK_V1         (3 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_20_V1          (0 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_40_V1          (1 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_80_V1          (2 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_160_V1         (3 << 
IWX_RATE_MCS_CHAN_WIDTH_POS)
 
 /* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
-#define IWX_RATE_MCS_SGI_POS           13
-#define IWX_RATE_MCS_SGI_MSK           (1 << IWX_RATE_MCS_SGI_POS)
+#define IWX_RATE_MCS_SGI_POS_V1                13
+#define IWX_RATE_MCS_SGI_MSK_V1                (1 << IWX_RATE_MCS_SGI_POS_V1)
 
-/* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C */
+/* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C (unused) */
 #define IWX_RATE_MCS_ANT_POS           14
 #define IWX_RATE_MCS_ANT_A_MSK         (1 << IWX_RATE_MCS_ANT_POS)
 #define IWX_RATE_MCS_ANT_B_MSK         (2 << IWX_RATE_MCS_ANT_POS)
-#define IWX_RATE_MCS_ANT_C_MSK         (4 << IWX_RATE_MCS_ANT_POS)
 #define IWX_RATE_MCS_ANT_AB_MSK                (IWX_RATE_MCS_ANT_A_MSK | \
                                         IWX_RATE_MCS_ANT_B_MSK)
-#define IWX_RATE_MCS_ANT_ABC_MSK               (IWX_RATE_MCS_ANT_AB_MSK | \
-                                        IWX_RATE_MCS_ANT_C_MSK)
 #define IWX_RATE_MCS_ANT_MSK           IWX_RATE_MCS_ANT_ABC_MSK
-#define IWX_RATE_MCS_ANT_NUM 3
+#define IWX_RATE_MCS_ANT_NUM 2
 
-/* Bit 17-18: (0) SS, (1) SS*2 */
+/* Bit 17: (0) SS, (1) SS*2 */
 #define IWX_RATE_MCS_STBC_POS          17
 #define IWX_RATE_MCS_STBC_MSK          (1 << IWX_RATE_MCS_STBC_POS)
 
+/* Bit 18: OFDM-HE dual carrier mode */
+#define IWX_RATE_HE_DUAL_CARRIER_MODE  18
+#define IWX_RATE_HE_DUAL_CARRIER_MODE_MSK (1 << IWX_RATE_HE_DUAL_CARRIER_MODE)
+
 /* Bit 19: (0) Beamforming is off, (1) Beamforming is on */
 #define IWX_RATE_MCS_BF_POS                    19
 #define IWX_RATE_MCS_BF_MSK                    (1 << IWX_RATE_MCS_BF_POS)
 
-/* Bit 20: (0) ZLF is off, (1) ZLF is on */
-#define IWX_RATE_MCS_ZLF_POS           20
-#define IWX_RATE_MCS_ZLF_MSK           (1 << IWX_RATE_MCS_ZLF_POS)
+/*
+ * Bit 20-21: HE LTF type and guard interval
+ * HE (ext) SU:
+ *     0                       1xLTF+0.8us
+ *     1                       2xLTF+0.8us
+ *     2                       2xLTF+1.6us
+ *     3 & SGI (bit 13) clear  4xLTF+3.2us
+ *     3 & SGI (bit 13) set    4xLTF+0.8us
+ * HE MU:
+ *     0                       4xLTF+0.8us
+ *     1                       2xLTF+0.8us
+ *     2                       2xLTF+1.6us
+ *     3                       4xLTF+3.2us
+ * HE TRIG:
+ *     0                       1xLTF+1.6us
+ *     1                       2xLTF+1.6us
+ *     2                       4xLTF+3.2us
+ *     3                       (does not occur)
+ */
+#define IWX_RATE_MCS_HE_GI_LTF_POS     20
+#define IWX_RATE_MCS_HE_GI_LTF_MSK_V1  (3 << IWX_RATE_MCS_HE_GI_LTF_POS)
 
+/* Bit 22-23: HE type. (0) SU, (1) SU_EXT, (2) MU, (3) trigger based */
+#define IWX_RATE_MCS_HE_TYPE_POS_V1    22
+#define IWX_RATE_MCS_HE_TYPE_SU_V1     (0 << IWX_RATE_MCS_HE_TYPE_POS_V1)
+#define IWX_RATE_MCS_HE_TYPE_EXT_SU_V1 (1 << IWX_RATE_MCS_HE_TYPE_POS_V1)
+#define IWX_RATE_MCS_HE_TYPE_MU_V1     (2 << IWX_RATE_MCS_HE_TYPE_POS_V1)
+#define IWX_RATE_MCS_HE_TYPE_TRIG_V1   (3 << IWX_RATE_MCS_HE_TYPE_POS_V1)
+#define IWX_RATE_MCS_HE_TYPE_MSK_V1    (3 << IWX_RATE_MCS_HE_TYPE_POS_V1)
+
 /* Bit 24-25: (0) 20MHz (no dup), (1) 2x20MHz, (2) 4x20MHz, 3 8x20MHz */
-#define IWX_RATE_MCS_DUP_POS           24
-#define IWX_RATE_MCS_DUP_MSK           (3 << IWX_RATE_MCS_DUP_POS)
+#define IWX_RATE_MCS_DUP_POS_V1                24
+#define IWX_RATE_MCS_DUP_MSK_V1                (3 << IWX_RATE_MCS_DUP_POS_V1)
 
 /* Bit 27: (1) LDPC enabled, (0) LDPC disabled */
-#define IWX_RATE_MCS_LDPC_POS          27
-#define IWX_RATE_MCS_LDPC_MSK          (1 << IWX_RATE_MCS_LDPC_POS)
+#define IWX_RATE_MCS_LDPC_POS_V1       27
+#define IWX_RATE_MCS_LDPC_MSK_V1       (1 << IWX_RATE_MCS_LDPC_POS_V1)
 
+/* Bit 28: (1) 106-tone RX (8 MHz RU), (0) normal bandwidth */
+#define IWX_RATE_MCS_HE_106T_POS_V1    28
+#define IWX_RATE_MCS_HE_106T_MSK_V1    (1 << IWX_RATE_MCS_HE_106T_POS_V1)
 
+/* Bit 30-31: (1) RTS, (2) CTS */
+#define IWX_RATE_MCS_RTS_REQUIRED_POS  (30)
+#define IWX_RATE_MCS_RTS_REQUIRED_MSK  (1 << IWX_RATE_MCS_RTS_REQUIRED_POS)
+#define IWX_RATE_MCS_CTS_REQUIRED_POS  (31)
+#define IWX_RATE_MCS_CTS_REQUIRED_MSK  (1 << IWX_RATE_MCS_CTS_REQUIRED_POS)
+
+
+/* rate_n_flags bit field version 2
+ *
+ * The 32-bit value has different layouts in the low 8 bits depending on the
+ * format. There are three formats, HT, VHT and legacy (11abg, with subformats
+ * for CCK and OFDM).
+ *
+ */
+
+/* Bits 10-8: rate format
+ * (0) Legacy CCK (1) Legacy OFDM (2) High-throughput (HT)
+ * (3) Very High-throughput (VHT) (4) High-efficiency (HE)
+ * (5) Extremely High-throughput (EHT)
+ */
+#define IWX_RATE_MCS_MOD_TYPE_POS      8
+#define IWX_RATE_MCS_MOD_TYPE_MSK      (0x7 << IWX_RATE_MCS_MOD_TYPE_POS)
+#define IWX_RATE_MCS_CCK_MSK           (0 << IWX_RATE_MCS_MOD_TYPE_POS)
+#define IWX_RATE_MCS_LEGACY_OFDM_MSK   (1 << IWX_RATE_MCS_MOD_TYPE_POS)
+#define IWX_RATE_MCS_HT_MSK            (2 << IWX_RATE_MCS_MOD_TYPE_POS)
+#define IWX_RATE_MCS_VHT_MSK           (3 << IWX_RATE_MCS_MOD_TYPE_POS)
+#define IWX_RATE_MCS_HE_MSK            (4 << IWX_RATE_MCS_MOD_TYPE_POS)
+#define IWX_RATE_MCS_EHT_MSK           (5 << IWX_RATE_MCS_MOD_TYPE_POS)
+
+/*
+ * Legacy CCK rate format for bits 0:3:
+ *
+ * (0) 0xa - 1 Mbps
+ * (1) 0x14 - 2 Mbps
+ * (2) 0x37 - 5.5 Mbps
+ * (3) 0x6e - 11 nbps
+ *
+ * Legacy OFDM rate format for bits 0:3:
+ *
+ * (0) 6 Mbps
+ * (1) 9 Mbps
+ * (2) 12 Mbps
+ * (3) 18 Mbps
+ * (4) 24 Mbps
+ * (5) 36 Mbps
+ * (6) 48 Mbps
+ * (7) 54 Mbps
+ *
+ */
+#define IWX_RATE_LEGACY_RATE_MSK       0x7
+
+/*
+ * HT, VHT, HE, EHT rate format for bits 3:0
+ * 3-0: MCS
+ *
+ */
+#define IWX_RATE_HT_MCS_CODE_MSK       0x7
+#define IWX_RATE_MCS_NSS_POS           4
+#define IWX_RATE_MCS_NSS_MSK           (1 << IWX_RATE_MCS_NSS_POS)
+#define IWX_RATE_MCS_CODE_MSK          0xf
+#define IWX_RATE_HT_MCS_INDEX(r)       ((((r) & IWX_RATE_MCS_NSS_MSK) >> 1) | \
+                                        ((r) & IWX_RATE_HT_MCS_CODE_MSK))
+
+/* Bits 7-5: reserved */
+
+/*
+ * Bits 13-11: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz, (4) 320MHz
+ */
+#define IWX_RATE_MCS_CHAN_WIDTH_MSK    (0x7 << IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_20     (0 << IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_40     (1 << IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_80     (2 << IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_160    (3 << IWX_RATE_MCS_CHAN_WIDTH_POS)
+#define IWX_RATE_MCS_CHAN_WIDTH_320    (4 << IWX_RATE_MCS_CHAN_WIDTH_POS)
+
+/* Bit 15-14: Antenna selection:
+ * Bit 14: Ant A active
+ * Bit 15: Ant B active
+ *
+ * All relevant definitions are same as in v1
+ */
+
+/* Bit 16 (1) LDPC enables, (0) LDPC disabled */
+#define IWX_RATE_MCS_LDPC_POS  16
+#define IWX_RATE_MCS_LDPC_MSK  (1 << IWX_RATE_MCS_LDPC_POS)
+
+/* Bit 17: (0) SS, (1) SS*2 (same as v1) */
+
+/* Bit 18: OFDM-HE dual carrier mode (same as v1) */
+
+/* Bit 19: (0) Beamforming is off, (1) Beamforming is on (same as v1) */
+
+/*
+ * Bit 22-20: HE LTF type and guard interval
+ * CCK:
+ *     0                       long preamble
+ *     1                       short preamble
+ * HT/VHT:
+ *     0                       0.8us
+ *     1                       0.4us
+ * HE (ext) SU:
+ *     0                       1xLTF+0.8us
+ *     1                       2xLTF+0.8us
+ *     2                       2xLTF+1.6us
+ *     3                       4xLTF+3.2us
+ *     4                       4xLTF+0.8us
+ * HE MU:
+ *     0                       4xLTF+0.8us
+ *     1                       2xLTF+0.8us
+ *     2                       2xLTF+1.6us
+ *     3                       4xLTF+3.2us
+ * HE TRIG:
+ *     0                       1xLTF+1.6us
+ *     1                       2xLTF+1.6us
+ *     2                       4xLTF+3.2us
+ * */
+#define IWX_RATE_MCS_HE_GI_LTF_MSK     (0x7 << IWX_RATE_MCS_HE_GI_LTF_POS)
+#define IWX_RATE_MCS_SGI_POS           IWX_RATE_MCS_HE_GI_LTF_POS
+#define IWX_RATE_MCS_SGI_MSK           (1 << IWX_RATE_MCS_SGI_POS)
+#define IWX_RATE_MCS_HE_SU_4_LTF       3
+#define IWX_RATE_MCS_HE_SU_4_LTF_08_GI 4
+
+/* Bit 24-23: HE type. (0) SU, (1) SU_EXT, (2) MU, (3) trigger based */
+#define IWX_RATE_MCS_HE_TYPE_POS       23
+#define IWX_RATE_MCS_HE_TYPE_SU                (0 << IWX_RATE_MCS_HE_TYPE_POS)
+#define IWX_RATE_MCS_HE_TYPE_EXT_SU    (1 << IWX_RATE_MCS_HE_TYPE_POS)
+#define IWX_RATE_MCS_HE_TYPE_MU                (2 << IWX_RATE_MCS_HE_TYPE_POS)
+#define IWX_RATE_MCS_HE_TYPE_TRIG      (3 << IWX_RATE_MCS_HE_TYPE_POS)
+#define IWX_RATE_MCS_HE_TYPE_MSK       (3 << IWX_RATE_MCS_HE_TYPE_POS)
+
+/* Bit 25: duplicate channel enabled
+ *
+ * if this bit is set, duplicate is according to BW (bits 11-13):
+ *
+ * CCK:  2x 20MHz
+ * OFDM Legacy: N x 20Mhz, (N = BW \ 2 , either 2, 4, 8, 16)
+ * EHT: 2 x BW/2, (80 - 2x40, 160 - 2x80, 320 - 2x160)
+ * */
+#define IWX_RATE_MCS_DUP_POS           25
+#define IWX_RATE_MCS_DUP_MSK           (1 << IWX_RATE_MCS_DUP_POS)
+
+/* Bit 26: (1) 106-tone RX (8 MHz RU), (0) normal bandwidth */
+#define IWX_RATE_MCS_HE_106T_POS       26
+#define IWX_RATE_MCS_HE_106T_MSK       (1 << IWX_RATE_MCS_HE_106T_POS)
+
+/* Bit 27: EHT extra LTF:
+ * instead of 1 LTF for SISO use 2 LTFs,
+ * instead of 2 LTFs for NSTS=2 use 4 LTFs*/
+#define IWX_RATE_MCS_EHT_EXTRA_LTF_POS 27
+#define IWX_RATE_MCS_EHT_EXTRA_LTF_MSK (1 << IWX_RATE_MCS_EHT_EXTRA_LTF_POS)
+
+/* Bit 31-28: reserved */
+
+
 /* Link Quality definitions */
 
 /* # entries in rate scale table to support Tx retries */
@@ -5063,7 +5294,193 @@ enum {
 #define IWX_LQ_FLAG_DYNAMIC_BW_POS          6
 #define IWX_LQ_FLAG_DYNAMIC_BW_MSK          (1 << IWX_LQ_FLAG_DYNAMIC_BW_POS)
 
+#define IWX_RLC_CHAIN_INFO_DRIVER_FORCE                (1 << 0)
+#define IWL_RLC_CHAIN_INFO_VALID               0x000e
+#define IWL_RLC_CHAIN_INFO_FORCE               0x0070
+#define IWL_RLC_CHAIN_INFO_FORCE_MIMO          0x0380
+#define IWL_RLC_CHAIN_INFO_COUNT               0x0c00
+#define IWL_RLC_CHAIN_INFO_MIMO_COUNT          0x3000
+
 /**
+ * struct iwx_rlc_properties - RLC properties
+ * @rx_chain_info: RX chain info, IWX_RLC_CHAIN_INFO_*
+ * @reserved: reserved
+ */
+struct iwx_rlc_properties {
+       uint32_t rx_chain_info;
+       uint32_t reserved;
+} __packed; /* RLC_PROPERTIES_S_VER_1 */
+
+#define IWX_SAD_MODE_ENABLED           (1 << 0)
+#define IWX_SAD_MODE_DEFAULT_ANT_MSK   0x6
+#define IWX_SAD_MODE_DEFAULT_ANT_FW    0x0
+#define IWX_SAD_MODE_DEFAULT_ANT_A     0x2
+#define IWX_SAD_MODE_DEFAULT_ANT_B     0x4
+
+/**
+ * struct iwx_sad_properties - SAD properties
+ * @chain_a_sad_mode: chain A SAD mode, IWX_SAD_MODE_*
+ * @chain_b_sad_mode: chain B SAD mode, IWX_SAD_MODE_*
+ * @mac_id: MAC index
+ * @reserved: reserved
+ */
+struct iwx_sad_properties {
+       uint32_t chain_a_sad_mode;
+       uint32_t chain_b_sad_mode;
+       uint32_t mac_id;
+       uint32_t reserved;
+} __packed;
+
+/**
+ * struct iwx_rlc_config_cmd - RLC configuration
+ * @phy_id: PHY index
+ * @rlc: RLC properties, &struct iwx_rlc_properties
+ * @sad: SAD (single antenna diversity) options, &struct iwx_sad_properties
+ * @flags: flags, IWX_RLC_FLAGS_*
+ * @reserved: reserved
+ */
+struct iwx_rlc_config_cmd {
+       uint32_t phy_id;
+       struct iwx_rlc_properties rlc;
+       struct iwx_sad_properties sad;
+       uint8_t flags;
+       uint8_t reserved[3];
+} __packed; /* RLC_CONFIG_CMD_API_S_VER_2 */
+
+#define IWX_MAX_BAID_OLD       16 /* MAX_IMMEDIATE_BA_API_D_VER_2 */
+#define IWX_MAX_BAID           32 /* MAX_IMMEDIATE_BA_API_D_VER_3 */
+
+/**
+ * BAID allocation/config action
+ * @IWX_RX_BAID_ACTION_ADD: add a new BAID session
+ * @IWX_RX_BAID_ACTION_MODIFY: modify the BAID session
+ * @IWX_RX_BAID_ACTION_REMOVE: remove the BAID session
+ */
+#define IWX_RX_BAID_ACTION_ADD         0
+#define IWX_RX_BAID_ACTION_MODIFY      1
+#define IWX_RX_BAID_ACTION_REMOVE      2
+/*  RX_BAID_ALLOCATION_ACTION_E_VER_1 */
+
+/**
+ * struct iwx_rx_baid_cfg_cmd_alloc - BAID allocation data
+ * @sta_id_mask: station ID mask
+ * @tid: the TID for this session
+ * @reserved: reserved
+ * @ssn: the starting sequence number
+ * @win_size: RX BA session window size
+ */
+struct iwx_rx_baid_cfg_cmd_alloc {
+       uint32_t sta_id_mask;
+       uint8_t tid;
+       uint8_t reserved[3];
+       uint16_t ssn;
+       uint16_t win_size;
+} __packed; /* RX_BAID_ALLOCATION_ADD_CMD_API_S_VER_1 */
+
+/**
+ * struct iwx_rx_baid_cfg_cmd_modify - BAID modification data
+ * @old_sta_id_mask: old station ID mask
+ * @new_sta_id_mask: new station ID mask
+ * @tid: TID of the BAID
+ */
+struct iwx_rx_baid_cfg_cmd_modify {
+       uint32_t old_sta_id_mask;
+       uint32_t new_sta_id_mask;
+       uint32_t tid;
+} __packed; /* RX_BAID_ALLOCATION_MODIFY_CMD_API_S_VER_2 */
+
+/**
+ * struct iwx_rx_baid_cfg_cmd_remove_v1 - BAID removal data
+ * @baid: the BAID to remove
+ */
+struct iwx_rx_baid_cfg_cmd_remove_v1 {
+       uint32_t baid;
+} __packed; /* RX_BAID_ALLOCATION_REMOVE_CMD_API_S_VER_1 */
+
+/**
+ * struct iwx_rx_baid_cfg_cmd_remove - BAID removal data
+ * @sta_id_mask: the station mask of the BAID to remove
+ * @tid: the TID of the BAID to remove
+ */
+struct iwx_rx_baid_cfg_cmd_remove {
+       uint32_t sta_id_mask;
+       uint32_t tid;
+} __packed; /* RX_BAID_ALLOCATION_REMOVE_CMD_API_S_VER_2 */
+
+/**
+ * struct iwx_rx_baid_cfg_cmd - BAID allocation/config command
+ * @action: the action, from &enum iwx_rx_baid_action
+ */
+struct iwx_rx_baid_cfg_cmd {
+       uint32_t action;
+       union {
+               struct iwx_rx_baid_cfg_cmd_alloc alloc;
+               struct iwx_rx_baid_cfg_cmd_modify modify;
+               struct iwx_rx_baid_cfg_cmd_remove_v1 remove_v1;
+               struct iwx_rx_baid_cfg_cmd_remove remove;
+       }; /* RX_BAID_ALLOCATION_OPERATION_API_U_VER_2 */
+} __packed; /* RX_BAID_ALLOCATION_CONFIG_CMD_API_S_VER_2 */
+
+/**
+ * struct iwx_rx_baid_cfg_resp - BAID allocation response
+ * @baid: the allocated BAID
+ */
+struct iwx_rx_baid_cfg_resp {
+       uint32_t baid;
+}; /* RX_BAID_ALLOCATION_RESPONSE_API_S_VER_1 */
+
+/**
+ * scheduler queue operation
+ * @IWX_SCD_QUEUE_ADD: allocate a new queue
+ * @IWX_SCD_QUEUE_REMOVE: remove a queue
+ * @IWX_SCD_QUEUE_MODIFY: modify a queue
+ */
+#define IWX_SCD_QUEUE_ADD      0
+#define IWX_SCD_QUEUE_REMOVE   1
+#define IWX_SCD_QUEUE_MODIFY   2
+
+/**
+ * struct iwx_scd_queue_cfg_cmd - scheduler queue allocation command
+ * @operation: the operation, see &enum iwl_scd_queue_cfg_operation
+ * @u.add.sta_mask: station mask
+ * @u.add.tid: TID
+ * @u.add.reserved: reserved
+ * @u.add.flags: flags from &enum iwl_tx_queue_cfg_actions, except
+ *     %TX_QUEUE_CFG_ENABLE_QUEUE is not valid
+ * @u.add.cb_size: size code
+ * @u.add.bc_dram_addr: byte-count table IOVA
+ * @u.add.tfdq_dram_addr: TFD queue IOVA
+ * @u.remove.sta_mask: station mask of queue to remove
+ * @u.remove.tid: TID of queue to remove
+ * @u.modify.old_sta_mask: old station mask for modify
+ * @u.modify.tid: TID of queue to modify
+ * @u.modify.new_sta_mask: new station mask for modify
+ */
+struct iwx_scd_queue_cfg_cmd {
+       uint32_t operation;
+       union {
+               struct {
+                       uint32_t sta_mask;
+                       uint8_t tid;
+                       uint8_t reserved[3];
+                       uint32_t flags;
+                       uint32_t cb_size;
+                       uint64_t bc_dram_addr;
+                       uint64_t tfdq_dram_addr;
+               } __packed add; /* TX_QUEUE_CFG_CMD_ADD_API_S_VER_1 */
+               struct {
+                       uint32_t sta_mask;
+                       uint32_t tid;
+               } __packed remove; /* TX_QUEUE_CFG_CMD_REMOVE_API_S_VER_1 */
+               struct {
+                       uint32_t old_sta_mask;
+                       uint32_t tid;
+                       uint32_t new_sta_mask;
+               } __packed modify; /* TX_QUEUE_CFG_CMD_MODIFY_API_S_VER_1 */
+       } __packed u; /* TX_QUEUE_CFG_CMD_OPERATION_API_U_VER_1 */
+} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_3 */
+
+/**
  * Options for TLC config flags
  * @IWX_TLC_MNG_CFG_FLAGS_STBC_MSK: enable STBC. For HE this enables STBC for
  *                                 bandwidths <= 80MHz
@@ -5089,14 +5506,14 @@ enum {
  * @IWX_TLC_MNG_CH_WIDTH_40MHZ: 40MHZ channel
  * @IWX_TLC_MNG_CH_WIDTH_80MHZ: 80MHZ channel
  * @IWX_TLC_MNG_CH_WIDTH_160MHZ: 160MHZ channel
- * @IWX_TLC_MNG_CH_WIDTH_LAST: maximum value
+ * @IWX_TLC_MNG_CH_WIDTH_320MHZ: 320MHZ channel
  */
 enum iwx_tlc_mng_cfg_cw {
        IWX_TLC_MNG_CH_WIDTH_20MHZ,
        IWX_TLC_MNG_CH_WIDTH_40MHZ,
        IWX_TLC_MNG_CH_WIDTH_80MHZ,
        IWX_TLC_MNG_CH_WIDTH_160MHZ,
-       IWX_TLC_MNG_CH_WIDTH_LAST = IWX_TLC_MNG_CH_WIDTH_160MHZ,
+       IWX_TLC_MNG_CH_WIDTH_320MHZ,
 };
 
 /**
@@ -5114,8 +5531,7 @@ enum iwx_tlc_mng_cfg_cw {
  * @IWX_TLC_MNG_MODE_HT: enable HT
  * @IWX_TLC_MNG_MODE_VHT: enable VHT
  * @IWX_TLC_MNG_MODE_HE: enable HE
- * @IWX_TLC_MNG_MODE_INVALID: invalid value
- * @IWX_TLC_MNG_MODE_NUM: a count of possible modes
+ * @IWX_TLC_MNG_MODE_EHT: enable EHT
  */
 enum iwx_tlc_mng_cfg_mode {
        IWX_TLC_MNG_MODE_CCK = 0,
@@ -5124,8 +5540,7 @@ enum iwx_tlc_mng_cfg_mode {
        IWX_TLC_MNG_MODE_HT,
        IWX_TLC_MNG_MODE_VHT,
        IWX_TLC_MNG_MODE_HE,
-       IWX_TLC_MNG_MODE_INVALID,
-       IWX_TLC_MNG_MODE_NUM = IWX_TLC_MNG_MODE_INVALID,
+       IWX_TLC_MNG_MODE_EHT,
 };
 
 /**
@@ -5163,11 +5578,23 @@ enum iwx_tlc_mng_ht_rates {
 #define IWX_TLC_NSS_2  1
 #define IWX_TLC_NSS_MAX        2
 
-#define IWX_TLC_HT_BW_NONE_160 0
-#define IWX_TLC_HT_BW_160      1
 
 /**
- * struct iwx_tlc_config_cmd - TLC configuration
+ * IWX_TLC_MCS_PER_BW - mcs index per BW
+ * @IWX_TLC_MCS_PER_BW_80: mcs for bw - 20Hhz, 40Hhz, 80Hhz
+ * @IWX_TLC_MCS_PER_BW_160: mcs for bw - 160Mhz
+ * @IWX_TLC_MCS_PER_BW_320: mcs for bw - 320Mhz
+ * @IWX_TLC_MCS_PER_BW_NUM_V3: number of entries up to version 3
+ * @IWX_TLC_MCS_PER_BW_NUM_V4: number of entries from version 4
+ */
+#define IWX_TLC_MCS_PER_BW_80  0
+#define IWX_TLC_MCS_PER_BW_160 1
+#define IWX_TLC_MCS_PER_BW_320  2
+#define IWX_TLC_MCS_PER_BW_NUM_V3      (IWX_TLC_MCS_PER_BW_160 + 1)
+#define IWX_TLC_MCS_PER_BW_NUM_V4      (IWX_TLC_MCS_PER_BW_320 + 1)
+
+/**
+ * struct iwx_tlc_config_cmd_v3 - TLC configuration version 3
  * @sta_id: station id
  * @reserved1: reserved
  * @max_ch_width: max supported channel width from @enum iwx_tlc_mng_cfg_cw
@@ -5176,16 +5603,16 @@ enum iwx_tlc_mng_ht_rates {
  * @amsdu: 1 = TX amsdu is supported, 0 = not supported
  * @flags: bitmask of IWX_TLC_MNG_CFG_*
  * @non_ht_rates: bitmap of supported legacy rates
- * @ht_rates: bitmap of &enum iwx_tlc_mng_ht_rates, per <nss, channel-width>
+ * @ht_rates: MCS index 0 - 11, per <nss, channel-width>
  *           pair (0 - 80mhz width and below, 1 - 160mhz).
  * @max_mpdu_len: max MPDU length, in bytes
  * @sgi_ch_width_supp: bitmap of SGI support per channel width
- *                    use (1 << @enum iwx_tlc_mng_cfg_cw)
+ *                    use (1 << IWX_TLC_MNG_CFG_CW_*)
  * @reserved2: reserved
  * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI),
  *            set zero for no limit.
  */
-struct iwx_tlc_config_cmd {
+struct iwx_tlc_config_cmd_v3 {
        uint8_t sta_id;
        uint8_t reserved1[3];
        uint8_t max_ch_width;
@@ -5194,7 +5621,7 @@ struct iwx_tlc_config_cmd {
        uint8_t amsdu;
        uint16_t flags;
        uint16_t non_ht_rates;
-       uint16_t ht_rates[IWX_TLC_NSS_MAX][2];
+       uint16_t ht_rates[IWX_TLC_NSS_MAX][IWX_TLC_MCS_PER_BW_NUM_V3];
        uint16_t max_mpdu_len;
        uint8_t sgi_ch_width_supp;
        uint8_t reserved2;
@@ -5202,6 +5629,37 @@ struct iwx_tlc_config_cmd {
 } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_3 */
 
 /**
+ * struct iwx_tlc_config_cmd_v4 - TLC configuration
+ * @sta_id: station id
+ * @reserved1: reserved
+ * @max_ch_width: max supported channel width from @enum iwx_tlc_mng_cfg_cw
+ * @mode: &enum iwx_tlc_mng_cfg_mode
+ * @chains: bitmask of IWX_TLC_MNG_CHAIN_*_MSK
+ * @sgi_ch_width_supp: bitmap of SGI support per channel width
+ *                    use (1 << IWX_TLC_MNG_CFG_CW_*)
+ * @flags: bitmask of IWX_TLC_MNG_CFG_*
+ * @non_ht_rates: bitmap of supported legacy rates
+ * @ht_rates: MCS index 0 - 11, per <nss, channel-width>
+ *           pair (0 - 80mhz width and below, 1 - 160mhz, 2 - 320mhz).
+ * @max_mpdu_len: max MPDU length, in bytes
+ * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI),
+ *            set zero for no limit.
+ */
+struct iwx_tlc_config_cmd_v4 {
+       uint8_t sta_id;
+       uint8_t reserved1[3];
+       uint8_t max_ch_width;
+       uint8_t mode;
+       uint8_t chains;
+       uint8_t sgi_ch_width_supp;
+       uint16_t flags;
+       uint16_t non_ht_rates;
+       uint16_t ht_rates[IWX_TLC_NSS_MAX][IWX_TLC_MCS_PER_BW_NUM_V4];
+       uint16_t max_mpdu_len;
+       uint16_t max_tx_op;
+} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_4 */
+
+/**
  * @IWX_TLC_NOTIF_FLAG_RATE: last initial rate update
  * @IWX_TLC_NOTIF_FLAG_AMSDU: umsdu parameters update
  */
@@ -5213,7 +5671,8 @@ struct iwx_tlc_config_cmd {
  * @sta_id: station id
  * @reserved: reserved
  * @flags: bitmap of notifications reported
- * @rate: current initial rate
+ * @rate: current initial rate; using rate_n_flags version 1 if notification
+ *  version is < 3 at run-time, else rate_n_flags version 2
  * @amsdu_size: Max AMSDU size, in bytes
  * @amsdu_enabled: bitmap for per-TID AMSDU enablement
  */
@@ -5344,10 +5803,14 @@ struct iwx_dram_sec_info {
  * @IWX_TX_FLAGS_HIGH_PRI: high priority frame (like EAPOL) - can affect rate
  *     selection, retry limits and BT kill
  */
+/* Valid for TX_FLAGS_BITS_API_S_VER_3: */
 #define IWX_TX_FLAGS_CMD_RATE          (1 << 0)
 #define IWX_TX_FLAGS_ENCRYPT_DIS       (1 << 1)
 #define IWX_TX_FLAGS_HIGH_PRI          (1 << 2)
-/* TX_FLAGS_BITS_API_S_VER_3 */
+/* Valid for TX_FLAGS_BITS_API_S_VER_4 and above: */
+#define IWX_TX_FLAGS_RTS               (1 << 3)
+#define IWX_TX_FLAGS_CTS               (1 << 4)
+/* TX_FLAGS_BITS_API_S_VER_4 */
 
 /**
  * struct iwx_tx_cmd_gen2 - TX command struct to FW for 22000 devices
blob - 6468bfec46e5cfe443f6444392fb1b3b018ff429
blob + 447e193b19ad0c58676e91bf48e180221d4236c4
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -123,7 +123,7 @@ struct iwx_tx_radiotap_header {
         (1 << IEEE80211_RADIOTAP_RATE) |                               \
         (1 << IEEE80211_RADIOTAP_CHANNEL))
 
-#define IWX_UCODE_SECT_MAX 54
+#define IWX_UCODE_SECT_MAX 57
 
 /*
  * fw_status is used to determine if we've already parsed the firmware file
@@ -471,21 +471,21 @@ struct iwx_device_cfg {
 };
 
 /* Firmware listed here must be available in fw_update(8). */
-#define IWX_CC_A_FW            "iwx-cc-a0-67"
-#define IWX_TY_A_GF_A_FW       "iwx-ty-a0-gf-a0-67"
+#define IWX_CC_A_FW            "iwx-cc-a0-77"
+#define IWX_TY_A_GF_A_FW       "iwx-ty-a0-gf-a0-77"
 #define IWX_TY_A_GF_A_PNVM     "iwx-ty-a0-gf-a0.pnvm"
-#define IWX_QU_B_HR_B_FW       "iwx-Qu-b0-hr-b0-63"
-#define IWX_QU_B_JF_B_FW       "iwx-Qu-b0-jf-b0-63"
-#define IWX_QU_C_HR_B_FW       "iwx-Qu-c0-hr-b0-63"
-#define IWX_QU_C_JF_B_FW       "iwx-Qu-c0-jf-b0-63"
-#define IWX_QUZ_A_HR_B_FW      "iwx-QuZ-a0-hr-b0-67"
-#define IWX_QUZ_A_JF_B_FW      "iwx-QuZ-a0-jf-b0-63"
-#define IWX_SO_A_GF_A_FW       "iwx-so-a0-gf-a0-67"
+#define IWX_QU_B_HR_B_FW       "iwx-Qu-b0-hr-b0-77"
+#define IWX_QU_B_JF_B_FW       "iwx-Qu-b0-jf-b0-77"
+#define IWX_QU_C_HR_B_FW       "iwx-Qu-c0-hr-b0-77"
+#define IWX_QU_C_JF_B_FW       "iwx-Qu-c0-jf-b0-77"
+#define IWX_QUZ_A_HR_B_FW      "iwx-QuZ-a0-hr-b0-77"
+#define IWX_QUZ_A_JF_B_FW      "iwx-QuZ-a0-jf-b0-77"
+#define IWX_SO_A_GF_A_FW       "iwx-so-a0-gf-a0-77"
 #define IWX_SO_A_GF_A_PNVM     "iwx-so-a0-gf-a0.pnvm"
-#define IWX_SO_A_GF4_A_FW      "iwx-so-a0-gf4-a0-67"
+#define IWX_SO_A_GF4_A_FW      "iwx-so-a0-gf4-a0-77"
 #define IWX_SO_A_GF4_A_PNVM    "iwx-so-a0-gf4-a0.pnvm"
-#define IWX_SO_A_HR_B_FW       "iwx-so-a0-hr-b0-64"
-#define IWX_SO_A_JF_B_FW       "iwx-so-a0-jf-b0-64"
+#define IWX_SO_A_HR_B_FW       "iwx-so-a0-hr-b0-77"
+#define IWX_SO_A_JF_B_FW       "iwx-so-a0-jf-b0-77"
 
 const struct iwx_device_cfg iwx_9560_quz_a0_jf_b0_cfg = {
        .fw_name = IWX_QUZ_A_JF_B_FW,
@@ -712,6 +712,7 @@ struct iwx_softc {
 #define IWX_MAX_FW_CMD_VERSIONS        704
        struct iwx_fw_cmd_version cmd_versions[IWX_MAX_FW_CMD_VERSIONS];
        int n_cmd_versions;
+       int sc_rate_n_flags_version;
 
        int sc_intmask;
        int sc_flags;
@@ -746,8 +747,6 @@ struct iwx_softc {
 
        int sc_scan_last_antenna;
 
-       int sc_fixed_ridx;
-
        int sc_staid;
        int sc_nodecolor;
 
@@ -759,7 +758,6 @@ struct iwx_softc {
 
        struct iwx_rx_phy_info sc_last_phy_info;
        int sc_ampdu_ref;
-#define IWX_MAX_BAID   32
        struct iwx_rxba_data sc_rxba_data[IWX_MAX_BAID];
 
        uint32_t sc_time_event_uid;


Reply via email to