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